video: rockchip: hdmi-cec: fix quick standby then wake-up crash
authorShen Zhenyi <szy@rock-chips.com>
Mon, 6 Jun 2016 02:40:11 +0000 (10:40 +0800)
committerGerrit Code Review <gerrit@rock-chips.com>
Mon, 6 Jun 2016 06:03:44 +0000 (14:03 +0800)
code sync from kernel-3.10

Change-Id: I45d69e3901ea5c94fc148b1ef9761562ae465961
Signed-off-by: Shen Zhenyi <szy@rock-chips.com>
drivers/video/rockchip/hdmi/rockchip-hdmi-cec.c
drivers/video/rockchip/hdmi/rockchip-hdmi-core.c
drivers/video/rockchip/hdmi/rockchip-hdmi.h
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_cec.c

index 59965cdaed9a5acf1b3babfef57ee75d3a2e3d2b..4bfe2413e66bd0b463865b8bd58656257ec8cb14 100644 (file)
@@ -1,33 +1,48 @@
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
 #include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
 #include <linux/errno.h>
+#include <linux/firmware.h>
+#include <linux/ioctl.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/workqueue.h>
-#include <linux/firmware.h>
 #include "rockchip-hdmi-cec.h"
-#include "linux/ioctl.h"
-#include "linux/pagemap.h"
 
 static struct cec_device *cec_dev;
 
 static int cecreadframe(struct cec_framedata *frame)
 {
-       if (!frame || !cec_dev || !cec_dev->readframe || !cec_dev->enable)
-               return -1;
-       else
-               return cec_dev->readframe(cec_dev->hdmi, frame);
+       int ret = -1;
+
+       if (frame && cec_dev && cec_dev->readframe && cec_dev->enable) {
+               mutex_lock(&cec_dev->hdmi->pclk_lock);
+               ret = cec_dev->readframe(cec_dev->hdmi, frame);
+               mutex_unlock(&cec_dev->hdmi->pclk_lock);
+       }
+       return ret;
 }
 
 static int cecsendframe(struct cec_framedata *frame)
 {
-       if (!frame || !cec_dev || !cec_dev->readframe)
-               return -1;
-       else
-               return cec_dev->sendframe(cec_dev->hdmi, frame);
+       int ret = -1;
+
+       if (frame && cec_dev && cec_dev->sendframe) {
+               mutex_lock(&cec_dev->hdmi->pclk_lock);
+               ret = cec_dev->sendframe(cec_dev->hdmi, frame);
+               mutex_unlock(&cec_dev->hdmi->pclk_lock);
+       }
+       return ret;
+}
+
+static void cecsetlogicaddr(int addr)
+{
+       if (cec_dev && cec_dev->setceclogicaddr) {
+               mutex_lock(&cec_dev->hdmi->pclk_lock);
+               cec_dev->setceclogicaddr(cec_dev->hdmi, addr);
+               mutex_unlock(&cec_dev->hdmi->pclk_lock);
+       }
 }
 
 static void cecworkfunc(struct work_struct *work)
@@ -190,9 +205,7 @@ static long cec_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case HDMI_IOCTL_CECSETLA:
                ret = copy_from_user(&cec_dev->address_logic,
                                     argp, sizeof(int));
