]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/amd/display: Add no_native_i2c codepath
authorMatthew Stewart <Matthew.Stewart2@amd.com>
Tue, 19 May 2026 01:34:57 +0000 (21:34 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 3 Jun 2026 17:43:29 +0000 (13:43 -0400)
[Why]
ASICs which do not have native DDC capability must use a different
codepath to access the AUX channel.

[How]
- BIOS cap NO_DDC_PIN is set to 1 for links which do not have the DDC pin.
- dp_connector_no_native_i2c in dc_config must also be set to true to
  use this codepath.

Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Matthew Stewart <Matthew.Stewart2@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
12 files changed:
drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
drivers/gpu/drm/amd/display/dc/dc.h
drivers/gpu/drm/amd/display/dc/dc_bios_types.h
drivers/gpu/drm/amd/display/dc/dc_fused_io.c
drivers/gpu/drm/amd/display/dc/dce/dce_aux.c
drivers/gpu/drm/amd/display/dc/dce/dce_aux.h
drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
drivers/gpu/drm/amd/display/dc/link/link_factory.c
drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.c
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
drivers/gpu/drm/amd/display/include/bios_parser_types.h

index 9764c1a478c54d3f581a5ac64d12e569782b4470..6774a501945bdb5ddca012a1698d6731335c1060 100644 (file)
@@ -718,6 +718,69 @@ static enum bp_result bios_parser_get_gpio_pin_info(
        return BP_RESULT_NORECORD;
 }
 
+static enum bp_result bios_parser_get_connector_aux_info(struct dc_bios *dcb,
+       struct graphics_object_id id,
+       struct graphics_object_i2c_info *info)
+{
+       uint32_t offset;
+       struct atom_display_object_path_v2 *object;
+       struct atom_display_object_path_v3 *object_path_v3;
+       struct atom_common_record_header *header;
+       struct atom_i2c_record *record;
+       struct bios_parser *bp = BP_FROM_DCB(dcb);
+
+       if (!info)
+               return BP_RESULT_BADINPUT;
+
+       switch (bp->object_info_tbl.revision.minor) {
+       case 4:
+       default:
+               object = get_bios_object(bp, id);
+
+               if (!object)
+                       return BP_RESULT_BADINPUT;
+
+               offset = object->disp_recordoffset + bp->object_info_tbl_offset;
+               break;
+       case 5:
+               object_path_v3 = get_bios_object_from_path_v3(bp, id);
+
+               if (!object_path_v3)
+                       return BP_RESULT_BADINPUT;
+
+               offset = object_path_v3->disp_recordoffset + bp->object_info_tbl_offset;
+               break;
+       }
+
+       for (;;) {
+               header = GET_IMAGE(struct atom_common_record_header, offset);
+
+               if (!header)
+                       return BP_RESULT_BADBIOSTABLE;
+
+               if (header->record_type == LAST_RECORD_TYPE ||
+                       !header->record_size)
+                       break;
+
+               if (header->record_type == ATOM_I2C_RECORD_TYPE
+                       && sizeof(struct atom_i2c_record) <=
+                       header->record_size) {
+                       /* get_connector_aux_info - which aux instance is used it is based
+                        * on record->i2c_id field only, does not need GPIO DDC
+                        */
+                       record = (struct atom_i2c_record *)header;
+
+                       info->i2c_line = record->i2c_id & I2C_HW_LANE_MUX;
+
+                       return BP_RESULT_OK;
+               }
+
+               offset += header->record_size;
+       }
+
+       return BP_RESULT_NORECORD;
+}
+
 static struct device_id device_type_from_device_id(uint16_t device_id)
 {
 
@@ -2349,6 +2412,9 @@ static enum bp_result bios_parser_get_disp_connector_caps_info(
                                                                        ? 1 : 0;
                info->INTERNAL_DISPLAY_BL = (record_path_v3->connector_caps & ATOM_CONNECTOR_CAP_INTERNAL_DISPLAY_BL)
                                                                                ? 1 : 0;
+               // All aux transactions for this connector should rely only on aux instance, not on ddc instance
+               info->NO_DDC_PIN = (record_path_v3->connector_caps & ATOM_CONNECTOR_CAP_DP_PLUS_PLUS_TYPE2_ONLY) ? 1 : 0;
+
                break;
        }
 
@@ -3717,6 +3783,7 @@ static const struct dc_vbios_funcs vbios_funcs = {
        .get_lttpr_interop = bios_parser_get_lttpr_interop,
 
        .get_connector_speed_cap_info = bios_parser_get_connector_speed_cap_info,
+       .get_connector_aux_info = bios_parser_get_connector_aux_info,
 };
 
 static bool bios_parser2_construct(
index 75f59ca927ffeef981e33303b04a7fc0e7c78268..3ffcb74552c4f7819c99e88e2a8abb198528fc92 100644 (file)
@@ -559,6 +559,7 @@ struct dc_config {
        bool enable_dpia_pre_training;
        bool unify_link_enc_assignment;
        bool enable_cursor_offload;
+       bool dp_connector_no_native_i2c;
        bool frame_update_cmd_version2;
        struct spl_sharpness_range dcn_sharpness_range;
        struct spl_sharpness_range dcn_override_sharpness_range;
@@ -1652,6 +1653,13 @@ struct dc_scratch_space {
        struct dc_link_training_overrides preferred_training_settings;
        struct dp_audio_test_data audio_test_data;
 
+       /* On ASICs with dp_connector_no_native_i2c cap set and no_ddc_pin cap
+        * set by IFWI, link aux_hw_inst is used in aux layer functions instead
+        * of ddc_pin to know which aux instance is associated with link.
+        */
+       bool no_ddc_pin;
+       enum gpio_ddc_line aux_hw_inst;
+
        enum gpio_ddc_line ddc_hw_inst;
 
        uint8_t hpd_src;
index 526f71616f94b8b9b9c2b55c72ee60be61d444e5..5f9560147939f91edd24fbff7935a5e7d5ce80fd 100644 (file)
@@ -172,6 +172,10 @@ struct dc_vbios_funcs {
                struct dc_bios *bios,
                struct graphics_object_id object_id,
                struct bp_connector_speed_cap_info *info);
+       enum bp_result(*get_connector_aux_info)(
+               struct dc_bios *dcb,
+               struct graphics_object_id id,
+               struct graphics_object_i2c_info *info);
 };
 
 struct bios_registers {
index 664cb4abf623b21bbee21ff7c9beb3bf344e6be4..923f70724419058bbcb9ee90d9f6fe266db9799b 100644 (file)
@@ -102,8 +102,8 @@ bool dm_atomic_write_poll_read_i2c(
        if (!link)
                return false;
 
-       const bool over_aux = false;
-       const uint32_t ddc_line = link->ddc->ddc_pin->pin_data->en;
+       const bool over_aux = link->no_ddc_pin;
+       const uint32_t ddc_line = over_aux ? link->aux_hw_inst : link->ddc->ddc_pin->pin_data->en;
 
        union dmub_rb_cmd commands[3] = { 0 };
        const bool converted = op_i2c_convert(&commands[0], write, FUSED_REQUEST_WRITE, ddc_line, over_aux)
index 181944ce77aba42e24380b8ff8450cbce5700c4b..72ad3ee3d6a57758119c6d2b8bbea74297f6ce49 100644 (file)
@@ -274,8 +274,14 @@ static void submit_channel_request(
        }
 
        REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1);
-       EVENT_LOG_AUX_REQ(engine->ddc->pin_data->en, EVENT_LOG_AUX_ORIGIN_NATIVE,
-                                       request->action, request->address, request->length, request->data);
+
+       if (engine->ddc) {
+               EVENT_LOG_AUX_REQ(engine->ddc->pin_data->en, EVENT_LOG_AUX_ORIGIN_NATIVE,
+                   request->action, request->address, request->length, request->data);
+       } else {
+               EVENT_LOG_AUX_REQ(engine->inst, EVENT_LOG_AUX_ORIGIN_NATIVE,
+                   request->action, request->address, request->length, request->data);
+       }
 }
 
 static int read_channel_reply(struct dce_aux *engine, uint32_t size,
@@ -421,6 +427,21 @@ static bool acquire(
        return true;
 }
 
+static bool acquire_aux_engine_without_ddc_pin(
+       struct dce_aux *engine,
+       struct ddc *ddc)
+{
+       (void)ddc;
+       if ((engine == NULL) || !is_engine_available(engine))
+               return false;
+
+       if (!acquire_engine(engine)) {
+               release_engine(engine);
+               return false;
+       }
+       return true;
+}
+
 void dce110_engine_destroy(struct dce_aux **engine)
 {
 
@@ -431,6 +452,73 @@ void dce110_engine_destroy(struct dce_aux **engine)
 
 }
 
+static uint32_t dce_aux_configure_timeout_without_ddc_pin(struct ddc_service *ddc,
+       uint32_t timeout_in_us)
+{
+       uint32_t multiplier = 0;
+       uint32_t length = 0;
+       uint32_t prev_length = 0;
+       uint32_t prev_mult = 0;
+       uint32_t prev_timeout_val = 0;
+       struct dce_aux *aux_engine = ddc->ctx->dc->res_pool->engines[ddc->link->aux_hw_inst];
+       struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(aux_engine);
+
+       /* 1-Update polling timeout period */
+       aux110->polling_timeout_period = timeout_in_us * SW_AUX_TIMEOUT_PERIOD_MULTIPLIER;
+
+       /* 2-Update aux timeout period length and multiplier */
+       if (timeout_in_us == 0) {
+               multiplier = DEFAULT_AUX_ENGINE_MULT;
+               length = DEFAULT_AUX_ENGINE_LENGTH;
+       } else if (timeout_in_us <= TIME_OUT_INCREMENT) {
+               multiplier = 0;
+               length = timeout_in_us / TIME_OUT_MULTIPLIER_8;
+               if (timeout_in_us % TIME_OUT_MULTIPLIER_8 != 0)
+                       length++;
+       } else if (timeout_in_us <= 2 * TIME_OUT_INCREMENT) {
+               multiplier = 1;
+               length = timeout_in_us / TIME_OUT_MULTIPLIER_16;
+               if (timeout_in_us % TIME_OUT_MULTIPLIER_16 != 0)
+                       length++;
+       } else if (timeout_in_us <= 4 * TIME_OUT_INCREMENT) {
+               multiplier = 2;
+               length = timeout_in_us / TIME_OUT_MULTIPLIER_32;
+               if (timeout_in_us % TIME_OUT_MULTIPLIER_32 != 0)
+                       length++;
+       } else if (timeout_in_us > 4 * TIME_OUT_INCREMENT) {
+               multiplier = 3;
+               length = timeout_in_us / TIME_OUT_MULTIPLIER_64;
+               if (timeout_in_us % TIME_OUT_MULTIPLIER_64 != 0)
+                       length++;
+       }
+
+       length = (length < MAX_TIMEOUT_LENGTH) ? length : MAX_TIMEOUT_LENGTH;
+
+       REG_GET_2(AUX_DPHY_RX_CONTROL1, AUX_RX_TIMEOUT_LEN, &prev_length, AUX_RX_TIMEOUT_LEN_MUL, &prev_mult);
+
+       switch (prev_mult) {
+       case 0:
+               prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_8;
+               break;
+       case 1:
+               prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_16;
+               break;
+       case 2:
+               prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_32;
+               break;
+       case 3:
+               prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_64;
+               break;
+       default:
+               prev_timeout_val = DEFAULT_AUX_ENGINE_LENGTH * TIME_OUT_MULTIPLIER_8;
+               break;
+       }
+
+       REG_UPDATE_SEQ_2(AUX_DPHY_RX_CONTROL1, AUX_RX_TIMEOUT_LEN, length, AUX_RX_TIMEOUT_LEN_MUL, multiplier);
+
+       return prev_timeout_val;
+}
+
 static uint32_t dce_aux_configure_timeout(struct ddc_service *ddc,
                uint32_t timeout_in_us)
 {
@@ -440,6 +528,10 @@ static uint32_t dce_aux_configure_timeout(struct ddc_service *ddc,
        uint32_t prev_mult = 0;
        uint32_t prev_timeout_val = 0;
        struct ddc *ddc_pin = ddc->ddc_pin;
+
+       if (ddc->ctx->dc->config.dp_connector_no_native_i2c && ddc->link->no_ddc_pin)
+               return dce_aux_configure_timeout_without_ddc_pin(ddc, timeout_in_us);
+
        struct dce_aux *aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en];
        struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(aux_engine);
 
@@ -560,11 +652,20 @@ int dce_aux_transfer_raw(struct ddc_service *ddc,
                struct aux_payload *payload,
                enum aux_return_code_type *operation_result)
 {
-       if (ddc->ctx->dc->debug.enable_dmub_aux_for_legacy_ddc ||
-           !ddc->ddc_pin) {
-               return dce_aux_transfer_dmub_raw(ddc, payload, operation_result);
+       if (ddc->ctx->dc->config.dp_connector_no_native_i2c && ddc->link->no_ddc_pin) {
+               /* Check whether aux to be processed via dmub or dcn directly */
+               if (ddc->ctx->dc->debug.enable_dmub_aux_for_legacy_ddc) {
+                       return dce_aux_transfer_dmub_raw(ddc, payload, operation_result);
+               } else {
+                       return dce_aux_transfer_raw_without_ddc_pin(ddc, payload, operation_result);
+               }
        } else {
-               return dce_aux_transfer_raw_with_ddc_pin(ddc, payload, operation_result);
+               if (ddc->ctx->dc->debug.enable_dmub_aux_for_legacy_ddc ||
+                   !ddc->ddc_pin) {
+                       return dce_aux_transfer_dmub_raw(ddc, payload, operation_result);
+               } else {
+                       return dce_aux_transfer_raw_with_ddc_pin(ddc, payload, operation_result);
+               }
        }
 }
 
@@ -625,6 +726,59 @@ int dce_aux_transfer_raw_with_ddc_pin(struct ddc_service *ddc,
        return res;
 }
 
+int dce_aux_transfer_raw_without_ddc_pin(struct ddc_service *ddc,
+       struct aux_payload *payload,
+       enum aux_return_code_type *operation_result)
+{
+       struct ddc *ddc_pin = ddc->ddc_pin;
+       struct dce_aux *aux_engine;
+       struct aux_request_transaction_data aux_req;
+       uint8_t returned_bytes = 0;
+       int res = -1;
+       uint32_t status;
+
+       memset(&aux_req, 0, sizeof(aux_req));
+
+       aux_engine = ddc->ctx->dc->res_pool->engines[ddc->link->aux_hw_inst];
+
+       if (!acquire_aux_engine_without_ddc_pin(aux_engine, ddc_pin)) {
+               *operation_result = AUX_RET_ERROR_ENGINE_ACQUIRE;
+               return -1;
+       }
+
+       if (payload->i2c_over_aux)
+               aux_req.type = AUX_TRANSACTION_TYPE_I2C;
+       else
+               aux_req.type = AUX_TRANSACTION_TYPE_DP;
+
+       aux_req.action = i2caux_action_from_payload(payload);
+
+       aux_req.address = payload->address;
+       aux_req.delay = 0;
+       aux_req.length = payload->length;
+       aux_req.data = payload->data;
+
+       submit_channel_request(aux_engine, &aux_req);
+       *operation_result = get_channel_status(aux_engine, &returned_bytes);
+
+       if (*operation_result == AUX_RET_SUCCESS) {
+               int __maybe_unused bytes_replied = 0;
+
+               bytes_replied = read_channel_reply(aux_engine, payload->length,
+                       payload->data, payload->reply,
+                       &status);
+               EVENT_LOG_AUX_REP(aux_engine->inst,
+                       EVENT_LOG_AUX_ORIGIN_NATIVE, *payload->reply,
+                       bytes_replied, payload->data);
+               res = returned_bytes;
+       } else {
+               res = -1;
+       }
+
+       release_engine(aux_engine);
+       return res;
+}
+
 int dce_aux_transfer_dmub_raw(struct ddc_service *ddc,
                struct aux_payload *payload,
                enum aux_return_code_type *operation_result)
@@ -641,6 +795,16 @@ int dce_aux_transfer_dmub_raw(struct ddc_service *ddc,
                release_engine(aux_engine);
        }
 
+       if (ddc->ctx->dc->config.dp_connector_no_native_i2c && ddc->link->no_ddc_pin) {
+               struct dce_aux *aux_engine = ddc->ctx->dc->res_pool->engines[ddc->link->aux_hw_inst];
+
+               if (!acquire_aux_engine_without_ddc_pin(aux_engine, ddc_pin)) {
+                       *operation_result = AUX_RET_ERROR_ENGINE_ACQUIRE;
+                       return -1;
+               }
+               release_engine(aux_engine);
+       }
+
        return dm_helper_dmub_aux_transfer_sync(ddc->ctx, ddc->link, payload, operation_result);
 }
 
@@ -729,6 +893,11 @@ bool dce_aux_transfer_with_retries(struct ddc_service *ddc,
                aux110 = FROM_AUX_ENGINE(aux_engine);
        }
 
+       if (ddc->ctx->dc->config.dp_connector_no_native_i2c && ddc->link->no_ddc_pin) {
+               aux_engine = ddc->ctx->dc->res_pool->engines[ddc->link->aux_hw_inst];
+               aux110 = FROM_AUX_ENGINE(aux_engine);
+       }
+
        if (!payload->reply) {
                payload_reply = false;
                payload->reply = &reply;
index 8f474569401661c2441fd986fd2d4dfa737a4558..b2153cb03b51cd303ef01693fc01acff1ed0a61e 100644 (file)
@@ -308,6 +308,10 @@ int dce_aux_transfer_raw_with_ddc_pin(struct ddc_service *ddc,
                struct aux_payload *cmd,
                enum aux_return_code_type *operation_result);
 
+int dce_aux_transfer_raw_without_ddc_pin(struct ddc_service *ddc,
+       struct aux_payload *cmd,
+       enum aux_return_code_type *operation_result);
+
 int dce_aux_transfer_dmub_raw(struct ddc_service *ddc,
                struct aux_payload *payload,
                enum aux_return_code_type *operation_result);
index c6b62870c46eb57d31f3828898e43e7d402efd83..2daa588a72e54d793d5a2c1015b03531c50817b3 100644 (file)
@@ -40,6 +40,7 @@
 #include "link_enc_cfg.h"
 #include "../hw_sequencer.h"
 #include "dio/dcn10/dcn10_dio.h"
+#include "gpio_service_interface.h"
 
 #define DC_LOGGER_INIT(logger)
 
@@ -319,6 +320,32 @@ void dcn401_init_hw(struct dc *dc)
                        backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl);
                        user_level = link->panel_cntl->stored_backlight_registers.USER_LEVEL;
                }
+
+               if (link->ctx->dc->config.dp_connector_no_native_i2c && link->no_ddc_pin) {
+                       struct graphics_object_i2c_info i2c_info;
+                       struct ddc *ddc_pin;
+                       struct gpio_ddc_hw_info hw_info;
+
+                       if (link->ctx->dc_bios->funcs->get_i2c_info(dcb, link->link_id, &i2c_info) == BP_RESULT_OK) {
+                               hw_info.ddc_channel = i2c_info.i2c_line;
+                               hw_info.hw_supported = i2c_info.i2c_hw_assist;
+
+                               ddc_pin = dal_gpio_create_ddc(
+                                       link->ctx->gpio_service,
+                                       i2c_info.gpio_info.clk_a_register_index,
+                                       1 << i2c_info.gpio_info.clk_a_shift,
+                                       &hw_info);
+
+                               if (ddc_pin) {
+                                       // need to switch pad to aux mode, one time only
+                                       // TODO: Handle result
+                                       dal_ddc_open(ddc_pin, GPIO_MODE_HARDWARE,
+                                               GPIO_DDC_CONFIG_TYPE_MODE_AUX);
+
+                                       dal_gpio_destroy_ddc(&ddc_pin);
+                               }
+                       }
+               }
        }
 
        for (i = 0; i < dc->res_pool->pipe_count; i++) {
index 032c97660658a87ced479f3927854e4d632e9986..f9260eb04ec6aa92c2f827a06420990f3eacd19e 100644 (file)
@@ -415,40 +415,43 @@ static enum channel_id get_ddc_line(struct dc_link *link)
 
        channel = CHANNEL_ID_UNKNOWN;
 
-       ddc = get_ddc_pin(link->ddc);
+       if (link->ctx->dc->config.dp_connector_no_native_i2c && link->no_ddc_pin) {
+               channel = link->aux_hw_inst + 1;
+       } else {
+               ddc = get_ddc_pin(link->ddc);
 
-       if (ddc) {
-               switch (dal_ddc_get_line(ddc)) {
-               case GPIO_DDC_LINE_DDC1:
-                       channel = CHANNEL_ID_DDC1;
-                       break;
-               case GPIO_DDC_LINE_DDC2:
-                       channel = CHANNEL_ID_DDC2;
-                       break;
-               case GPIO_DDC_LINE_DDC3:
-                       channel = CHANNEL_ID_DDC3;
-                       break;
-               case GPIO_DDC_LINE_DDC4:
-                       channel = CHANNEL_ID_DDC4;
-                       break;
-               case GPIO_DDC_LINE_DDC5:
-                       channel = CHANNEL_ID_DDC5;
-                       break;
-               case GPIO_DDC_LINE_DDC6:
-                       channel = CHANNEL_ID_DDC6;
-                       break;
-               case GPIO_DDC_LINE_DDC_VGA:
-                       channel = CHANNEL_ID_DDC_VGA;
-                       break;
-               case GPIO_DDC_LINE_I2C_PAD:
-                       channel = CHANNEL_ID_I2C_PAD;
-                       break;
-               default:
-                       BREAK_TO_DEBUGGER();
-                       break;
+               if (ddc) {
+                       switch (dal_ddc_get_line(ddc)) {
+                       case GPIO_DDC_LINE_DDC1:
+                               channel = CHANNEL_ID_DDC1;
+                               break;
+                       case GPIO_DDC_LINE_DDC2:
+                               channel = CHANNEL_ID_DDC2;
+                               break;
+                       case GPIO_DDC_LINE_DDC3:
+                               channel = CHANNEL_ID_DDC3;
+                               break;
+                       case GPIO_DDC_LINE_DDC4:
+                               channel = CHANNEL_ID_DDC4;
+                               break;
+                       case GPIO_DDC_LINE_DDC5:
+                               channel = CHANNEL_ID_DDC5;
+                               break;
+                       case GPIO_DDC_LINE_DDC6:
+                               channel = CHANNEL_ID_DDC6;
+                               break;
+                       case GPIO_DDC_LINE_DDC_VGA:
+                               channel = CHANNEL_ID_DDC_VGA;
+                               break;
+                       case GPIO_DDC_LINE_I2C_PAD:
+                               channel = CHANNEL_ID_I2C_PAD;
+                               break;
+                       default:
+                               BREAK_TO_DEBUGGER();
+                               break;
+                       }
                }
        }
-
        return channel;
 }
 
@@ -546,6 +549,7 @@ static bool construct_phy(struct dc_link *link,
                bios->funcs->get_disp_connector_caps_info(bios, link->link_id, &disp_connect_caps_info);
                link->is_internal_display = (disp_connect_caps_info.INTERNAL_DISPLAY != 0);
                DC_LOG_DC("BIOS object table - is_internal_display: %d", link->is_internal_display);
+               link->no_ddc_pin = disp_connect_caps_info.NO_DDC_PIN != 0;
        }
 
        if (link->link_id.type != OBJECT_TYPE_CONNECTOR) {
@@ -568,15 +572,19 @@ static bool construct_phy(struct dc_link *link,
                goto ddc_create_fail;
        }
 
-       /* Embedded display connectors such as LVDS may not have DDC. */
-       if (!link->ddc->ddc_pin &&
-           !dc_is_embedded_signal(link->connector_signal)) {
-               DC_ERROR("Failed to get I2C info for connector!\n");
-               goto ddc_create_fail;
-       }
+       if (link->ctx->dc->config.dp_connector_no_native_i2c && link->no_ddc_pin) {
+               link->ddc_hw_inst = link->aux_hw_inst;
+       } else {
+               /* Embedded display connectors such as LVDS may not have DDC. */
+               if (!link->ddc->ddc_pin &&
+                   !dc_is_embedded_signal(link->connector_signal)) {
+                       DC_ERROR("Failed to get I2C info for connector!\n");
+                       goto ddc_create_fail;
+               }
 
-       link->ddc_hw_inst =
-               dal_ddc_get_line(get_ddc_pin(link->ddc));
+               link->ddc_hw_inst =
+                       dal_ddc_get_line(get_ddc_pin(link->ddc));
+       }
 
        enc_init_data.ctx = dc_ctx;
        enc_init_data.connector = link->link_id;
index a0ea853f5f6457d33a10587afb0c8d32b29a408f..6467ec4b8565dc4dbcde9c47fcf3918a6b6f38b8 100644 (file)
@@ -119,25 +119,32 @@ static void ddc_service_construct(
        ddc_service->link = init_data->link;
        ddc_service->ctx = init_data->ctx;
 
-       if (init_data->is_dpia_link ||
-           dcb->funcs->get_i2c_info(dcb, init_data->id, &i2c_info) != BP_RESULT_OK) {
-               ddc_service->ddc_pin = NULL;
-       } else {
-               DC_LOGGER_INIT(ddc_service->ctx->logger);
-               DC_LOG_DC("BIOS object table - i2c_line: %d", i2c_info.i2c_line);
-               DC_LOG_DC("BIOS object table - i2c_engine_id: %d", i2c_info.i2c_engine_id);
-
-               hw_info.ddc_channel = i2c_info.i2c_line;
-               if (ddc_service->link != NULL)
-                       hw_info.hw_supported = i2c_info.i2c_hw_assist;
-               else
-                       hw_info.hw_supported = false;
-
-               ddc_service->ddc_pin = dal_gpio_create_ddc(
-                       gpio_service,
-                       i2c_info.gpio_info.clk_a_register_index,
-                       1 << i2c_info.gpio_info.clk_a_shift,
-                       &hw_info);
+       if (ddc_service->link && ddc_service->ctx->dc->config.dp_connector_no_native_i2c &&
+               ddc_service->link->no_ddc_pin) {
+               // Obtain aux instance info from i2c_info without GPIO DDC pin info
+               if (dcb->funcs->get_connector_aux_info(dcb, init_data->id, &i2c_info) == BP_RESULT_OK)
+                       ddc_service->link->aux_hw_inst = (uint8_t)i2c_info.i2c_line;
+       }  else {
+               if (init_data->is_dpia_link ||
+               dcb->funcs->get_i2c_info(dcb, init_data->id, &i2c_info) != BP_RESULT_OK) {
+                       ddc_service->ddc_pin = NULL;
+               } else {
+                       DC_LOGGER_INIT(ddc_service->ctx->logger);
+                       DC_LOG_DC("BIOS object table - i2c_line: %d", i2c_info.i2c_line);
+                       DC_LOG_DC("BIOS object table - i2c_engine_id: %d", i2c_info.i2c_engine_id);
+
+                       hw_info.ddc_channel = i2c_info.i2c_line;
+                       if (ddc_service->link != NULL)
+                               hw_info.hw_supported = i2c_info.i2c_hw_assist;
+                       else
+                               hw_info.hw_supported = false;
+
+                       ddc_service->ddc_pin = dal_gpio_create_ddc(
+                               gpio_service,
+                               i2c_info.gpio_info.clk_a_register_index,
+                               1 << i2c_info.gpio_info.clk_a_shift,
+                               &hw_info);
+               }
        }
 
        ddc_service->flags.EDID_QUERY_DONE_ONCE = false;
@@ -518,11 +525,18 @@ bool try_to_configure_aux_timeout(struct ddc_service *ddc,
        if (ddc->link->ep_type != DISPLAY_ENDPOINT_PHY)
                return true;
 
-       if (ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]->funcs->configure_timeout) {
-               ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]->funcs->configure_timeout(ddc, timeout);
-               result = true;
-       }
+       if (ddc->ctx->dc->config.dp_connector_no_native_i2c && ddc->link->no_ddc_pin) {
+               if (ddc->ctx->dc->res_pool->engines[ddc->link->aux_hw_inst]->funcs->configure_timeout) {
+                       ddc->ctx->dc->res_pool->engines[ddc->link->aux_hw_inst]->funcs->configure_timeout(ddc, timeout);
+                       result = true;
+               }
+       } else {
+               if (ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]->funcs->configure_timeout) {
+                       ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]->funcs->configure_timeout(ddc, timeout);
+                       result = true;
+               }
 
+       }
        return result;
 }
 
index 817b4010edcbe8fa8f807efcec44d398acedab70..47abb40667092cf1c609723e72c6f2de06402257 100644 (file)
@@ -2570,6 +2570,12 @@ bool dp_is_sink_present(struct dc_link *link)
                (connector_id == CONNECTOR_ID_EDP) ||
                (connector_id == CONNECTOR_ID_USBC));
 
+       /* We can't perform the step below for ASICs with no Native
+        * I2C signaling support on DP connectors, so skip it.
+        */
+       if (link->ctx->dc->config.dp_connector_no_native_i2c && link->no_ddc_pin)
+               return present;
+
        ddc = get_ddc_pin(link->ddc);
 
        if (!ddc) {
index 3db4f10d1654803cce69e1785726316cc537b6e5..80a372ceaa517dc6aac3e8c0e4a46906442b2d44 100644 (file)
@@ -788,7 +788,10 @@ bool edp_setup_psr(struct dc_link *link,
                }
        }
 
-       psr_context->channel = link->ddc->ddc_pin->hw_info.ddc_channel;
+       if (dc->config.dp_connector_no_native_i2c && link->no_ddc_pin)
+               psr_context->channel = (enum channel_id)link->aux_hw_inst;
+       else
+               psr_context->channel = link->ddc->ddc_pin->hw_info.ddc_channel;
        psr_context->transmitterId = link->link_enc->transmitter;
        psr_context->engineId = link->link_enc->preferred_engine;
 
index b5d97b394131b1a416c10551b7a112c2ea3d4df2..13da300fd4b79c7e0a4b411c5695a0eebea07025 100644 (file)
@@ -317,6 +317,7 @@ struct bp_spread_spectrum_parameters {
 struct bp_disp_connector_caps_info {
        uint32_t INTERNAL_DISPLAY    : 1;
        uint32_t INTERNAL_DISPLAY_BL : 1;
+       uint32_t NO_DDC_PIN : 1;
 };
 
 struct bp_encoder_cap_info {