summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJi Soo Shin <jisshin@google.com>2023-04-11 13:22:51 +0200
committerJi Soo Shin <jisshin@google.com>2023-04-13 15:33:09 +0200
commit020efa21655d0a7c92cb0bdc12d6e176002e8180 (patch)
treea273f3656f4182f9a2f9023391effb43f3fcd24d
parent9f6f4e9e06f1ecac01b304fe2a938822b961ef52 (diff)
downloadsamsung-020efa21655d0a7c92cb0bdc12d6e176002e8180.tar.gz
zuma: migrate hdcp1.3 features
Bug: 271268975 Bug: 271270186 Bug: 274950373 Bug: 277216601 Bug: 275583366 Change-Id: Ifbf466111721219e9dd583e1baf6f59449e481f8
-rw-r--r--Kbuild1
-rw-r--r--exynos-hdcp1-auth.c239
-rw-r--r--exynos-hdcp1-auth.h18
-rw-r--r--exynos-hdcp2-dplink-if.c61
-rw-r--r--exynos-hdcp2-dplink-if.h13
-rw-r--r--exynos-hdcp2-dplink-inter.c166
-rw-r--r--exynos-hdcp2-dplink-inter.h3
-rw-r--r--exynos-hdcp2-dplink-reg.h9
-rw-r--r--exynos-hdcp2-dplink.c4
-rw-r--r--exynos-hdcp2-dplink.h6
-rw-r--r--exynos-hdcp2-log.h12
-rw-r--r--exynos-hdcp2-main.c19
-rw-r--r--exynos-hdcp2-selftest.c6
-rw-r--r--exynos-hdcp2-teeif.c66
-rw-r--r--exynos-hdcp2-teeif.h54
-rw-r--r--exynos-hdcp2.h4
16 files changed, 517 insertions, 164 deletions
diff --git a/Kbuild b/Kbuild
index c683683..be4cbd0 100644
--- a/Kbuild
+++ b/Kbuild
@@ -5,6 +5,7 @@
ccflags-y += -I$(srctree)/include/
+exynos-hdcp2-y += exynos-hdcp1-auth.o
exynos-hdcp2-y += exynos-hdcp2-main.o
exynos-hdcp2-y += exynos-hdcp2-teeif.o
exynos-hdcp2-y += exynos-hdcp2-session.o
diff --git a/exynos-hdcp1-auth.c b/exynos-hdcp1-auth.c
new file mode 100644
index 0000000..9e9b3c9
--- /dev/null
+++ b/exynos-hdcp1-auth.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Samsung DisplayPort driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <drm/drm_dp_helper.h>
+
+#include "exynos-hdcp1-auth.h"
+#include "exynos-hdcp2.h"
+#include "exynos-hdcp2-dplink-if.h"
+#include "exynos-hdcp2-log.h"
+#include "exynos-hdcp2-teeif.h"
+
+#define HDCP_R0_SIZE 2
+#define HDCP_BKSV_SIZE 5
+#define HDCP_AN_SIZE 8
+#define HDCP_AKSV_SIZE 5
+
+#define V_READ_RETRY_CNT 3
+#define RI_READ_RETRY_CNT 3
+#define RI_AVAILABLE_WAITING 2
+#define RI_DELAY 100
+#define REPEATER_READY_MAX_WAIT_DELAY 5000
+
+#define MAX_CASCADE_EXCEEDED (0x00000800)
+#define MAX_DEVS_EXCEEDED (0x00000080)
+#define BKSV_LIST_FIFO_SIZE (15)
+
+extern enum dp_state dp_hdcp_state;
+extern enum auth_state auth_proc_state;
+
+static int compare_rprime(void)
+{
+ uint8_t bstatus, ri_retry_cnt = 0;
+ uint16_t rprime;
+ int ret;
+
+ usleep_range(RI_DELAY * 1000, RI_DELAY * 1000 + 1);
+
+ ret = hdcp_dplink_recv(HDCP13_MSG_BSTATUS_R, &bstatus,
+ sizeof(bstatus));
+ if (ret || !(bstatus & DP_BSTATUS_R0_PRIME_READY)) {
+ hdcp_err("BSTATUS read err ret(%d) bstatus(%d)\n",
+ ret, bstatus);
+ return -EIO;
+ }
+
+ hdcp_info("R0-Prime is ready in HDCP Receiver\n");
+ do {
+ ret = hdcp_dplink_recv(HDCP13_MSG_RI_PRIME_R, (uint8_t*)&rprime,
+ HDCP_R0_SIZE);
+ if (!ret) {
+ ret = teei_verify_r_prime(rprime);
+ if (!ret)
+ return 0;
+
+ hdcp_err("RPrime verification fails (%d)\n", ret);
+ } else {
+ hdcp_err("RPrime read fails (%d)\n", ret);
+ }
+
+ ri_retry_cnt++;
+ usleep_range(RI_DELAY * 1000, RI_DELAY * 1000 + 1);
+ }
+ while (ri_retry_cnt < RI_READ_RETRY_CNT);
+
+ return -EFAULT;
+}
+
+static int read_ksv_list(u8* hdcp_ksv, u32 len)
+{
+ uint32_t read_len = len < BKSV_LIST_FIFO_SIZE ?
+ len : BKSV_LIST_FIFO_SIZE;
+
+ return hdcp_dplink_recv(HDCP13_MSG_KSV_FIFO_R, hdcp_ksv, read_len) ?
+ -EIO : read_len;
+}
+
+static int proceed_repeater(void)
+{
+ uint8_t ksv_list[HDCP_KSV_MAX_LEN];
+ uint8_t *ksv_list_ptr = ksv_list;
+ uint16_t binfo;
+ uint8_t v_read_retry_cnt = 0;
+ uint8_t vprime[HDCP_SHA1_SIZE];
+ ktime_t start_time_ns;
+ int64_t waiting_time_ms;
+ uint8_t bstatus;
+ uint32_t ksv_len, bytes_read;
+ int ret;
+
+ hdcp_info("Start HDCP Repeater Authentication!!!\n");
+
+ // Step0-1. Poll BStatus Ready
+ start_time_ns = ktime_get();
+ do {
+ usleep_range(RI_AVAILABLE_WAITING * 1000, RI_AVAILABLE_WAITING * 1000 + 1);
+ waiting_time_ms = (s64)((ktime_get() - start_time_ns) / 1000000);
+ if ((waiting_time_ms >= REPEATER_READY_MAX_WAIT_DELAY) ||
+ (dp_hdcp_state == DP_DISCONNECT)) {
+ hdcp_err("Not repeater ready in RX part %lld\n",
+ waiting_time_ms);
+ return -EINVAL;
+ }
+
+ ret = hdcp_dplink_recv(HDCP13_MSG_BSTATUS_R, &bstatus,
+ sizeof(bstatus));
+ if (ret) {
+ hdcp_err("Read BSTATUS failed (%d)\n", ret);
+ return -EIO;
+ }
+ } while (!(bstatus & DP_BSTATUS_READY));
+ hdcp_info("Ready HDCP RX Repeater!!!\n");
+
+ if (dp_hdcp_state == DP_DISCONNECT)
+ return -EINVAL;
+
+ ret = hdcp_dplink_recv(HDCP13_MSG_BINFO_R, (uint8_t*)&binfo, HDCP_BINFO_SIZE);
+ if (ret) {
+ hdcp_err("Read BINFO failed (%d)\n", ret);
+ return -EIO;
+ }
+
+ if (binfo & MAX_DEVS_EXCEEDED) {
+ hdcp_err("Max Devs Exceeded\n");
+ return -EIO;
+ }
+
+ if (binfo & MAX_CASCADE_EXCEEDED) {
+ hdcp_err("Max Cascade Exceeded\n");
+ return -EIO;
+ }
+
+ ksv_len = (binfo & HDCP_BINFO_DEVS_COUNT_MAX) * HDCP_KSV_SIZE;
+ while (ksv_len != 0) {
+ bytes_read = read_ksv_list(ksv_list_ptr, ksv_len);
+ if (bytes_read < 0) {
+ hdcp_err("Read KSV failed (%d)\n", bytes_read);
+ return -EIO;
+ }
+ ksv_len -= bytes_read;
+ ksv_list_ptr += bytes_read;
+ }
+
+ do {
+ ret = hdcp_dplink_recv(HDCP13_MSG_VPRIME_R, vprime,
+ HDCP_SHA1_SIZE);
+ if (!ret) {
+ ret = teei_verify_v_prime(binfo, ksv_list,
+ ksv_list_ptr - ksv_list, vprime);
+ if (!ret) {
+ hdcp_info("Done 2nd Authentication!!!\n");
+ return 0;
+ }
+
+ hdcp_err("Vprime verify failed (%d)\n", ret);
+ } else
+ hdcp_err("Vprime read failed (%d)\n", ret);
+
+ v_read_retry_cnt++;
+ } while(v_read_retry_cnt < V_READ_RETRY_CNT);
+
+ hdcp_err("2nd Auth fail!!!\n");
+ return -EIO;
+}
+
+void hdcp13_dplink_authenticate(void)
+{
+ uint64_t aksv, bksv, an;
+ uint8_t bcaps;
+ int ret;
+
+ hdcp_info("Start SW Authentication\n");
+
+ if (dp_hdcp_state == DP_DISCONNECT) {
+ hdcp_err("DP is disconnected\n");
+ return;
+ }
+
+ auth_proc_state = HDCP_AUTH_PROCESS_IDLE;
+
+ aksv = bksv = an = 0;
+ ret = hdcp_dplink_recv(HDCP13_MSG_BKSV_R, (uint8_t*)&bksv, HDCP_BKSV_SIZE);
+ if (ret) {
+ hdcp_err("Read Bksv failed (%d)\n", ret);
+ return;
+ }
+
+ ret = teei_ksv_exchange(bksv, &aksv, &an);
+ if (ret) {
+ hdcp_err("Ksv exchange failed (%d)\n", ret);
+ return;
+ }
+
+ ret = hdcp_dplink_send(HDCP13_MSG_AN_W, (uint8_t*)&an, HDCP_AN_SIZE);
+ if (ret) {
+ hdcp_err("Write AN failed (%d)\n", ret);
+ return;
+ }
+ ret = hdcp_dplink_send(HDCP13_MSG_AKSV_W, (uint8_t*)&aksv, HDCP_AKSV_SIZE);
+ if (ret) {
+ hdcp_err("Write AKSV failed (%d)\n", ret);
+ return;
+ }
+
+ if (compare_rprime() != 0) {
+ hdcp_err("R0 is not same\n");
+ return;
+ }
+
+ hdcp_tee_enable_enc_13();
+ hdcp_info("Done 1st Authentication\n");
+
+ ret = hdcp_dplink_recv(HDCP13_MSG_BCAPS_R, (uint8_t*)&bcaps, sizeof(bcaps));
+ if (ret) {
+ hdcp_err("BCaps Read failure (%d)\n", ret);
+ return;
+ }
+
+ if ((bcaps & DP_BCAPS_REPEATER_PRESENT) && proceed_repeater()) {
+ hdcp_err("HDCP Authentication fail!!!\n");
+ hdcp_tee_disable_enc();
+ return;
+ }
+
+ auth_proc_state = HDCP1_AUTH_PROCESS_DONE;
+ hdcp_info("Done SW Authentication\n");
+ return;
+}
+
diff --git a/exynos-hdcp1-auth.h b/exynos-hdcp1-auth.h
new file mode 100644
index 0000000..e36de3f
--- /dev/null
+++ b/exynos-hdcp1-auth.h
@@ -0,0 +1,18 @@
+/*
+ * drivers/soc/samsung/exynos-hdcp/exynos-hdcp1-auth.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __EXYNOS_HDCP1_AUTH_H__
+#define __EXYNOS_HDCP1_AUTH_H__
+
+void hdcp13_dplink_authenticate(void);
+
+#endif
diff --git a/exynos-hdcp2-dplink-if.c b/exynos-hdcp2-dplink-if.c
index e5e7a9b..8d53f22 100644
--- a/exynos-hdcp2-dplink-if.c
+++ b/exynos-hdcp2-dplink-if.c
@@ -23,7 +23,16 @@ static int (*pdp_dpcd_read_for_hdcp22)(u32 address, u32 length, u8 *data);
static int (*pdp_dpcd_write_for_hdcp22)(u32 address, u32 length, u8 *data);
/* Address define for HDCP within DPCD address space */
-static uint32_t dpcd_addr[NUM_HDCP22_MSG_NAME] = {
+static uint32_t dpcd_addr[NUM_HDCP_MSG_NAME] = {
+ DPCD_ADDR_HDCP13_Bksv,
+ DPCD_ADDR_HDCP13_Ri_prime,
+ DPCD_ADDR_HDCP13_Aksv,
+ DPCD_ADDR_HDCP13_An,
+ DPCD_ADDR_HDCP13_Vprime,
+ DPCD_ADDR_HDCP13_Bcaps,
+ DPCD_ADDR_HDCP13_Bstatus,
+ DPCD_ADDR_HDCP13_Binfo,
+ DPCD_ADDR_HDCP13_Ksv_fifo,
DPCD_ADDR_HDCP22_Rtx,
DPCD_ADDR_HDCP22_TxCaps,
DPCD_ADDR_HDCP22_cert_rx,
@@ -76,58 +85,12 @@ int hdcp_dplink_get_stream_info(uint16_t *num, uint8_t *strm_id)
int hdcp_dplink_recv(uint32_t msg_name, uint8_t *data, uint32_t size)
{
- int i;
- int ret;
- int remain;
-
- if (size > DPCD_PACKET_SIZE) {
- for (i = 0; i < (size / DPCD_PACKET_SIZE); i++) {
- ret = pdp_dpcd_read_for_hdcp22(
- dpcd_addr[msg_name] + i * DPCD_PACKET_SIZE,
- DPCD_PACKET_SIZE,
- &data[i * DPCD_PACKET_SIZE]);
- if (ret) {
- hdcp_err("dpcd read fail. ret(%d)\n", ret);
- return ret;
- }
- }
-
- remain = size % DPCD_PACKET_SIZE;
- if (remain) {
- ret = pdp_dpcd_read_for_hdcp22(
- dpcd_addr[msg_name] + i * DPCD_PACKET_SIZE,
- remain,
- &data[i * DPCD_PACKET_SIZE]);
- if (ret) {
- hdcp_err("dpcd read fail. ret(%d)\n", ret);
- return ret;
- }
- }
- return 0;
- } else
- return pdp_dpcd_read_for_hdcp22(dpcd_addr[msg_name], size, data);
+ return pdp_dpcd_read_for_hdcp22(dpcd_addr[msg_name], size, data);
}
int hdcp_dplink_send(uint32_t msg_name, uint8_t *data, uint32_t size)
{
- int i;
- int ret;
-
- if (size > DPCD_PACKET_SIZE) {
- for (i = 0; i < (size / DPCD_PACKET_SIZE); i++) {
- ret = pdp_dpcd_write_for_hdcp22(
- dpcd_addr[msg_name] + i * DPCD_PACKET_SIZE,
- DPCD_PACKET_SIZE,
- &data[i * DPCD_PACKET_SIZE]);
- if (ret) {
- hdcp_err("dpcd write fail. ret(%d)\n", ret);
- return ret;
- }
- }
- return 0;
- }
- else
- return pdp_dpcd_write_for_hdcp22(dpcd_addr[msg_name], size, data);
+ return pdp_dpcd_write_for_hdcp22(dpcd_addr[msg_name], size, data);
}
void dp_register_func_for_hdcp22(void (*func0)(u32 en), int (*func1)(u32 address, u32 length, u8 *data), int (*func2)(u32 address, u32 length, u8 *data))
diff --git a/exynos-hdcp2-dplink-if.h b/exynos-hdcp2-dplink-if.h
index 140b204..feff163 100644
--- a/exynos-hdcp2-dplink-if.h
+++ b/exynos-hdcp2-dplink-if.h
@@ -10,7 +10,16 @@
#ifndef __EXYNOS_HDCP2_DPLINK_IF_H__
#define __EXYNOS_HDCP2_DPLINK_IF_H__
-enum hdcp22_msg_name {
+enum hdcp_msg_name {
+ HDCP13_MSG_BKSV_R,
+ HDCP13_MSG_RI_PRIME_R,
+ HDCP13_MSG_AKSV_W,
+ HDCP13_MSG_AN_W,
+ HDCP13_MSG_VPRIME_R,
+ HDCP13_MSG_BCAPS_R,
+ HDCP13_MSG_BSTATUS_R,
+ HDCP13_MSG_BINFO_R,
+ HDCP13_MSG_KSV_FIFO_R,
HDCP22_MSG_RTX_W,
HDCP22_MSG_TXCAPS_W,
HDCP22_MSG_CERT_RX_R,
@@ -37,7 +46,7 @@ enum hdcp22_msg_name {
HDCP22_MSG_MPRIME_R,
HDCP22_MSG_RXSTATUS_R,
HDCP22_MSG_TYPE_W,
- NUM_HDCP22_MSG_NAME,
+ NUM_HDCP_MSG_NAME,
};
#define DP_HDCP22_DISABLE 0
diff --git a/exynos-hdcp2-dplink-inter.c b/exynos-hdcp2-dplink-inter.c
index 401b7cb..5344375 100644
--- a/exynos-hdcp2-dplink-inter.c
+++ b/exynos-hdcp2-dplink-inter.c
@@ -8,6 +8,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <drm/drm_dp_helper.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
@@ -17,6 +18,7 @@
#include <linux/types.h>
#include <linux/delay.h>
+#include "exynos-hdcp1-auth.h"
#include "exynos-hdcp2.h"
#include "exynos-hdcp2-log.h"
#include "exynos-hdcp2-dplink.h"
@@ -28,86 +30,91 @@
#define DRM_WAIT_RETRY_COUNT 1000
/* current link data */
enum auth_state auth_proc_state;
-EXPORT_SYMBOL_GPL(auth_proc_state);
enum dp_state dp_hdcp_state;
-EXPORT_SYMBOL_GPL(dp_hdcp_state);
-int hdcp_dplink_auth_check(enum auth_signal hdcp_signal)
+int hdcp_dplink_auth_control(enum auth_signal hdcp_signal)
{
- int ret = 0;
-
switch (hdcp_signal) {
- case HDCP_DRM_OFF:
- return ret;
- case HDCP_DRM_ON:
- dplink_clear_irqflag_all();
- ret = hdcp_dplink_authenticate();
- return ret;
- case HDCP_RP_READY:
- if (auth_proc_state == HDCP_AUTH_PROCESS_DONE) {
- ret = hdcp_dplink_authenticate();
- if (ret == 0)
- auth_proc_state = HDCP_AUTH_PROCESS_DONE;
- }
+ case HDCP_OFF:
return 0;
+ case HDCP1_ON:
+ hdcp13_dplink_authenticate();
+ return 0;
+ case HDCP2_ON:
+ dplink_clear_irqflag_all();
+ return hdcp_dplink_authenticate();
default:
- ret = HDCP_ERROR_INVALID_STATE;
+ return HDCP_ERROR_INVALID_STATE;
break;
}
- return ret;
+ return 0;
}
-EXPORT_SYMBOL_GPL(hdcp_dplink_auth_check);
+EXPORT_SYMBOL_GPL(hdcp_dplink_auth_control);
-int hdcp_dplink_get_rxstatus(uint8_t *status)
-{
- int ret = 0;
+int hdcp_dplink_handle_hdcp22_irq(void) {
+ uint8_t rxstatus = 0;
+ hdcp_dplink_get_rxinfo(&rxstatus);
- ret = hdcp_dplink_get_rxinfo(status);
- return ret;
-}
-EXPORT_SYMBOL_GPL(hdcp_dplink_get_rxstatus);
+ if (HDCP_2_2_DP_RXSTATUS_LINK_FAILED(rxstatus)) {
+ hdcp_info("integrity check fail.\n");
+ hdcp_tee_disable_enc();
+ dplink_set_integrity_fail();
+ return 0;
+ } else if (HDCP_2_2_DP_RXSTATUS_REAUTH_REQ(rxstatus)) {
+ hdcp_info("reauth requested.\n");
+ hdcp_tee_disable_enc();
+ dplink_set_reauth_req();
+ return -EAGAIN;
+ } else if (HDCP_2_2_DP_RXSTATUS_PAIRING(rxstatus)) {
+ hdcp_info("pairing avaible\n");
+ dplink_set_paring_available();
+ return 0;
+ } else if (HDCP_2_2_DP_RXSTATUS_H_PRIME(rxstatus)) {
+ hdcp_info("h-prime avaible\n");
+ dplink_set_hprime_available();
+ return 0;
+ } else if (HDCP_2_2_DP_RXSTATUS_READY(rxstatus)) {
+ hdcp_info("ready avaible\n");
+ dplink_set_rp_ready();
+ if (auth_proc_state == HDCP2_AUTH_PROCESS_DONE) {
+ if (hdcp_dplink_authenticate() == 0)
+ auth_proc_state = HDCP2_AUTH_PROCESS_DONE;
+ }
+ return 0;
+ }
-int hdcp_dplink_set_paring_available(void)
-{
- hdcp_info("pairing avaible\n");
- return dplink_set_paring_available();
+ hdcp_err("undefined RxStatus(0x%x). ignore\n", rxstatus);
+ return -EINVAL;
}
-EXPORT_SYMBOL_GPL(hdcp_dplink_set_paring_available);
+EXPORT_SYMBOL_GPL(hdcp_dplink_handle_hdcp22_irq);
-int hdcp_dplink_set_hprime_available(void)
+int hdcp_dplink_handle_hdcp13_irq(void)
{
- hdcp_info("h-prime avaible\n");
- return dplink_set_hprime_available();
-}
-EXPORT_SYMBOL_GPL(hdcp_dplink_set_hprime_available);
+ uint8_t bstatus;
-int hdcp_dplink_set_rp_ready(void)
-{
- hdcp_info("ready avaible\n");
- return dplink_set_rp_ready();
-}
-EXPORT_SYMBOL_GPL(hdcp_dplink_set_rp_ready);
+ if (auth_proc_state != HDCP1_AUTH_PROCESS_DONE) {
+ hdcp_err("Ignoring IRQ during auth\n");
+ return 0;
+ }
-int hdcp_dplink_set_reauth(void)
-{
- hdcp_info("reauth requested.\n");
- hdcp_tee_send_cmd(HDCP_CMD_AUTH_CANCEL);
- return dplink_set_reauth_req();
-}
-EXPORT_SYMBOL_GPL(hdcp_dplink_set_reauth);
+ hdcp_dplink_recv(HDCP13_MSG_BSTATUS_R, &bstatus,
+ sizeof(bstatus));
-int hdcp_dplink_set_integrity_fail(void)
-{
- hdcp_info("integrity check fail.\n");
- hdcp_tee_send_cmd(HDCP_CMD_AUTH_CANCEL);
- return dplink_set_integrity_fail();
+ if (bstatus & DP_BSTATUS_LINK_FAILURE ||
+ bstatus & DP_BSTATUS_REAUTH_REQ) {
+ hdcp_err("Resetting link and encryption\n");
+ hdcp_tee_disable_enc();
+ return -EAGAIN;
+ }
+
+ return 0;
}
-EXPORT_SYMBOL_GPL(hdcp_dplink_set_integrity_fail);
+EXPORT_SYMBOL_GPL(hdcp_dplink_handle_hdcp13_irq);
int hdcp_dplink_cancel_auth(void)
{
hdcp_info("Cancel authenticate.\n");
- hdcp_tee_send_cmd(HDCP_CMD_AUTH_CANCEL);
+ hdcp_tee_disable_enc();
auth_proc_state = HDCP_AUTH_PROCESS_STOP;
return dplink_set_integrity_fail();
@@ -117,7 +124,7 @@ EXPORT_SYMBOL_GPL(hdcp_dplink_cancel_auth);
void hdcp_dplink_clear_all(void)
{
hdcp_info("HDCP flag clear\n");
- hdcp_tee_send_cmd(HDCP_CMD_AUTH_CANCEL);
+ hdcp_tee_disable_enc();
dplink_clear_irqflag_all();
}
EXPORT_SYMBOL_GPL(hdcp_dplink_clear_all);
@@ -129,3 +136,46 @@ void hdcp_dplink_connect_state(enum dp_state state)
hdcp_tee_connect_info((int)dp_hdcp_state);
}
EXPORT_SYMBOL_GPL(hdcp_dplink_connect_state);
+
+int hdcp_dplink_auth_check(enum auth_signal hdcp_signal)
+{
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(hdcp_dplink_auth_check);
+
+int hdcp_dplink_get_rxstatus(uint8_t *status)
+{
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(hdcp_dplink_get_rxstatus);
+
+int hdcp_dplink_set_paring_available(void)
+{
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(hdcp_dplink_set_paring_available);
+
+int hdcp_dplink_set_hprime_available(void)
+{
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(hdcp_dplink_set_hprime_available);
+
+int hdcp_dplink_set_rp_ready(void)
+{
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(hdcp_dplink_set_rp_ready);
+
+int hdcp_dplink_set_reauth(void)
+{
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(hdcp_dplink_set_reauth);
+
+int hdcp_dplink_set_integrity_fail(void)
+{
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(hdcp_dplink_set_integrity_fail);
+
diff --git a/exynos-hdcp2-dplink-inter.h b/exynos-hdcp2-dplink-inter.h
index ecfd9f0..763a1d4 100644
--- a/exynos-hdcp2-dplink-inter.h
+++ b/exynos-hdcp2-dplink-inter.h
@@ -26,6 +26,9 @@ int hdcp_dplink_set_integrity_fail(void);
int hdcp_dplink_cancel_auth(void);
int hdcp_dplink_stream_manage(void);
int hdcp_dplink_auth_check(enum auth_signal);
+int hdcp_dplink_auth_control(enum auth_signal);
void hdcp_dplink_clear_all(void);
void hdcp_dplink_connect_state(enum dp_state state);
+int hdcp_dplink_handle_hdcp13_irq(void);
+int hdcp_dplink_handle_hdcp22_irq(void);
#endif
diff --git a/exynos-hdcp2-dplink-reg.h b/exynos-hdcp2-dplink-reg.h
index afd0bca..42fb404 100644
--- a/exynos-hdcp2-dplink-reg.h
+++ b/exynos-hdcp2-dplink-reg.h
@@ -12,6 +12,15 @@
#define DPCD_PACKET_SIZE (8)
+#define DPCD_ADDR_HDCP13_Bksv 0x68000
+#define DPCD_ADDR_HDCP13_Ri_prime 0x68005
+#define DPCD_ADDR_HDCP13_Aksv 0x68007
+#define DPCD_ADDR_HDCP13_An 0x6800C
+#define DPCD_ADDR_HDCP13_Vprime 0x68014
+#define DPCD_ADDR_HDCP13_Bcaps 0x68028
+#define DPCD_ADDR_HDCP13_Bstatus 0x68029
+#define DPCD_ADDR_HDCP13_Binfo 0x6802A
+#define DPCD_ADDR_HDCP13_Ksv_fifo 0x6802C
#define DPCD_ADDR_HDCP22_Rtx 0x69000
#define DPCD_ADDR_HDCP22_TxCaps 0x69008
#define DPCD_ADDR_HDCP22_cert_rx 0x6900B
diff --git a/exynos-hdcp2-dplink.c b/exynos-hdcp2-dplink.c
index 3367458..bbdb7b9 100644
--- a/exynos-hdcp2-dplink.c
+++ b/exynos-hdcp2-dplink.c
@@ -149,7 +149,7 @@ int do_dplink_auth(struct hdcp_link_info *lk_handle)
if (hdcp_enabled)
hdcp_dplink_config(DP_HDCP22_ENABLE);
/* Transmitter has completed the authentication protocol */
- ret = hdcp_tee_send_cmd(HDCP_CMD_AUTH_DONE);
+ ret = hdcp_tee_enable_enc_22();
return HDCP_SUCCESS;
case LINK_ST_A6_WAIT_RECEIVER_ID_LIST:
rval = dplink_wait_for_receiver_id_list(lk_data);
@@ -198,7 +198,7 @@ int do_dplink_auth(struct hdcp_link_info *lk_handle)
UPDATE_LINK_STATE(lk_data, LINK_ST_H1_TX_LOW_VALUE_CONTENT);
} else {
UPDATE_LINK_STATE(lk_data, LINK_ST_A5_AUTHENTICATED);
- auth_proc_state = HDCP_AUTH_PROCESS_DONE;
+ auth_proc_state = HDCP2_AUTH_PROCESS_DONE;
}
break;
default:
diff --git a/exynos-hdcp2-dplink.h b/exynos-hdcp2-dplink.h
index 6318c82..b7385db 100644
--- a/exynos-hdcp2-dplink.h
+++ b/exynos-hdcp2-dplink.h
@@ -13,9 +13,9 @@
#include "exynos-hdcp2.h"
enum auth_signal {
- HDCP_DRM_OFF = 0x100,
- HDCP_DRM_ON = 0x200,
- HDCP_RP_READY = 0x300,
+ HDCP_OFF = 0x100,
+ HDCP1_ON = 0x200,
+ HDCP2_ON = 0x300,
};
enum drm_state {
diff --git a/exynos-hdcp2-log.h b/exynos-hdcp2-log.h
index 3c78c17..5d07c6b 100644
--- a/exynos-hdcp2-log.h
+++ b/exynos-hdcp2-log.h
@@ -10,15 +10,15 @@
* (at your option) any later version.
*/
-#ifndef __EXYNOS_HDCP2_LOG_H__
-#define __EXYNOS_HDCP2_LOG_H__
+#ifndef __EXYNOS_HDCP_LOG_H__
+#define __EXYNOS_HDCP_LOG_H__
-#undef HDCP_DEBUG
+#define HDCP_DEBUG
#ifdef HDCP_DEBUG
#define hdcp_debug(fmt, args...) \
do { \
- printk(KERN_ERR "[HDCP2]%s:%d: " fmt, \
+ printk(KERN_ERR "exynos-drm-hdcp: %s:%d: " fmt, \
__func__, __LINE__, ##args); \
} while (0)
#else
@@ -27,13 +27,13 @@
#define hdcp_err(fmt, args...) \
do { \
- printk(KERN_ERR "[HDCP2]%s:%d: " fmt, \
+ printk(KERN_ERR "exynos-drm-hdcp: %s:%d: " fmt, \
__func__, __LINE__, ##args); \
} while (0)
#define hdcp_info(fmt, args...) \
do { \
- printk(KERN_INFO "[HDCP2]%s:%d: " fmt, \
+ printk(KERN_INFO "exynos-drm-hdcp: %s:%d: " fmt, \
__func__, __LINE__, ##args); \
} while (0)
#endif
diff --git a/exynos-hdcp2-main.c b/exynos-hdcp2-main.c
index 68e6858..3d0a350 100644
--- a/exynos-hdcp2-main.c
+++ b/exynos-hdcp2-main.c
@@ -103,16 +103,13 @@ static void exynos_hdcp_worker(struct work_struct *work)
}
hdcp_info("Exynos HDCP interrupt occur by LDFW.\n");
- hdcp_dplink_auth_check(HDCP_DRM_ON);
+ hdcp_dplink_auth_control(HDCP2_ON);
}
static irqreturn_t exynos_hdcp_irq_handler(int irq, void *dev_id)
{
if (h_ctx.enabled) {
- if (dp_hdcp_state == DP_HDCP_READY)
- schedule_delayed_work(&h_ctx.work, msecs_to_jiffies(0));
- else
- schedule_delayed_work(&h_ctx.work, msecs_to_jiffies(2500));
+ schedule_delayed_work(&h_ctx.work, msecs_to_jiffies(0));
}
return IRQ_HANDLED;
@@ -120,8 +117,6 @@ static irqreturn_t exynos_hdcp_irq_handler(int irq, void *dev_id)
static int exynos_hdcp_probe(struct platform_device *pdev)
{
- struct irq_data *hdcp_irqd = NULL;
- irq_hw_number_t hwirq = 0;
int err;
h_ctx.irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
@@ -130,15 +125,7 @@ static int exynos_hdcp_probe(struct platform_device *pdev)
return -EINVAL;
}
- /* Get irq_data for secure log */
- hdcp_irqd = irq_get_irq_data(h_ctx.irq);
- if (!hdcp_irqd) {
- dev_err(&pdev->dev, "Fail to get irq_data\n");
- return -EINVAL;
- }
-
/* Get hardware interrupt number */
- hwirq = irqd_to_hwirq(hdcp_irqd);
err = devm_request_irq(&pdev->dev, h_ctx.irq,
exynos_hdcp_irq_handler,
IRQF_TRIGGER_RISING, pdev->name, NULL);
@@ -159,8 +146,6 @@ static int exynos_hdcp_probe(struct platform_device *pdev)
INIT_DELAYED_WORK(&h_ctx.work, exynos_hdcp_worker);
h_ctx.enabled = true;
- err = hdcp_tee_notify_intr_num(hwirq);
-
hdcp_info("Exynos HDCP driver probe done! (%d)\n", err);
return err;
}
diff --git a/exynos-hdcp2-selftest.c b/exynos-hdcp2-selftest.c
index f640f54..75b4dee 100644
--- a/exynos-hdcp2-selftest.c
+++ b/exynos-hdcp2-selftest.c
@@ -226,9 +226,9 @@ static int dp_hdcp_protocol_self_test_internal(void) {
size_t i;
int rc, version;
- hdcp_dplink_connect_state(DP_HDCP_READY);
+ hdcp_dplink_connect_state(DP_CONNECT);
- rc = hdcp_tee_send_cmd(HDCP_CMD_AUTH_START);
+ rc = hdcp_tee_send_cmd(HDCP_CMD_AUTH_MANUAL_START);
if (rc) {
hdcp_err("starting authentication failed: %d", rc);
return rc;
@@ -271,7 +271,7 @@ int dp_hdcp_protocol_self_test(void) {
return rc;
}
rc = dp_hdcp_protocol_self_test_internal();
- hdcp_tee_send_cmd(HDCP_CMD_AUTH_CANCEL);
+ hdcp_tee_disable_enc();
hdcp_tee_set_test_mode(false);
return rc;
diff --git a/exynos-hdcp2-teeif.c b/exynos-hdcp2-teeif.c
index dc8f017..d846709 100644
--- a/exynos-hdcp2-teeif.c
+++ b/exynos-hdcp2-teeif.c
@@ -26,6 +26,10 @@
#define TZ_MSG_TIMEOUT 10000
#define HDCP_TA_PORT "com.android.trusty.hdcp.auth"
+#define HDCP_V2_3 (5)
+#define HDCP_V1 (1)
+#define HDCP_NONE (0)
+
struct hdcp_auth_req {
uint32_t cmd;
int32_t arg;
@@ -241,21 +245,25 @@ static int hdcp_tee_comm_xchg(uint32_t cmd, int32_t arg, int32_t *rsp,
return ret;
}
-static irq_hw_number_t saved_hwirq = 0;
-
int hdcp_tee_send_cmd(uint32_t cmd) {
- if (HDCP_CMD_AUTH_START == cmd)
- hdcp_tee_comm_xchg(HDCP_CMD_NOTIFY_INTR_NUM, saved_hwirq, NULL, NULL);
return hdcp_tee_comm_xchg(cmd, 0, NULL, NULL);
}
-int hdcp_tee_check_protection(int* version) {
- return hdcp_tee_comm_xchg(HDCP_CMD_PROTECTION_CHECK, 0, version, NULL);
+int hdcp_tee_enable_enc_22(void) {
+ return hdcp_tee_comm_xchg(HDCP_CMD_ENCRYPTION_SET, HDCP_V2_3, NULL,
+ NULL);
}
-int hdcp_tee_notify_intr_num(irq_hw_number_t hwirq) {
- saved_hwirq = hwirq;
- return 0;
+int hdcp_tee_enable_enc_13(void) {
+ return hdcp_tee_comm_xchg(HDCP_CMD_ENCRYPTION_SET, HDCP_V1, NULL, NULL);
+}
+
+int hdcp_tee_disable_enc(void) {
+ return hdcp_tee_comm_xchg(HDCP_CMD_ENCRYPTION_SET, HDCP_NONE, NULL, NULL);
+}
+
+int hdcp_tee_check_protection(int* version) {
+ return hdcp_tee_comm_xchg(HDCP_CMD_ENCRYPTION_GET, 0, version, NULL);
}
int hdcp_tee_set_test_mode(bool enable) {
@@ -575,3 +583,43 @@ int teei_verify_m_prime(uint8_t *m_prime, uint8_t *input, size_t input_len)
return ret;
}
+
+int teei_ksv_exchange(uint64_t bksv, uint64_t *aksv, uint64_t *an) {
+ int ret = 0;
+ struct hci_message msg;
+ struct hci_message *hci = &msg;
+
+ hci->cmd_id = HDCP_TEEI_KSV_EXCHANGE;
+ hci->ksvexchange.bksv = bksv;
+
+ if ((ret = hdcp_tee_comm(hci)) < 0)
+ return ret;
+
+ *aksv = hci->ksvexchange.aksv;
+ *an = hci->ksvexchange.an;
+ return 0;
+}
+
+int teei_verify_r_prime(uint16_t rprime) {
+ struct hci_message msg;
+ struct hci_message *hci = &msg;
+
+ hci->cmd_id = HDCP_TEEI_VERIFY_R_PRIME;
+ hci->verifyrprime.r_prime = rprime;
+
+ return hdcp_tee_comm(hci);
+}
+
+int teei_verify_v_prime(uint16_t binfo, uint8_t *ksv, uint32_t ksv_len,
+ uint8_t *vprime) {
+ struct hci_message msg;
+ struct hci_message *hci = &msg;
+
+ hci->cmd_id = HDCP_TEEI_VERIFY_V_PRIME;
+ hci->verifyvprime.ksv_len = ksv_len;
+ hci->verifyvprime.binfo = binfo;
+ memcpy(hci->verifyvprime.ksv, ksv, ksv_len);
+ memcpy(hci->verifyvprime.v_prime, vprime, HDCP_SHA1_SIZE);
+
+ return hdcp_tee_comm(hci);
+}
diff --git a/exynos-hdcp2-teeif.h b/exynos-hdcp2-teeif.h
index 3b01319..228f249 100644
--- a/exynos-hdcp2-teeif.h
+++ b/exynos-hdcp2-teeif.h
@@ -38,7 +38,9 @@ enum {
HDCP_TEEI_SET_RCV_ID_LIST,
HDCP_TEEI_GEN_STREAM_MANAGE,
HDCP_TEEI_VERIFY_M_PRIME,
- HDCP_TEEI_WRAP_KEY,
+ HDCP_TEEI_KSV_EXCHANGE,
+ HDCP_TEEI_VERIFY_R_PRIME,
+ HDCP_TEEI_VERIFY_V_PRIME,
HDCP_TEEI_MSG_END
};
@@ -48,6 +50,12 @@ enum {
#define HDCP_WSM_SIZE (1024)
#define AKE_INFO_SIZE (128)
+#define HDCP_BINFO_DEVS_COUNT_MAX (0x7F)
+#define HDCP_BINFO_SIZE (2)
+#define HDCP_SHA1_SIZE (20)
+#define HDCP_KSV_SIZE (5)
+#define HDCP_KSV_MAX_LEN (HDCP_KSV_SIZE * HDCP_BINFO_DEVS_COUNT_MAX)
+#define HDCP_SHA1_MAX_INPUT_LEN (HDCP_BINFO_SIZE + HDCP_KSV_MAX_LEN + HDCP_M0_SIZE)
#define HDCP_RX_MODULUS_LEN (1024 / 8)
#define HDCP_RX_PUB_EXP_LEN (24 / 8)
#define HDCP_AKE_ENCKEY_BYTE_LEN (1024 / 8)
@@ -216,11 +224,23 @@ typedef struct {
typedef struct {
uint32_t id;
- uint8_t key[HDCP_WRAP_KEY];
- uint8_t enc_key[HDCP_WRAP_MAX_SIZE];
- uint32_t wrapped;
- uint32_t key_len;
-} hci_wrap_key_t;
+ uint64_t bksv;
+ uint64_t an;
+ uint64_t aksv;
+} hci_ksvexchange_t;
+
+typedef struct {
+ uint32_t id;
+ uint16_t r_prime;
+} hci_verifyrprime_t;
+
+typedef struct {
+ uint32_t id;
+ uint32_t ksv_len;
+ uint16_t binfo;
+ uint8_t ksv[HDCP_KSV_MAX_LEN];
+ uint8_t v_prime[HDCP_SHA1_SIZE];
+} hci_verifyvprime_t;
/* todo: define WSM message format for AKE */
struct hci_message {
@@ -241,7 +261,9 @@ struct hci_message {
hci_setrcvlist_t setrcvlist;
hci_genstreaminfo_t genstrminfo;
hci_verifymprime_t verifymprime;
- hci_wrap_key_t wrap_key;
+ hci_ksvexchange_t ksvexchange;
+ hci_verifyrprime_t verifyrprime;
+ hci_verifyvprime_t verifyvprime;
uint8_t data[HDCP_WSM_SIZE];
};
};
@@ -255,11 +277,9 @@ enum hdcp_auth_cmd {
HDCP_CMD_AUTH_RESP = (1U << 31),
HDCP_CMD_REINIT = 0,
HDCP_CMD_PROTOCOL,
- HDCP_CMD_NOTIFY_INTR_NUM,
- HDCP_CMD_AUTH_START,
- HDCP_CMD_AUTH_DONE,
- HDCP_CMD_AUTH_CANCEL,
- HDCP_CMD_PROTECTION_CHECK,
+ HDCP_CMD_ENCRYPTION_SET,
+ HDCP_CMD_ENCRYPTION_GET,
+ HDCP_CMD_AUTH_MANUAL_START,
HDCP_CMD_SESSION_SET,
HDCP_CMD_SET_TEST_MODE,
HDCP_CMD_CONNECT_INFO,
@@ -268,8 +288,10 @@ enum hdcp_auth_cmd {
void hdcp_tee_init(void);
int hdcp_tee_open(void);
int hdcp_tee_close(void);
+int hdcp_tee_enable_enc_22(void);
+int hdcp_tee_enable_enc_13(void);
+int hdcp_tee_disable_enc(void);
int hdcp_tee_send_cmd(uint32_t cmd);
-int hdcp_tee_notify_intr_num(irq_hw_number_t hwirq);
int hdcp_tee_check_protection(int* version);
int hdcp_tee_set_test_mode(bool enable);
int hdcp_tee_connect_info(int connect_info);
@@ -311,4 +333,10 @@ int teei_gen_stream_manage(uint16_t stream_num,
uint8_t *k,
uint8_t *streamid_type);
int teei_verify_m_prime(uint8_t *m_prime, uint8_t *input, size_t input_len);
+
+int teei_verify_r_prime(uint16_t rprime);
+int teei_ksv_exchange(uint64_t bksv, uint64_t *aksv, uint64_t *an);
+int teei_verify_v_prime(uint16_t binfo, uint8_t *ksv, uint32_t ksv_len,
+ uint8_t *vprime);
+
#endif
diff --git a/exynos-hdcp2.h b/exynos-hdcp2.h
index bec9095..4ca2e29 100644
--- a/exynos-hdcp2.h
+++ b/exynos-hdcp2.h
@@ -257,13 +257,13 @@ enum hdcp_result hdcp_unwrap_key(char *wkey);
enum dp_state {
DP_DISCONNECT,
DP_CONNECT,
- DP_HDCP_READY,
};
enum auth_state {
HDCP_AUTH_PROCESS_IDLE = 0x1,
HDCP_AUTH_PROCESS_STOP = 0x2,
- HDCP_AUTH_PROCESS_DONE = 0x3
+ HDCP1_AUTH_PROCESS_DONE = 0x3,
+ HDCP2_AUTH_PROCESS_DONE = 0x4
};
#endif