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 5b096be44e596495b49a16aca3c38cf2961dc940..01d04fa2419efa3cdac0b6eb0823d2015d601c32 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 @@ -435,3 +435,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 069511bb6fab5921afe716fb01894bffd46df084..187464ac27b30d6180ed0cc417e94efa446bec69 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; @@ -418,7 +437,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 6130d62ac65c4d36ca131e24f71d635b740104c6..418061f3b46b8122f3413ec11a5bdde900e4c409 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 c09af2b3350c8d8e715452d44a2f6dd382ca6547..345df1b6d82b2fa20fc9023ebfc9bbda3ac891b9 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 @@ -2047,7 +2047,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) @@ -3038,9 +3038,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 b3891228b499c6a2806bb8be51e6461678ce0aab..40a800155fe60a36560252e3c3f7acda4d14d98e 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 74dd272d745264819f20dab72233fc7ba2e3b4d8..0f825f6326aba4ead1d1c8c73b56b11c9e7f2fd7 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 4e9465b630d13dd999445973ed38ced1f420e1ef..2f5a89c5b063fbe09f1e7af05b7493640605979e 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 b8c40e8bee5a253b474b0925889d8c0457c52936..9f12ba87827a01f553b6dbf062bd8013e7af494f 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 d2960552c78ea424f4349cdb5267325816f4219c..a27a6aba0df16edb6d13f99c0a3a79860eb358e5 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 242dd7b3b6b1dd2308dab4bc5d7311aa792a20fa..e0436e317341f77a829dbbc1d7eac3713b10fb1b 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 d6c52d31f0f07b5010d6ba5561e31f49b846623b..c15a25ce8049926b6f5ae0a1bb6f970aba204ce8 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 bd84b932aaaef195dc198fb18ccc1c79e563ab04..0743265e933cfbf7b42eb86178cd858ac5c61adc 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 830fc3d039c91405debbb2b42436128307a43c21..9c2f670c3dc32fe9bfdfb408b89267787ea7570a 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 effe03b8f4181a4e7d828bf0a1febc78de0a5d9e..0ff2a899b8f7506b6bef56a316a4d5b6bbab3a16 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 d2ec04d1c5923cdbb3cc35074bbf9a395c429923..13a3c82d118f170963e752f415adcc7a73e439a8 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 {