drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
Extension
.c
Size
26989 bytes
Lines
835
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (content_type == DRM_MODE_HDCP_CONTENT_TYPE0) {
			link_adjust.hdcp2.force_type = MOD_HDCP_FORCE_TYPE_0;
		} else if (content_type == DRM_MODE_HDCP_CONTENT_TYPE1) {
			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));
	} else {
		display_adjust.disable = MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION;
		hdcp_w->encryption_status[conn_index] = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
		cancel_delayed_work(&hdcp_w->property_validate_dwork);
	}

	mod_hdcp_update_display(&hdcp_w->hdcp, conn_index, &link_adjust, &display_adjust, &hdcp_w->output);

	process_output(hdcp_w);
}

static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work,
				unsigned int link_index,
			 struct amdgpu_dm_connector *aconnector)
{
	struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index];
	struct drm_connector_state *conn_state = aconnector->base.state;
	unsigned int conn_index = aconnector->base.index;

	guard(mutex)(&hdcp_w->mutex);

	/* the removal of display will invoke auth reset -> hdcp destroy and
	 * we'd expect the Content Protection (CP) property changed back to
	 * DESIRED if at the time ENABLED. CP property change should occur
	 * before the element removed from linked list.
	 */
	if (conn_state && conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
		conn_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;

		DRM_DEBUG_DRIVER("[HDCP_DM] display %d, CP 2 -> 1, type %u, DPMS %u\n",
				 aconnector->base.index, conn_state->hdcp_content_type,
				 aconnector->base.dpms);
	}

	mod_hdcp_remove_display(&hdcp_w->hdcp, aconnector->base.index, &hdcp_w->output);
	if (hdcp_w->aconnector[conn_index]) {
		drm_connector_put(&hdcp_w->aconnector[conn_index]->base);
		hdcp_w->aconnector[conn_index] = NULL;
	}
	process_output(hdcp_w);
}

void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_index)
{
	struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index];
	unsigned int conn_index;

	guard(mutex)(&hdcp_w->mutex);

	mod_hdcp_reset_connection(&hdcp_w->hdcp,  &hdcp_w->output);

	cancel_delayed_work(&hdcp_w->property_validate_dwork);

	for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX; conn_index++) {
		hdcp_w->encryption_status[conn_index] =
			MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
		if (hdcp_w->aconnector[conn_index]) {
			drm_connector_put(&hdcp_w->aconnector[conn_index]->base);
			hdcp_w->aconnector[conn_index] = NULL;
		}
	}

	process_output(hdcp_w);
}

void hdcp_handle_cpirq(struct hdcp_workqueue *hdcp_work, unsigned int link_index)
{
	struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index];

	schedule_work(&hdcp_w->cpirq_work);
}

static void event_callback(struct work_struct *work)
{
	struct hdcp_workqueue *hdcp_work;

	hdcp_work = container_of(to_delayed_work(work), struct hdcp_workqueue,
				 callback_dwork);

Annotation

Implementation Notes