Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f077c02e authored by Terence Hampson's avatar Terence Hampson Committed by Stephen Boyd
Browse files

msm: mpq8064: Dummy read to prevent false interrupt from triggering



The VBIF is capable of triggering a false bus error the first time
it performs a read. This fix creates a dummy read event that
happens every time that the VCAP is powered on that will ignore
the false positive VBIF interrupt error, so that during normal
operation the error can be properly identified.

Change-Id: Ie56e60faf2067fab7a05a0f16c2d840408c35035
Signed-off-by: default avatarTerence Hampson <thampson@codeaurora.org>
parent c554b121
Loading
Loading
Loading
Loading
+53 −31
Original line number Diff line number Diff line
@@ -1113,7 +1113,6 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
	struct vcap_client_data *c_data = to_client_data(file->private_data);
	struct vcap_dev *dev = c_data->dev;
	unsigned long flags;
	int rc;
	unsigned long rate;
	long rate_rc;
@@ -1126,14 +1125,14 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)

	switch (c_data->op_mode) {
	case VC_VCAP_OP:
		spin_lock_irqsave(&dev->dev_slock, flags);
		mutex_lock(&dev->dev_mutex);
		if (dev->vc_resource) {
			pr_err("VCAP Err: %s: VC resource taken", __func__);
			spin_unlock_irqrestore(&dev->dev_slock, flags);
			mutex_unlock(&dev->dev_mutex);
			return -EBUSY;
		}
		dev->vc_resource = 1;
		spin_unlock_irqrestore(&dev->dev_slock, flags);
		mutex_unlock(&dev->dev_mutex);

		c_data->dev->vc_client = c_data;

@@ -1179,14 +1178,14 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
			goto free_res;
		break;
	case VP_VCAP_OP:
		spin_lock_irqsave(&dev->dev_slock, flags);
		mutex_lock(&dev->dev_mutex);
		if (dev->vp_resource) {
			pr_err("VCAP Err: %s: VP resource taken", __func__);
			spin_unlock_irqrestore(&dev->dev_slock, flags);
			mutex_unlock(&dev->dev_mutex);
			return -EBUSY;
		}
		dev->vp_resource = 1;
		spin_unlock_irqrestore(&dev->dev_slock, flags);
		mutex_unlock(&dev->dev_mutex);
		c_data->dev->vp_client = c_data;

		rate = 160000000;
@@ -1240,16 +1239,16 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
			goto s_on_deinit_nr_buf;
		break;
	case VC_AND_VP_VCAP_OP:
		spin_lock_irqsave(&dev->dev_slock, flags);
		mutex_lock(&dev->dev_mutex);
		if (dev->vc_resource || dev->vp_resource) {
			pr_err("VCAP Err: %s: VC/VP resource taken",
				__func__);
			spin_unlock_irqrestore(&dev->dev_slock, flags);
			mutex_unlock(&dev->dev_mutex);
			return -EBUSY;
		}
		dev->vc_resource = 1;
		dev->vp_resource = 1;
		spin_unlock_irqrestore(&dev->dev_slock, flags);
		mutex_unlock(&dev->dev_mutex);
		c_data->dev->vc_client = c_data;
		c_data->dev->vp_client = c_data;

@@ -1347,7 +1346,7 @@ s_on_deinit_nr_buf:
s_on_deinit_m_buf:
	deinit_motion_buf(c_data);
free_res:
	spin_lock_irqsave(&dev->dev_slock, flags);
	mutex_lock(&dev->dev_mutex);
	if (c_data->op_mode == VC_VCAP_OP) {
		dev->vc_resource = 0;
		c_data->dev->vc_client = NULL;
@@ -1360,7 +1359,7 @@ free_res:
		dev->vc_resource = 0;
		dev->vp_resource = 0;
	}
	spin_unlock_irqrestore(&dev->dev_slock, flags);
	mutex_unlock(&dev->dev_mutex);
	return rc;
}

