diff options
author | Ji Soo Shin <jisshin@google.com> | 2023-04-11 13:22:51 +0200 |
---|---|---|
committer | Ji Soo Shin <jisshin@google.com> | 2023-04-13 15:33:09 +0200 |
commit | 020efa21655d0a7c92cb0bdc12d6e176002e8180 (patch) | |
tree | a273f3656f4182f9a2f9023391effb43f3fcd24d | |
parent | 9f6f4e9e06f1ecac01b304fe2a938822b961ef52 (diff) | |
download | samsung-020efa21655d0a7c92cb0bdc12d6e176002e8180.tar.gz |
zuma: migrate hdcp1.3 features
Bug: 271268975
Bug: 271270186
Bug: 274950373
Bug: 277216601
Bug: 275583366
Change-Id: Ifbf466111721219e9dd583e1baf6f59449e481f8
-rw-r--r-- | Kbuild | 1 | ||||
-rw-r--r-- | exynos-hdcp1-auth.c | 239 | ||||
-rw-r--r-- | exynos-hdcp1-auth.h | 18 | ||||
-rw-r--r-- | exynos-hdcp2-dplink-if.c | 61 | ||||
-rw-r--r-- | exynos-hdcp2-dplink-if.h | 13 | ||||
-rw-r--r-- | exynos-hdcp2-dplink-inter.c | 166 | ||||
-rw-r--r-- | exynos-hdcp2-dplink-inter.h | 3 | ||||
-rw-r--r-- | exynos-hdcp2-dplink-reg.h | 9 | ||||
-rw-r--r-- | exynos-hdcp2-dplink.c | 4 | ||||
-rw-r--r-- | exynos-hdcp2-dplink.h | 6 | ||||
-rw-r--r-- | exynos-hdcp2-log.h | 12 | ||||
-rw-r--r-- | exynos-hdcp2-main.c | 19 | ||||
-rw-r--r-- | exynos-hdcp2-selftest.c | 6 | ||||
-rw-r--r-- | exynos-hdcp2-teeif.c | 66 | ||||
-rw-r--r-- | exynos-hdcp2-teeif.h | 54 | ||||
-rw-r--r-- | exynos-hdcp2.h | 4 |
16 files changed, 517 insertions, 164 deletions
@@ -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 |