mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
drm/amd/display: fw locality check refactors
[why] There are some new changes for HDCP2 firmware locality check. The implementation doesn't perfectly fit the intended design and clarity. 1. Clarify and consolidate variable responsibilities. The previous implementation introduced the following variables: - config.ddc.funcs.atomic_write_poll_read_i2c (optional pointer) - hdcp->config.ddc.funcs.atomic_write_poll_read_aux (optional pointer) - hdcp->connection.link.adjust.hdcp2.force_sw_locality_check (bool) - hdcp->config.debug.lc_enable_sw_fallback (bool) - use_fw (bool) They will be used together to determine two operations: - Whether to use FW locality check - Whether to use SW fallback on FW locality check failure The refactor streamlines this by introducing two variables in the hdcp2 link adjustment, while ensuring function pointers are always assigned and remain independent from policy decisions: - use_fw_locality_check (bool) -> true if fw locality should be used. - use_sw_locality_fallback (bool) -> true to reset use_fw_locality_check back to false and retry on fw locality check failure. 2. Mixed meanings of l_prime_read transition input l_prime_read originally means if l_prime is read when sw locality check is used. When FW locality check is used, l_prime_read means if lc init write, l prime poll and l_prime read combo operation is successful. The mix of meanings is confusing. The refactor introduces a new variable l_prime_combo_read to isolate the second meaning into its own variable. 3. Missing specific error code on firmware locality error. The original change reuses the generic DDC failure error code when firmware fails to return locality check result. This is not ideal as DDC failure indicates an error occurred during an I2C/AUX transaction. FW locality failure could be caused by polling timeout in firmware or failure to acquire firmware access. Which sits at a higher level of abstraction above DDC hardware. An incorrect error code could mislead the debug into a wrong direction. 4. Correcting misplaced comments. The previous implementation of the firmware locality check resulted in some comments in hdcp2_transition being incorrectly positioned. This refactor relocates those comments to their appropriate locations for better clarity. Reviewed-by: Aric Cyr <aric.cyr@amd.com> Signed-off-by: Wenjing Liu <wenjing.liu@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>
This commit is contained in:
committed by
Alex Deucher
parent
290f46cf57
commit
face6a3615
@@ -201,6 +201,7 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work,
|
||||
struct mod_hdcp_link_adjustment link_adjust;
|
||||
struct mod_hdcp_display_adjustment display_adjust;
|
||||
unsigned int conn_index = aconnector->base.index;
|
||||
const struct dc *dc = aconnector->dc_link->dc;
|
||||
|
||||
guard(mutex)(&hdcp_w->mutex);
|
||||
drm_connector_get(&aconnector->base);
|
||||
@@ -231,6 +232,9 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work,
|
||||
link_adjust.hdcp1.disable = 1;
|
||||
link_adjust.hdcp2.force_type = MOD_HDCP_FORCE_TYPE_1;
|
||||
}
|
||||
link_adjust.hdcp2.use_fw_locality_check =
|
||||
(dc->caps.fused_io_supported || dc->debug.hdcp_lc_force_fw_enable);
|
||||
link_adjust.hdcp2.use_sw_locality_fallback = dc->debug.hdcp_lc_enable_sw_fallback;
|
||||
|
||||
schedule_delayed_work(&hdcp_w->property_validate_dwork,
|
||||
msecs_to_jiffies(DRM_HDCP_CHECK_PERIOD_MS));
|
||||
@@ -534,6 +538,7 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
|
||||
struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index];
|
||||
struct dc_sink *sink = NULL;
|
||||
bool link_is_hdcp14 = false;
|
||||
const struct dc *dc = aconnector->dc_link->dc;
|
||||
|
||||
if (config->dpms_off) {
|
||||
hdcp_remove_display(hdcp_work, link_index, aconnector);
|
||||
@@ -575,6 +580,8 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
|
||||
link->adjust.auth_delay = 2;
|
||||
link->adjust.retry_limit = MAX_NUM_OF_ATTEMPTS;
|
||||
link->adjust.hdcp1.disable = 0;
|
||||
link->adjust.hdcp2.use_fw_locality_check = (dc->caps.fused_io_supported || dc->debug.hdcp_lc_force_fw_enable);
|
||||
link->adjust.hdcp2.use_sw_locality_fallback = dc->debug.hdcp_lc_enable_sw_fallback;
|
||||
hdcp_w->encryption_status[display->index] = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
|
||||
|
||||
DRM_DEBUG_DRIVER("[HDCP_DM] display %d, CP %d, type %d\n", aconnector->base.index,
|
||||
@@ -786,15 +793,8 @@ struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev,
|
||||
ddc_funcs->read_i2c = lp_read_i2c;
|
||||
ddc_funcs->write_dpcd = lp_write_dpcd;
|
||||
ddc_funcs->read_dpcd = lp_read_dpcd;
|
||||
|
||||
config->debug.lc_enable_sw_fallback = dc->debug.hdcp_lc_enable_sw_fallback;
|
||||
if (dc->caps.fused_io_supported || dc->debug.hdcp_lc_force_fw_enable) {
|
||||
ddc_funcs->atomic_write_poll_read_i2c = lp_atomic_write_poll_read_i2c;
|
||||
ddc_funcs->atomic_write_poll_read_aux = lp_atomic_write_poll_read_aux;
|
||||
} else {
|
||||
ddc_funcs->atomic_write_poll_read_i2c = NULL;
|
||||
ddc_funcs->atomic_write_poll_read_aux = NULL;
|
||||
}
|
||||
ddc_funcs->atomic_write_poll_read_i2c = lp_atomic_write_poll_read_i2c;
|
||||
ddc_funcs->atomic_write_poll_read_aux = lp_atomic_write_poll_read_aux;
|
||||
|
||||
memset(hdcp_work[i].aconnector, 0,
|
||||
sizeof(struct amdgpu_dm_connector *) *
|
||||
|
||||
@@ -88,6 +88,7 @@ struct mod_hdcp_transition_input_hdcp2 {
|
||||
uint8_t lc_init_write;
|
||||
uint8_t l_prime_available_poll;
|
||||
uint8_t l_prime_read;
|
||||
uint8_t l_prime_combo_read;
|
||||
uint8_t l_prime_validation;
|
||||
uint8_t eks_prepare;
|
||||
uint8_t eks_write;
|
||||
|
||||
@@ -465,54 +465,11 @@ out:
|
||||
return status;
|
||||
}
|
||||
|
||||
static enum mod_hdcp_status locality_check_sw(struct mod_hdcp *hdcp,
|
||||
struct mod_hdcp_event_context *event_ctx,
|
||||
struct mod_hdcp_transition_input_hdcp2 *input)
|
||||
{
|
||||
enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
|
||||
|
||||
if (!mod_hdcp_execute_and_set(mod_hdcp_write_lc_init,
|
||||
&input->lc_init_write, &status,
|
||||
hdcp, "lc_init_write"))
|
||||
goto out;
|
||||
if (is_dp_hdcp(hdcp))
|
||||
msleep(16);
|
||||
else
|
||||
if (!mod_hdcp_execute_and_set(poll_l_prime_available,
|
||||
&input->l_prime_available_poll, &status,
|
||||
hdcp, "l_prime_available_poll"))
|
||||
goto out;
|
||||
if (!mod_hdcp_execute_and_set(mod_hdcp_read_l_prime,
|
||||
&input->l_prime_read, &status,
|
||||
hdcp, "l_prime_read"))
|
||||
goto out;
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
static enum mod_hdcp_status locality_check_fw(struct mod_hdcp *hdcp,
|
||||
struct mod_hdcp_event_context *event_ctx,
|
||||
struct mod_hdcp_transition_input_hdcp2 *input)
|
||||
{
|
||||
enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
|
||||
|
||||
if (!mod_hdcp_execute_and_set(mod_hdcp_write_poll_read_lc_fw,
|
||||
&input->l_prime_read, &status,
|
||||
hdcp, "l_prime_read"))
|
||||
goto out;
|
||||
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
static enum mod_hdcp_status locality_check(struct mod_hdcp *hdcp,
|
||||
struct mod_hdcp_event_context *event_ctx,
|
||||
struct mod_hdcp_transition_input_hdcp2 *input)
|
||||
{
|
||||
enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
|
||||
const bool use_fw = hdcp->config.ddc.funcs.atomic_write_poll_read_i2c
|
||||
&& hdcp->config.ddc.funcs.atomic_write_poll_read_aux
|
||||
&& !hdcp->connection.link.adjust.hdcp2.force_sw_locality_check;
|
||||
|
||||
if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) {
|
||||
event_ctx->unexpected_event = 1;
|
||||
@@ -524,9 +481,28 @@ static enum mod_hdcp_status locality_check(struct mod_hdcp *hdcp,
|
||||
hdcp, "lc_init_prepare"))
|
||||
goto out;
|
||||
|
||||
status = (use_fw ? locality_check_fw : locality_check_sw)(hdcp, event_ctx, input);
|
||||
if (status != MOD_HDCP_STATUS_SUCCESS)
|
||||
goto out;
|
||||
if (hdcp->connection.link.adjust.hdcp2.use_fw_locality_check) {
|
||||
if (!mod_hdcp_execute_and_set(mod_hdcp_write_poll_read_lc_fw,
|
||||
&input->l_prime_combo_read, &status,
|
||||
hdcp, "l_prime_combo_read"))
|
||||
goto out;
|
||||
} else {
|
||||
if (!mod_hdcp_execute_and_set(mod_hdcp_write_lc_init,
|
||||
&input->lc_init_write, &status,
|
||||
hdcp, "lc_init_write"))
|
||||
goto out;
|
||||
if (is_dp_hdcp(hdcp))
|
||||
msleep(16);
|
||||
else
|
||||
if (!mod_hdcp_execute_and_set(poll_l_prime_available,
|
||||
&input->l_prime_available_poll, &status,
|
||||
hdcp, "l_prime_available_poll"))
|
||||
goto out;
|
||||
if (!mod_hdcp_execute_and_set(mod_hdcp_read_l_prime,
|
||||
&input->l_prime_read, &status,
|
||||
hdcp, "l_prime_read"))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!mod_hdcp_execute_and_set(mod_hdcp_hdcp2_validate_l_prime,
|
||||
&input->l_prime_validation, &status,
|
||||
|
||||
@@ -184,31 +184,33 @@ enum mod_hdcp_status mod_hdcp_hdcp2_transition(struct mod_hdcp *hdcp,
|
||||
callback_in_ms(0, output);
|
||||
set_state_id(hdcp, output, H2_A2_LOCALITY_CHECK);
|
||||
break;
|
||||
case H2_A2_LOCALITY_CHECK: {
|
||||
const bool use_fw = hdcp->config.ddc.funcs.atomic_write_poll_read_i2c
|
||||
&& !adjust->hdcp2.force_sw_locality_check;
|
||||
|
||||
/*
|
||||
* 1A-05: consider disconnection after LC init a failure
|
||||
* 1A-13-1: consider invalid l' a failure
|
||||
* 1A-13-2: consider l' timeout a failure
|
||||
*/
|
||||
case H2_A2_LOCALITY_CHECK:
|
||||
/* 1A-05: consider disconnection after LC init a failure */
|
||||
if (hdcp->state.stay_count > 10 ||
|
||||
input->lc_init_prepare != PASS ||
|
||||
(!use_fw && input->lc_init_write != PASS) ||
|
||||
(!use_fw && input->l_prime_available_poll != PASS)) {
|
||||
input->lc_init_prepare != PASS) {
|
||||
fail_and_restart_in_ms(0, &status, output);
|
||||
break;
|
||||
} else if (input->l_prime_read != PASS) {
|
||||
if (use_fw && hdcp->config.debug.lc_enable_sw_fallback) {
|
||||
adjust->hdcp2.force_sw_locality_check = true;
|
||||
} else if (adjust->hdcp2.use_fw_locality_check &&
|
||||
input->l_prime_combo_read != PASS) {
|
||||
/* 1A-13-2: consider l' timeout a failure */
|
||||
if (adjust->hdcp2.use_sw_locality_fallback) {
|
||||
/* switch to software locality check */
|
||||
adjust->hdcp2.use_fw_locality_check = 0;
|
||||
callback_in_ms(0, output);
|
||||
increment_stay_counter(hdcp);
|
||||
break;
|
||||
}
|
||||
|
||||
fail_and_restart_in_ms(0, &status, output);
|
||||
break;
|
||||
} else if (!adjust->hdcp2.use_fw_locality_check &&
|
||||
(input->lc_init_write != PASS ||
|
||||
input->l_prime_available_poll != PASS ||
|
||||
input->l_prime_read != PASS)) {
|
||||
/* 1A-13-2: consider l' timeout a failure */
|
||||
fail_and_restart_in_ms(0, &status, output);
|
||||
break;
|
||||
} else if (input->l_prime_validation != PASS) {
|
||||
/* 1A-13-1: consider invalid l' a failure */
|
||||
callback_in_ms(0, output);
|
||||
increment_stay_counter(hdcp);
|
||||
break;
|
||||
@@ -216,7 +218,6 @@ enum mod_hdcp_status mod_hdcp_hdcp2_transition(struct mod_hdcp *hdcp,
|
||||
callback_in_ms(0, output);
|
||||
set_state_id(hdcp, output, H2_A3_EXCHANGE_KS_AND_TEST_FOR_REPEATER);
|
||||
break;
|
||||
}
|
||||
case H2_A3_EXCHANGE_KS_AND_TEST_FOR_REPEATER:
|
||||
if (input->eks_prepare != PASS ||
|
||||
input->eks_write != PASS) {
|
||||
@@ -510,26 +511,29 @@ enum mod_hdcp_status mod_hdcp_hdcp2_dp_transition(struct mod_hdcp *hdcp,
|
||||
callback_in_ms(0, output);
|
||||
set_state_id(hdcp, output, D2_A2_LOCALITY_CHECK);
|
||||
break;
|
||||
case D2_A2_LOCALITY_CHECK: {
|
||||
const bool use_fw = hdcp->config.ddc.funcs.atomic_write_poll_read_aux
|
||||
&& !adjust->hdcp2.force_sw_locality_check;
|
||||
|
||||
case D2_A2_LOCALITY_CHECK:
|
||||
if (hdcp->state.stay_count > 10 ||
|
||||
input->lc_init_prepare != PASS ||
|
||||
(!use_fw && input->lc_init_write != PASS)) {
|
||||
/* 1A-12: consider invalid l' a failure */
|
||||
input->lc_init_prepare != PASS) {
|
||||
fail_and_restart_in_ms(0, &status, output);
|
||||
break;
|
||||
} else if (input->l_prime_read != PASS) {
|
||||
if (use_fw && hdcp->config.debug.lc_enable_sw_fallback) {
|
||||
adjust->hdcp2.force_sw_locality_check = true;
|
||||
} else if (adjust->hdcp2.use_fw_locality_check &&
|
||||
input->l_prime_combo_read != PASS) {
|
||||
if (adjust->hdcp2.use_sw_locality_fallback) {
|
||||
/* switch to software locality check */
|
||||
adjust->hdcp2.use_fw_locality_check = 0;
|
||||
callback_in_ms(0, output);
|
||||
increment_stay_counter(hdcp);
|
||||
break;
|
||||
}
|
||||
|
||||
fail_and_restart_in_ms(0, &status, output);
|
||||
break;
|
||||
} else if (!adjust->hdcp2.use_fw_locality_check &&
|
||||
(input->lc_init_write != PASS ||
|
||||
input->l_prime_read != PASS)) {
|
||||
fail_and_restart_in_ms(0, &status, output);
|
||||
break;
|
||||
} else if (input->l_prime_validation != PASS) {
|
||||
/* 1A-12: consider invalid l' a failure */
|
||||
callback_in_ms(0, output);
|
||||
increment_stay_counter(hdcp);
|
||||
break;
|
||||
@@ -537,7 +541,6 @@ enum mod_hdcp_status mod_hdcp_hdcp2_dp_transition(struct mod_hdcp *hdcp,
|
||||
callback_in_ms(0, output);
|
||||
set_state_id(hdcp, output, D2_A34_EXCHANGE_KS_AND_TEST_FOR_REPEATER);
|
||||
break;
|
||||
}
|
||||
case D2_A34_EXCHANGE_KS_AND_TEST_FOR_REPEATER:
|
||||
if (input->eks_prepare != PASS ||
|
||||
input->eks_write != PASS) {
|
||||
|
||||
@@ -758,6 +758,6 @@ enum mod_hdcp_status mod_hdcp_write_poll_read_lc_fw(struct mod_hdcp *hdcp)
|
||||
{
|
||||
const bool success = (is_dp_hdcp(hdcp) ? write_stall_read_lc_fw_aux : write_poll_read_lc_fw_i2c)(hdcp);
|
||||
|
||||
return success ? MOD_HDCP_STATUS_SUCCESS : MOD_HDCP_STATUS_DDC_FAILURE;
|
||||
return success ? MOD_HDCP_STATUS_SUCCESS : MOD_HDCP_STATUS_HDCP2_LOCALITY_COMBO_READ_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
@@ -248,6 +248,8 @@ char *mod_hdcp_status_to_str(int32_t status)
|
||||
return "MOD_HDCP_STATUS_HDCP2_DEVICE_COUNT_MISMATCH_FAILURE";
|
||||
case MOD_HDCP_STATUS_UNSUPPORTED_PSP_VER_FAILURE:
|
||||
return "MOD_HDCP_STATUS_UNSUPPORTED_PSP_VER_FAILURE";
|
||||
case MOD_HDCP_STATUS_HDCP2_LOCALITY_COMBO_READ_FAILURE:
|
||||
return "MOD_HDCP_STATUS_HDCP2_LOCALITY_COMBO_READ_FAILURE";
|
||||
default:
|
||||
return "MOD_HDCP_STATUS_UNKNOWN";
|
||||
}
|
||||
|
||||
@@ -98,6 +98,7 @@ enum mod_hdcp_status {
|
||||
MOD_HDCP_STATUS_HDCP2_REAUTH_LINK_INTEGRITY_FAILURE,
|
||||
MOD_HDCP_STATUS_HDCP2_DEVICE_COUNT_MISMATCH_FAILURE,
|
||||
MOD_HDCP_STATUS_UNSUPPORTED_PSP_VER_FAILURE,
|
||||
MOD_HDCP_STATUS_HDCP2_LOCALITY_COMBO_READ_FAILURE,
|
||||
};
|
||||
|
||||
struct mod_hdcp_displayport {
|
||||
@@ -214,8 +215,9 @@ struct mod_hdcp_link_adjustment_hdcp2 {
|
||||
uint8_t force_type : 2;
|
||||
uint8_t force_no_stored_km : 1;
|
||||
uint8_t increase_h_prime_timeout: 1;
|
||||
uint8_t force_sw_locality_check : 1;
|
||||
uint8_t reserved : 2;
|
||||
uint8_t use_fw_locality_check : 1;
|
||||
uint8_t use_sw_locality_fallback: 1;
|
||||
uint8_t reserved : 1;
|
||||
};
|
||||
|
||||
struct mod_hdcp_link_adjustment {
|
||||
@@ -317,10 +319,6 @@ struct mod_hdcp_display_query {
|
||||
struct mod_hdcp_config {
|
||||
struct mod_hdcp_psp psp;
|
||||
struct mod_hdcp_ddc ddc;
|
||||
struct {
|
||||
uint8_t lc_enable_sw_fallback : 1;
|
||||
uint8_t reserved : 7;
|
||||
} debug;
|
||||
uint8_t index;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user