@@ -1381,7 +1380,6 @@ int streamoff_validate_q(struct vb2_queue *q)
int streamoff_work(struct vcap_client_data *c_data)
{
	struct vcap_dev *dev = c_data->dev;
	unsigned long flags;
	int rc;
	switch (c_data->op_mode) {
	case VC_VCAP_OP:
@@ -1390,14 +1388,14 @@ int streamoff_work(struct vcap_client_data *c_data)
				__func__);
			return -EBUSY;
		}
		spin_lock_irqsave(&dev->dev_slock, flags);
		mutex_lock(&dev->dev_mutex);
		if (!dev->vc_resource) {
			pr_err("VCAP Err: %s: VC res not acquired", __func__);
			spin_unlock_irqrestore(&dev->dev_slock, flags);
			mutex_unlock(&dev->dev_mutex);
			return -EBUSY;
		}
		dev->vc_resource = 0;
		spin_unlock_irqrestore(&dev->dev_slock, flags);
		mutex_unlock(&dev->dev_mutex);
		rc = vb2_streamoff(&c_data->vc_vidq,
				V4L2_BUF_TYPE_VIDEO_CAPTURE);
		if (rc >= 0) {
@@ -1406,19 +1404,24 @@ int streamoff_work(struct vcap_client_data *c_data)
		}
		return rc;
	case VP_VCAP_OP:
		if (!dev->vp_dummy_complete) {
			pr_err("VCAP Err: %s: VP dummy read not complete",
				__func__);
			return -EINVAL;
		}
		if (c_data != dev->vp_client) {
			pr_err("VCAP Err: %s: VP held by other client",
				__func__);
			return -EBUSY;
		}
		spin_lock_irqsave(&dev->dev_slock, flags);
		mutex_lock(&dev->dev_mutex);
		if (!dev->vp_resource) {
			pr_err("VCAP Err: %s: VP res not acquired", __func__);
			spin_unlock_irqrestore(&dev->dev_slock, flags);
			mutex_unlock(&dev->dev_mutex);
			return -EBUSY;
		}
		dev->vp_resource = 0;
		spin_unlock_irqrestore(&dev->dev_slock, flags);
		mutex_unlock(&dev->dev_mutex);
		rc = streamoff_validate_q(&c_data->vp_in_vidq);
		if (rc < 0)
			return rc;
@@ -1444,21 +1447,26 @@ int streamoff_work(struct vcap_client_data *c_data)
		atomic_set(&c_data->dev->vp_enabled, 0);
		return rc;
	case VC_AND_VP_VCAP_OP:
		if (!dev->vp_dummy_complete) {
			pr_err("VCAP Err: %s: VP dummy read not complete",
				__func__);
			return -EINVAL;
		}
		if (c_data != dev->vp_client || c_data != dev->vc_client) {
			pr_err("VCAP Err: %s: VC/VP held by other client",
				__func__);
			return -EBUSY;
		}
		spin_lock_irqsave(&dev->dev_slock, flags);
		mutex_lock(&dev->dev_mutex);
		if (!(dev->vc_resource || dev->vp_resource)) {
			pr_err("VCAP Err: %s: VC or VP res not acquired",
				__func__);
			spin_unlock_irqrestore(&dev->dev_slock, flags);
			mutex_unlock(&dev->dev_mutex);
			return -EBUSY;
		}
		dev->vc_resource = 0;
		dev->vp_resource = 0;
		spin_unlock_irqrestore(&dev->dev_slock, flags);
		mutex_unlock(&dev->dev_mutex);
		rc = streamoff_validate_q(&c_data->vc_vidq);
		if (rc < 0)
			return rc;
@@ -1566,10 +1574,11 @@ static int vcap_open(struct file *file)
	struct vcap_dev *dev = video_drvdata(file);
	struct vcap_client_data *c_data;
	struct vb2_queue *q;
	unsigned long flags;
	int ret;
	c_data = kzalloc(sizeof(*c_data), GFP_KERNEL);
	if (!dev)
		return -EINVAL;
	c_data = kzalloc(sizeof(*c_data), GFP_KERNEL);
	if (!c_data)
		return -ENOMEM;

	c_data->dev = dev;
