media: rockchip: hdmirx: add hdcp2 support

Signed-off-by: Chen Shunqing <csq@rock-chips.com>
Change-Id: I71146b743c1957a97333cbe1e35c1754cf6f1c90
This commit is contained in:
Chen Shunqing
2022-06-05 09:04:04 +00:00
committed by Tao Huang
parent f023c52a1f
commit ec31f2140f
4 changed files with 201 additions and 44 deletions

View File

@@ -218,8 +218,9 @@ struct rk_hdmirx_dev {
bool power_on;
bool initialized;
bool freq_qos_add;
bool hdcp1x_enable;
bool get_timing;
u8 hdcp_enable;
u8 hdcp_support;
u32 num_clks;
u32 edid_blocks_written;
u32 hpd_trigger_level;
@@ -827,7 +828,7 @@ static int hdmirx_query_dv_timings(struct file *file, void *_fh,
return 0;
}
static void hdmirx_hpd_ctrl(struct rk_hdmirx_dev *hdmirx_dev, bool en)
static void hdmirx_hpd_config(struct rk_hdmirx_dev *hdmirx_dev, bool en)
{
struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev;
@@ -839,6 +840,21 @@ static void hdmirx_hpd_ctrl(struct rk_hdmirx_dev *hdmirx_dev, bool en)
hdmirx_writel(hdmirx_dev, CORE_CONFIG, en);
}
static void hdmirx_hpd_ctrl(struct rk_hdmirx_dev *hdmirx_dev, bool en)
{
struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev;
v4l2_dbg(1, debug, v4l2_dev, "%s: %sable, hpd_trigger_level:%d\n",
__func__, en ? "en" : "dis",
hdmirx_dev->hpd_trigger_level);
hdmirx_hpd_config(hdmirx_dev, en);
if (hdmirx_dev->hdcp && hdmirx_dev->hdcp->hdcp2_connect_ctrl) {
regmap_write(hdmirx_dev->vo1_grf, VO1_GRF_VO1_CON1,
HDCP1_P0_GPIO_IN_SEL | HDCP1_P0_GPIO_IN_SEL << 16);
hdmirx_dev->hdcp->hdcp2_connect_ctrl(hdmirx_dev->hdcp, en);
}
}
static int hdmirx_write_edid(struct rk_hdmirx_dev *hdmirx_dev,
struct v4l2_edid *edid, bool hpd_up)
{
@@ -992,13 +1008,16 @@ static int hdmirx_enum_dv_timings(struct file *file, void *_fh,
static void hdmirx_register_hdcp(struct device *dev,
struct rk_hdmirx_dev *hdmirx_dev,
bool hdcp1x_enable)
u8 hdcp_enable)
{
struct rk_hdmirx_hdcp hdmirx_hdcp = {
.hdmirx = hdmirx_dev,
.write = hdmirx_writel,
.read = hdmirx_readl,
.enable = hdcp1x_enable,
.hpd_config = hdmirx_hpd_config,
.tx_5v_power = tx_5v_power_present,
.enable = hdcp_enable,
.hdcp_support = hdmirx_dev->hdcp_support,
.dev = hdmirx_dev->dev,
};
@@ -1374,7 +1393,6 @@ static void hdmirx_submodule_init(struct rk_hdmirx_dev *hdmirx_dev)
{
/* Note: if not config HDCP2_CONFIG, there will be some errors; */
hdmirx_update_bits(hdmirx_dev, HDCP2_CONFIG,
HDCP2_SWITCH_OVR_VALUE |
HDCP2_SWITCH_OVR_EN,
HDCP2_SWITCH_OVR_EN);
hdmirx_scdc_init(hdmirx_dev);
@@ -2897,8 +2915,18 @@ static int hdmirx_parse_dt(struct rk_hdmirx_dev *hdmirx_dev)
dev_warn(dev, "failed to get hpd-trigger-level, set high as default\n");
}
if (of_property_read_bool(np, "hdcp1x-enable"))
hdmirx_dev->hdcp1x_enable = true;
if (of_property_read_bool(np, "hdcp1x-enable")) {
hdmirx_dev->hdcp_support |= HDCP_1X_ENABLE;
hdmirx_dev->hdcp_enable = HDCP_1X_ENABLE;
}
if (of_property_read_bool(np, "hdcp2x-enable")) {
hdmirx_dev->hdcp_support |= HDCP_2X_ENABLE;
hdmirx_dev->hdcp_enable = HDCP_2X_ENABLE;
}
if (of_property_read_bool(np, "hdcp1x-default-enable")) {
hdmirx_dev->hdcp_support |= HDCP_1X_ENABLE;
hdmirx_dev->hdcp_enable = HDCP_1X_ENABLE;
}
ret = of_reserved_mem_device_init(dev);
if (ret)
@@ -2947,6 +2975,8 @@ static int hdmirx_power_on(struct rk_hdmirx_dev *hdmirx_dev)
regmap_write(hdmirx_dev->vo1_grf, VO1_GRF_VO1_CON2,
(HDCP1_GATING_EN | HDMIRX_SDAIN_MSK | HDMIRX_SCLIN_MSK) |
((HDCP1_GATING_EN | HDMIRX_SDAIN_MSK | HDMIRX_SCLIN_MSK) << 16));
regmap_write(hdmirx_dev->vo1_grf, VO1_GRF_VO1_CON1,
HDCP1_P0_GPIO_IN_SEL | HDCP1_P0_GPIO_IN_SEL << 16);
/*
* Some interrupts are enabled by default, so we disable
@@ -3037,6 +3067,8 @@ static int hdmirx_runtime_resume(struct device *dev)
regmap_write(hdmirx_dev->vo1_grf, VO1_GRF_VO1_CON2,
(HDCP1_GATING_EN | HDMIRX_SDAIN_MSK | HDMIRX_SCLIN_MSK) |
((HDCP1_GATING_EN | HDMIRX_SDAIN_MSK | HDMIRX_SCLIN_MSK) << 16));
regmap_write(hdmirx_dev->vo1_grf, VO1_GRF_VO1_CON1,
HDCP1_P0_GPIO_IN_SEL | HDCP1_P0_GPIO_IN_SEL << 16);
if (hdmirx_dev->initialized)
schedule_delayed_work_on(hdmirx_dev->bound_cpu,
&hdmirx_dev->delayed_work_hotplug,
@@ -3771,7 +3803,7 @@ static int hdmirx_probe(struct platform_device *pdev)
cec_data.irq = irq;
cec_data.edid = edid_init_data_340M;
hdmirx_dev->cec = rk_hdmirx_cec_register(&cec_data);
hdmirx_register_hdcp(dev, hdmirx_dev, hdmirx_dev->hdcp1x_enable);
hdmirx_register_hdcp(dev, hdmirx_dev, hdmirx_dev->hdcp_enable);
hdmirx_register_debugfs(hdmirx_dev->dev, hdmirx_dev);

View File

@@ -22,10 +22,15 @@
#define SYS_GRF_CHIP_ID 0x0600
// -------------------- VO1_GRF ---------------------------------
#define VO1_GRF_VO1_CON1 0x0004
#define HDCP1_P0_GPIO_IN_SEL BIT(8)
#define VO1_GRF_VO1_CON2 0x0008
#define HDCP1_GATING_EN BIT(10)
#define HDMIRX_SDAIN_MSK BIT(2)
#define HDMIRX_SCLIN_MSK BIT(1)
#define HDCP2_SWITCH_LCK BIT(0)
#define HDCP2_ESM_P0_GPIO_IN 0x0300
// -------------------- HDMIRX PHY -------------------------------
#define SUP_DIG_ANA_CREGS_SUP_ANA_NC 0x004f
@@ -159,6 +164,8 @@
#define HDCP2_CONNECTED BIT(12)
#define HDCP2_SWITCH_OVR_VALUE BIT(2)
#define HDCP2_SWITCH_OVR_EN BIT(1)
#define HDCP2_STATUS 0x02f4
#define HDCP2_ESM_P0_GPIO_OUT 0x0304
#define VIDEO_CONFIG2 0x042c
#define VPROC_VSYNC_POL_OVR_VALUE BIT(19)

View File

@@ -5,6 +5,7 @@
* Author: Shunqing Chen <csq@rock-chips.com>
*/
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -104,9 +105,6 @@ static int rk_hdmirx_hdcp_load_key(struct rk_hdmirx_hdcp *hdcp)
static int rk_hdmirx_hdcp1x_start(struct rk_hdmirx_hdcp *hdcp)
{
if (!hdcp->enable)
return -EPERM;
rk_hdmirx_hdcp_load_key(hdcp);
dev_dbg(hdcp->dev, "%s success\n", __func__);
@@ -115,37 +113,96 @@ static int rk_hdmirx_hdcp1x_start(struct rk_hdmirx_hdcp *hdcp)
static int rk_hdmirx_hdcp1x_stop(struct rk_hdmirx_hdcp *hdcp)
{
if (!hdcp->enable)
return -EPERM;
hdmirx_hdcp_update_bits(hdcp, GLOBAL_SWENABLE, HDCP_ENABLE, 0);
hdcp->status = HDMIRX_HDCP_DISABLED;
return 0;
}
static void rk_hdmirx_hdcp2_hpd_config(struct rk_hdmirx_hdcp *hdcp, bool en)
{
if (hdcp->tx_5v_power(hdcp->hdmirx))
hdcp->hpd_config(hdcp->hdmirx, en);
}
static int rk_hdmirx_hdcp2x_start(struct rk_hdmirx_hdcp *hdcp)
{
hdmirx_hdcp_update_bits(hdcp, HDCP2_CONFIG,
HDCP2_SWITCH_OVR_VALUE |
HDCP2_SWITCH_LCK,
HDCP2_SWITCH_OVR_VALUE |
HDCP2_SWITCH_LCK);
if (hdcp->tx_5v_power(hdcp->hdmirx))
hdmirx_hdcp_write(hdcp, HDCP2_ESM_P0_GPIO_IN, 0x2);
dev_dbg(hdcp->dev, "%s success\n", __func__);
return 0;
}
static int rk_hdmirx_hdcp2x_stop(struct rk_hdmirx_hdcp *hdcp)
{
rk_hdmirx_hdcp2_hpd_config(hdcp, false);
hdmirx_hdcp_write(hdcp, HDCP2_ESM_P0_GPIO_IN, 0x0);
hdmirx_hdcp_update_bits(hdcp, HDCP2_CONFIG,
HDCP2_SWITCH_OVR_VALUE |
HDCP2_SWITCH_LCK, 0);
msleep(300);
rk_hdmirx_hdcp2_hpd_config(hdcp, true);
return 0;
}
static void rk_hdmirx_hdcp2_connect_ctrl(struct rk_hdmirx_hdcp *hdcp, bool en)
{
if (hdcp->enable != HDCP_2X_ENABLE)
return;
if (en) {
hdmirx_hdcp_write(hdcp, HDCP2_ESM_P0_GPIO_IN, 0x2);
hdmirx_hdcp_update_bits(hdcp, HDCP2_CONFIG, HDCP2_CONNECTED,
HDCP2_CONNECTED);
} else {
hdmirx_hdcp_write(hdcp, HDCP2_ESM_P0_GPIO_IN, 0x0);
hdmirx_hdcp_update_bits(hdcp, HDCP2_CONFIG,
HDCP2_CONNECTED, 0);
}
}
static int rk_hdmirx_hdcp_start(struct rk_hdmirx_hdcp *hdcp)
{
if (hdcp->hdcp2 && hdcp->hdcp2->enable) {
hdcp->hdcp2->start();
if ((hdcp->hdcp_support & HDCP_2X_ENABLE) &&
hdcp->enable == HDCP_2X_ENABLE) {
rk_hdmirx_hdcp2x_start(hdcp);
return 0;
}
return rk_hdmirx_hdcp1x_start(hdcp);
if ((hdcp->hdcp_support & HDCP_1X_ENABLE) &&
hdcp->enable == HDCP_1X_ENABLE)
rk_hdmirx_hdcp1x_start(hdcp);
return 0;
}
static int rk_hdmirx_hdcp_stop(struct rk_hdmirx_hdcp *hdcp)
{
if (hdcp->hdcp2 && hdcp->hdcp2->stop) {
hdcp->hdcp2->stop();
if ((hdcp->hdcp_support & HDCP_2X_ENABLE) &&
hdcp->enable == HDCP_2X_ENABLE) {
rk_hdmirx_hdcp2x_stop(hdcp);
dev_dbg(hdcp->dev, "hdcp2 stop\n");
}
return rk_hdmirx_hdcp1x_stop(hdcp);
if ((hdcp->hdcp_support & HDCP_1X_ENABLE) &&
hdcp->enable == HDCP_1X_ENABLE) {
rk_hdmirx_hdcp1x_stop(hdcp);
dev_dbg(hdcp->dev, "hdcp1x stop\n");
}
hdcp->enable = 0;
return 0;
}
static ssize_t enable_show(struct device *device,
struct device_attribute *attr, char *buf)
{
bool enable = 0;
u8 enable = 0;
struct rk_hdmirx_hdcp *hdcp = g_hdmirx_hdcp;
if (hdcp)
@@ -158,23 +215,41 @@ static ssize_t enable_store(struct device *device,
struct device_attribute *attr,
const char *buf, size_t count)
{
bool enable;
int enable, hdcp_support;
struct rk_hdmirx_hdcp *hdcp = g_hdmirx_hdcp;
if (!hdcp)
return -EINVAL;
if (kstrtobool(buf, &enable))
if (kstrtoint(buf, 10, &enable))
return -EINVAL;
if (hdcp->hdcp_support & HDCP_2X_ENABLE)
hdcp_support = HDCP_2X_ENABLE;
else if (hdcp->hdcp_support & HDCP_1X_ENABLE)
hdcp_support = HDCP_1X_ENABLE;
else
hdcp_support = 0;
if (enable > hdcp_support)
return count;
if (hdcp->enable != enable) {
if (enable) {
hdcp->enable = enable;
if (enable == HDCP_2X_ENABLE) {
if (hdcp->enable == HDCP_1X_ENABLE)
rk_hdmirx_hdcp1x_stop(hdcp);
rk_hdmirx_hdcp2x_start(hdcp);
} else if (enable == HDCP_1X_ENABLE) {
if (hdcp->enable == HDCP_2X_ENABLE)
rk_hdmirx_hdcp2x_stop(hdcp);
rk_hdmirx_hdcp1x_start(hdcp);
} else {
rk_hdmirx_hdcp1x_stop(hdcp);
hdcp->enable = enable;
if (hdcp->enable == HDCP_2X_ENABLE)
rk_hdmirx_hdcp2x_stop(hdcp);
if (hdcp->enable == HDCP_1X_ENABLE)
rk_hdmirx_hdcp1x_stop(hdcp);
}
hdcp->enable = enable;
}
return count;
@@ -188,10 +263,34 @@ static ssize_t status_show(struct device *device,
int status = HDMIRX_HDCP_DISABLED;
struct rk_hdmirx_hdcp *hdcp = g_hdmirx_hdcp;
u32 val;
int n;
if (hdcp)
status = hdcp->status;
if (!hdcp)
return 0;
if (hdcp->enable == HDCP_2X_ENABLE) {
val = hdmirx_hdcp_read(hdcp, HDCP2_STATUS);
n = snprintf(buf, PAGE_SIZE, "HDCP2:\n%s\n",
(val & BIT(0)) ? "Dectypted" : "No dectypted");
val = hdmirx_hdcp_read(hdcp, HDCP2_ESM_P0_GPIO_OUT);
if (val & BIT(0))
n += snprintf(buf + n, PAGE_SIZE - n, "Capable\n");
if (val & BIT(1))
n += snprintf(buf + n, PAGE_SIZE - n, "Not capable\n");
if (val & BIT(2))
n += snprintf(buf + n, PAGE_SIZE - n, "Authenticated success\n");
if (val & BIT(3))
n += snprintf(buf + n, PAGE_SIZE - n, "Authenticated failed\n");
if (val & BIT(4))
n += snprintf(buf + n, PAGE_SIZE - n, "Link Error\n");
if (val & BIT(7))
n += snprintf(buf + n, PAGE_SIZE - n, "AKE Init or SKE done\n");
return n;
}
status = hdcp->status;
if (status == HDMIRX_HDCP_AUTH_START) {
val = hdmirx_hdcp_read(hdcp, HDCP14_STATUS);
if ((val & 0x3) == 0)
@@ -217,6 +316,16 @@ static ssize_t status_show(struct device *device,
static DEVICE_ATTR_RO(status);
static ssize_t support_show(struct device *device,
struct device_attribute *attr, char *buf)
{
struct rk_hdmirx_hdcp *hdcp = g_hdmirx_hdcp;
return snprintf(buf, PAGE_SIZE, "%d\n", hdcp->hdcp_support);
}
static DEVICE_ATTR_RO(support);
struct rk_hdmirx_hdcp *rk_hdmirx_hdcp_register(struct rk_hdmirx_hdcp *hdcp_data)
{
int ret = 0;
@@ -233,11 +342,14 @@ struct rk_hdmirx_hdcp *rk_hdmirx_hdcp_register(struct rk_hdmirx_hdcp *hdcp_data)
hdcp->hdmirx = hdcp_data->hdmirx;
hdcp->write = hdcp_data->write;
hdcp->read = hdcp_data->read;
hdcp->tx_5v_power = hdcp_data->tx_5v_power;
hdcp->hpd_config = hdcp_data->hpd_config;
hdcp->enable = hdcp_data->enable;
hdcp->hdcp_support = hdcp_data->hdcp_support;
hdcp->dev = hdcp_data->dev;
g_hdmirx_hdcp = hdcp;
hdcp->mdev.minor = MISC_DYNAMIC_MINOR;
hdcp->mdev.name = "hdmirx_hdcp1x";
hdcp->mdev.name = "hdmirx_hdcp";
hdcp->mdev.mode = 0666;
if (misc_register(&hdcp->mdev)) {
@@ -257,11 +369,20 @@ struct rk_hdmirx_hdcp *rk_hdmirx_hdcp_register(struct rk_hdmirx_hdcp *hdcp_data)
goto error1;
}
ret = device_create_file(hdcp->mdev.this_device, &dev_attr_support);
if (ret) {
dev_err(hdcp->dev, "HDCP: Could not add sys file support\n");
goto error2;
}
hdcp->hdcp_start = rk_hdmirx_hdcp_start;
hdcp->hdcp_stop = rk_hdmirx_hdcp_stop;
hdcp->hdcp2_connect_ctrl = rk_hdmirx_hdcp2_connect_ctrl;
dev_info(hdcp->dev, "%s success\n", __func__);
return hdcp;
error2:
device_remove_file(hdcp->mdev.this_device, &dev_attr_status);
error1:
device_remove_file(hdcp->mdev.this_device, &dev_attr_enable);
error0:
@@ -273,5 +394,6 @@ void rk_hdmirx_hdcp_unregister(struct rk_hdmirx_hdcp *hdcp)
{
device_remove_file(hdcp->mdev.this_device, &dev_attr_enable);
device_remove_file(hdcp->mdev.this_device, &dev_attr_status);
device_remove_file(hdcp->mdev.this_device, &dev_attr_support);
misc_deregister(&hdcp->mdev);
}

View File

@@ -27,6 +27,11 @@
#define HDCP_SIG_MAGIC 0x4B534541 /* "AESK" */
#define HDCP_FLG_AES 1
enum hdmirx_hdcp_enable {
HDCP_1X_ENABLE = 0x1,
HDCP_2X_ENABLE = 0x2,
};
struct hdcp_key_data_t {
unsigned int signature;
unsigned int length;
@@ -35,24 +40,12 @@ struct hdcp_key_data_t {
unsigned char data[0];
};
struct rk_hdmirx_hdcp2 {
int enable;
void (*start)(void);
void (*stop)(void);
struct device *dev;
int wait_hdcp2_reset;
int hot_plug;
struct miscdevice mdev;
int auth_success;
};
struct rk_hdmirx_hdcp {
bool enable;
u8 enable;
u8 hdcp_support;
int hdcp2_enable;
int status;
struct rk_hdmirx_hdcp2 *hdcp2;
struct miscdevice mdev;
bool keys_is_load;
bool aes_encrypt;
@@ -61,8 +54,11 @@ struct rk_hdmirx_hdcp {
void (*write)(struct rk_hdmirx_dev *hdmirx, int reg, u32 val);
u32 (*read)(struct rk_hdmirx_dev *hdmirx, int reg);
void (*hpd_config)(struct rk_hdmirx_dev *hdmirx, bool en);
bool (*tx_5v_power)(struct rk_hdmirx_dev *hdmirx);
int (*hdcp_start)(struct rk_hdmirx_hdcp *hdcp);
int (*hdcp_stop)(struct rk_hdmirx_hdcp *hdcp);
void (*hdcp2_connect_ctrl)(struct rk_hdmirx_hdcp *hdcp, bool en);
};
struct rk_hdmirx_hdcp *rk_hdmirx_hdcp_register(struct rk_hdmirx_hdcp *hdcp);