-               if (cec_dev->setceclogicaddr)
-                       cec_dev->setceclogicaddr(cec_dev->hdmi,
-                                                cec_dev->address_logic);
+               cecsetlogicaddr(cec_dev->address_logic);
                break;
        case HDMI_IOCTL_CECSEND:
                ret = copy_from_user(&cecsendtemp, argp,
index 0a88285cc84ca211e580e6f0b75fdd1abeb09c22..fa1a00d91d393907714996c8864a370ebe4ccd62 100644 (file)
@@ -487,6 +487,7 @@ struct hdmi *rockchip_hdmi_register(struct hdmi_property *property,
 
        memset(hdmi, 0, sizeof(struct hdmi));
        mutex_init(&hdmi->lock);
+       mutex_init(&hdmi->pclk_lock);
 
        hdmi->property = property;
        hdmi->ops = ops;
index 4826a09354197148bbf76dc7a68268242e90dc1b..4e09eef6a1c2a637aebbaac5aa57d5280d2ccd49 100644 (file)
@@ -396,6 +396,7 @@ struct hdmi {
        struct hdmi_ops *ops;
 
        struct mutex lock;                      /* mutex for hdmi operation */
+       struct mutex pclk_lock;                 /* mutex for pclk operation */
        struct workqueue_struct *workqueue;
 
        bool uboot;     /* if true, HDMI is initialized in uboot*/
index bc5244f453a1046756b25c94c0995f0eeb7d87f9..c5a757b75fb213604f404443f7da5fb16f38add4 100644 (file)
@@ -198,12 +198,6 @@ void ext_pll_set_27m_out(void)
                                  0x1d);
 }
 
-#define HDMI_PD_ON             BIT(0)
-#define HDMI_PCLK_ON           BIT(1)
-#define HDMI_HDCPCLK_ON                BIT(2)
-#define HDMI_CECCLK_ON         BIT(3)
-#define HDMI_EXT_PHY_CLK_ON    BIT(4)
-
 static int rockchip_hdmiv2_clk_enable(struct hdmi_dev *hdmi_dev)
 {
        if ((hdmi_dev->clk_on & HDMI_PD_ON) == 0) {
@@ -332,7 +326,9 @@ static int rockchip_hdmiv2_fb_event_notify(struct notifier_block *self,
                                                 0, 1);
                                if (hdmi_dev->hdcp2_en)
                                        hdmi_dev->hdcp2_en(0);
+                               mutex_lock(&hdmi->pclk_lock);
                                rockchip_hdmiv2_clk_disable(hdmi_dev);
+                               mutex_unlock(&hdmi->pclk_lock);
                                #ifdef CONFIG_PINCTRL
                                if (hdmi_dev->soctype == HDMI_SOC_RK3288)
                                        gpio_state =
@@ -357,7 +353,9 @@ static int rockchip_hdmiv2_fb_event_notify(struct notifier_block *self,
                                pinctrl_select_state(pins->p,
                                                     pins->default_state);
                                #endif
+                               mutex_lock(&hdmi->pclk_lock);
                                rockchip_hdmiv2_clk_enable(hdmi_dev);
+                               mutex_unlock(&hdmi->pclk_lock);
                                rockchip_hdmiv2_dev_initial(hdmi_dev);
                                if (hdmi->ops->hdcp_power_on_cb)
                                        hdmi->ops->hdcp_power_on_cb();
index 77f2c9da35f0a96f327272733b6080f0fdac4135..8f97c4c6f13fb645de76aedba2fe60b5d0b132ca 100644 (file)
 #define HDMIDBG(format, ...)
 #endif
 
+#define HDMI_PD_ON             BIT(0)
+#define HDMI_PCLK_ON           BIT(1)
+#define HDMI_HDCPCLK_ON                BIT(2)
+#define HDMI_CECCLK_ON         BIT(3)
+#define HDMI_EXT_PHY_CLK_ON    BIT(4)
+
 struct hdmi_dev_phy_para {
        u32 maxfreq;
        int pre_emphasis;
index 3c546d5fdfe4f3f29c5da6d80d97f9552fb8be58..fb7eba309b9d85f5fa117557010de6eb49ce2ed1 100644 (file)
@@ -21,7 +21,7 @@ static int rockchip_hdmiv2_cec_readframe(struct hdmi *hdmi,
        int i, count;
        char *data = (char *)frame;
 
-       if (!frame)
+       if (((hdmi_dev->clk_on & HDMI_PCLK_ON) == 0) || !frame)
                return -1;
        count = hdmi_readl(hdmi_dev, CEC_RX_CNT);
        CECDBG("%s count %d\n", __func__, count);
@@ -39,6 +39,8 @@ void rockchip_hdmiv2_cec_setcecla(struct hdmi *hdmi, int ceclgaddr)
        struct hdmi_dev *hdmi_dev = hdmi->property->priv;
        short val;
 
+       if ((hdmi_dev->clk_on & HDMI_PCLK_ON) == 0)
+               return;
        if (ceclgaddr < 0 || ceclgaddr > 16)
                return;
        val = 1 << ceclgaddr;
@@ -52,6 +54,8 @@ static int rockchip_hdmiv2_cec_sendframe(struct hdmi *hdmi,
        struct hdmi_dev *hdmi_dev = hdmi->property->priv;
        int i, interrupt;
 
+       if ((hdmi_dev->clk_on & HDMI_PCLK_ON) == 0)
+               return CEC_SEND_NACK;
        CECDBG("TX srcdestaddr %02x opcode %02x ",
               frame->srcdestaddr, frame->opcode);
        if (frame->argcount) {