@@ -1623,22 +1632,33 @@ static int vcap_open(struct file *file)
	v4l2_fh_init(&c_data->vfh, dev->vfd);
	v4l2_fh_add(&c_data->vfh);

	spin_lock_irqsave(&dev->dev_slock, flags);
	mutex_lock(&dev->dev_mutex);
	atomic_inc(&dev->open_clients);
	ret = atomic_read(&dev->open_clients);
	spin_unlock_irqrestore(&dev->dev_slock, flags);
	if (ret == 1) {
		ret = vcap_enable(dev, dev->ddev, 54860000);
		if (ret < 0) {
			pr_err("Err: %s: Power on vcap failed", __func__);
			mutex_unlock(&dev->dev_mutex);
			goto vcap_power_failed;
		}

		ret = vp_dummy_event(c_data);
		if (ret < 0) {
			pr_err("Err: %s: Dummy Event failed", __func__);
			mutex_unlock(&dev->dev_mutex);
			vcap_disable(dev);
			goto vcap_power_failed;
		}
	}
	mutex_unlock(&dev->dev_mutex);

	file->private_data = &c_data->vfh;
	return 0;

vcap_power_failed:
	atomic_dec(&dev->open_clients);

	v4l2_fh_del(&c_data->vfh);
	v4l2_fh_exit(&c_data->vfh);
	vb2_queue_release(&c_data->vp_out_vidq);
@@ -1655,7 +1675,6 @@ static int vcap_close(struct file *file)
{
	struct vcap_dev *dev = video_drvdata(file);
	struct vcap_client_data *c_data = to_client_data(file->private_data);
	unsigned long flags;
	int ret;

	if (c_data == NULL)
@@ -1664,12 +1683,14 @@ static int vcap_close(struct file *file)
	if (c_data->streaming)
		streamoff_work(c_data);

	spin_lock_irqsave(&dev->dev_slock, flags);
	mutex_lock(&dev->dev_mutex);
	atomic_dec(&dev->open_clients);
	ret = atomic_read(&dev->open_clients);
	spin_unlock_irqrestore(&dev->dev_slock, flags);
	if (ret == 0)
	mutex_unlock(&dev->dev_mutex);
	if (ret == 0) {
		vcap_disable(dev);
		dev->vp_dummy_complete = false;
	}
	v4l2_fh_del(&c_data->vfh);
	v4l2_fh_exit(&c_data->vfh);
	vb2_queue_release(&c_data->vp_out_vidq);
@@ -1910,7 +1931,8 @@ static int vcap_probe(struct platform_device *pdev)
	atomic_set(&dev->vp_enabled, 0);
	atomic_set(&dev->open_clients, 0);
	dev->ddev = &pdev->dev;
	spin_lock_init(&dev->dev_slock);
	mutex_init(&dev->dev_mutex);
	init_waitqueue_head(&dev->vp_dummy_waitq);
	vcap_disable(dev);

	dprintk(1, "Exit probe succesfully");
+77 −1
Original line number Diff line number Diff line
@@ -261,6 +261,12 @@ irqreturn_t vp_handler(struct vcap_dev *dev)
	int rc;

	irq = readl_relaxed(VCAP_VP_INT_STATUS);
	if (dev->vp_dummy_event == true) {
		writel_relaxed(irq, VCAP_VP_INT_CLEAR);
		dev->vp_dummy_complete = true;
		wake_up(&dev->vp_dummy_waitq);
		return IRQ_HANDLED;
	}

	if (irq & 0x02000000) {
		v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
@@ -434,6 +440,8 @@ int init_nr_buf(struct vcap_client_data *c_data)
		return -ENOEXEC;
	}
	buf = &c_data->vid_vp_action.bufNR;
	if (!buf)
		return -ENOMEM;

	frame_size = c_data->vp_in_fmt.width * c_data->vp_in_fmt.height;
	if (c_data->vp_in_fmt.pixfmt == V4L2_PIX_FMT_NV16)
@@ -442,7 +450,7 @@ int init_nr_buf(struct vcap_client_data *c_data)
		tot_size = frame_size / 2 * 3;

	buf->vaddr = kzalloc(tot_size, GFP_KERNEL);
	if (!buf)
	if (!buf->vaddr)
		return -ENOMEM;

	buf->paddr = virt_to_phys(buf->vaddr);
@@ -478,6 +486,74 @@ void deinit_nr_buf(struct vcap_client_data *c_data)
	return;
}

