From c342d6c1517ab16a7ac2c2e1211249339d8b6929 Mon Sep 17 00:00:00 2001 From: Chris Park Date: Wed, 27 Jan 2016 16:14:24 -0500 Subject: [PATCH 0745/1110] drm/amd/dal: Relocate dcs to core Ddc service and I2caux helper moved to dc_link_ddc. Signed-off-by: Chris Park Acked-by: Harry Wentland --- drivers/gpu/drm/amd/dal/dc/Makefile | 4 +- drivers/gpu/drm/amd/dal/dc/core/dc.c | 2 +- drivers/gpu/drm/amd/dal/dc/core/dc_link.c | 2 +- drivers/gpu/drm/amd/dal/dc/core/dc_link_ddc.c | 1151 ++++++++++++++++++++ drivers/gpu/drm/amd/dal/dc/core/dc_link_dp.c | 2 +- drivers/gpu/drm/amd/dal/dc/core/dc_link_hwss.c | 2 +- drivers/gpu/drm/amd/dal/dc/dcs/Makefile | 10 - drivers/gpu/drm/amd/dal/dc/dcs/ddc_i2caux_helper.c | 159 --- drivers/gpu/drm/amd/dal/dc/dcs/ddc_i2caux_helper.h | 60 - drivers/gpu/drm/amd/dal/dc/dcs/ddc_service.c | 1036 ------------------ drivers/gpu/drm/amd/dal/dc/dcs/ddc_service.h | 49 - drivers/gpu/drm/amd/dal/dc/inc/dc_link_ddc.h | 151 +++ .../drm/amd/dal/include/ddc_service_interface.h | 100 -- 13 files changed, 1308 insertions(+), 1420 deletions(-) create mode 100644 drivers/gpu/drm/amd/dal/dc/core/dc_link_ddc.c delete mode 100644 drivers/gpu/drm/amd/dal/dc/dcs/Makefile delete mode 100644 drivers/gpu/drm/amd/dal/dc/dcs/ddc_i2caux_helper.c delete mode 100644 drivers/gpu/drm/amd/dal/dc/dcs/ddc_i2caux_helper.h delete mode 100644 drivers/gpu/drm/amd/dal/dc/dcs/ddc_service.c delete mode 100644 drivers/gpu/drm/amd/dal/dc/dcs/ddc_service.h create mode 100644 drivers/gpu/drm/amd/dal/dc/inc/dc_link_ddc.h delete mode 100644 drivers/gpu/drm/amd/dal/include/ddc_service_interface.h diff --git a/drivers/gpu/drm/amd/dal/dc/Makefile b/drivers/gpu/drm/amd/dal/dc/Makefile index 4396203..aed26ee 100644 --- a/drivers/gpu/drm/amd/dal/dc/Makefile +++ b/drivers/gpu/drm/amd/dal/dc/Makefile @@ -3,7 +3,7 @@ # DC_LIBS = adapter asic_capability audio basics bios calcs \ -dcs gpio gpu i2caux irq virtual +gpio gpu i2caux irq virtual ifdef CONFIG_DRM_AMD_DAL_DCE11_0 DC_LIBS += dce110 @@ -18,7 +18,7 @@ AMD_DC = $(addsuffix /Makefile, $(addprefix $(FULL_AMD_DAL_PATH)/dc/,$(DC_LIBS)) include $(AMD_DC) DISPLAY_CORE = dc.o dc_link.o dc_resource.o dc_target.o dc_sink.o dc_stream.o \ -dc_hw_sequencer.o dc_surface.o dc_link_hwss.o dc_link_dp.o +dc_hw_sequencer.o dc_surface.o dc_link_hwss.o dc_link_dp.o dc_link_ddc.o AMD_DISPLAY_CORE = $(addprefix $(AMDDALPATH)/dc/core/,$(DISPLAY_CORE)) diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc.c b/drivers/gpu/drm/amd/dal/dc/core/dc.c index b3c919c..770a66c 100644 --- a/drivers/gpu/drm/amd/dal/dc/core/dc.c +++ b/drivers/gpu/drm/amd/dal/dc/core/dc.c @@ -45,7 +45,7 @@ #include "link_hwss.h" #include "link_encoder.h" -#include "dcs/ddc_service.h" +#include "dc_link_ddc.h" /******************************************************************************* * Private structures diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_link.c b/drivers/gpu/drm/amd/dal/dc/core/dc_link.c index c81f4a2..71653fa 100644 --- a/drivers/gpu/drm/amd/dal/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/dal/dc/core/dc_link.c @@ -30,9 +30,9 @@ #include "adapter_service_interface.h" #include "grph_object_id.h" #include "gpio_service_interface.h" -#include "ddc_service_interface.h" #include "core_status.h" #include "dc_link_dp.h" +#include "dc_link_ddc.h" #include "link_hwss.h" #include "stream_encoder.h" #include "link_encoder.h" diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/dal/dc/core/dc_link_ddc.c new file mode 100644 index 0000000..60fc743 --- /dev/null +++ b/drivers/gpu/drm/amd/dal/dc/core/dc_link_ddc.c @@ -0,0 +1,1151 @@ +/* + * 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 "dc_services.h" + +#include "include/adapter_service_interface.h" +#include "include/ddc_service_types.h" +#include "include/grph_object_id.h" +#include "include/dpcd_defs.h" +#include "include/logger_interface.h" +#include "include/vector.h" + +#include "dc_link_ddc.h" + +#define AUX_POWER_UP_WA_DELAY 500 +#define I2C_OVER_AUX_DEFER_WA_DELAY 70 + +/* CV smart dongle slave address for retrieving supported HDTV modes*/ +#define CV_SMART_DONGLE_ADDRESS 0x20 +/* DVI-HDMI dongle slave address for retrieving dongle signature*/ +#define DVI_HDMI_DONGLE_ADDRESS 0x68 +static const int8_t dvi_hdmi_dongle_signature_str[] = "6140063500G"; +struct dvi_hdmi_dongle_signature_data { + int8_t vendor[3];/* "AMD" */ + uint8_t version[2]; + uint8_t size; + int8_t id[11];/* "6140063500G"*/ +}; +/* DP-HDMI dongle slave address for retrieving dongle signature*/ +#define DP_HDMI_DONGLE_ADDRESS 0x40 +static const uint8_t dp_hdmi_dongle_signature_str[] = "DP-HDMI ADAPTOR"; +#define DP_HDMI_DONGLE_SIGNATURE_EOT 0x04 + +struct dp_hdmi_dongle_signature_data { + int8_t id[15];/* "DP-HDMI ADAPTOR"*/ + uint8_t eot;/* end of transmition '\x4' */ +}; + +/* Address range from 0x00 to 0x1F.*/ +#define DP_ADAPTOR_TYPE2_SIZE 0x20 +#define DP_ADAPTOR_TYPE2_REG_ID 0x10 +#define DP_ADAPTOR_TYPE2_REG_MAX_TMDS_CLK 0x1D +/* Identifies adaptor as Dual-mode adaptor */ +#define DP_ADAPTOR_TYPE2_ID 0xA0 +/* MHz*/ +#define DP_ADAPTOR_TYPE2_MAX_TMDS_CLK 600 +/* MHz*/ +#define DP_ADAPTOR_TYPE2_MIN_TMDS_CLK 25 +/* kHZ*/ +#define DP_ADAPTOR_DVI_MAX_TMDS_CLK 165000 +/* kHZ*/ +#define DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK 165000 + +#define DDC_I2C_COMMAND_ENGINE I2C_COMMAND_ENGINE_SW + +enum edid_read_result { + EDID_READ_RESULT_EDID_MATCH = 0, + EDID_READ_RESULT_EDID_MISMATCH, + EDID_READ_RESULT_CHECKSUM_READ_ERR, + EDID_READ_RESULT_VENDOR_READ_ERR +}; + +/* SCDC Address defines (HDMI 2.0)*/ +#define HDMI_SCDC_WRITE_UPDATE_0_ARRAY 3 +#define HDMI_SCDC_ADDRESS 0x54 +#define HDMI_SCDC_SINK_VERSION 0x01 +#define HDMI_SCDC_SOURCE_VERSION 0x02 +#define HDMI_SCDC_UPDATE_0 0x10 +#define HDMI_SCDC_TMDS_CONFIG 0x20 +#define HDMI_SCDC_SCRAMBLER_STATUS 0x21 +#define HDMI_SCDC_CONFIG_0 0x30 +#define HDMI_SCDC_STATUS_FLAGS 0x40 +#define HDMI_SCDC_ERR_DETECT 0x50 +#define HDMI_SCDC_TEST_CONFIG 0xC0 + + +union hdmi_scdc_update_read_data { + uint8_t byte[2]; + struct { + uint8_t STATUS_UPDATE:1; + uint8_t CED_UPDATE:1; + uint8_t RR_TEST:1; + uint8_t RESERVED:5; + uint8_t RESERVED2:8; + } fields; +}; + +union hdmi_scdc_status_flags_data { + uint8_t byte[2]; + struct { + uint8_t CLOCK_DETECTED:1; + uint8_t CH0_LOCKED:1; + uint8_t CH1_LOCKED:1; + uint8_t CH2_LOCKED:1; + uint8_t RESERVED:4; + uint8_t RESERVED2:8; + } fields; +}; + +union hdmi_scdc_ced_data { + uint8_t byte[7]; + struct { + uint8_t CH0_8LOW:8; + uint8_t CH0_7HIGH:7; + uint8_t CH0_VALID:1; + uint8_t CH1_8LOW:8; + uint8_t CH1_7HIGH:7; + uint8_t CH1_VALID:1; + uint8_t CH2_8LOW:8; + uint8_t CH2_7HIGH:7; + uint8_t CH2_VALID:1; + uint8_t CHECKSUM:8; + } fields; +}; + +union hdmi_scdc_test_config_Data { + uint8_t byte; + struct { + uint8_t TEST_READ_REQUEST_DELAY:7; + uint8_t TEST_READ_REQUEST: 1; + } fields; +}; + + + +union ddc_wa { + struct { + uint32_t DP_SKIP_POWER_OFF:1; + uint32_t DP_AUX_POWER_UP_WA_DELAY:1; + } bits; + uint32_t raw; +}; + +struct ddc_flags { + uint8_t EDID_QUERY_DONE_ONCE:1; + uint8_t IS_INTERNAL_DISPLAY:1; + uint8_t FORCE_READ_REPEATED_START:1; + uint8_t EDID_STRESS_READ:1; + +}; + +struct ddc_service { + struct ddc *ddc_pin; + struct ddc_flags flags; + union ddc_wa wa; + enum ddc_transaction_type transaction_type; + enum display_dongle_type dongle_type; + struct dp_receiver_id_info dp_receiver_id_info; + struct adapter_service *as; + struct dc_context *ctx; + + uint32_t address; + uint32_t edid_buf_len; + uint8_t edid_buf[MAX_EDID_BUFFER_SIZE]; +}; + +struct i2c_payloads { + struct vector payloads; +}; + +struct aux_payloads { + struct vector payloads; +}; + +struct i2c_payloads *dal_ddc_i2c_payloads_create(struct dc_context *ctx, uint32_t count) +{ + struct i2c_payloads *payloads; + + payloads = dc_service_alloc(ctx, sizeof(struct i2c_payloads)); + + if (!payloads) + return NULL; + + if (dal_vector_construct( + &payloads->payloads, ctx, count, sizeof(struct i2c_payload))) + return payloads; + + dc_service_free(ctx, payloads); + return NULL; + +} + +struct i2c_payload *dal_ddc_i2c_payloads_get(struct i2c_payloads *p) +{ + return (struct i2c_payload *)p->payloads.container; +} + +uint32_t dal_ddc_i2c_payloads_get_count(struct i2c_payloads *p) +{ + return p->payloads.count; +} + +void dal_ddc_i2c_payloads_destroy(struct i2c_payloads **p) +{ + if (!p || !*p) + return; + dal_vector_destruct(&(*p)->payloads); + dc_service_free((*p)->payloads.ctx, *p); + *p = NULL; + +} + +struct aux_payloads *dal_ddc_aux_payloads_create(struct dc_context *ctx, uint32_t count) +{ + struct aux_payloads *payloads; + + payloads = dc_service_alloc(ctx, sizeof(struct aux_payloads)); + + if (!payloads) + return NULL; + + if (dal_vector_construct( + &payloads->payloads, ctx, count, sizeof(struct aux_payloads))) + return payloads; + + dc_service_free(ctx, payloads); + return NULL; +} + +struct aux_payload *dal_ddc_aux_payloads_get(struct aux_payloads *p) +{ + return (struct aux_payload *)p->payloads.container; +} + +uint32_t dal_ddc_aux_payloads_get_count(struct aux_payloads *p) +{ + return p->payloads.count; +} + + +void dal_ddc_aux_payloads_destroy(struct aux_payloads **p) +{ + if (!p || !*p) + return; + + dal_vector_destruct(&(*p)->payloads); + dc_service_free((*p)->payloads.ctx, *p); + *p = NULL; +} + +#define DDC_MIN(a, b) (((a) < (b)) ? (a) : (b)) + +void dal_ddc_i2c_payloads_add( + struct i2c_payloads *payloads, + uint32_t address, + uint32_t len, + uint8_t *data, + bool write) +{ + uint32_t payload_size = EDID_SEGMENT_SIZE; + uint32_t pos; + + for (pos = 0; pos < len; pos += payload_size) { + struct i2c_payload payload = { + .write = write, + .address = address, + .length = DDC_MIN(payload_size, len - pos), + .data = data + pos }; + dal_vector_append(&payloads->payloads, &payload); + } + +} + +void dal_ddc_aux_payloads_add( + struct aux_payloads *payloads, + uint32_t address, + uint32_t len, + uint8_t *data, + bool write) +{ + uint32_t payload_size = DEFAULT_AUX_MAX_DATA_SIZE; + uint32_t pos; + + for (pos = 0; pos < len; pos += payload_size) { + struct aux_payload payload = { + .i2c_over_aux = true, + .write = write, + .address = address, + .length = DDC_MIN(payload_size, len - pos), + .data = data + pos }; + dal_vector_append(&payloads->payloads, &payload); + } +} + + +static bool construct( + struct ddc_service *ddc_service, + struct ddc_service_init_data *init_data) +{ + enum connector_id connector_id = + dal_graphics_object_id_get_connector_id(init_data->id); + + ddc_service->ctx = init_data->ctx; + ddc_service->as = init_data->as; + ddc_service->ddc_pin = dal_adapter_service_obtain_ddc( + init_data->as, init_data->id); + + ddc_service->flags.EDID_QUERY_DONE_ONCE = false; + + ddc_service->flags.FORCE_READ_REPEATED_START = + dal_adapter_service_is_feature_supported( + FEATURE_DDC_READ_FORCE_REPEATED_START); + + ddc_service->flags.EDID_STRESS_READ = + dal_adapter_service_is_feature_supported( + FEATURE_EDID_STRESS_READ); + + + ddc_service->flags.IS_INTERNAL_DISPLAY = + connector_id == CONNECTOR_ID_EDP || + connector_id == CONNECTOR_ID_LVDS; + + ddc_service->wa.raw = 0; + return true; +} + +struct ddc_service *dal_ddc_service_create( + struct ddc_service_init_data *init_data) +{ + struct ddc_service *ddc_service; + + ddc_service = dc_service_alloc(init_data->ctx, sizeof(struct ddc_service)); + + if (!ddc_service) + return NULL; + + if (construct(ddc_service, init_data)) + return ddc_service; + + dc_service_free(init_data->ctx, ddc_service); + return NULL; +} + +static void destruct(struct ddc_service *ddc) +{ + if (ddc->ddc_pin) + dal_adapter_service_release_ddc(ddc->as, ddc->ddc_pin); +} + +void dal_ddc_service_destroy(struct ddc_service **ddc) +{ + if (!ddc || !*ddc) { + BREAK_TO_DEBUGGER(); + return; + } + destruct(*ddc); + dc_service_free((*ddc)->ctx, *ddc); + *ddc = NULL; +} + +enum ddc_service_type dal_ddc_service_get_type(struct ddc_service *ddc) +{ + return DDC_SERVICE_TYPE_CONNECTOR; +} + +void dal_ddc_service_set_transaction_type( + struct ddc_service *ddc, + enum ddc_transaction_type type) +{ + ddc->transaction_type = type; +} + +bool dal_ddc_service_is_in_aux_transaction_mode(struct ddc_service *ddc) +{ + switch (ddc->transaction_type) { + case DDC_TRANSACTION_TYPE_I2C_OVER_AUX: + case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_WITH_DEFER: + case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_RETRY_DEFER: + return true; + default: + break; + } + return false; +} + +void ddc_service_set_dongle_type(struct ddc_service *ddc, + enum display_dongle_type dongle_type) +{ + ddc->dongle_type = dongle_type; +} + +static uint32_t defer_delay_converter_wa( + struct ddc_service *ddc, + uint32_t defer_delay) +{ + struct dp_receiver_id_info dp_rec_info = {0}; + + if (dal_ddc_service_get_dp_receiver_id_info(ddc, &dp_rec_info) && + (dp_rec_info.branch_id == DP_BRANCH_DEVICE_ID_4) && + !dal_strncmp(dp_rec_info.branch_name, + DP_DVI_CONVERTER_ID_4, + sizeof(dp_rec_info.branch_name))) + return defer_delay > I2C_OVER_AUX_DEFER_WA_DELAY ? + defer_delay : I2C_OVER_AUX_DEFER_WA_DELAY; + + return defer_delay; + +} + +#define DP_TRANSLATOR_DELAY 5 + +static uint32_t get_defer_delay(struct ddc_service *ddc) +{ + uint32_t defer_delay = 0; + + switch (ddc->transaction_type) { + case DDC_TRANSACTION_TYPE_I2C_OVER_AUX: + if ((DISPLAY_DONGLE_DP_VGA_CONVERTER == ddc->dongle_type) || + (DISPLAY_DONGLE_DP_DVI_CONVERTER == ddc->dongle_type) || + (DISPLAY_DONGLE_DP_HDMI_CONVERTER == + ddc->dongle_type)) { + + defer_delay = DP_TRANSLATOR_DELAY; + + defer_delay = + defer_delay_converter_wa(ddc, defer_delay); + + } else /*sink has a delay different from an Active Converter*/ + defer_delay = 0; + break; + case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_WITH_DEFER: + defer_delay = DP_TRANSLATOR_DELAY; + break; + default: + break; + } + return defer_delay; +} + +static bool i2c_read( + struct ddc_service *ddc, + uint32_t address, + uint8_t *buffer, + uint32_t len) +{ + uint8_t offs_data = 0; + struct i2c_payload payloads[2] = { + { + .write = true, + .address = address, + .length = 1, + .data = &offs_data }, + { + .write = false, + .address = address, + .length = len, + .data = buffer } }; + + struct i2c_command command = { + .payloads = payloads, + .number_of_payloads = 2, + .engine = DDC_I2C_COMMAND_ENGINE, + .speed = dal_adapter_service_get_sw_i2c_speed(ddc->as) }; + + return dal_i2caux_submit_i2c_command( + dal_adapter_service_get_i2caux(ddc->as), + ddc->ddc_pin, + &command); +} + +static uint8_t aux_read_edid_block( + struct ddc_service *ddc, + uint8_t address, + uint8_t index, + uint8_t *buf) +{ + struct aux_command cmd = { + .payloads = NULL, + .number_of_payloads = 0, + .defer_delay = get_defer_delay(ddc), + .max_defer_write_retry = 0 }; + + uint8_t retrieved = 0; + uint8_t base_offset = + (index % DDC_EDID_BLOCKS_PER_SEGMENT) * DDC_EDID_BLOCK_SIZE; + uint8_t segment = index / DDC_EDID_BLOCKS_PER_SEGMENT; + + for (retrieved = 0; retrieved < DDC_EDID_BLOCK_SIZE; + retrieved += DEFAULT_AUX_MAX_DATA_SIZE) { + + uint8_t offset = base_offset + retrieved; + + struct aux_payload payloads[3] = { + { + .i2c_over_aux = true, + .write = true, + .address = DDC_EDID_SEGMENT_ADDRESS, + .length = 1, + .data = &segment }, + { + .i2c_over_aux = true, + .write = true, + .address = address, + .length = 1, + .data = &offset }, + { + .i2c_over_aux = true, + .write = false, + .address = address, + .length = DEFAULT_AUX_MAX_DATA_SIZE, + .data = &buf[retrieved] } }; + + if (segment == 0) { + cmd.payloads = &payloads[1]; + cmd.number_of_payloads = 2; + } else { + cmd.payloads = payloads; + cmd.number_of_payloads = 3; + } + + if (!dal_i2caux_submit_aux_command( + dal_adapter_service_get_i2caux(ddc->as), + ddc->ddc_pin, + &cmd)) + /* cannot read, break*/ + break; + } + + /* Reset segment to 0. Needed by some panels */ + if (0 != segment) { + struct aux_payload payloads[1] = { { + .i2c_over_aux = true, + .write = true, + .address = DDC_EDID_SEGMENT_ADDRESS, + .length = 1, + .data = &segment } }; + bool result = false; + + segment = 0; + + cmd.number_of_payloads = ARRAY_SIZE(payloads); + cmd.payloads = payloads; + + result = dal_i2caux_submit_aux_command( + dal_adapter_service_get_i2caux(ddc->as), + ddc->ddc_pin, + &cmd); + + if (false == result) + dal_logger_write( + ddc->ctx->logger, + LOG_MAJOR_ERROR, + LOG_MINOR_COMPONENT_DISPLAY_CAPABILITY_SERVICE, + "%s: Writing of EDID Segment (0x30) failed!\n", + __func__); + } + + return retrieved; +} + +static uint8_t i2c_read_edid_block( + struct ddc_service *ddc, + uint8_t address, + uint8_t index, + uint8_t *buf) +{ + bool ret = false; + uint8_t offset = (index % DDC_EDID_BLOCKS_PER_SEGMENT) * + DDC_EDID_BLOCK_SIZE; + uint8_t segment = index / DDC_EDID_BLOCKS_PER_SEGMENT; + + struct i2c_command cmd = { + .payloads = NULL, + .number_of_payloads = 0, + .engine = DDC_I2C_COMMAND_ENGINE, + .speed = dal_adapter_service_get_sw_i2c_speed(ddc->as) }; + + struct i2c_payload payloads[3] = { + { + .write = true, + .address = DDC_EDID_SEGMENT_ADDRESS, + .length = 1, + .data = &segment }, + { + .write = true, + .address = address, + .length = 1, + .data = &offset }, + { + .write = false, + .address = address, + .length = DDC_EDID_BLOCK_SIZE, + .data = buf } }; +/* + * Some I2C engines don't handle stop/start between write-offset and read-data + * commands properly. For those displays, we have to force the newer E-DDC + * behavior of repeated-start which can be enabled by runtime parameter. */ +/* Originally implemented for OnLive using NXP receiver chip */ + + if (index == 0 && !ddc->flags.FORCE_READ_REPEATED_START) { + /* base block, use use DDC2B, submit as 2 commands */ + cmd.payloads = &payloads[1]; + cmd.number_of_payloads = 1; + + if (dal_i2caux_submit_i2c_command( + dal_adapter_service_get_i2caux(ddc->as), + ddc->ddc_pin, + &cmd)) { + + cmd.payloads = &payloads[2]; + cmd.number_of_payloads = 1; + + ret = dal_i2caux_submit_i2c_command( + dal_adapter_service_get_i2caux(ddc->as), + ddc->ddc_pin, + &cmd); + } + + } else { + /* + * extension block use E-DDC, submit as 1 command + * or if repeated-start is forced by runtime parameter + */ + if (segment != 0) { + /* include segment offset in command*/ + cmd.payloads = payloads; + cmd.number_of_payloads = 3; + } else { + /* we are reading first segment, + * segment offset is not required */ + cmd.payloads = &payloads[1]; + cmd.number_of_payloads = 2; + } + + ret = dal_i2caux_submit_i2c_command( + dal_adapter_service_get_i2caux(ddc->as), + ddc->ddc_pin, + &cmd); + } + + return ret ? DDC_EDID_BLOCK_SIZE : 0; +} + +static uint32_t query_edid_block( + struct ddc_service *ddc, + uint8_t address, + uint8_t index, + uint8_t *buf, + uint32_t size) +{ + uint32_t size_retrieved = 0; + + if (size < DDC_EDID_BLOCK_SIZE) + return 0; + + if (dal_ddc_service_is_in_aux_transaction_mode(ddc)) { + + ASSERT(index < 2); + size_retrieved = + aux_read_edid_block(ddc, address, index, buf); + } else { + size_retrieved = + i2c_read_edid_block(ddc, address, index, buf); + } + + return size_retrieved; +} + +#define DDC_DPCD_EDID_CHECKSUM_WRITE_ADDRESS 0x261 +#define DDC_TEST_ACK_ADDRESS 0x260 +#define DDC_DPCD_EDID_TEST_ACK 0x04 +#define DDC_DPCD_EDID_TEST_MASK 0x04 +#define DDC_DPCD_TEST_REQUEST_ADDRESS 0x218 + +/* AG TODO GO throug DM callback here like for DPCD */ + +static void write_dp_edid_checksum( + struct ddc_service *ddc, + uint8_t checksum) +{ + uint8_t dpcd_data; + + dal_ddc_service_read_dpcd_data( + ddc, + DDC_DPCD_TEST_REQUEST_ADDRESS, + &dpcd_data, + 1); + + if (dpcd_data & DDC_DPCD_EDID_TEST_MASK) { + + dal_ddc_service_write_dpcd_data( + ddc, + DDC_DPCD_EDID_CHECKSUM_WRITE_ADDRESS, + &checksum, + 1); + + dpcd_data = DDC_DPCD_EDID_TEST_ACK; + + dal_ddc_service_write_dpcd_data( + ddc, + DDC_TEST_ACK_ADDRESS, + &dpcd_data, + 1); + } +} + +uint32_t dal_ddc_service_edid_query(struct ddc_service *ddc) +{ + uint32_t bytes_read = 0; + uint32_t ext_cnt = 0; + + uint8_t address; + uint32_t i; + + for (address = DDC_EDID_ADDRESS_START; + address <= DDC_EDID_ADDRESS_END; ++address) { + + bytes_read = query_edid_block( + ddc, + address, + 0, + ddc->edid_buf, + sizeof(ddc->edid_buf) - bytes_read); + + if (bytes_read != DDC_EDID_BLOCK_SIZE) + continue; + + /* get the number of ext blocks*/ + ext_cnt = ddc->edid_buf[DDC_EDID_EXT_COUNT_OFFSET]; + + /* EDID 2.0, need to read 1 more block because EDID2.0 is + * 256 byte in size*/ + if (ddc->edid_buf[DDC_EDID_20_SIGNATURE_OFFSET] == + DDC_EDID_20_SIGNATURE) + ext_cnt = 1; + + for (i = 0; i < ext_cnt; i++) { + /* read additional ext blocks accordingly */ + bytes_read += query_edid_block( + ddc, + address, + i+1, + &ddc->edid_buf[bytes_read], + sizeof(ddc->edid_buf) - bytes_read); + } + + /*this is special code path for DP compliance*/ + if (DDC_TRANSACTION_TYPE_I2C_OVER_AUX == ddc->transaction_type) + write_dp_edid_checksum( + ddc, + ddc->edid_buf[(ext_cnt * DDC_EDID_BLOCK_SIZE) + + DDC_EDID1X_CHECKSUM_OFFSET]); + + /*remembers the address where we fetch the EDID from + * for later signature check use */ + ddc->address = address; + + break;/* already read edid, done*/ + } + + ddc->edid_buf_len = bytes_read; + return bytes_read; +} + +uint32_t dal_ddc_service_get_edid_buf_len(struct ddc_service *ddc) +{ + return ddc->edid_buf_len; +} + +void dal_ddc_service_get_edid_buf(struct ddc_service *ddc, uint8_t *edid_buf) +{ + dc_service_memmove(edid_buf, + ddc->edid_buf, ddc->edid_buf_len); +} + +void dal_ddc_service_i2c_query_dp_dual_mode_adaptor( + struct ddc_service *ddc, + struct display_sink_capability *sink_cap) +{ + uint8_t i; + bool is_valid_hdmi_signature; + enum display_dongle_type *dongle = &sink_cap->dongle_type; + uint8_t type2_dongle_buf[DP_ADAPTOR_TYPE2_SIZE]; + bool is_type2_dongle = false; + struct dp_hdmi_dongle_signature_data *dongle_signature; + + /* Assume we have no valid DP passive dongle connected */ + *dongle = DISPLAY_DONGLE_NONE; + sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK; + + /* Read DP-HDMI dongle I2c (no response interpreted as DP-DVI dongle)*/ + if (!i2c_read( + ddc, + DP_HDMI_DONGLE_ADDRESS, + type2_dongle_buf, + sizeof(type2_dongle_buf))) { + dal_logger_write(ddc->ctx->logger, + LOG_MAJOR_DCS, + LOG_MINOR_DCS_DONGLE_DETECTION, + "Detected DP-DVI dongle.\n"); + *dongle = DISPLAY_DONGLE_DP_DVI_DONGLE; + sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_DVI_MAX_TMDS_CLK; + return; + } + + /* Check if Type 2 dongle.*/ + if (type2_dongle_buf[DP_ADAPTOR_TYPE2_REG_ID] == DP_ADAPTOR_TYPE2_ID) + is_type2_dongle = true; + + dongle_signature = + (struct dp_hdmi_dongle_signature_data *)type2_dongle_buf; + + is_valid_hdmi_signature = true; + + /* Check EOT */ + if (dongle_signature->eot != DP_HDMI_DONGLE_SIGNATURE_EOT) { + is_valid_hdmi_signature = false; + } + + /* Check signature */ + for (i = 0; i < sizeof(dongle_signature->id); ++i) { + /* If its not the right signature, + * skip mismatch in subversion byte.*/ + if (dongle_signature->id[i] != + dp_hdmi_dongle_signature_str[i] && i != 3) { + + if (is_type2_dongle) { + is_valid_hdmi_signature = false; + break; + } + + } + } + + if (is_type2_dongle) { + uint32_t max_tmds_clk = + type2_dongle_buf[DP_ADAPTOR_TYPE2_REG_MAX_TMDS_CLK]; + + max_tmds_clk = max_tmds_clk * 2 + max_tmds_clk / 2; + + if (0 == max_tmds_clk || + max_tmds_clk < DP_ADAPTOR_TYPE2_MIN_TMDS_CLK || + max_tmds_clk > DP_ADAPTOR_TYPE2_MAX_TMDS_CLK) { + dal_logger_write(ddc->ctx->logger, + LOG_MAJOR_DCS, + LOG_MINOR_DCS_DONGLE_DETECTION, + "Invalid Maximum TMDS clock"); + *dongle = DISPLAY_DONGLE_DP_DVI_DONGLE; + } else { + if (is_valid_hdmi_signature == true) { + *dongle = DISPLAY_DONGLE_DP_HDMI_DONGLE; + dal_logger_write(ddc->ctx->logger, + LOG_MAJOR_DCS, + LOG_MINOR_DCS_DONGLE_DETECTION, + "Detected Type 2 DP-HDMI Maximum TMDS " + "clock, max TMDS clock: %d MHz", + max_tmds_clk); + } else { + *dongle = DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE; + dal_logger_write(ddc->ctx->logger, + LOG_MAJOR_DCS, + LOG_MINOR_DCS_DONGLE_DETECTION, + "Detected Type 2 DP-HDMI (no valid HDMI" + " signature) Maximum TMDS clock, max " + "TMDS clock: %d MHz", + max_tmds_clk); + } + + /* Multiply by 1000 to convert to kHz. */ + sink_cap->max_hdmi_pixel_clock = + max_tmds_clk * 1000; + } + + } else { + if (is_valid_hdmi_signature == true) { + dal_logger_write(ddc->ctx->logger, + LOG_MAJOR_DCS, + LOG_MINOR_DCS_DONGLE_DETECTION, + "Detected Type 1 DP-HDMI dongle.\n"); + *dongle = DISPLAY_DONGLE_DP_HDMI_DONGLE; + } else { + dal_logger_write(ddc->ctx->logger, + LOG_MAJOR_DCS, + LOG_MINOR_DCS_DONGLE_DETECTION, + "Detected Type 1 DP-HDMI dongle (no valid HDMI " + "signature).\n"); + + *dongle = DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE; + } + } + + return; +} + +enum { + DP_SINK_CAP_SIZE = + DPCD_ADDRESS_EDP_CONFIG_CAP - DPCD_ADDRESS_DPCD_REV + 1 +}; + +bool dal_ddc_service_query_ddc_data( + struct ddc_service *ddc, + uint32_t address, + uint8_t *write_buf, + uint32_t write_size, + uint8_t *read_buf, + uint32_t read_size) +{ + bool ret; + uint32_t payload_size = + dal_ddc_service_is_in_aux_transaction_mode(ddc) ? + DEFAULT_AUX_MAX_DATA_SIZE : EDID_SEGMENT_SIZE; + + uint32_t write_payloads = + (write_size + payload_size - 1) / payload_size; + + uint32_t read_payloads = + (read_size + payload_size - 1) / payload_size; + + uint32_t payloads_num = write_payloads + read_payloads; + + if (write_size > EDID_SEGMENT_SIZE || read_size > EDID_SEGMENT_SIZE) + return false; + + /*TODO: len of payload data for i2c and aux is uint8!!!!, + * but we want to read 256 over i2c!!!!*/ + if (dal_ddc_service_is_in_aux_transaction_mode(ddc)) { + + struct aux_payloads *payloads = + dal_ddc_aux_payloads_create(ddc->ctx, payloads_num); + + struct aux_command command = { + .payloads = dal_ddc_aux_payloads_get(payloads), + .number_of_payloads = 0, + .defer_delay = get_defer_delay(ddc), + .max_defer_write_retry = 0 }; + + dal_ddc_aux_payloads_add( + payloads, address, write_size, write_buf, true); + + dal_ddc_aux_payloads_add( + payloads, address, read_size, read_buf, false); + + command.number_of_payloads = + dal_ddc_aux_payloads_get_count(payloads); + + ret = dal_i2caux_submit_aux_command( + dal_adapter_service_get_i2caux(ddc->as), + ddc->ddc_pin, + &command); + + dal_ddc_aux_payloads_destroy(&payloads); + + } else { + struct i2c_payloads *payloads = + dal_ddc_i2c_payloads_create(ddc->ctx, payloads_num); + + struct i2c_command command = { + .payloads = dal_ddc_i2c_payloads_get(payloads), + .number_of_payloads = 0, + .engine = DDC_I2C_COMMAND_ENGINE, + .speed = + dal_adapter_service_get_sw_i2c_speed(ddc->as) }; + + dal_ddc_i2c_payloads_add( + payloads, address, write_size, write_buf, true); + + dal_ddc_i2c_payloads_add( + payloads, address, read_size, read_buf, false); + + command.number_of_payloads = + dal_ddc_i2c_payloads_get_count(payloads); + + ret = dal_i2caux_submit_i2c_command( + dal_adapter_service_get_i2caux(ddc->as), + ddc->ddc_pin, + &command); + + dal_ddc_i2c_payloads_destroy(&payloads); + } + + return ret; +} + +bool dal_ddc_service_get_dp_receiver_id_info( + struct ddc_service *ddc, + struct dp_receiver_id_info *info) +{ + if (!info) + return false; + + *info = ddc->dp_receiver_id_info; + return true; +} + +enum ddc_result dal_ddc_service_read_dpcd_data( + struct ddc_service *ddc, + uint32_t address, + uint8_t *data, + uint32_t len) +{ + struct aux_payload read_payload = { + .i2c_over_aux = false, + .write = false, + .address = address, + .length = len, + .data = data, + }; + struct aux_command command = { + .payloads = &read_payload, + .number_of_payloads = 1, + .defer_delay = 0, + .max_defer_write_retry = 0, + }; + + if (len > DEFAULT_AUX_MAX_DATA_SIZE) { + BREAK_TO_DEBUGGER(); + return DDC_RESULT_FAILED_INVALID_OPERATION; + } + + if (dal_i2caux_submit_aux_command( + dal_adapter_service_get_i2caux(ddc->as), + ddc->ddc_pin, + &command)) + return DDC_RESULT_SUCESSFULL; + + return DDC_RESULT_FAILED_OPERATION; +} + +enum ddc_result dal_ddc_service_write_dpcd_data( + struct ddc_service *ddc, + uint32_t address, + const uint8_t *data, + uint32_t len) +{ + struct aux_payload write_payload = { + .i2c_over_aux = false, + .write = true, + .address = address, + .length = len, + .data = (uint8_t *)data, + }; + struct aux_command command = { + .payloads = &write_payload, + .number_of_payloads = 1, + .defer_delay = 0, + .max_defer_write_retry = 0, + }; + + if (len > DEFAULT_AUX_MAX_DATA_SIZE) { + BREAK_TO_DEBUGGER(); + return DDC_RESULT_FAILED_INVALID_OPERATION; + } + + if (dal_i2caux_submit_aux_command( + dal_adapter_service_get_i2caux(ddc->as), + ddc->ddc_pin, + &command)) + return DDC_RESULT_SUCESSFULL; + + return DDC_RESULT_FAILED_OPERATION; +} + +/*test only function*/ +void dal_ddc_service_set_ddc_pin( + struct ddc_service *ddc_service, + struct ddc *ddc) +{ + ddc_service->ddc_pin = ddc; +} + +struct ddc *dal_ddc_service_get_ddc_pin(struct ddc_service *ddc_service) +{ + return ddc_service->ddc_pin; +} + + +void dal_ddc_service_reset_dp_receiver_id_info(struct ddc_service *ddc_service) +{ + dc_service_memset(&ddc_service->dp_receiver_id_info, + 0, sizeof(struct dp_receiver_id_info)); +} + +void dal_ddc_service_write_scdc_data(struct ddc_service *ddc_service, + uint32_t pix_clk, + bool lte_340_scramble) +{ + bool over_340_mhz = pix_clk > 340000 ? 1 : 0; + uint8_t slave_address = HDMI_SCDC_ADDRESS; + uint8_t offset = HDMI_SCDC_SINK_VERSION; + uint8_t sink_version = 0; + uint8_t write_buffer[2] = {0}; + /*Lower than 340 Scramble bit from SCDC caps*/ + + dal_ddc_service_query_ddc_data(ddc_service, slave_address, &offset, + sizeof(offset), &sink_version, sizeof(sink_version)); + if (sink_version == 1) { + /*Source Version = 1*/ + write_buffer[0] = HDMI_SCDC_SOURCE_VERSION; + write_buffer[1] = 1; + dal_ddc_service_query_ddc_data(ddc_service, slave_address, + write_buffer, sizeof(write_buffer), NULL, 0); + /*Read Request from SCDC caps*/ + } + write_buffer[0] = HDMI_SCDC_TMDS_CONFIG; + + if (over_340_mhz) { + write_buffer[1] = 3; + } else if (lte_340_scramble) { + write_buffer[1] = 1; + } else { + write_buffer[1] = 0; + } + dal_ddc_service_query_ddc_data(ddc_service, slave_address, write_buffer, + sizeof(write_buffer), NULL, 0); +} + +void dal_ddc_service_read_scdc_data(struct ddc_service *ddc_service) +{ + uint8_t slave_address = HDMI_SCDC_ADDRESS; + uint8_t offset = HDMI_SCDC_TMDS_CONFIG; + uint8_t tmds_config = 0; + + dal_ddc_service_query_ddc_data(ddc_service, slave_address, &offset, + sizeof(offset), &tmds_config, sizeof(tmds_config)); + if (tmds_config & 0x1) { + union hdmi_scdc_status_flags_data status_data = { {0} }; + uint8_t scramble_status = 0; + + offset = HDMI_SCDC_SCRAMBLER_STATUS; + dal_ddc_service_query_ddc_data(ddc_service, slave_address, + &offset, sizeof(offset), &scramble_status, + sizeof(scramble_status)); + offset = HDMI_SCDC_STATUS_FLAGS; + dal_ddc_service_query_ddc_data(ddc_service, slave_address, + &offset, sizeof(offset), status_data.byte, + sizeof(status_data.byte)); + } +} + diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/dal/dc/core/dc_link_dp.c index c4cbede..96ba910 100644 --- a/drivers/gpu/drm/amd/dal/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/dal/dc/core/dc_link_dp.c @@ -5,7 +5,7 @@ #include "dc_helpers.h" #include "inc/core_types.h" #include "link_hwss.h" -#include "ddc_service_interface.h" +#include "dc_link_ddc.h" #include "core_status.h" #include "dpcd_defs.h" diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_link_hwss.c b/drivers/gpu/drm/amd/dal/dc/core/dc_link_hwss.c index 2ed9eb8..656ec71 100644 --- a/drivers/gpu/drm/amd/dal/dc/core/dc_link_hwss.c +++ b/drivers/gpu/drm/amd/dal/dc/core/dc_link_hwss.c @@ -7,7 +7,7 @@ #include "include/i2caux_interface.h" #include "link_hwss.h" #include "hw_sequencer.h" -#include "include/ddc_service_interface.h" +#include "dc_link_ddc.h" #include "dc_helpers.h" #include "dce110/dce110_link_encoder.h" #include "dce110/dce110_stream_encoder.h" diff --git a/drivers/gpu/drm/amd/dal/dc/dcs/Makefile b/drivers/gpu/drm/amd/dal/dc/dcs/Makefile deleted file mode 100644 index a266942..0000000 --- a/drivers/gpu/drm/amd/dal/dc/dcs/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Makefile for the 'gpu' sub-component of DAL. -# It provides the control and status of HW adapter resources, -# that are global for the ASIC and sharable between pipes. - -DCS = ddc_service.o ddc_i2caux_helper.o - -AMD_DAL_DCS = $(addprefix $(AMDDALPATH)/dc/dcs/,$(DCS)) - -AMD_DAL_FILES += $(AMD_DAL_DCS) diff --git a/drivers/gpu/drm/amd/dal/dc/dcs/ddc_i2caux_helper.c b/drivers/gpu/drm/amd/dal/dc/dcs/ddc_i2caux_helper.c deleted file mode 100644 index 0af4df6..0000000 --- a/drivers/gpu/drm/amd/dal/dc/dcs/ddc_i2caux_helper.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * 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 "dc_services.h" -#include "ddc_i2caux_helper.h" -#include "include/ddc_service_types.h" -#include "include/vector.h" - -struct i2c_payloads { - struct vector payloads; -}; - -struct aux_payloads { - struct vector payloads; -}; - -struct i2c_payloads *dal_ddc_i2c_payloads_create(struct dc_context *ctx, uint32_t count) -{ - struct i2c_payloads *payloads; - - payloads = dc_service_alloc(ctx, sizeof(struct i2c_payloads)); - - if (!payloads) - return NULL; - - if (dal_vector_construct( - &payloads->payloads, ctx, count, sizeof(struct i2c_payload))) - return payloads; - - dc_service_free(ctx, payloads); - return NULL; - -} - -struct i2c_payload *dal_ddc_i2c_payloads_get(struct i2c_payloads *p) -{ - return (struct i2c_payload *)p->payloads.container; -} - -uint32_t dal_ddc_i2c_payloads_get_count(struct i2c_payloads *p) -{ - return p->payloads.count; -} - -void dal_ddc_i2c_payloads_destroy(struct i2c_payloads **p) -{ - if (!p || !*p) - return; - dal_vector_destruct(&(*p)->payloads); - dc_service_free((*p)->payloads.ctx, *p); - *p = NULL; - -} - -struct aux_payloads *dal_ddc_aux_payloads_create(struct dc_context *ctx, uint32_t count) -{ - struct aux_payloads *payloads; - - payloads = dc_service_alloc(ctx, sizeof(struct aux_payloads)); - - if (!payloads) - return NULL; - - if (dal_vector_construct( - &payloads->payloads, ctx, count, sizeof(struct aux_payloads))) - return payloads; - - dc_service_free(ctx, payloads); - return NULL; -} - -struct aux_payload *dal_ddc_aux_payloads_get(struct aux_payloads *p) -{ - return (struct aux_payload *)p->payloads.container; -} - -uint32_t dal_ddc_aux_payloads_get_count(struct aux_payloads *p) -{ - return p->payloads.count; -} - - -void dal_ddc_aux_payloads_destroy(struct aux_payloads **p) -{ - if (!p || !*p) - return; - - dal_vector_destruct(&(*p)->payloads); - dc_service_free((*p)->payloads.ctx, *p); - *p = NULL; -} - -#define DDC_MIN(a, b) (((a) < (b)) ? (a) : (b)) - -void dal_ddc_i2c_payloads_add( - struct i2c_payloads *payloads, - uint32_t address, - uint32_t len, - uint8_t *data, - bool write) -{ - uint32_t payload_size = EDID_SEGMENT_SIZE; - uint32_t pos; - - for (pos = 0; pos < len; pos += payload_size) { - struct i2c_payload payload = { - .write = write, - .address = address, - .length = DDC_MIN(payload_size, len - pos), - .data = data + pos }; - dal_vector_append(&payloads->payloads, &payload); - } - -} - -void dal_ddc_aux_payloads_add( - struct aux_payloads *payloads, - uint32_t address, - uint32_t len, - uint8_t *data, - bool write) -{ - uint32_t payload_size = DEFAULT_AUX_MAX_DATA_SIZE; - uint32_t pos; - - for (pos = 0; pos < len; pos += payload_size) { - struct aux_payload payload = { - .i2c_over_aux = true, - .write = write, - .address = address, - .length = DDC_MIN(payload_size, len - pos), - .data = data + pos }; - dal_vector_append(&payloads->payloads, &payload); - } -} - - diff --git a/drivers/gpu/drm/amd/dal/dc/dcs/ddc_i2caux_helper.h b/drivers/gpu/drm/amd/dal/dc/dcs/ddc_i2caux_helper.h deleted file mode 100644 index bb628cd..0000000 --- a/drivers/gpu/drm/amd/dal/dc/dcs/ddc_i2caux_helper.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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_I2CAUX_HELPER_H__ -#define __DAL_I2CAUX_HELPER_H__ - -#include "include/i2caux_interface.h" - -#define EDID_SEGMENT_SIZE 256 - -struct i2c_payloads; -struct aux_payloads; - -struct i2c_payloads *dal_ddc_i2c_payloads_create(struct dc_context *ctx, uint32_t count); -struct i2c_payload *dal_ddc_i2c_payloads_get(struct i2c_payloads *p); -uint32_t dal_ddc_i2c_payloads_get_count(struct i2c_payloads *p); -void dal_ddc_i2c_payloads_destroy(struct i2c_payloads **p); - -struct aux_payloads *dal_ddc_aux_payloads_create(struct dc_context *ctx, uint32_t count); -struct aux_payload *dal_ddc_aux_payloads_get(struct aux_payloads *p); -uint32_t dal_ddc_aux_payloads_get_count(struct aux_payloads *p); -void dal_ddc_aux_payloads_destroy(struct aux_payloads **p); - -void dal_ddc_i2c_payloads_add( - struct i2c_payloads *payloads, - uint32_t address, - uint32_t len, - uint8_t *data, - bool write); - -void dal_ddc_aux_payloads_add( - struct aux_payloads *payloads, - uint32_t address, - uint32_t len, - uint8_t *data, - bool write); - -#endif /* __DAL_I2CAUX_HELPER_H__ */ diff --git a/drivers/gpu/drm/amd/dal/dc/dcs/ddc_service.c b/drivers/gpu/drm/amd/dal/dc/dcs/ddc_service.c deleted file mode 100644 index bbab51c..0000000 --- a/drivers/gpu/drm/amd/dal/dc/dcs/ddc_service.c +++ /dev/null @@ -1,1036 +0,0 @@ -/* - * 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 "dc_services.h" - -#include "include/adapter_service_interface.h" -#include "include/i2caux_interface.h" -#include "include/ddc_service_interface.h" -#include "include/ddc_service_types.h" -#include "include/grph_object_id.h" -#include "include/dpcd_defs.h" -#include "include/logger_interface.h" -#include "ddc_i2caux_helper.h" -#include "ddc_service.h" - -#define AUX_POWER_UP_WA_DELAY 500 -#define I2C_OVER_AUX_DEFER_WA_DELAY 70 - -/* CV smart dongle slave address for retrieving supported HDTV modes*/ -#define CV_SMART_DONGLE_ADDRESS 0x20 -/* DVI-HDMI dongle slave address for retrieving dongle signature*/ -#define DVI_HDMI_DONGLE_ADDRESS 0x68 -static const int8_t dvi_hdmi_dongle_signature_str[] = "6140063500G"; -struct dvi_hdmi_dongle_signature_data { - int8_t vendor[3];/* "AMD" */ - uint8_t version[2]; - uint8_t size; - int8_t id[11];/* "6140063500G"*/ -}; -/* DP-HDMI dongle slave address for retrieving dongle signature*/ -#define DP_HDMI_DONGLE_ADDRESS 0x40 -static const uint8_t dp_hdmi_dongle_signature_str[] = "DP-HDMI ADAPTOR"; -#define DP_HDMI_DONGLE_SIGNATURE_EOT 0x04 - -struct dp_hdmi_dongle_signature_data { - int8_t id[15];/* "DP-HDMI ADAPTOR"*/ - uint8_t eot;/* end of transmition '\x4' */ -}; - -/* Address range from 0x00 to 0x1F.*/ -#define DP_ADAPTOR_TYPE2_SIZE 0x20 -#define DP_ADAPTOR_TYPE2_REG_ID 0x10 -#define DP_ADAPTOR_TYPE2_REG_MAX_TMDS_CLK 0x1D -/* Identifies adaptor as Dual-mode adaptor */ -#define DP_ADAPTOR_TYPE2_ID 0xA0 -/* MHz*/ -#define DP_ADAPTOR_TYPE2_MAX_TMDS_CLK 600 -/* MHz*/ -#define DP_ADAPTOR_TYPE2_MIN_TMDS_CLK 25 -/* kHZ*/ -#define DP_ADAPTOR_DVI_MAX_TMDS_CLK 165000 -/* kHZ*/ -#define DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK 165000 - -#define DDC_I2C_COMMAND_ENGINE I2C_COMMAND_ENGINE_SW - -enum edid_read_result { - EDID_READ_RESULT_EDID_MATCH = 0, - EDID_READ_RESULT_EDID_MISMATCH, - EDID_READ_RESULT_CHECKSUM_READ_ERR, - EDID_READ_RESULT_VENDOR_READ_ERR -}; - -/* SCDC Address defines (HDMI 2.0)*/ -#define HDMI_SCDC_WRITE_UPDATE_0_ARRAY 3 -#define HDMI_SCDC_ADDRESS 0x54 -#define HDMI_SCDC_SINK_VERSION 0x01 -#define HDMI_SCDC_SOURCE_VERSION 0x02 -#define HDMI_SCDC_UPDATE_0 0x10 -#define HDMI_SCDC_TMDS_CONFIG 0x20 -#define HDMI_SCDC_SCRAMBLER_STATUS 0x21 -#define HDMI_SCDC_CONFIG_0 0x30 -#define HDMI_SCDC_STATUS_FLAGS 0x40 -#define HDMI_SCDC_ERR_DETECT 0x50 -#define HDMI_SCDC_TEST_CONFIG 0xC0 - - -union hdmi_scdc_update_read_data -{ - uint8_t byte[2]; - struct - { - uint8_t STATUS_UPDATE:1; - uint8_t CED_UPDATE:1; - uint8_t RR_TEST:1; - uint8_t RESERVED:5; - uint8_t RESERVED2:8; - } fields; -}; - -union hdmi_scdc_status_flags_data -{ - uint8_t byte[2]; - struct - { - uint8_t CLOCK_DETECTED:1; - uint8_t CH0_LOCKED:1; - uint8_t CH1_LOCKED:1; - uint8_t CH2_LOCKED:1; - uint8_t RESERVED:4; - uint8_t RESERVED2:8; - } fields; -}; - -union hdmi_scdc_ced_data -{ - uint8_t byte[7]; - struct - { - uint8_t CH0_8LOW:8; - uint8_t CH0_7HIGH:7; - uint8_t CH0_VALID:1; - uint8_t CH1_8LOW:8; - uint8_t CH1_7HIGH:7; - uint8_t CH1_VALID:1; - uint8_t CH2_8LOW:8; - uint8_t CH2_7HIGH:7; - uint8_t CH2_VALID:1; - uint8_t CHECKSUM:8; - } fields; -}; - -union hdmi_scdc_test_config_Data -{ - uint8_t byte; - struct - { - uint8_t TEST_READ_REQUEST_DELAY:7; - uint8_t TEST_READ_REQUEST: 1; - } fields; -}; - - - -union ddc_wa { - struct { - uint32_t DP_SKIP_POWER_OFF:1; - uint32_t DP_AUX_POWER_UP_WA_DELAY:1; - } bits; - uint32_t raw; -}; - -struct ddc_flags { - uint8_t EDID_QUERY_DONE_ONCE:1; - uint8_t IS_INTERNAL_DISPLAY:1; - uint8_t FORCE_READ_REPEATED_START:1; - uint8_t EDID_STRESS_READ:1; - -}; - -struct ddc_service { - struct ddc *ddc_pin; - struct ddc_flags flags; - union ddc_wa wa; - enum ddc_transaction_type transaction_type; - enum display_dongle_type dongle_type; - struct dp_receiver_id_info dp_receiver_id_info; - struct adapter_service *as; - struct dc_context *ctx; - - uint32_t address; - uint32_t edid_buf_len; - uint8_t edid_buf[MAX_EDID_BUFFER_SIZE]; -}; - -static bool construct( - struct ddc_service *ddc_service, - struct ddc_service_init_data *init_data) -{ - enum connector_id connector_id = - dal_graphics_object_id_get_connector_id(init_data->id); - - ddc_service->ctx = init_data->ctx; - ddc_service->as = init_data->as; - ddc_service->ddc_pin = dal_adapter_service_obtain_ddc( - init_data->as, init_data->id); - - ddc_service->flags.EDID_QUERY_DONE_ONCE = false; - - ddc_service->flags.FORCE_READ_REPEATED_START = - dal_adapter_service_is_feature_supported( - FEATURE_DDC_READ_FORCE_REPEATED_START); - - ddc_service->flags.EDID_STRESS_READ = - dal_adapter_service_is_feature_supported( - FEATURE_EDID_STRESS_READ); - - - ddc_service->flags.IS_INTERNAL_DISPLAY = - connector_id == CONNECTOR_ID_EDP || - connector_id == CONNECTOR_ID_LVDS; - - ddc_service->wa.raw = 0; - return true; -} - -struct ddc_service *dal_ddc_service_create( - struct ddc_service_init_data *init_data) -{ - struct ddc_service *ddc_service; - - ddc_service = dc_service_alloc(init_data->ctx, sizeof(struct ddc_service)); - - if (!ddc_service) - return NULL; - - if (construct(ddc_service, init_data)) - return ddc_service; - - dc_service_free(init_data->ctx, ddc_service); - return NULL; -} - -static void destruct(struct ddc_service *ddc) -{ - if (ddc->ddc_pin) - dal_adapter_service_release_ddc(ddc->as, ddc->ddc_pin); -} - -void dal_ddc_service_destroy(struct ddc_service **ddc) -{ - if (!ddc || !*ddc) { - BREAK_TO_DEBUGGER(); - return; - } - destruct(*ddc); - dc_service_free((*ddc)->ctx, *ddc); - *ddc = NULL; -} - -enum ddc_service_type dal_ddc_service_get_type(struct ddc_service *ddc) -{ - return DDC_SERVICE_TYPE_CONNECTOR; -} - -void dal_ddc_service_set_transaction_type( - struct ddc_service *ddc, - enum ddc_transaction_type type) -{ - ddc->transaction_type = type; -} - -bool dal_ddc_service_is_in_aux_transaction_mode(struct ddc_service *ddc) -{ - switch (ddc->transaction_type) { - case DDC_TRANSACTION_TYPE_I2C_OVER_AUX: - case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_WITH_DEFER: - case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_RETRY_DEFER: - return true; - default: - break; - } - return false; -} - -void ddc_service_set_dongle_type(struct ddc_service *ddc, - enum display_dongle_type dongle_type) -{ - ddc->dongle_type = dongle_type; -} - -static uint32_t defer_delay_converter_wa( - struct ddc_service *ddc, - uint32_t defer_delay) -{ - struct dp_receiver_id_info dp_rec_info = {0}; - - if (dal_ddc_service_get_dp_receiver_id_info(ddc, &dp_rec_info) && - (dp_rec_info.branch_id == DP_BRANCH_DEVICE_ID_4) && - !dal_strncmp(dp_rec_info.branch_name, - DP_DVI_CONVERTER_ID_4, - sizeof(dp_rec_info.branch_name))) - return defer_delay > I2C_OVER_AUX_DEFER_WA_DELAY ? - defer_delay : I2C_OVER_AUX_DEFER_WA_DELAY; - - return defer_delay; - -} - -#define DP_TRANSLATOR_DELAY 5 - -static uint32_t get_defer_delay(struct ddc_service *ddc) -{ - uint32_t defer_delay = 0; - - switch (ddc->transaction_type) { - case DDC_TRANSACTION_TYPE_I2C_OVER_AUX: - if ((DISPLAY_DONGLE_DP_VGA_CONVERTER == ddc->dongle_type) || - (DISPLAY_DONGLE_DP_DVI_CONVERTER == ddc->dongle_type) || - (DISPLAY_DONGLE_DP_HDMI_CONVERTER == - ddc->dongle_type)) { - - defer_delay = DP_TRANSLATOR_DELAY; - - defer_delay = - defer_delay_converter_wa(ddc, defer_delay); - - } else /*sink has a delay different from an Active Converter*/ - defer_delay = 0; - break; - case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_WITH_DEFER: - defer_delay = DP_TRANSLATOR_DELAY; - break; - default: - break; - } - return defer_delay; -} - -static bool i2c_read( - struct ddc_service *ddc, - uint32_t address, - uint8_t *buffer, - uint32_t len) -{ - uint8_t offs_data = 0; - struct i2c_payload payloads[2] = { - { - .write = true, - .address = address, - .length = 1, - .data = &offs_data }, - { - .write = false, - .address = address, - .length = len, - .data = buffer } }; - - struct i2c_command command = { - .payloads = payloads, - .number_of_payloads = 2, - .engine = DDC_I2C_COMMAND_ENGINE, - .speed = dal_adapter_service_get_sw_i2c_speed(ddc->as) }; - - return dal_i2caux_submit_i2c_command( - dal_adapter_service_get_i2caux(ddc->as), - ddc->ddc_pin, - &command); -} - -static uint8_t aux_read_edid_block( - struct ddc_service *ddc, - uint8_t address, - uint8_t index, - uint8_t *buf) -{ - struct aux_command cmd = { - .payloads = NULL, - .number_of_payloads = 0, - .defer_delay = get_defer_delay(ddc), - .max_defer_write_retry = 0 }; - - uint8_t retrieved = 0; - uint8_t base_offset = - (index % DDC_EDID_BLOCKS_PER_SEGMENT) * DDC_EDID_BLOCK_SIZE; - uint8_t segment = index / DDC_EDID_BLOCKS_PER_SEGMENT; - - for (retrieved = 0; retrieved < DDC_EDID_BLOCK_SIZE; - retrieved += DEFAULT_AUX_MAX_DATA_SIZE) { - - uint8_t offset = base_offset + retrieved; - - struct aux_payload payloads[3] = { - { - .i2c_over_aux = true, - .write = true, - .address = DDC_EDID_SEGMENT_ADDRESS, - .length = 1, - .data = &segment }, - { - .i2c_over_aux = true, - .write = true, - .address = address, - .length = 1, - .data = &offset }, - { - .i2c_over_aux = true, - .write = false, - .address = address, - .length = DEFAULT_AUX_MAX_DATA_SIZE, - .data = &buf[retrieved] } }; - - if (segment == 0) { - cmd.payloads = &payloads[1]; - cmd.number_of_payloads = 2; - } else { - cmd.payloads = payloads; - cmd.number_of_payloads = 3; - } - - if (!dal_i2caux_submit_aux_command( - dal_adapter_service_get_i2caux(ddc->as), - ddc->ddc_pin, - &cmd)) - /* cannot read, break*/ - break; - } - - /* Reset segment to 0. Needed by some panels */ - if (0 != segment) { - struct aux_payload payloads[1] = { { - .i2c_over_aux = true, - .write = true, - .address = DDC_EDID_SEGMENT_ADDRESS, - .length = 1, - .data = &segment } }; - bool result = false; - - segment = 0; - - cmd.number_of_payloads = ARRAY_SIZE(payloads); - cmd.payloads = payloads; - - result = dal_i2caux_submit_aux_command( - dal_adapter_service_get_i2caux(ddc->as), - ddc->ddc_pin, - &cmd); - - if (false == result) - dal_logger_write( - ddc->ctx->logger, - LOG_MAJOR_ERROR, - LOG_MINOR_COMPONENT_DISPLAY_CAPABILITY_SERVICE, - "%s: Writing of EDID Segment (0x30) failed!\n", - __func__); - } - - return retrieved; -} - -static uint8_t i2c_read_edid_block( - struct ddc_service *ddc, - uint8_t address, - uint8_t index, - uint8_t *buf) -{ - bool ret = false; - uint8_t offset = (index % DDC_EDID_BLOCKS_PER_SEGMENT) * - DDC_EDID_BLOCK_SIZE; - uint8_t segment = index / DDC_EDID_BLOCKS_PER_SEGMENT; - - struct i2c_command cmd = { - .payloads = NULL, - .number_of_payloads = 0, - .engine = DDC_I2C_COMMAND_ENGINE, - .speed = dal_adapter_service_get_sw_i2c_speed(ddc->as) }; - - struct i2c_payload payloads[3] = { - { - .write = true, - .address = DDC_EDID_SEGMENT_ADDRESS, - .length = 1, - .data = &segment }, - { - .write = true, - .address = address, - .length = 1, - .data = &offset }, - { - .write = false, - .address = address, - .length = DDC_EDID_BLOCK_SIZE, - .data = buf } }; -/* - * Some I2C engines don't handle stop/start between write-offset and read-data - * commands properly. For those displays, we have to force the newer E-DDC - * behavior of repeated-start which can be enabled by runtime parameter. */ -/* Originally implemented for OnLive using NXP receiver chip */ - - if (index == 0 && !ddc->flags.FORCE_READ_REPEATED_START) { - /* base block, use use DDC2B, submit as 2 commands */ - cmd.payloads = &payloads[1]; - cmd.number_of_payloads = 1; - - if (dal_i2caux_submit_i2c_command( - dal_adapter_service_get_i2caux(ddc->as), - ddc->ddc_pin, - &cmd)) { - - cmd.payloads = &payloads[2]; - cmd.number_of_payloads = 1; - - ret = dal_i2caux_submit_i2c_command( - dal_adapter_service_get_i2caux(ddc->as), - ddc->ddc_pin, - &cmd); - } - - } else { - /* - * extension block use E-DDC, submit as 1 command - * or if repeated-start is forced by runtime parameter - */ - if (segment != 0) { - /* include segment offset in command*/ - cmd.payloads = payloads; - cmd.number_of_payloads = 3; - } else { - /* we are reading first segment, - * segment offset is not required */ - cmd.payloads = &payloads[1]; - cmd.number_of_payloads = 2; - } - - ret = dal_i2caux_submit_i2c_command( - dal_adapter_service_get_i2caux(ddc->as), - ddc->ddc_pin, - &cmd); - } - - return ret ? DDC_EDID_BLOCK_SIZE : 0; -} - -static uint32_t query_edid_block( - struct ddc_service *ddc, - uint8_t address, - uint8_t index, - uint8_t *buf, - uint32_t size) -{ - uint32_t size_retrieved = 0; - - if (size < DDC_EDID_BLOCK_SIZE) - return 0; - - if (dal_ddc_service_is_in_aux_transaction_mode(ddc)) { - - ASSERT(index < 2); - size_retrieved = - aux_read_edid_block(ddc, address, index, buf); - } else { - size_retrieved = - i2c_read_edid_block(ddc, address, index, buf); - } - - return size_retrieved; -} - -#define DDC_DPCD_EDID_CHECKSUM_WRITE_ADDRESS 0x261 -#define DDC_TEST_ACK_ADDRESS 0x260 -#define DDC_DPCD_EDID_TEST_ACK 0x04 -#define DDC_DPCD_EDID_TEST_MASK 0x04 -#define DDC_DPCD_TEST_REQUEST_ADDRESS 0x218 - -/* AG TODO GO throug DM callback here like for DPCD */ - -static void write_dp_edid_checksum( - struct ddc_service *ddc, - uint8_t checksum) -{ - uint8_t dpcd_data; - - dal_ddc_service_read_dpcd_data( - ddc, - DDC_DPCD_TEST_REQUEST_ADDRESS, - &dpcd_data, - 1); - - if (dpcd_data & DDC_DPCD_EDID_TEST_MASK) { - - dal_ddc_service_write_dpcd_data( - ddc, - DDC_DPCD_EDID_CHECKSUM_WRITE_ADDRESS, - &checksum, - 1); - - dpcd_data = DDC_DPCD_EDID_TEST_ACK; - - dal_ddc_service_write_dpcd_data( - ddc, - DDC_TEST_ACK_ADDRESS, - &dpcd_data, - 1); - } -} - -uint32_t dal_ddc_service_edid_query(struct ddc_service *ddc) -{ - uint32_t bytes_read = 0; - uint32_t ext_cnt = 0; - - uint8_t address; - uint32_t i; - - for (address = DDC_EDID_ADDRESS_START; - address <= DDC_EDID_ADDRESS_END; ++address) { - - bytes_read = query_edid_block( - ddc, - address, - 0, - ddc->edid_buf, - sizeof(ddc->edid_buf) - bytes_read); - - if (bytes_read != DDC_EDID_BLOCK_SIZE) - continue; - - /* get the number of ext blocks*/ - ext_cnt = ddc->edid_buf[DDC_EDID_EXT_COUNT_OFFSET]; - - /* EDID 2.0, need to read 1 more block because EDID2.0 is - * 256 byte in size*/ - if (ddc->edid_buf[DDC_EDID_20_SIGNATURE_OFFSET] == - DDC_EDID_20_SIGNATURE) - ext_cnt = 1; - - for (i = 0; i < ext_cnt; i++) { - /* read additional ext blocks accordingly */ - bytes_read += query_edid_block( - ddc, - address, - i+1, - &ddc->edid_buf[bytes_read], - sizeof(ddc->edid_buf) - bytes_read); - } - - /*this is special code path for DP compliance*/ - if (DDC_TRANSACTION_TYPE_I2C_OVER_AUX == ddc->transaction_type) - write_dp_edid_checksum( - ddc, - ddc->edid_buf[(ext_cnt * DDC_EDID_BLOCK_SIZE) + - DDC_EDID1X_CHECKSUM_OFFSET]); - - /*remembers the address where we fetch the EDID from - * for later signature check use */ - ddc->address = address; - - break;/* already read edid, done*/ - } - - ddc->edid_buf_len = bytes_read; - return bytes_read; -} - -uint32_t dal_ddc_service_get_edid_buf_len(struct ddc_service *ddc) -{ - return ddc->edid_buf_len; -} - -void dal_ddc_service_get_edid_buf(struct ddc_service *ddc, uint8_t *edid_buf) -{ - dc_service_memmove(edid_buf, - ddc->edid_buf, ddc->edid_buf_len); -} - -void dal_ddc_service_i2c_query_dp_dual_mode_adaptor( - struct ddc_service *ddc, - struct display_sink_capability *sink_cap) -{ - uint8_t i; - bool is_valid_hdmi_signature; - enum display_dongle_type *dongle = &sink_cap->dongle_type; - uint8_t type2_dongle_buf[DP_ADAPTOR_TYPE2_SIZE]; - bool is_type2_dongle = false; - struct dp_hdmi_dongle_signature_data *dongle_signature; - - /* Assume we have no valid DP passive dongle connected */ - *dongle = DISPLAY_DONGLE_NONE; - sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK; - - /* Read DP-HDMI dongle I2c (no response interpreted as DP-DVI dongle)*/ - if (!i2c_read( - ddc, - DP_HDMI_DONGLE_ADDRESS, - type2_dongle_buf, - sizeof(type2_dongle_buf))) { - dal_logger_write(ddc->ctx->logger, - LOG_MAJOR_DCS, - LOG_MINOR_DCS_DONGLE_DETECTION, - "Detected DP-DVI dongle.\n"); - *dongle = DISPLAY_DONGLE_DP_DVI_DONGLE; - sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_DVI_MAX_TMDS_CLK; - return; - } - - /* Check if Type 2 dongle.*/ - if (type2_dongle_buf[DP_ADAPTOR_TYPE2_REG_ID] == DP_ADAPTOR_TYPE2_ID) - is_type2_dongle = true; - - dongle_signature = - (struct dp_hdmi_dongle_signature_data *)type2_dongle_buf; - - is_valid_hdmi_signature = true; - - /* Check EOT */ - if (dongle_signature->eot != DP_HDMI_DONGLE_SIGNATURE_EOT) { - is_valid_hdmi_signature = false; - } - - /* Check signature */ - for (i = 0; i < sizeof(dongle_signature->id); ++i) { - /* If its not the right signature, - * skip mismatch in subversion byte.*/ - if (dongle_signature->id[i] != - dp_hdmi_dongle_signature_str[i] && i != 3) { - - if (is_type2_dongle) { - is_valid_hdmi_signature = false; - break; - } - - } - } - - if (is_type2_dongle) { - uint32_t max_tmds_clk = - type2_dongle_buf[DP_ADAPTOR_TYPE2_REG_MAX_TMDS_CLK]; - - max_tmds_clk = max_tmds_clk * 2 + max_tmds_clk / 2; - - if (0 == max_tmds_clk || - max_tmds_clk < DP_ADAPTOR_TYPE2_MIN_TMDS_CLK || - max_tmds_clk > DP_ADAPTOR_TYPE2_MAX_TMDS_CLK) { - dal_logger_write(ddc->ctx->logger, - LOG_MAJOR_DCS, - LOG_MINOR_DCS_DONGLE_DETECTION, - "Invalid Maximum TMDS clock"); - *dongle = DISPLAY_DONGLE_DP_DVI_DONGLE; - } else { - if (is_valid_hdmi_signature == true) { - *dongle = DISPLAY_DONGLE_DP_HDMI_DONGLE; - dal_logger_write(ddc->ctx->logger, - LOG_MAJOR_DCS, - LOG_MINOR_DCS_DONGLE_DETECTION, - "Detected Type 2 DP-HDMI Maximum TMDS " - "clock, max TMDS clock: %d MHz", - max_tmds_clk); - } else { - *dongle = DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE; - dal_logger_write(ddc->ctx->logger, - LOG_MAJOR_DCS, - LOG_MINOR_DCS_DONGLE_DETECTION, - "Detected Type 2 DP-HDMI (no valid HDMI" - " signature) Maximum TMDS clock, max " - "TMDS clock: %d MHz", - max_tmds_clk); - } - - /* Multiply by 1000 to convert to kHz. */ - sink_cap->max_hdmi_pixel_clock = - max_tmds_clk * 1000; - } - - } else { - if (is_valid_hdmi_signature == true) { - dal_logger_write(ddc->ctx->logger, - LOG_MAJOR_DCS, - LOG_MINOR_DCS_DONGLE_DETECTION, - "Detected Type 1 DP-HDMI dongle.\n"); - *dongle = DISPLAY_DONGLE_DP_HDMI_DONGLE; - } - else { - dal_logger_write(ddc->ctx->logger, - LOG_MAJOR_DCS, - LOG_MINOR_DCS_DONGLE_DETECTION, - "Detected Type 1 DP-HDMI dongle (no valid HDMI " - "signature).\n"); - - *dongle = DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE; - } - } - - return; -} - -enum { - DP_SINK_CAP_SIZE = - DPCD_ADDRESS_EDP_CONFIG_CAP - DPCD_ADDRESS_DPCD_REV + 1 -}; - -bool dal_ddc_service_query_ddc_data( - struct ddc_service *ddc, - uint32_t address, - uint8_t *write_buf, - uint32_t write_size, - uint8_t *read_buf, - uint32_t read_size) -{ - bool ret; - uint32_t payload_size = - dal_ddc_service_is_in_aux_transaction_mode(ddc) ? - DEFAULT_AUX_MAX_DATA_SIZE : EDID_SEGMENT_SIZE; - - uint32_t write_payloads = - (write_size + payload_size - 1) / payload_size; - - uint32_t read_payloads = - (read_size + payload_size - 1) / payload_size; - - uint32_t payloads_num = write_payloads + read_payloads; - - if (write_size > EDID_SEGMENT_SIZE || read_size > EDID_SEGMENT_SIZE) - return false; - - /*TODO: len of payload data for i2c and aux is uint8!!!!, - * but we want to read 256 over i2c!!!!*/ - if (dal_ddc_service_is_in_aux_transaction_mode(ddc)) { - - struct aux_payloads *payloads = - dal_ddc_aux_payloads_create(ddc->ctx, payloads_num); - - struct aux_command command = { - .payloads = dal_ddc_aux_payloads_get(payloads), - .number_of_payloads = 0, - .defer_delay = get_defer_delay(ddc), - .max_defer_write_retry = 0 }; - - dal_ddc_aux_payloads_add( - payloads, address, write_size, write_buf, true); - - dal_ddc_aux_payloads_add( - payloads, address, read_size, read_buf, false); - - command.number_of_payloads = - dal_ddc_aux_payloads_get_count(payloads); - - ret = dal_i2caux_submit_aux_command( - dal_adapter_service_get_i2caux(ddc->as), - ddc->ddc_pin, - &command); - - dal_ddc_aux_payloads_destroy(&payloads); - - } else { - struct i2c_payloads *payloads = - dal_ddc_i2c_payloads_create(ddc->ctx, payloads_num); - - struct i2c_command command = { - .payloads = dal_ddc_i2c_payloads_get(payloads), - .number_of_payloads = 0, - .engine = DDC_I2C_COMMAND_ENGINE, - .speed = - dal_adapter_service_get_sw_i2c_speed(ddc->as) }; - - dal_ddc_i2c_payloads_add( - payloads, address, write_size, write_buf, true); - - dal_ddc_i2c_payloads_add( - payloads, address, read_size, read_buf, false); - - command.number_of_payloads = - dal_ddc_i2c_payloads_get_count(payloads); - - ret = dal_i2caux_submit_i2c_command( - dal_adapter_service_get_i2caux(ddc->as), - ddc->ddc_pin, - &command); - - dal_ddc_i2c_payloads_destroy(&payloads); - } - - return ret; -} - -bool dal_ddc_service_get_dp_receiver_id_info( - struct ddc_service *ddc, - struct dp_receiver_id_info *info) -{ - if (!info) - return false; - - *info = ddc->dp_receiver_id_info; - return true; -} - -enum ddc_result dal_ddc_service_read_dpcd_data( - struct ddc_service *ddc, - uint32_t address, - uint8_t *data, - uint32_t len) -{ - struct aux_payload read_payload = { - .i2c_over_aux = false, - .write = false, - .address = address, - .length = len, - .data = data, - }; - struct aux_command command = { - .payloads = &read_payload, - .number_of_payloads = 1, - .defer_delay = 0, - .max_defer_write_retry = 0, - }; - - if (len > DEFAULT_AUX_MAX_DATA_SIZE) { - BREAK_TO_DEBUGGER(); - return DDC_RESULT_FAILED_INVALID_OPERATION; - } - - if (dal_i2caux_submit_aux_command( - dal_adapter_service_get_i2caux(ddc->as), - ddc->ddc_pin, - &command)) - return DDC_RESULT_SUCESSFULL; - - return DDC_RESULT_FAILED_OPERATION; -} - -enum ddc_result dal_ddc_service_write_dpcd_data( - struct ddc_service *ddc, - uint32_t address, - const uint8_t *data, - uint32_t len) -{ - struct aux_payload write_payload = { - .i2c_over_aux = false, - .write = true, - .address = address, - .length = len, - .data = (uint8_t *)data, - }; - struct aux_command command = { - .payloads = &write_payload, - .number_of_payloads = 1, - .defer_delay = 0, - .max_defer_write_retry = 0, - }; - - if (len > DEFAULT_AUX_MAX_DATA_SIZE) { - BREAK_TO_DEBUGGER(); - return DDC_RESULT_FAILED_INVALID_OPERATION; - } - - if (dal_i2caux_submit_aux_command( - dal_adapter_service_get_i2caux(ddc->as), - ddc->ddc_pin, - &command)) - return DDC_RESULT_SUCESSFULL; - - return DDC_RESULT_FAILED_OPERATION; -} - -/*test only function*/ -void dal_ddc_service_set_ddc_pin( - struct ddc_service *ddc_service, - struct ddc *ddc) -{ - ddc_service->ddc_pin = ddc; -} - -struct ddc *dal_ddc_service_get_ddc_pin(struct ddc_service *ddc_service) -{ - return ddc_service->ddc_pin; -} - - -void dal_ddc_service_reset_dp_receiver_id_info(struct ddc_service *ddc_service) -{ - dc_service_memset(&ddc_service->dp_receiver_id_info, - 0, sizeof(struct dp_receiver_id_info)); -} - -void dal_ddc_service_write_scdc_data(struct ddc_service *ddc_service, - uint32_t pix_clk, - bool lte_340_scramble) -{ - bool over_340_mhz = pix_clk > 340000 ? 1 : 0; - uint8_t slave_address = HDMI_SCDC_ADDRESS; - uint8_t offset = HDMI_SCDC_SINK_VERSION; - uint8_t sink_version = 0; - uint8_t write_buffer[2] = {0}; - /*Lower than 340 Scramble bit from SCDC caps*/ - - dal_ddc_service_query_ddc_data(ddc_service, slave_address, &offset, - sizeof(offset), &sink_version, sizeof(sink_version)); - if (sink_version == 1) { - /*Source Version = 1*/ - write_buffer[0] = HDMI_SCDC_SOURCE_VERSION; - write_buffer[1] = 1; - dal_ddc_service_query_ddc_data(ddc_service, slave_address, - write_buffer, sizeof(write_buffer), NULL, 0); - /*Read Request from SCDC caps*/ - } - write_buffer[0] = HDMI_SCDC_TMDS_CONFIG; - - if (over_340_mhz) - { - write_buffer[1] = 3; - } - else if (lte_340_scramble) - { - write_buffer[1] = 1; - } - else - { - write_buffer[1] = 0; - } - dal_ddc_service_query_ddc_data(ddc_service, slave_address, write_buffer, - sizeof(write_buffer), NULL, 0); -} - -void dal_ddc_service_read_scdc_data(struct ddc_service *ddc_service) -{ - uint8_t slave_address = HDMI_SCDC_ADDRESS; - uint8_t offset = HDMI_SCDC_TMDS_CONFIG; - uint8_t tmds_config = 0; - - dal_ddc_service_query_ddc_data(ddc_service, slave_address, &offset, - sizeof(offset), &tmds_config, sizeof(tmds_config)); - if (tmds_config & 0x1){ - union hdmi_scdc_status_flags_data status_data = {{0}}; - uint8_t scramble_status = 0; - - offset = HDMI_SCDC_SCRAMBLER_STATUS; - dal_ddc_service_query_ddc_data(ddc_service, slave_address, - &offset, sizeof(offset),&scramble_status, - sizeof(scramble_status)); - offset = HDMI_SCDC_STATUS_FLAGS; - dal_ddc_service_query_ddc_data(ddc_service, slave_address, - &offset, sizeof(offset),status_data.byte, - sizeof(status_data.byte)); - } -} diff --git a/drivers/gpu/drm/amd/dal/dc/dcs/ddc_service.h b/drivers/gpu/drm/amd/dal/dc/dcs/ddc_service.h deleted file mode 100644 index 3bf2a9e..0000000 --- a/drivers/gpu/drm/amd/dal/dc/dcs/ddc_service.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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_DDC_SERVICE_H__ -#define __DAL_DDC_SERVICE_H__ - -#include "include/ddc_service_types.h" - -void dal_ddc_service_set_ddc_pin( - struct ddc_service *ddc_service, - struct ddc *ddc); - -struct ddc *dal_ddc_service_get_ddc_pin(struct ddc_service *ddc_service); -void dal_ddc_service_reset_dp_receiver_id_info(struct ddc_service *ddc_service); - -enum ddc_result dal_ddc_service_read_dpcd_data( - struct ddc_service *ddc, - uint32_t address, - uint8_t *data, - uint32_t len); -enum ddc_result dal_ddc_service_write_dpcd_data( - struct ddc_service *ddc, - uint32_t address, - const uint8_t *data, - uint32_t len); - -#endif /* __DAL_DDC_SERVICE_H__ */ diff --git a/drivers/gpu/drm/amd/dal/dc/inc/dc_link_ddc.h b/drivers/gpu/drm/amd/dal/dc/inc/dc_link_ddc.h new file mode 100644 index 0000000..18104d6 --- /dev/null +++ b/drivers/gpu/drm/amd/dal/dc/inc/dc_link_ddc.h @@ -0,0 +1,151 @@ +/* + * 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_DDC_SERVICE_H__ +#define __DAL_DDC_SERVICE_H__ + +#include "include/ddc_service_types.h" +#include "include/i2caux_interface.h" + +#define EDID_SEGMENT_SIZE 256 + +struct ddc_service; +struct adapter_service; +struct graphics_object_id; +enum ddc_result; +struct av_sync_data; +struct dp_receiver_id_info; + +struct i2c_payloads; +struct aux_payloads; + +struct i2c_payloads *dal_ddc_i2c_payloads_create(struct dc_context *ctx, uint32_t count); +struct i2c_payload *dal_ddc_i2c_payloads_get(struct i2c_payloads *p); +uint32_t dal_ddc_i2c_payloads_get_count(struct i2c_payloads *p); +void dal_ddc_i2c_payloads_destroy(struct i2c_payloads **p); + +struct aux_payloads *dal_ddc_aux_payloads_create(struct dc_context *ctx, uint32_t count); +struct aux_payload *dal_ddc_aux_payloads_get(struct aux_payloads *p); +uint32_t dal_ddc_aux_payloads_get_count(struct aux_payloads *p); +void dal_ddc_aux_payloads_destroy(struct aux_payloads **p); + +void dal_ddc_i2c_payloads_add( + struct i2c_payloads *payloads, + uint32_t address, + uint32_t len, + uint8_t *data, + bool write); + +void dal_ddc_aux_payloads_add( + struct aux_payloads *payloads, + uint32_t address, + uint32_t len, + uint8_t *data, + bool write); + +struct ddc_service_init_data { + struct adapter_service *as; + struct graphics_object_id id; + struct dc_context *ctx; +}; + +struct ddc_service *dal_ddc_service_create( + struct ddc_service_init_data *ddc_init_data); + +void dal_ddc_service_destroy(struct ddc_service **ddc); + +enum ddc_service_type dal_ddc_service_get_type(struct ddc_service *ddc); + +void dal_ddc_service_set_transaction_type( + struct ddc_service *ddc, + enum ddc_transaction_type type); + +bool dal_ddc_service_is_in_aux_transaction_mode(struct ddc_service *ddc); + +uint32_t dal_ddc_service_edid_query(struct ddc_service *ddc); + +uint32_t dal_ddc_service_get_edid_buf_len(struct ddc_service *ddc); + +void dal_ddc_service_get_edid_buf(struct ddc_service *ddc, uint8_t *edid_buf); + +void dal_ddc_service_i2c_query_dp_dual_mode_adaptor( + struct ddc_service *ddc, + struct display_sink_capability *sink_cap); + +bool dal_ddc_service_query_ddc_data( + struct ddc_service *ddc, + uint32_t address, + uint8_t *write_buf, + uint32_t write_size, + uint8_t *read_buf, + uint32_t read_size); + +bool dal_ddc_service_get_dp_receiver_id_info( + struct ddc_service *ddc, + struct dp_receiver_id_info *info); + +enum ddc_result dal_ddc_service_read_dpcd_data( + struct ddc_service *ddc, + uint32_t address, + uint8_t *data, + uint32_t len); + +enum ddc_result dal_ddc_service_write_dpcd_data( + struct ddc_service *ddc, + uint32_t address, + const uint8_t *data, + uint32_t len); + +void dal_ddc_service_write_scdc_data( + struct ddc_service *ddc_service, + uint32_t pix_clk, + bool lte_340_scramble); + +void dal_ddc_service_read_scdc_data( + struct ddc_service *ddc_service); + +void ddc_service_set_dongle_type(struct ddc_service *ddc, + enum display_dongle_type dongle_type); + +void dal_ddc_service_set_ddc_pin( + struct ddc_service *ddc_service, + struct ddc *ddc); + +struct ddc *dal_ddc_service_get_ddc_pin(struct ddc_service *ddc_service); +void dal_ddc_service_reset_dp_receiver_id_info(struct ddc_service *ddc_service); + +enum ddc_result dal_ddc_service_read_dpcd_data( + struct ddc_service *ddc, + uint32_t address, + uint8_t *data, + uint32_t len); +enum ddc_result dal_ddc_service_write_dpcd_data( + struct ddc_service *ddc, + uint32_t address, + const uint8_t *data, + uint32_t len); + +#endif /* __DAL_DDC_SERVICE_H__ */ + diff --git a/drivers/gpu/drm/amd/dal/include/ddc_service_interface.h b/drivers/gpu/drm/amd/dal/include/ddc_service_interface.h deleted file mode 100644 index ca3e6ce..0000000 --- a/drivers/gpu/drm/amd/dal/include/ddc_service_interface.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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_DDC_SERVICE_INTERFACE_H__ -#define __DAL_DDC_SERVICE_INTERFACE_H__ - -#include "ddc_service_types.h" - -struct ddc_service; -struct adapter_service; -struct graphics_object_id; -enum ddc_result; -struct av_sync_data; -struct dp_receiver_id_info; - -struct ddc_service_init_data { - struct adapter_service *as; - struct graphics_object_id id; - struct dc_context *ctx; -}; -struct ddc_service *dal_ddc_service_create( - struct ddc_service_init_data *ddc_init_data); - -void dal_ddc_service_destroy(struct ddc_service **ddc); - -enum ddc_service_type dal_ddc_service_get_type(struct ddc_service *ddc); - -void dal_ddc_service_set_transaction_type( - struct ddc_service *ddc, - enum ddc_transaction_type type); - -bool dal_ddc_service_is_in_aux_transaction_mode(struct ddc_service *ddc); - -uint32_t dal_ddc_service_edid_query(struct ddc_service *ddc); - -uint32_t dal_ddc_service_get_edid_buf_len(struct ddc_service *ddc); - -void dal_ddc_service_get_edid_buf(struct ddc_service *ddc, uint8_t *edid_buf); - -void dal_ddc_service_i2c_query_dp_dual_mode_adaptor( - struct ddc_service *ddc, - struct display_sink_capability *sink_cap); - -bool dal_ddc_service_query_ddc_data( - struct ddc_service *ddc, - uint32_t address, - uint8_t *write_buf, - uint32_t write_size, - uint8_t *read_buf, - uint32_t read_size); - -bool dal_ddc_service_get_dp_receiver_id_info( - struct ddc_service *ddc, - struct dp_receiver_id_info *info); - -enum ddc_result dal_ddc_service_read_dpcd_data( - struct ddc_service *ddc, - uint32_t address, - uint8_t *data, - uint32_t len); - -enum ddc_result dal_ddc_service_write_dpcd_data( - struct ddc_service *ddc, - uint32_t address, - const uint8_t *data, - uint32_t len); - -void dal_ddc_service_write_scdc_data( - struct ddc_service *ddc_service, - uint32_t pix_clk, - bool lte_340_scramble); - -void dal_ddc_service_read_scdc_data( - struct ddc_service *ddc_service); - -void ddc_service_set_dongle_type(struct ddc_service *ddc, - enum display_dongle_type dongle_type); - -#endif /* __DAL_DDC_SERVICE_INTERFACE_H__ */ -- 2.7.4