xref: /linux/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c (revision 4e273bca232ec71bbf072f10f7d395a28e85e4e1)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright 2023, Intel Corporation.
4  */
5 
6 #include <linux/delay.h>
7 
8 #include <drm/drm_print.h>
9 #include <drm/intel/display_parent_interface.h>
10 #include <drm/intel/i915_hdcp_interface.h>
11 
12 #include "abi/gsc_command_header_abi.h"
13 #include "xe_bo.h"
14 #include "xe_device.h"
15 #include "xe_device_types.h"
16 #include "xe_force_wake.h"
17 #include "xe_gsc_proxy.h"
18 #include "xe_gsc_submit.h"
19 #include "xe_hdcp_gsc.h"
20 #include "xe_map.h"
21 #include "xe_pm.h"
22 #include "xe_uc_fw.h"
23 
24 #define HECI_MEADDRESS_HDCP 18
25 
26 struct intel_hdcp_gsc_context {
27 	struct xe_device *xe;
28 	struct xe_bo *hdcp_bo;
29 	u64 hdcp_cmd_in;
30 	u64 hdcp_cmd_out;
31 };
32 
33 #define HDCP_GSC_HEADER_SIZE sizeof(struct intel_gsc_mtl_header)
34 
35 static bool intel_hdcp_gsc_check_status(struct drm_device *drm)
36 {
37 	struct xe_device *xe = to_xe_device(drm);
38 	struct xe_tile *tile = xe_device_get_root_tile(xe);
39 	struct xe_gt *gt = tile->media_gt;
40 	struct xe_gsc *gsc;
41 
42 	if (!gt) {
43 		drm_dbg_kms(&xe->drm,
44 			    "not checking GSC status for HDCP2.x: media GT not present or disabled\n");
45 		return false;
46 	}
47 
48 	gsc = &gt->uc.gsc;
49 
50 	if (!xe_uc_fw_is_available(&gsc->fw)) {
51 		drm_dbg_kms(&xe->drm,
52 			    "GSC Components not ready for HDCP2.x\n");
53 		return false;
54 	}
55 
56 	guard(xe_pm_runtime)(xe);
57 	CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GSC);
58 	if (!fw_ref.domains) {
59 		drm_dbg_kms(&xe->drm,
60 			    "failed to get forcewake to check proxy status\n");
61 		return false;
62 	}
63 
64 	return xe_gsc_proxy_init_done(gsc);
65 }
66 
67 /*This function helps allocate memory for the command that we will send to gsc cs */
68 static int intel_hdcp_gsc_initialize_message(struct xe_device *xe,
69 					     struct intel_hdcp_gsc_context *gsc_context)
70 {
71 	struct xe_bo *bo = NULL;
72 	u64 cmd_in, cmd_out;
73 	int ret = 0;
74 
75 	/* allocate object of two page for HDCP command memory and store it */
76 	bo = xe_bo_create_pin_map_novm(xe, xe_device_get_root_tile(xe), PAGE_SIZE * 2,
77 				       ttm_bo_type_kernel,
78 				       XE_BO_FLAG_SYSTEM |
79 				       XE_BO_FLAG_GGTT, false);
80 
81 	if (IS_ERR(bo)) {
82 		drm_err(&xe->drm, "Failed to allocate bo for HDCP streaming command!\n");
83 		ret = PTR_ERR(bo);
84 		goto out;
85 	}
86 
87 	cmd_in = xe_bo_ggtt_addr(bo);
88 	cmd_out = cmd_in + PAGE_SIZE;
89 	xe_map_memset(xe, &bo->vmap, 0, 0, xe_bo_size(bo));
90 
91 	gsc_context->hdcp_bo = bo;
92 	gsc_context->hdcp_cmd_in = cmd_in;
93 	gsc_context->hdcp_cmd_out = cmd_out;
94 	gsc_context->xe = xe;
95 
96 out:
97 	return ret;
98 }
99 
100 static struct intel_hdcp_gsc_context *intel_hdcp_gsc_context_alloc(struct drm_device *drm)
101 {
102 	struct xe_device *xe = to_xe_device(drm);
103 	struct intel_hdcp_gsc_context *gsc_context;
104 	int ret;
105 
106 	gsc_context = kzalloc_obj(*gsc_context);
107 	if (!gsc_context)
108 		return ERR_PTR(-ENOMEM);
109 
110 	/*
111 	 * NOTE: No need to lock the comp mutex here as it is already
112 	 * going to be taken before this function called
113 	 */
114 	ret = intel_hdcp_gsc_initialize_message(xe, gsc_context);
115 	if (ret) {
116 		drm_err(&xe->drm, "Could not initialize gsc_context\n");
117 		kfree(gsc_context);
118 		gsc_context = ERR_PTR(ret);
119 	}
120 
121 	return gsc_context;
122 }
123 
124 static void intel_hdcp_gsc_context_free(struct intel_hdcp_gsc_context *gsc_context)
125 {
126 	if (!gsc_context)
127 		return;
128 
129 	xe_bo_unpin_map_no_vm(gsc_context->hdcp_bo);
130 	kfree(gsc_context);
131 }
132 
133 static int xe_gsc_send_sync(struct xe_device *xe,
134 			    struct intel_hdcp_gsc_context *gsc_context,
135 			    u32 msg_size_in, u32 msg_size_out,
136 			    u32 addr_out_off)
137 {
138 	struct xe_gt *gt = gsc_context->hdcp_bo->tile->media_gt;
139 	struct iosys_map *map = &gsc_context->hdcp_bo->vmap;
140 	struct xe_gsc *gsc = &gt->uc.gsc;
141 	int ret;
142 
143 	ret = xe_gsc_pkt_submit_kernel(gsc, gsc_context->hdcp_cmd_in, msg_size_in,
144 				       gsc_context->hdcp_cmd_out, msg_size_out);
145 	if (ret) {
146 		drm_err(&xe->drm, "failed to send gsc HDCP msg (%d)\n", ret);
147 		return ret;
148 	}
149 
150 	if (xe_gsc_check_and_update_pending(xe, map, 0, map, addr_out_off))
151 		return -EAGAIN;
152 
153 	ret = xe_gsc_read_out_header(xe, map, addr_out_off,
154 				     sizeof(struct hdcp_cmd_header), NULL);
155 
156 	return ret;
157 }
158 
159 static ssize_t intel_hdcp_gsc_msg_send(struct intel_hdcp_gsc_context *gsc_context,
160 				       void *msg_in, size_t msg_in_len,
161 				       void *msg_out, size_t msg_out_len)
162 {
163 	struct xe_device *xe = gsc_context->xe;
164 	const size_t max_msg_size = PAGE_SIZE - HDCP_GSC_HEADER_SIZE;
165 	u64 host_session_id;
166 	u32 msg_size_in, msg_size_out;
167 	u32 addr_out_off, addr_in_wr_off = 0;
168 	int ret, tries = 0;
169 
170 	if (msg_in_len > max_msg_size || msg_out_len > max_msg_size)
171 		return -ENOSPC;
172 
173 	msg_size_in = msg_in_len + HDCP_GSC_HEADER_SIZE;
174 	msg_size_out = msg_out_len + HDCP_GSC_HEADER_SIZE;
175 	addr_out_off = PAGE_SIZE;
176 
177 	host_session_id = xe_gsc_create_host_session_id();
178 	guard(xe_pm_runtime_noresume)(xe);
179 	addr_in_wr_off = xe_gsc_emit_header(xe, &gsc_context->hdcp_bo->vmap,
180 					    addr_in_wr_off, HECI_MEADDRESS_HDCP,
181 					    host_session_id, msg_in_len);
182 	xe_map_memcpy_to(xe, &gsc_context->hdcp_bo->vmap, addr_in_wr_off,
183 			 msg_in, msg_in_len);
184 	/*
185 	 * Keep sending request in case the pending bit is set no need to add
186 	 * message handle as we are using same address hence loc. of header is
187 	 * same and it will contain the message handle. we will send the message
188 	 * 20 times each message 50 ms apart
189 	 */
190 	do {
191 		ret = xe_gsc_send_sync(xe, gsc_context, msg_size_in, msg_size_out,
192 				       addr_out_off);
193 
194 		/* Only try again if gsc says so */
195 		if (ret != -EAGAIN)
196 			break;
197 
198 		msleep(50);
199 
200 	} while (++tries < 20);
201 
202 	if (ret)
203 		return ret;
204 
205 	xe_map_memcpy_from(xe, msg_out, &gsc_context->hdcp_bo->vmap,
206 			   addr_out_off + HDCP_GSC_HEADER_SIZE,
207 			   msg_out_len);
208 
209 	return ret;
210 }
211 
212 const struct intel_display_hdcp_interface xe_display_hdcp_interface = {
213 	.gsc_msg_send = intel_hdcp_gsc_msg_send,
214 	.gsc_check_status = intel_hdcp_gsc_check_status,
215 	.gsc_context_alloc = intel_hdcp_gsc_context_alloc,
216 	.gsc_context_free = intel_hdcp_gsc_context_free,
217 };
218