diff --git a/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.c b/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.c index 11ef5a9ba0fa..0a09527950f0 100644 --- a/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.c +++ b/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.c @@ -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); diff --git a/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.h b/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.h index ec7925dcc9e6..4192ae5e77f7 100644 --- a/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.h +++ b/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.h @@ -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) diff --git a/drivers/media/platform/rockchip/hdmirx/rk_hdmirx_hdcp.c b/drivers/media/platform/rockchip/hdmirx/rk_hdmirx_hdcp.c index eea58538fe7e..6cb7232207e1 100644 --- a/drivers/media/platform/rockchip/hdmirx/rk_hdmirx_hdcp.c +++ b/drivers/media/platform/rockchip/hdmirx/rk_hdmirx_hdcp.c @@ -5,6 +5,7 @@ * Author: Shunqing Chen */ +#include #include #include #include @@ -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); } diff --git a/drivers/media/platform/rockchip/hdmirx/rk_hdmirx_hdcp.h b/drivers/media/platform/rockchip/hdmirx/rk_hdmirx_hdcp.h index 361c62f43bf8..cc74f4968e90 100644 --- a/drivers/media/platform/rockchip/hdmirx/rk_hdmirx_hdcp.h +++ b/drivers/media/platform/rockchip/hdmirx/rk_hdmirx_hdcp.h @@ -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);