1/*
2 * Copyright 2019 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: AMD
23 *
24 */
25
26#include "dm_services.h"
27#include "dm_helpers.h"
28#include "include/hdcp_msg_types.h"
29#include "include/signal_types.h"
30#include "core_types.h"
31#include "link.h"
32#include "link_hwss.h"
33#include "link/protocols/link_dpcd.h"
34
35#define DC_LOGGER \
36 link->ctx->logger
37#define HDCP14_KSV_SIZE 5
38#define HDCP14_MAX_KSV_FIFO_SIZE 127*HDCP14_KSV_SIZE
39
40static const bool hdcp_cmd_is_read[HDCP_MESSAGE_ID_MAX] = {
41 [HDCP_MESSAGE_ID_READ_BKSV] = true,
42 [HDCP_MESSAGE_ID_READ_RI_R0] = true,
43 [HDCP_MESSAGE_ID_READ_PJ] = true,
44 [HDCP_MESSAGE_ID_WRITE_AKSV] = false,
45 [HDCP_MESSAGE_ID_WRITE_AINFO] = false,
46 [HDCP_MESSAGE_ID_WRITE_AN] = false,
47 [HDCP_MESSAGE_ID_READ_VH_X] = true,
48 [HDCP_MESSAGE_ID_READ_VH_0] = true,
49 [HDCP_MESSAGE_ID_READ_VH_1] = true,
50 [HDCP_MESSAGE_ID_READ_VH_2] = true,
51 [HDCP_MESSAGE_ID_READ_VH_3] = true,
52 [HDCP_MESSAGE_ID_READ_VH_4] = true,
53 [HDCP_MESSAGE_ID_READ_BCAPS] = true,
54 [HDCP_MESSAGE_ID_READ_BSTATUS] = true,
55 [HDCP_MESSAGE_ID_READ_KSV_FIFO] = true,
56 [HDCP_MESSAGE_ID_READ_BINFO] = true,
57 [HDCP_MESSAGE_ID_HDCP2VERSION] = true,
58 [HDCP_MESSAGE_ID_RX_CAPS] = true,
59 [HDCP_MESSAGE_ID_WRITE_AKE_INIT] = false,
60 [HDCP_MESSAGE_ID_READ_AKE_SEND_CERT] = true,
61 [HDCP_MESSAGE_ID_WRITE_AKE_NO_STORED_KM] = false,
62 [HDCP_MESSAGE_ID_WRITE_AKE_STORED_KM] = false,
63 [HDCP_MESSAGE_ID_READ_AKE_SEND_H_PRIME] = true,
64 [HDCP_MESSAGE_ID_READ_AKE_SEND_PAIRING_INFO] = true,
65 [HDCP_MESSAGE_ID_WRITE_LC_INIT] = false,
66 [HDCP_MESSAGE_ID_READ_LC_SEND_L_PRIME] = true,
67 [HDCP_MESSAGE_ID_WRITE_SKE_SEND_EKS] = false,
68 [HDCP_MESSAGE_ID_READ_REPEATER_AUTH_SEND_RECEIVERID_LIST] = true,
69 [HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_SEND_ACK] = false,
70 [HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_STREAM_MANAGE] = false,
71 [HDCP_MESSAGE_ID_READ_REPEATER_AUTH_STREAM_READY] = true,
72 [HDCP_MESSAGE_ID_READ_RXSTATUS] = true,
73 [HDCP_MESSAGE_ID_WRITE_CONTENT_STREAM_TYPE] = false
74};
75
76static const uint8_t hdcp_i2c_offsets[HDCP_MESSAGE_ID_MAX] = {
77 [HDCP_MESSAGE_ID_READ_BKSV] = 0x0,
78 [HDCP_MESSAGE_ID_READ_RI_R0] = 0x8,
79 [HDCP_MESSAGE_ID_READ_PJ] = 0xA,
80 [HDCP_MESSAGE_ID_WRITE_AKSV] = 0x10,
81 [HDCP_MESSAGE_ID_WRITE_AINFO] = 0x15,
82 [HDCP_MESSAGE_ID_WRITE_AN] = 0x18,
83 [HDCP_MESSAGE_ID_READ_VH_X] = 0x20,
84 [HDCP_MESSAGE_ID_READ_VH_0] = 0x20,
85 [HDCP_MESSAGE_ID_READ_VH_1] = 0x24,
86 [HDCP_MESSAGE_ID_READ_VH_2] = 0x28,
87 [HDCP_MESSAGE_ID_READ_VH_3] = 0x2C,
88 [HDCP_MESSAGE_ID_READ_VH_4] = 0x30,
89 [HDCP_MESSAGE_ID_READ_BCAPS] = 0x40,
90 [HDCP_MESSAGE_ID_READ_BSTATUS] = 0x41,
91 [HDCP_MESSAGE_ID_READ_KSV_FIFO] = 0x43,
92 [HDCP_MESSAGE_ID_READ_BINFO] = 0xFF,
93 [HDCP_MESSAGE_ID_HDCP2VERSION] = 0x50,
94 [HDCP_MESSAGE_ID_WRITE_AKE_INIT] = 0x60,
95 [HDCP_MESSAGE_ID_READ_AKE_SEND_CERT] = 0x80,
96 [HDCP_MESSAGE_ID_WRITE_AKE_NO_STORED_KM] = 0x60,
97 [HDCP_MESSAGE_ID_WRITE_AKE_STORED_KM] = 0x60,
98 [HDCP_MESSAGE_ID_READ_AKE_SEND_H_PRIME] = 0x80,
99 [HDCP_MESSAGE_ID_READ_AKE_SEND_PAIRING_INFO] = 0x80,
100 [HDCP_MESSAGE_ID_WRITE_LC_INIT] = 0x60,
101 [HDCP_MESSAGE_ID_READ_LC_SEND_L_PRIME] = 0x80,
102 [HDCP_MESSAGE_ID_WRITE_SKE_SEND_EKS] = 0x60,
103 [HDCP_MESSAGE_ID_READ_REPEATER_AUTH_SEND_RECEIVERID_LIST] = 0x80,
104 [HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_SEND_ACK] = 0x60,
105 [HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_STREAM_MANAGE] = 0x60,
106 [HDCP_MESSAGE_ID_READ_REPEATER_AUTH_STREAM_READY] = 0x80,
107 [HDCP_MESSAGE_ID_READ_RXSTATUS] = 0x70,
108 [HDCP_MESSAGE_ID_WRITE_CONTENT_STREAM_TYPE] = 0x0,
109};
110
111struct protection_properties {
112 bool supported;
113 bool (*process_transaction)(
114 struct dc_link *link,
115 struct hdcp_protection_message *message_info);
116};
117
118static const struct protection_properties non_supported_protection = {
119 .supported = false
120};
121
122static bool hdmi_14_process_transaction(
123 struct dc_link *link,
124 struct hdcp_protection_message *message_info)
125{
126 uint8_t *buff = NULL;
127 bool result;
128 const uint8_t hdcp_i2c_addr_link_primary = 0x3a; /* 0x74 >> 1*/
129 const uint8_t hdcp_i2c_addr_link_secondary = 0x3b; /* 0x76 >> 1*/
130 struct i2c_command i2c_command;
131 uint8_t offset = hdcp_i2c_offsets[message_info->msg_id];
132 struct i2c_payload i2c_payloads[] = {
133 { true, 0, 1, &offset },
134 /* actual hdcp payload, will be filled later, zeroed for now*/
135 { 0 }
136 };
137
138 switch (message_info->link) {
139 case HDCP_LINK_SECONDARY:
140 i2c_payloads[0].address = hdcp_i2c_addr_link_secondary;
141 i2c_payloads[1].address = hdcp_i2c_addr_link_secondary;
142 break;
143 case HDCP_LINK_PRIMARY:
144 default:
145 i2c_payloads[0].address = hdcp_i2c_addr_link_primary;
146 i2c_payloads[1].address = hdcp_i2c_addr_link_primary;
147 break;
148 }
149
150 if (hdcp_cmd_is_read[message_info->msg_id]) {
151 i2c_payloads[1].write = false;
152 i2c_command.number_of_payloads = ARRAY_SIZE(i2c_payloads);
153 i2c_payloads[1].length = message_info->length;
154 i2c_payloads[1].data = message_info->data;
155 } else {
156 i2c_command.number_of_payloads = 1;
157 buff = kzalloc(size: message_info->length + 1, GFP_KERNEL);
158
159 if (!buff)
160 return false;
161
162 buff[0] = offset;
163 memmove(&buff[1], message_info->data, message_info->length);
164 i2c_payloads[0].length = message_info->length + 1;
165 i2c_payloads[0].data = buff;
166 }
167
168 i2c_command.payloads = i2c_payloads;
169 i2c_command.engine = I2C_COMMAND_ENGINE_HW;//only HW
170 i2c_command.speed = link->ddc->ctx->dc->caps.i2c_speed_in_khz;
171
172 result = dm_helpers_submit_i2c(
173 ctx: link->ctx,
174 link,
175 cmd: &i2c_command);
176 kfree(objp: buff);
177
178 return result;
179}
180
181static const struct protection_properties hdmi_14_protection = {
182 .supported = true,
183 .process_transaction = hdmi_14_process_transaction
184};
185
186static const uint32_t hdcp_dpcd_addrs[HDCP_MESSAGE_ID_MAX] = {
187 [HDCP_MESSAGE_ID_READ_BKSV] = 0x68000,
188 [HDCP_MESSAGE_ID_READ_RI_R0] = 0x68005,
189 [HDCP_MESSAGE_ID_READ_PJ] = 0xFFFFFFFF,
190 [HDCP_MESSAGE_ID_WRITE_AKSV] = 0x68007,
191 [HDCP_MESSAGE_ID_WRITE_AINFO] = 0x6803B,
192 [HDCP_MESSAGE_ID_WRITE_AN] = 0x6800c,
193 [HDCP_MESSAGE_ID_READ_VH_X] = 0x68014,
194 [HDCP_MESSAGE_ID_READ_VH_0] = 0x68014,
195 [HDCP_MESSAGE_ID_READ_VH_1] = 0x68018,
196 [HDCP_MESSAGE_ID_READ_VH_2] = 0x6801c,
197 [HDCP_MESSAGE_ID_READ_VH_3] = 0x68020,
198 [HDCP_MESSAGE_ID_READ_VH_4] = 0x68024,
199 [HDCP_MESSAGE_ID_READ_BCAPS] = 0x68028,
200 [HDCP_MESSAGE_ID_READ_BSTATUS] = 0x68029,
201 [HDCP_MESSAGE_ID_READ_KSV_FIFO] = 0x6802c,
202 [HDCP_MESSAGE_ID_READ_BINFO] = 0x6802a,
203 [HDCP_MESSAGE_ID_RX_CAPS] = 0x6921d,
204 [HDCP_MESSAGE_ID_WRITE_AKE_INIT] = 0x69000,
205 [HDCP_MESSAGE_ID_READ_AKE_SEND_CERT] = 0x6900b,
206 [HDCP_MESSAGE_ID_WRITE_AKE_NO_STORED_KM] = 0x69220,
207 [HDCP_MESSAGE_ID_WRITE_AKE_STORED_KM] = 0x692a0,
208 [HDCP_MESSAGE_ID_READ_AKE_SEND_H_PRIME] = 0x692c0,
209 [HDCP_MESSAGE_ID_READ_AKE_SEND_PAIRING_INFO] = 0x692e0,
210 [HDCP_MESSAGE_ID_WRITE_LC_INIT] = 0x692f0,
211 [HDCP_MESSAGE_ID_READ_LC_SEND_L_PRIME] = 0x692f8,
212 [HDCP_MESSAGE_ID_WRITE_SKE_SEND_EKS] = 0x69318,
213 [HDCP_MESSAGE_ID_READ_REPEATER_AUTH_SEND_RECEIVERID_LIST] = 0x69330,
214 [HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_SEND_ACK] = 0x693e0,
215 [HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_STREAM_MANAGE] = 0x693f0,
216 [HDCP_MESSAGE_ID_READ_REPEATER_AUTH_STREAM_READY] = 0x69473,
217 [HDCP_MESSAGE_ID_READ_RXSTATUS] = 0x69493,
218 [HDCP_MESSAGE_ID_WRITE_CONTENT_STREAM_TYPE] = 0x69494
219};
220
221static bool dpcd_access_helper(
222 struct dc_link *link,
223 uint32_t length,
224 uint8_t *data,
225 uint32_t dpcd_addr,
226 bool is_read)
227{
228 enum dc_status status;
229 uint32_t cur_length = 0;
230 uint32_t offset = 0;
231 uint32_t ksv_read_size = 0x6803b - 0x6802c;
232
233 /* Read KSV, need repeatedly handle */
234 if (dpcd_addr == 0x6802c) {
235 if (length % HDCP14_KSV_SIZE) {
236 DC_LOG_ERROR("%s: KsvFifo Size(%d) is not a multiple of HDCP14_KSV_SIZE(%d)\n",
237 __func__,
238 length,
239 HDCP14_KSV_SIZE);
240 }
241 if (length > HDCP14_MAX_KSV_FIFO_SIZE) {
242 DC_LOG_ERROR("%s: KsvFifo Size(%d) is greater than HDCP14_MAX_KSV_FIFO_SIZE(%d)\n",
243 __func__,
244 length,
245 HDCP14_MAX_KSV_FIFO_SIZE);
246 }
247
248 DC_LOG_ERROR("%s: Reading %d Ksv(s) from KsvFifo\n",
249 __func__,
250 length / HDCP14_KSV_SIZE);
251
252 while (length > 0) {
253 if (length > ksv_read_size) {
254 status = core_link_read_dpcd(
255 link,
256 address: dpcd_addr + offset,
257 data: data + offset,
258 size: ksv_read_size);
259
260 data += ksv_read_size;
261 length -= ksv_read_size;
262 } else {
263 status = core_link_read_dpcd(
264 link,
265 address: dpcd_addr + offset,
266 data: data + offset,
267 size: length);
268
269 data += length;
270 length = 0;
271 }
272
273 if (status != DC_OK)
274 return false;
275 }
276 } else {
277 while (length > 0) {
278 if (length > DEFAULT_AUX_MAX_DATA_SIZE)
279 cur_length = DEFAULT_AUX_MAX_DATA_SIZE;
280 else
281 cur_length = length;
282
283 if (is_read) {
284 status = core_link_read_dpcd(
285 link,
286 address: dpcd_addr + offset,
287 data: data + offset,
288 size: cur_length);
289 } else {
290 status = core_link_write_dpcd(
291 link,
292 address: dpcd_addr + offset,
293 data: data + offset,
294 size: cur_length);
295 }
296
297 if (status != DC_OK)
298 return false;
299
300 length -= cur_length;
301 offset += cur_length;
302 }
303 }
304 return true;
305}
306
307static bool dp_11_process_transaction(
308 struct dc_link *link,
309 struct hdcp_protection_message *message_info)
310{
311 return dpcd_access_helper(
312 link,
313 length: message_info->length,
314 data: message_info->data,
315 dpcd_addr: hdcp_dpcd_addrs[message_info->msg_id],
316 is_read: hdcp_cmd_is_read[message_info->msg_id]);
317}
318
319static const struct protection_properties dp_11_protection = {
320 .supported = true,
321 .process_transaction = dp_11_process_transaction
322};
323
324static const struct protection_properties *get_protection_properties_by_signal(
325 struct dc_link *link,
326 enum signal_type st,
327 enum hdcp_version version)
328{
329 switch (version) {
330 case HDCP_VERSION_14:
331 switch (st) {
332 case SIGNAL_TYPE_DVI_SINGLE_LINK:
333 case SIGNAL_TYPE_DVI_DUAL_LINK:
334 case SIGNAL_TYPE_HDMI_TYPE_A:
335 return &hdmi_14_protection;
336 case SIGNAL_TYPE_DISPLAY_PORT:
337 if (link &&
338 (link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER ||
339 link->dpcd_caps.dongle_caps.dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER)) {
340 return &non_supported_protection;
341 }
342 return &dp_11_protection;
343 case SIGNAL_TYPE_DISPLAY_PORT_MST:
344 case SIGNAL_TYPE_EDP:
345 return &dp_11_protection;
346 default:
347 return &non_supported_protection;
348 }
349 break;
350 case HDCP_VERSION_22:
351 switch (st) {
352 case SIGNAL_TYPE_DVI_SINGLE_LINK:
353 case SIGNAL_TYPE_DVI_DUAL_LINK:
354 case SIGNAL_TYPE_HDMI_TYPE_A:
355 return &hdmi_14_protection; //todo version2.2
356 case SIGNAL_TYPE_DISPLAY_PORT:
357 case SIGNAL_TYPE_DISPLAY_PORT_MST:
358 case SIGNAL_TYPE_EDP:
359 return &dp_11_protection; //todo version2.2
360 default:
361 return &non_supported_protection;
362 }
363 break;
364 default:
365 return &non_supported_protection;
366 }
367}
368
369enum hdcp_message_status dc_process_hdcp_msg(
370 enum signal_type signal,
371 struct dc_link *link,
372 struct hdcp_protection_message *message_info)
373{
374 enum hdcp_message_status status = HDCP_MESSAGE_FAILURE;
375 uint32_t i = 0;
376
377 const struct protection_properties *protection_props;
378
379 if (!message_info)
380 return HDCP_MESSAGE_UNSUPPORTED;
381
382 if (message_info->msg_id < HDCP_MESSAGE_ID_READ_BKSV ||
383 message_info->msg_id >= HDCP_MESSAGE_ID_MAX)
384 return HDCP_MESSAGE_UNSUPPORTED;
385
386 protection_props =
387 get_protection_properties_by_signal(
388 link,
389 st: signal,
390 version: message_info->version);
391
392 if (!protection_props->supported)
393 return HDCP_MESSAGE_UNSUPPORTED;
394
395 if (protection_props->process_transaction(
396 link,
397 message_info)) {
398 status = HDCP_MESSAGE_SUCCESS;
399 } else {
400 for (i = 0; i < message_info->max_retries; i++) {
401 if (protection_props->process_transaction(
402 link,
403 message_info)) {
404 status = HDCP_MESSAGE_SUCCESS;
405 break;
406 }
407 }
408 }
409
410 return status;
411}
412
413

source code of linux/drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c