int vp_dummy_event(struct vcap_client_data *c_data)
{
	struct vcap_dev *dev = c_data->dev;
	unsigned int width, height;
	unsigned long paddr;
	void *temp;
	uint32_t reg;
	int rc = 0;

	dprintk(2, "%s: Start VP dummy event\n", __func__);
	temp = kzalloc(0x1200, GFP_KERNEL);
	if (!temp) {
		pr_err("%s: Failed to alloc mem", __func__);
		return -ENOMEM;
	}
	paddr = virt_to_phys(temp);

	width = c_data->vp_out_fmt.width;
	height = c_data->vp_out_fmt.height;

	c_data->vp_out_fmt.width = 0x3F;
	c_data->vp_out_fmt.height = 0x16;

	config_vp_format(c_data);
	writel_relaxed(paddr, VCAP_VP_T1_Y_BASE_ADDR);
	writel_relaxed(paddr + 0x2C0, VCAP_VP_T1_C_BASE_ADDR);
	writel_relaxed(paddr + 0x440, VCAP_VP_T2_Y_BASE_ADDR);
	writel_relaxed(paddr + 0x700, VCAP_VP_T2_C_BASE_ADDR);
	writel_relaxed(paddr + 0x880, VCAP_VP_OUT_Y_BASE_ADDR);
	writel_relaxed(paddr + 0xB40, VCAP_VP_OUT_C_BASE_ADDR);
	writel_iowmb(paddr + 0x1100, VCAP_VP_MOTION_EST_ADDR);
	writel_relaxed(4 << 20 | 0x2 << 4, VCAP_VP_IN_CONFIG);
	writel_relaxed(4 << 20 | 0x1 << 4, VCAP_VP_OUT_CONFIG);

	dev->vp_dummy_event = true;

	writel_relaxed(0x01100101, VCAP_VP_INTERRUPT_ENABLE);
	writel_iowmb(0x00000000, VCAP_VP_CTRL);
	writel_iowmb(0x00030000, VCAP_VP_CTRL);

	enable_irq(dev->vpirq->start);
	rc = wait_event_interruptible_timeout(dev->vp_dummy_waitq,
		dev->vp_dummy_complete, msecs_to_jiffies(50));
	if (!rc && !dev->vp_dummy_complete) {
		pr_err("%s: VP dummy event timeout", __func__);
		rc = -ETIME;
		writel_iowmb(0x00000000, VCAP_VP_CTRL);

		writel_iowmb(0x00000001, VCAP_VP_SW_RESET);
		writel_iowmb(0x00000000, VCAP_VP_SW_RESET);
		dev->vp_dummy_complete = false;
	}

	writel_relaxed(0x00000000, VCAP_VP_INTERRUPT_ENABLE);
	disable_irq(dev->vpirq->start);
	dev->vp_dummy_event = false;

	reg = readl_relaxed(VCAP_OFFSET(0x0D94));
	writel_relaxed(reg, VCAP_OFFSET(0x0D9C));

	c_data->vp_out_fmt.width = width;
	c_data->vp_out_fmt.height = height;
	kfree(temp);

	dprintk(2, "%s: Exit VP dummy event\n", __func__);
	return rc;
}

int kickoff_vp(struct vcap_client_data *c_data)
{
	struct vcap_dev *dev;
+1 −0
Original line number Diff line number Diff line
@@ -100,5 +100,6 @@ int init_nr_buf(struct vcap_client_data *c_data);
void deinit_nr_buf(struct vcap_client_data *c_data);
int kickoff_vp(struct vcap_client_data *c_data);
int continue_vp(struct vcap_client_data *c_data);
int vp_dummy_event(struct vcap_client_data *c_data);

#endif
+4 −1
Original line number Diff line number Diff line
@@ -158,10 +158,13 @@ struct vcap_dev {
	atomic_t			    vc_enabled;
	atomic_t			    vp_enabled;

	spinlock_t				dev_slock;
	struct mutex			dev_mutex;
	atomic_t			    open_clients;
	bool					vc_resource;
	bool					vp_resource;
	bool					vp_dummy_event;
	bool					vp_dummy_complete;
	wait_queue_head_t		vp_dummy_waitq;

	struct workqueue_struct	*vcap_wq;
	struct vp_work_t		vp_work;