aboutsummaryrefslogtreecommitdiffstats
path: root/meta-v1000/recipes-kernel/linux/linux-yocto-4.14.71/0321-drm-amd-display-Refactor-edid-read.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-v1000/recipes-kernel/linux/linux-yocto-4.14.71/0321-drm-amd-display-Refactor-edid-read.patch')
-rw-r--r--meta-v1000/recipes-kernel/linux/linux-yocto-4.14.71/0321-drm-amd-display-Refactor-edid-read.patch1123
1 files changed, 1123 insertions, 0 deletions
diff --git a/meta-v1000/recipes-kernel/linux/linux-yocto-4.14.71/0321-drm-amd-display-Refactor-edid-read.patch b/meta-v1000/recipes-kernel/linux/linux-yocto-4.14.71/0321-drm-amd-display-Refactor-edid-read.patch
new file mode 100644
index 00000000..3eb40489
--- /dev/null
+++ b/meta-v1000/recipes-kernel/linux/linux-yocto-4.14.71/0321-drm-amd-display-Refactor-edid-read.patch
@@ -0,0 +1,1123 @@
+From 436dca3938da2421f7ca20ec25e1740219aee890 Mon Sep 17 00:00:00 2001
+From: Andrey Grodzovsky <Andrey.Grodzovsky@amd.com>
+Date: Tue, 28 Mar 2017 16:57:52 -0400
+Subject: [PATCH 0321/4131] drm/amd/display: Refactor edid read.
+
+Allow Linux to use DRM provided EDID read functioality
+by moving DAL edid implementation to module hence
+removing this code from DC by this cleaning up DC
+code for upstream.
+
+v2: Removing ddc_service. No more need for it.
+
+Signed-off-by: Andrey Grodzovsky <Andrey.Grodzovsky@amd.com>
+Acked-by: Harry Wentland <Harry.Wentland@amd.com>
+Reviewed-by: Tony Cheng <Tony.Cheng@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+---
+ .../drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 47 +++
+ .../amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 47 ++-
+ .../amd/display/amdgpu_dm/amdgpu_dm_mst_types.h | 2 +-
+ .../drm/amd/display/amdgpu_dm/amdgpu_dm_types.c | 10 +-
+ drivers/gpu/drm/amd/display/dc/core/dc.c | 78 +++--
+ drivers/gpu/drm/amd/display/dc/core/dc_link.c | 53 +---
+ drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c | 337 +--------------------
+ drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 30 +-
+ drivers/gpu/drm/amd/display/dc/dc.h | 21 +-
+ drivers/gpu/drm/amd/display/dc/dc_types.h | 6 +
+ drivers/gpu/drm/amd/display/dc/dm_helpers.h | 10 +
+ drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c | 9 +-
+ drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h | 38 ++-
+ .../drm/amd/display/include/ddc_service_types.h | 28 --
+ .../gpu/drm/amd/display/include/i2caux_interface.h | 3 +
+ 15 files changed, 254 insertions(+), 465 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+index ca4fa5c..3401780 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+@@ -434,3 +434,50 @@ bool dm_helpers_submit_i2c(
+
+ return result;
+ }
++
++enum dc_edid_status dm_helpers_read_local_edid(
++ struct dc_context *ctx,
++ struct dc_link *link,
++ struct dc_sink *sink)
++{
++ struct amdgpu_connector *aconnector = link->priv;
++ struct i2c_adapter *ddc;
++ int retry = 3;
++ enum dc_edid_status edid_status;
++ struct edid *edid;
++
++ if (link->aux_mode)
++ ddc = &aconnector->dm_dp_aux.aux.ddc;
++ else
++ ddc = &aconnector->i2c->base;
++
++ /* some dongles read edid incorrectly the first time,
++ * do check sum and retry to make sure read correct edid.
++ */
++ do {
++
++ edid = drm_get_edid(&aconnector->base, ddc);
++
++ if (!edid)
++ return EDID_NO_RESPONSE;
++
++ sink->dc_edid.length = EDID_LENGTH * (edid->extensions + 1);
++ memmove(sink->dc_edid.raw_edid, (uint8_t *)edid, sink->dc_edid.length);
++
++ /* We don't need the original edid anymore */
++ kfree(edid);
++
++ edid_status = dm_helpers_parse_edid_caps(
++ ctx,
++ &sink->dc_edid,
++ &sink->edid_caps);
++
++ } while (edid_status == EDID_BAD_CHECKSUM && --retry > 0);
++
++ if (edid_status != EDID_OK)
++ DRM_ERROR("EDID err: %d, on connector: %s",
++ edid_status,
++ aconnector->base.name);
++
++ return edid_status;
++}
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+index cea8afb..436fa56 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+@@ -81,24 +81,43 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg
+ struct drm_device *drm_dev = pci_get_drvdata(pdev);
+ struct amdgpu_device *adev = drm_dev->dev_private;
+ struct dc *dc = adev->dm.dc;
++ enum i2c_mot_mode mot = (msg->request & DP_AUX_I2C_MOT) ? I2C_MOT_TRUE : I2C_MOT_FALSE;
+ bool res;
+
+- switch (msg->request) {
++ switch (msg->request & ~DP_AUX_I2C_MOT) {
+ case DP_AUX_NATIVE_READ:
+- res = dc_read_dpcd(
+- dc,
+- TO_DM_AUX(aux)->link_index,
+- msg->address,
+- msg->buffer,
+- msg->size);
++ res = dc_read_aux_dpcd(
++ dc,
++ TO_DM_AUX(aux)->link_index,
++ msg->address,
++ msg->buffer,
++ msg->size);
+ break;
+ case DP_AUX_NATIVE_WRITE:
+- res = dc_write_dpcd(
+- dc,
+- TO_DM_AUX(aux)->link_index,
+- msg->address,
+- msg->buffer,
+- msg->size);
++ res = dc_write_aux_dpcd(
++ dc,
++ TO_DM_AUX(aux)->link_index,
++ msg->address,
++ msg->buffer,
++ msg->size);
++ break;
++ case DP_AUX_I2C_READ:
++ res = dc_read_aux_i2c(
++ dc,
++ TO_DM_AUX(aux)->link_index,
++ mot,
++ msg->address,
++ msg->buffer,
++ msg->size);
++ break;
++ case DP_AUX_I2C_WRITE:
++ res = dc_write_aux_i2c(
++ dc,
++ TO_DM_AUX(aux)->link_index,
++ mot,
++ msg->address,
++ msg->buffer,
++ msg->size);
+ break;
+ default:
+ return 0;
+@@ -420,7 +439,7 @@ static const struct drm_dp_mst_topology_cbs dm_mst_cbs = {
+ .register_connector = dm_dp_mst_register_connector
+ };
+
+-void amdgpu_dm_initialize_mst_connector(
++void amdgpu_dm_initialize_dp_connector(
+ struct amdgpu_display_manager *dm,
+ struct amdgpu_connector *aconnector)
+ {
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
+index 6130d62..418061f 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
+@@ -29,7 +29,7 @@
+ struct amdgpu_display_manager;
+ struct amdgpu_connector;
+
+-void amdgpu_dm_initialize_mst_connector(
++void amdgpu_dm_initialize_dp_connector(
+ struct amdgpu_display_manager *dm,
+ struct amdgpu_connector *aconnector);
+
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_types.c
+index 4fba5ad..e9876574 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_types.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_types.c
+@@ -2218,7 +2218,7 @@ int amdgpu_dm_connector_init(
+
+ if (connector_type == DRM_MODE_CONNECTOR_DisplayPort
+ || connector_type == DRM_MODE_CONNECTOR_eDP)
+- amdgpu_dm_initialize_mst_connector(dm, aconnector);
++ amdgpu_dm_initialize_dp_connector(dm, aconnector);
+
+ #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) ||\
+ defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
+@@ -3209,9 +3209,11 @@ static bool is_dp_capable_without_timing_msa(
+ uint8_t dpcd_data;
+ bool capable = false;
+ if (amdgpu_connector->dc_link &&
+- dc_read_dpcd(dc, amdgpu_connector->dc_link->link_index,
+- DP_DOWN_STREAM_PORT_COUNT,
+- &dpcd_data, sizeof(dpcd_data)) )
++ dc_read_aux_dpcd(
++ dc,
++ amdgpu_connector->dc_link->link_index,
++ DP_DOWN_STREAM_PORT_COUNT,
++ &dpcd_data, sizeof(dpcd_data)))
+ capable = (dpcd_data & DP_MSA_TIMING_PAR_IGNORED) ? true:false;
+
+ return capable;
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
+index b389122..40a8001 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
+@@ -1553,7 +1553,7 @@ void dc_resume(const struct dc *dc)
+ core_link_resume(core_dc->links[i]);
+ }
+
+-bool dc_read_dpcd(
++bool dc_read_aux_dpcd(
+ struct dc *dc,
+ uint32_t link_index,
+ uint32_t address,
+@@ -1565,56 +1565,100 @@ bool dc_read_dpcd(
+ struct core_link *link = core_dc->links[link_index];
+ enum ddc_result r = dal_ddc_service_read_dpcd_data(
+ link->ddc,
++ false,
++ I2C_MOT_UNDEF,
+ address,
+ data,
+ size);
+ return r == DDC_RESULT_SUCESSFULL;
+ }
+
+-bool dc_query_ddc_data(
++bool dc_write_aux_dpcd(
+ struct dc *dc,
+ uint32_t link_index,
+ uint32_t address,
+- uint8_t *write_buf,
+- uint32_t write_size,
+- uint8_t *read_buf,
+- uint32_t read_size) {
+-
++ const uint8_t *data,
++ uint32_t size)
++{
+ struct core_dc *core_dc = DC_TO_CORE(dc);
+-
+ struct core_link *link = core_dc->links[link_index];
+
+- bool result = dal_ddc_service_query_ddc_data(
++ enum ddc_result r = dal_ddc_service_write_dpcd_data(
+ link->ddc,
++ false,
++ I2C_MOT_UNDEF,
+ address,
+- write_buf,
+- write_size,
+- read_buf,
+- read_size);
+-
+- return result;
++ data,
++ size);
++ return r == DDC_RESULT_SUCESSFULL;
+ }
+
++bool dc_read_aux_i2c(
++ struct dc *dc,
++ uint32_t link_index,
++ enum i2c_mot_mode mot,
++ uint32_t address,
++ uint8_t *data,
++ uint32_t size)
++{
++ struct core_dc *core_dc = DC_TO_CORE(dc);
+
+-bool dc_write_dpcd(
++ struct core_link *link = core_dc->links[link_index];
++ enum ddc_result r = dal_ddc_service_read_dpcd_data(
++ link->ddc,
++ true,
++ mot,
++ address,
++ data,
++ size);
++ return r == DDC_RESULT_SUCESSFULL;
++}
++
++bool dc_write_aux_i2c(
+ struct dc *dc,
+ uint32_t link_index,
++ enum i2c_mot_mode mot,
+ uint32_t address,
+ const uint8_t *data,
+ uint32_t size)
+ {
+ struct core_dc *core_dc = DC_TO_CORE(dc);
+-
+ struct core_link *link = core_dc->links[link_index];
+
+ enum ddc_result r = dal_ddc_service_write_dpcd_data(
+ link->ddc,
++ true,
++ mot,
+ address,
+ data,
+ size);
+ return r == DDC_RESULT_SUCESSFULL;
+ }
+
++bool dc_query_ddc_data(
++ struct dc *dc,
++ uint32_t link_index,
++ uint32_t address,
++ uint8_t *write_buf,
++ uint32_t write_size,
++ uint8_t *read_buf,
++ uint32_t read_size) {
++
++ struct core_dc *core_dc = DC_TO_CORE(dc);
++
++ struct core_link *link = core_dc->links[link_index];
++
++ bool result = dal_ddc_service_query_ddc_data(
++ link->ddc,
++ address,
++ write_buf,
++ write_size,
++ read_buf,
++ read_size);
++
++ return result;
++}
++
+ bool dc_submit_i2c(
+ struct dc *dc,
+ uint32_t link_index,
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+index 74dd272..0f825f6 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+@@ -464,39 +464,6 @@ static void link_disconnect_sink(struct core_link *link)
+ link->dpcd_sink_count = 0;
+ }
+
+-static enum dc_edid_status read_edid(
+- struct core_link *link,
+- struct core_sink *sink)
+-{
+- uint32_t edid_retry = 3;
+- enum dc_edid_status edid_status;
+-
+- /* some dongles read edid incorrectly the first time,
+- * do check sum and retry to make sure read correct edid.
+- */
+- do {
+- sink->public.dc_edid.length =
+- dal_ddc_service_edid_query(link->ddc);
+-
+- if (0 == sink->public.dc_edid.length)
+- return EDID_NO_RESPONSE;
+-
+- dal_ddc_service_get_edid_buf(link->ddc,
+- sink->public.dc_edid.raw_edid);
+- edid_status = dm_helpers_parse_edid_caps(
+- sink->ctx,
+- &sink->public.dc_edid,
+- &sink->public.edid_caps);
+- --edid_retry;
+- if (edid_status == EDID_BAD_CHECKSUM)
+- dm_logger_write(link->ctx->logger, LOG_WARNING,
+- "Bad EDID checksum, retry remain: %d\n",
+- edid_retry);
+- } while (edid_status == EDID_BAD_CHECKSUM && edid_retry > 0);
+-
+- return edid_status;
+-}
+-
+ static void detect_dp(
+ struct core_link *link,
+ struct display_sink_capability *sink_caps,
+@@ -673,6 +640,9 @@ bool dc_link_detect(const struct dc_link *dc_link, bool boot)
+ link->ddc,
+ sink_caps.transaction_type);
+
++ link->public.aux_mode = dal_ddc_service_is_in_aux_transaction_mode(
++ link->ddc);
++
+ sink_init_data.link = &link->public;
+ sink_init_data.sink_signal = sink_caps.signal;
+
+@@ -688,7 +658,10 @@ bool dc_link_detect(const struct dc_link *dc_link, bool boot)
+ sink = DC_SINK_TO_CORE(dc_sink);
+ link->public.local_sink = &sink->public;
+
+- edid_status = read_edid(link, sink);
++ edid_status = dm_helpers_read_local_edid(
++ link->ctx,
++ &link->public,
++ &sink->public);
+
+ switch (edid_status) {
+ case EDID_BAD_CHECKSUM:
+@@ -1500,11 +1473,13 @@ bool dc_link_setup_psr(const struct dc_link *dc_link,
+ */
+ psr_configuration.bits.IRQ_HPD_WITH_CRC_ERROR = 1;
+ }
+- dal_ddc_service_write_dpcd_data(
+- link->ddc,
+- 368,
+- &psr_configuration.raw,
+- sizeof(psr_configuration.raw));
++
++ dm_helpers_dp_write_dpcd(
++ link->ctx,
++ dc_link,
++ 368,
++ &psr_configuration.raw,
++ sizeof(psr_configuration.raw));
+
+ psr_context.channel = link->ddc->ddc_pin->hw_info.ddc_channel;
+ if (psr_context.channel == 0)
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
+index 4e9465b..2f5a89c 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
+@@ -58,30 +58,6 @@ struct dp_hdmi_dongle_signature_data {
+ 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
+@@ -392,7 +368,7 @@ static uint32_t defer_delay_converter_wa(
+
+ #define DP_TRANSLATOR_DELAY 5
+
+-static uint32_t get_defer_delay(struct ddc_service *ddc)
++uint32_t get_defer_delay(struct ddc_service *ddc)
+ {
+ uint32_t defer_delay = 0;
+
+@@ -451,307 +427,6 @@ static bool i2c_read(
+ &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(
+- ddc->ctx->i2caux,
+- 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(
+- ddc->ctx->i2caux,
+- ddc->ddc_pin,
+- &cmd);
+-
+- if (false == result)
+- dm_logger_write(
+- ddc->ctx->logger, LOG_ERROR,
+- "%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 = ddc->ctx->dc->caps.i2c_speed_in_khz };
+-
+- 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 (dm_helpers_submit_i2c(
+- ddc->ctx,
+- &ddc->link->public,
+- &cmd)) {
+-
+- cmd.payloads = &payloads[2];
+- cmd.number_of_payloads = 1;
+-
+- ret = dm_helpers_submit_i2c(
+- ddc->ctx,
+- &ddc->link->public,
+- &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 = dm_helpers_submit_i2c(
+- ddc->ctx,
+- &ddc->link->public,
+- &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)) {
+- 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)
+-{
+- 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)
+@@ -960,12 +635,14 @@ bool dal_ddc_service_query_ddc_data(
+
+ enum ddc_result dal_ddc_service_read_dpcd_data(
+ struct ddc_service *ddc,
++ bool i2c,
++ enum i2c_mot_mode mot,
+ uint32_t address,
+ uint8_t *data,
+ uint32_t len)
+ {
+ struct aux_payload read_payload = {
+- .i2c_over_aux = false,
++ .i2c_over_aux = i2c,
+ .write = false,
+ .address = address,
+ .length = len,
+@@ -976,6 +653,7 @@ enum ddc_result dal_ddc_service_read_dpcd_data(
+ .number_of_payloads = 1,
+ .defer_delay = 0,
+ .max_defer_write_retry = 0,
++ .mot = mot
+ };
+
+ if (len > DEFAULT_AUX_MAX_DATA_SIZE) {
+@@ -994,12 +672,14 @@ enum ddc_result dal_ddc_service_read_dpcd_data(
+
+ enum ddc_result dal_ddc_service_write_dpcd_data(
+ struct ddc_service *ddc,
++ bool i2c,
++ enum i2c_mot_mode mot,
+ uint32_t address,
+ const uint8_t *data,
+ uint32_t len)
+ {
+ struct aux_payload write_payload = {
+- .i2c_over_aux = false,
++ .i2c_over_aux = i2c,
+ .write = true,
+ .address = address,
+ .length = len,
+@@ -1010,6 +690,7 @@ enum ddc_result dal_ddc_service_write_dpcd_data(
+ .number_of_payloads = 1,
+ .defer_delay = 0,
+ .max_defer_write_retry = 0,
++ .mot = mot
+ };
+
+ if (len > DEFAULT_AUX_MAX_DATA_SIZE) {
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
+index 6cfd880..802d8cc 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
+@@ -1481,22 +1481,25 @@ static bool handle_hpd_irq_psr_sink(const struct core_link *link)
+ if (link->public.psr_caps.psr_version == 0)
+ return false;
+
+- dal_ddc_service_read_dpcd_data(
+- link->ddc,
+- 368 /*DpcdAddress_PSR_Enable_Cfg*/,
+- &psr_configuration.raw,
+- sizeof(psr_configuration.raw));
++ dm_helpers_dp_read_dpcd(
++ link->ctx,
++ &link->public,
++ 368,/*DpcdAddress_PSR_Enable_Cfg*/
++ &psr_configuration.raw,
++ sizeof(psr_configuration.raw));
++
+
+ if (psr_configuration.bits.ENABLE) {
+ unsigned char dpcdbuf[3] = {0};
+ union psr_error_status psr_error_status;
+ union psr_sink_psr_status psr_sink_psr_status;
+
+- dal_ddc_service_read_dpcd_data(
+- link->ddc,
+- 0x2006 /*DpcdAddress_PSR_Error_Status*/,
+- (unsigned char *) dpcdbuf,
+- sizeof(dpcdbuf));
++ dm_helpers_dp_read_dpcd(
++ link->ctx,
++ &link->public,
++ 0x2006, /*DpcdAddress_PSR_Error_Status*/
++ (unsigned char *) dpcdbuf,
++ sizeof(dpcdbuf));
+
+ /*DPCD 2006h ERROR STATUS*/
+ psr_error_status.raw = dpcdbuf[0];
+@@ -1506,9 +1509,10 @@ static bool handle_hpd_irq_psr_sink(const struct core_link *link)
+ if (psr_error_status.bits.LINK_CRC_ERROR ||
+ psr_error_status.bits.RFB_STORAGE_ERROR) {
+ /* Acknowledge and clear error bits */
+- dal_ddc_service_write_dpcd_data(
+- link->ddc,
+- 8198 /*DpcdAddress_PSR_Error_Status*/,
++ dm_helpers_dp_write_dpcd(
++ link->ctx,
++ &link->public,
++ 8198,/*DpcdAddress_PSR_Error_Status*/
+ &psr_error_status.raw,
+ sizeof(psr_error_status.raw));
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
+index d296055..a27a6ab 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc.h
++++ b/drivers/gpu/drm/amd/display/dc/dc.h
+@@ -594,6 +594,7 @@ struct dc_link {
+ union compliance_test_state compliance_test_state;
+
+ void *priv;
++ bool aux_mode;
+ };
+
+ struct dpcd_caps {
+@@ -788,20 +789,36 @@ const struct ddc_service *dc_get_ddc_at_index(
+ * DPCD access interfaces
+ */
+
+-bool dc_read_dpcd(
++bool dc_read_aux_dpcd(
+ struct dc *dc,
+ uint32_t link_index,
+ uint32_t address,
+ uint8_t *data,
+ uint32_t size);
+
+-bool dc_write_dpcd(
++bool dc_write_aux_dpcd(
+ struct dc *dc,
+ uint32_t link_index,
+ uint32_t address,
+ const uint8_t *data,
+ uint32_t size);
+
++bool dc_read_aux_i2c(
++ struct dc *dc,
++ uint32_t link_index,
++ enum i2c_mot_mode mot,
++ uint32_t address,
++ uint8_t *data,
++ uint32_t size);
++
++bool dc_write_aux_i2c(
++ struct dc *dc,
++ uint32_t link_index,
++ enum i2c_mot_mode mot,
++ uint32_t address,
++ const uint8_t *data,
++ uint32_t size);
++
+ bool dc_query_ddc_data(
+ struct dc *dc,
+ uint32_t link_index,
+diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h
+index 242dd7b..e0436e3 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc_types.h
++++ b/drivers/gpu/drm/amd/display/dc/dc_types.h
+@@ -489,4 +489,10 @@ struct psr_caps {
+ unsigned int psr_sdp_transmit_line_num_deadline;
+ };
+
++enum i2c_mot_mode {
++ I2C_MOT_UNDEF,
++ I2C_MOT_TRUE,
++ I2C_MOT_FALSE
++};
++
+ #endif /* DC_TYPES_H_ */
+diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
+index d6c52d3..c15a25c 100644
+--- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h
++++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
+@@ -98,4 +98,14 @@ bool dm_helpers_submit_i2c(
+ struct i2c_command *cmd);
+
+
++
++
++
++
++enum dc_edid_status dm_helpers_read_local_edid(
++ struct dc_context *ctx,
++ struct dc_link *link,
++ struct dc_sink *sink);
++
++
+ #endif /* __DM_HELPERS__ */
+diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c b/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c
+index bd84b93..0743265 100644
+--- a/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c
++++ b/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c
+@@ -185,6 +185,7 @@ bool dal_i2caux_submit_aux_command(
+ struct aux_engine *engine;
+ uint8_t index_of_payload = 0;
+ bool result;
++ bool mot;
+
+ if (!ddc) {
+ BREAK_TO_DEBUGGER();
+@@ -207,12 +208,14 @@ bool dal_i2caux_submit_aux_command(
+ result = true;
+
+ while (index_of_payload < cmd->number_of_payloads) {
+- bool mot = (index_of_payload != cmd->number_of_payloads - 1);
+-
+ struct aux_payload *payload = cmd->payloads + index_of_payload;
+-
+ struct i2caux_transaction_request request = { 0 };
+
++ if (cmd->mot == I2C_MOT_UNDEF)
++ mot = (index_of_payload != cmd->number_of_payloads - 1);
++ else
++ mot = (cmd->mot == I2C_MOT_TRUE);
++
+ request.operation = payload->write ?
+ I2CAUX_TRANSACTION_WRITE :
+ I2CAUX_TRANSACTION_READ;
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h
+index 830fc3d..9c2f670 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h
+@@ -31,6 +31,23 @@
+
+ #define EDID_SEGMENT_SIZE 256
+
++/* 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
++
+ struct ddc_service;
+ struct graphics_object_id;
+ enum ddc_result;
+@@ -83,12 +100,6 @@ void dal_ddc_service_set_transaction_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);
+@@ -103,12 +114,16 @@ bool dal_ddc_service_query_ddc_data(
+
+ enum ddc_result dal_ddc_service_read_dpcd_data(
+ struct ddc_service *ddc,
++ bool i2c,
++ enum i2c_mot_mode mot,
+ uint32_t address,
+ uint8_t *data,
+ uint32_t len);
+
+ enum ddc_result dal_ddc_service_write_dpcd_data(
+ struct ddc_service *ddc,
++ bool i2c,
++ enum i2c_mot_mode mot,
+ uint32_t address,
+ const uint8_t *data,
+ uint32_t len);
+@@ -130,16 +145,7 @@ void dal_ddc_service_set_ddc_pin(
+
+ struct ddc *dal_ddc_service_get_ddc_pin(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);
++uint32_t get_defer_delay(struct ddc_service *ddc);
+
+ #endif /* __DAL_DDC_SERVICE_H__ */
+
+diff --git a/drivers/gpu/drm/amd/display/include/ddc_service_types.h b/drivers/gpu/drm/amd/display/include/ddc_service_types.h
+index effe03b..0ff2a89 100644
+--- a/drivers/gpu/drm/amd/display/include/ddc_service_types.h
++++ b/drivers/gpu/drm/amd/display/include/ddc_service_types.h
+@@ -115,34 +115,6 @@ struct av_sync_data {
+ uint8_t aud_del_ins3;/* DPCD 0002Dh */
+ };
+
+-/** EDID retrieval related constants, also used by MstMgr **/
+-
+-#define DDC_EDID_SEGMENT_SIZE 256
+-#define DDC_EDID_BLOCK_SIZE 128
+-#define DDC_EDID_BLOCKS_PER_SEGMENT \
+- (DDC_EDID_SEGMENT_SIZE / DDC_EDID_BLOCK_SIZE)
+-
+-#define DDC_EDID_EXT_COUNT_OFFSET 0x7E
+-
+-#define DDC_EDID_ADDRESS_START 0x50
+-#define DDC_EDID_ADDRESS_END 0x52
+-#define DDC_EDID_SEGMENT_ADDRESS 0x30
+-
+-/* signatures for Edid 1x */
+-#define DDC_EDID1X_VENDORID_SIGNATURE_OFFSET 8
+-#define DDC_EDID1X_VENDORID_SIGNATURE_LEN 4
+-#define DDC_EDID1X_EXT_CNT_AND_CHECKSUM_OFFSET 126
+-#define DDC_EDID1X_EXT_CNT_AND_CHECKSUM_LEN 2
+-#define DDC_EDID1X_CHECKSUM_OFFSET 127
+-/* signatures for Edid 20*/
+-#define DDC_EDID_20_SIGNATURE_OFFSET 0
+-#define DDC_EDID_20_SIGNATURE 0x20
+-
+-#define DDC_EDID20_VENDORID_SIGNATURE_OFFSET 1
+-#define DDC_EDID20_VENDORID_SIGNATURE_LEN 4
+-#define DDC_EDID20_CHECKSUM_OFFSET 255
+-#define DDC_EDID20_CHECKSUM_LEN 1
+-
+ /*DP to VGA converter*/
+ static const uint8_t DP_VGA_CONVERTER_ID_1[] = "mVGAa";
+ /*DP to Dual link DVI converter*/
+diff --git a/drivers/gpu/drm/amd/display/include/i2caux_interface.h b/drivers/gpu/drm/amd/display/include/i2caux_interface.h
+index d2ec04d..13a3c82 100644
+--- a/drivers/gpu/drm/amd/display/include/i2caux_interface.h
++++ b/drivers/gpu/drm/amd/display/include/i2caux_interface.h
+@@ -26,6 +26,7 @@
+ #ifndef __DAL_I2CAUX_INTERFACE_H__
+ #define __DAL_I2CAUX_INTERFACE_H__
+
++#include "dc_types.h"
+ #include "gpio_service_interface.h"
+
+
+@@ -54,6 +55,8 @@ struct aux_command {
+
+ /* zero means "use default value" */
+ uint32_t max_defer_write_retry;
++
++ enum i2c_mot_mode mot;
+ };
+
+ union aux_config {
+--
+2.7.4
+