HDMI: rk3368: add function for HDCP2.2.
authorZheng Yang <zhengyang@rock-chips.com>
Tue, 28 Apr 2015 11:17:27 +0000 (19:17 +0800)
committerZheng Yang <zhengyang@rock-chips.com>
Tue, 28 Apr 2015 11:17:27 +0000 (19:17 +0800)
Signed-off-by: Zheng Yang <zhengyang@rock-chips.com>
drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2.c
drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2.h
drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2_hdcp.c
drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2_hw.c
drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2_hw.h

index eaa91be7097e6bee91886f4bfba223f94d2c205f..82e8b9cc203a96dd7a965c3656bc607c2a7987c9 100644 (file)
@@ -250,6 +250,9 @@ static int rockchip_hdmiv2_fb_event_notify(struct notifier_block *self,
        struct hdmi *hdmi = hdmi_dev->hdmi;
        struct delayed_work *delay_work;
        struct pinctrl_state *gpio_state;
+#ifdef CONFIG_PINCTRL
+       struct dev_pin_info *pins = hdmi_dev->dev->pins;
+#endif
 
        if (action == FB_EARLY_EVENT_BLANK) {
                switch (blank_mode) {
@@ -264,9 +267,16 @@ static int rockchip_hdmiv2_fb_event_notify(struct notifier_block *self,
                                                         0, NULL);
                                if (delay_work)
                                        flush_delayed_work(delay_work);
+                               if (hdmi_dev->hdcp2_en)
+                                       hdmi_dev->hdcp2_en(0);
                                rockchip_hdmiv2_clk_disable(hdmi_dev);
-                               gpio_state = pinctrl_lookup_state(hdmi_dev->dev->pins->p, "gpio");
-                               pinctrl_select_state(hdmi_dev->dev->pins->p, gpio_state);
+                               #ifdef CONFIG_PINCTRL
+                               gpio_state =
+                               pinctrl_lookup_state(pins->p,
+                                                    "gpio");
+                               pinctrl_select_state(pins->p,
+                                                    gpio_state);
+                               #endif
                        }
                        break;
                }
@@ -275,12 +285,18 @@ static int rockchip_hdmiv2_fb_event_notify(struct notifier_block *self,
                case FB_BLANK_UNBLANK:
                        HDMIDBG("resume hdmi\n");
                        if (hdmi->sleep) {
-                               pinctrl_select_state(hdmi_dev->dev->pins->p,
-                                                    hdmi_dev->dev->pins->default_state);
+                               #ifdef CONFIG_PINCTRL
+                               pinctrl_select_state(pins->p,
+                                                    pins->default_state);
+                               #endif
                                rockchip_hdmiv2_clk_enable(hdmi_dev);
                                rockchip_hdmiv2_dev_initial(hdmi_dev);
                                if (hdmi->ops->hdcp_power_on_cb)
                                        hdmi->ops->hdcp_power_on_cb();
+                               if (hdmi_dev->hdcp2_reset)
+                                       hdmi_dev->hdcp2_reset();
+                               if (hdmi_dev->hdcp2_en)
+                                       hdmi_dev->hdcp2_en(1);
                                hdmi_submit_work(hdmi, HDMI_RESUME_CTL,
                                                 0, NULL);
                        }
index 7e4b4535c0f4f1ee047b71823c9c97411aead8fd..1bb9561a1a3359e6261752edcfa11a3923c780ae 100644 (file)
@@ -38,6 +38,7 @@ struct hdmi_dev {
        int                     soctype;
        int                     audiosrc;
        int                     enable;
+       int                     hdcp2_enable;
        unsigned char           clk_disable;
        unsigned char           clk_on;
 
@@ -48,5 +49,9 @@ struct hdmi_dev {
 
        bool                    tmdsclk_ratio_change;
        struct mutex            ddc_lock;       /*mutex for ddc operation */
+
+       void                    (*hdcp2_en)(int);
+       void                    (*hdcp2_reset)(void);
+       void                    (*hdcp2_start)(void);
 };
 #endif /*__RK32_HDMI_H__*/
index d321811dd81f1609c0afb9ed0c2f4870da6bf29d..0e5a76c55d2463869cad492721357026a2e96454 100644 (file)
@@ -30,7 +30,7 @@ struct hdcp {
 };
 
 static struct miscdevice mdev;
-static struct hdcp *hdcp = NULL;
+static struct hdcp *hdcp;
 
 static void hdcp_load_key(struct hdmi *hdmi, struct hdcp_keys *key)
 {
@@ -111,6 +111,52 @@ static void hdcp_load_keys_cb(const struct firmware *fw,
        hdcp_load_key(hdmi, hdcp->keys);
 }
 
+void rockchip_hdmiv2_hdcp2_enable(int enable)
+{
+       struct hdmi_dev *hdmi_dev;
+
+       if (!hdcp) {
+               pr_err("rockchip hdmiv2 hdcp is not exist\n");
+               return;
+       }
+       hdmi_dev = hdcp->hdmi->property->priv;
+       if (hdmi_dev->soctype == HDMI_SOC_RK3368 &&
+           hdmi_dev->hdcp2_enable != enable) {
+               hdmi_dev->hdcp2_enable = enable;
+               if (hdmi_dev->hdcp2_enable == 0) {
+                       hdmi_msk_reg(hdmi_dev, HDCP2REG_CTRL,
+                                    m_HDCP2_OVR_EN | m_HDCP2_FORCE,
+                                    v_HDCP2_OVR_EN(1) | v_HDCP2_FORCE(0));
+                       hdmi_writel(hdmi_dev, HDCP2REG_MASK, 0xff);
+                       hdmi_writel(hdmi_dev, HDCP2REG_MUTE, 0xff);
+               } else {
+                       hdmi_msk_reg(hdmi_dev, HDCP2REG_CTRL,
+                                    m_HDCP2_OVR_EN | m_HDCP2_FORCE,
+                                    v_HDCP2_OVR_EN(0) | v_HDCP2_FORCE(0));
+                       hdmi_writel(hdmi_dev, HDCP2REG_MASK, 0x00);
+                       hdmi_writel(hdmi_dev, HDCP2REG_MUTE, 0x00);
+               }
+       }
+}
+EXPORT_SYMBOL(rockchip_hdmiv2_hdcp2_enable);
+
+void rockchip_hdmiv2_hdcp2_init(void (*hdcp2_enble)(int),
+                               void (*hdcp2_reset)(void),
+                               void (*hdcp2_start)(void))
+{
+       struct hdmi_dev *hdmi_dev;
+
+       if (!hdcp) {
+               pr_err("rockchip hdmiv2 hdcp is not exist\n");
+               return;
+       }
+       hdmi_dev = hdcp->hdmi->property->priv;
+       hdmi_dev->hdcp2_en = hdcp2_enble;
+       hdmi_dev->hdcp2_reset = hdcp2_reset;
+       hdmi_dev->hdcp2_start = hdcp2_start;
+}
+EXPORT_SYMBOL(rockchip_hdmiv2_hdcp2_init);
+
 static void rockchip_hdmiv2_hdcp_start(struct hdmi *hdmi)
 {
        struct hdmi_dev *hdmi_dev = hdmi->property->priv;
@@ -118,11 +164,19 @@ static void rockchip_hdmiv2_hdcp_start(struct hdmi *hdmi)
        if (!hdcp->enable)
                return;
        if (hdmi_dev->soctype == HDMI_SOC_RK3368) {
-               hdmi_msk_reg(hdmi_dev, HDCP2REG_CTRL,
-                            m_HDCP2_OVR_EN | m_HDCP2_FORCE,
-                            v_HDCP2_OVR_EN(1) | v_HDCP2_FORCE(0));
-               hdmi_writel(hdmi_dev, HDCP2REG_MASK, 0x00);
-               hdmi_writel(hdmi_dev, HDCP2REG_MUTE, 0x00);
+               if (hdmi_dev->hdcp2_enable == 0) {
+                       hdmi_msk_reg(hdmi_dev, HDCP2REG_CTRL,
+                                    m_HDCP2_OVR_EN | m_HDCP2_FORCE,
+                                    v_HDCP2_OVR_EN(1) | v_HDCP2_FORCE(0));
+                       hdmi_writel(hdmi_dev, HDCP2REG_MASK, 0xff);
+                       hdmi_writel(hdmi_dev, HDCP2REG_MUTE, 0xff);
+               } else {
+                       hdmi_msk_reg(hdmi_dev, HDCP2REG_CTRL,
+                                    m_HDCP2_OVR_EN | m_HDCP2_FORCE,
+                                    v_HDCP2_OVR_EN(0) | v_HDCP2_FORCE(0));
+                       hdmi_writel(hdmi_dev, HDCP2REG_MASK, 0x00);
+                       hdmi_writel(hdmi_dev, HDCP2REG_MUTE, 0x00);
+               }
        }
 
        hdmi_msk_reg(hdmi_dev, FC_INVIDCONF,
@@ -146,6 +200,8 @@ static void rockchip_hdmiv2_hdcp_start(struct hdmi *hdmi)
 
        hdmi_msk_reg(hdmi_dev, MC_CLKDIS,
                     m_HDCPCLK_DISABLE, v_HDCPCLK_DISABLE(0));
+       if (hdmi_dev->hdcp2_start)
+               hdmi_dev->hdcp2_start();
        pr_info("%s success\n", __func__);
 }
 
@@ -160,6 +216,7 @@ static void rockchip_hdmiv2_hdcp_stop(struct hdmi *hdmi)
                     m_HDCPCLK_DISABLE, v_HDCPCLK_DISABLE(1));
        hdmi_writel(hdmi_dev, A_APIINTMSK, 0xff);
        hdmi_msk_reg(hdmi_dev, A_HDCPCFG0, m_RX_DETECT, v_RX_DETECT(0));
+       rockchip_hdmiv2_hdcp2_enable(0);
 }
 
 static ssize_t hdcp_enable_read(struct device *device,
@@ -296,4 +353,3 @@ void rockchip_hdmiv2_hdcp_init(struct hdmi *hdmi)
        else
                hdcp_load_key(hdmi, hdcp->keys);
 }
-
index afa3b3974ed3f62cbbd06b66c336492708e0c7d0..e1ef8a6d9cac0de90303db9cc77d9c405588f2e7 100755 (executable)
@@ -1511,8 +1511,8 @@ static int hdmi_dev_config_audio(struct hdmi *hdmi, struct hdmi_audio *audio)
                        HDMIDBG("hbr mode.\n");
                        hdmi_writel(hdmi_dev, AUD_CONF2, 0x1);
                        word_length = I2S_24BIT_SAMPLE;
-               } else if ((HDMI_AUDIO_FS_48000 == audio->rate)
-                          || (HDMI_AUDIO_FS_192000 == audio->rate)) {
+               } else if ((HDMI_AUDIO_FS_48000 == audio->rate) ||
+                          (HDMI_AUDIO_FS_192000 == audio->rate)) {
                        HDMIDBG("nlpcm mode.\n");
                        hdmi_writel(hdmi_dev, AUD_CONF2, 0x2);
                        word_length = I2S_24BIT_SAMPLE;
@@ -1751,6 +1751,12 @@ irqreturn_t rockchip_hdmiv2_dev_irq(int irq, void *priv)
        if (hdcp2_int) {
                hdmi_writel(hdmi_dev, HDCP2REG_STAT, hdcp2_int);
                pr_info("hdcp2_int is 0x%02x\n", hdcp2_int);
+               if ((hdcp2_int & m_HDCP2_AUTH_FAIL ||
+                    hdcp2_int & m_HDCP2_AUTH_LOST) &&
+                   hdmi_dev->hdcp2_start) {
+                       pr_info("hdcp2 failed or lost\n");
+                       hdmi_dev->hdcp2_start();
+               }
        }
        return IRQ_HANDLED;
 }
index 83b7924051b6d0e5e41a91eabe59eaad3939a7d5..ac69f94935b7a96f4f2e7602db71f4fcc11e17d7 100644 (file)
@@ -1314,6 +1314,7 @@ enum {
        #define m_HDCP2_AUTH_LOST       (1 << 2)
        #define m_HDCP2_AUTH_OK         (1 << 3)
        #define m_HDCP2_AUTH_FAIL       (1 << 4)
+       #define m_HDCP2_DECRYPTED_CHG   (1 << 5)
 
 /* CEC Engine Registers */
 #define CEC_ENGINE_BASE                        0x7d00
@@ -1565,4 +1566,5 @@ void rockchip_hdmiv2_cec_init(struct hdmi *hdmi);
 void rockchip_hdmiv2_cec_isr(struct hdmi_dev *hdmi_dev, char cec_int);
 void rockchip_hdmiv2_dump_phy_regs(struct hdmi_dev *hdmi_dev);
 void rockchip_hdmiv2_hdcp_init(struct hdmi *hdmi);
+void rockchip_hdmiv2_hdcp2_enable(int enable);
 #endif