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

Commit 905db3f2 authored by Ashwini Rao's avatar Ashwini Rao Committed by Razziell
Browse files

msm: jpeg: DMA V4L2 driver changes



Fixed issues in jpeg DMA v4l2 driver, related to
incorrect clock index, incorrect buffer offset,
incorrect dtsi node names for VBIF, QOS and
mmu prefetch.

CRs-Fixed: 1083323
Change-Id: Ice15afd63e006401a469376277b50a129ef177b4
Signed-off-by: default avatarKrupal Divvela <kdivvela@codeaurora.org>
parent 35b8dda0
Loading
Loading
Loading
Loading
+82 −25
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
#include <linux/ion.h>
#include <linux/msm_ion.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/compat.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
#include <media/videobuf2-core.h>
@@ -70,18 +72,31 @@ static struct msm_jpegdma_format formats[] = {
		.planes[1] = JPEGDMA_PLANE_TYPE_CBCR,
	},
	{
		.name = "YUV 4:2:0 planar, YCbCr",
		.fourcc = V4L2_PIX_FMT_YUV420,
		.name = "YVU 4:2:0 planar, YCrCb",
		.fourcc = V4L2_PIX_FMT_YVU420,
		.depth = 12,
		.num_planes = 3,
		.colplane_h = 2,
		.colplane_v = 2,
		.colplane_h = 1,
		.colplane_v = 4,
		.h_align = 2,
		.v_align = 2,
		.planes[0] = JPEGDMA_PLANE_TYPE_Y,
		.planes[1] = JPEGDMA_PLANE_TYPE_CR,
		.planes[2] = JPEGDMA_PLANE_TYPE_CB,
	},
	{
		.name = "YUV 4:2:0 planar, YCbCr",
		.fourcc = V4L2_PIX_FMT_YUV420,
		.depth = 12,
		.num_planes = 3,
		.colplane_h = 1,
		.colplane_v = 4,
		.h_align = 2,
		.v_align = 2,
		.planes[0] = JPEGDMA_PLANE_TYPE_Y,
		.planes[1] = JPEGDMA_PLANE_TYPE_CB,
		.planes[2] = JPEGDMA_PLANE_TYPE_CR,
	},
};

/*
@@ -196,7 +211,8 @@ static void msm_jpegdma_align_format(struct v4l2_format *f, int format_idx)
	if (formats[format_idx].num_planes > 1)
		for (i = 1; i < formats[format_idx].num_planes; i++)
			size_image += (f->fmt.pix.bytesperline *
			  (f->fmt.pix.height / formats[format_idx].colplane_v));
				(f->fmt.pix.height /
				formats[format_idx].colplane_v));

	f->fmt.pix.sizeimage = size_image;
	f->fmt.pix.field = V4L2_FIELD_NONE;
@@ -250,6 +266,9 @@ static int msm_jpegdma_update_hw_config(struct jpegdma_ctx *ctx)
		size.fps = ctx->timeperframe.denominator /
			ctx->timeperframe.numerator;

		size.in_offset = ctx->in_offset;
		size.out_offset = ctx->out_offset;

		size.format = formats[ctx->format_idx];

		msm_jpegdma_fill_size_from_ctx(ctx, &size);
@@ -362,6 +381,8 @@ static void msm_jpegdma_stop_streaming(struct vb2_queue *q)
		dev_err(ctx->jdma_device->dev, "Ctx wait timeout\n");
		ret = -ETIME;
	}

	if (ctx->jdma_device->ref_count > 0)
		msm_jpegdma_hw_put(ctx->jdma_device);
}

@@ -385,13 +406,29 @@ static void *msm_jpegdma_get_userptr(void *alloc_ctx,
{
	struct msm_jpegdma_device *dma = alloc_ctx;
	struct msm_jpegdma_buf_handle *buf;
	struct msm_jpeg_dma_buff __user *up_buff = compat_ptr(vaddr);
	struct msm_jpeg_dma_buff kp_buff;
	int ret;

	if (!access_ok(VERIFY_READ, up_buff,
		sizeof(struct msm_jpeg_dma_buff)) ||
		get_user(kp_buff.fd, &up_buff->fd)) {
		dev_err(dma->dev, "Error getting user data\n");
		return ERR_PTR(-ENOMEM);
	}

	if (!access_ok(VERIFY_WRITE, up_buff,
		sizeof(struct msm_jpeg_dma_buff)) ||
		put_user(kp_buff.fd, &up_buff->fd)) {
		dev_err(dma->dev, "Error putting user data\n");
		return ERR_PTR(-ENOMEM);
	}

	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
	if (!buf)
		return ERR_PTR(-ENOMEM);

	ret = msm_jpegdma_hw_map_buffer(dma, vaddr, buf);
	ret = msm_jpegdma_hw_map_buffer(dma, kp_buff.fd, buf);
	if (ret < 0 || buf->size < size)
		goto error;

@@ -479,7 +516,6 @@ static int msm_jpegdma_open(struct file *file)
	if (!ctx)
		return -ENOMEM;

	mutex_init(&ctx->lock);
	ctx->jdma_device = device;
	dev_dbg(ctx->jdma_device->dev, "Jpeg v4l2 dma open\n");
	/* Set ctx defaults */
@@ -528,7 +564,9 @@ static int msm_jpegdma_release(struct file *file)
	struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(file->private_data);

	/* release all the resources */
	if (ctx->jdma_device->ref_count > 0)
		msm_jpegdma_hw_put(ctx->jdma_device);

	atomic_set(&ctx->active, 0);
	complete_all(&ctx->completion);
	v4l2_m2m_ctx_release(ctx->m2m_ctx);
@@ -771,16 +809,46 @@ static int msm_jpegdma_qbuf(struct file *file, void *fh,
	struct v4l2_buffer *buf)
{
	struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh);
	struct msm_jpeg_dma_buff __user *up_buff = compat_ptr(buf->m.userptr);
	struct msm_jpeg_dma_buff kp_buff;
	int ret;

	mutex_lock(&ctx->lock);
	if (!access_ok(VERIFY_READ, up_buff,
		sizeof(struct msm_jpeg_dma_buff)) ||
		get_user(kp_buff.fd, &up_buff->fd) ||
		get_user(kp_buff.offset, &up_buff->offset)) {
		dev_err(ctx->jdma_device->dev, "Error getting user data\n");
		return -EFAULT;
	}

	if (!access_ok(VERIFY_WRITE, up_buff,
		sizeof(struct msm_jpeg_dma_buff)) ||
		put_user(kp_buff.fd, &up_buff->fd) ||
		put_user(kp_buff.offset, &up_buff->offset)) {
		dev_err(ctx->jdma_device->dev, "Error putting user data\n");
		return -EFAULT;
	}

	switch (buf->type) {
	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
		ctx->in_offset = kp_buff.offset;
		dev_dbg(ctx->jdma_device->dev, "input buf offset %d\n",
			ctx->in_offset);
		break;
	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
		ctx->out_offset = kp_buff.offset;
		dev_dbg(ctx->jdma_device->dev, "output buf offset %d\n",
			ctx->out_offset);
		break;
	}

	if (atomic_read(&ctx->active))
		ret = msm_jpegdma_update_hw_config(ctx);

	ret = v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
	if (ret < 0)
		dev_err(ctx->jdma_device->dev, "QBuf fail\n");

	mutex_unlock(&ctx->lock);

	return ret;
}

@@ -813,14 +881,10 @@ static int msm_jpegdma_streamon(struct file *file,
	if (!msm_jpegdma_config_ok(ctx))
		return -EINVAL;

	mutex_lock(&ctx->lock);

	ret = v4l2_m2m_streamon(file, ctx->m2m_ctx, buf_type);
	if (ret < 0)
		dev_err(ctx->jdma_device->dev, "Stream on fail\n");

	mutex_unlock(&ctx->lock);

	return ret;
}

@@ -951,14 +1015,10 @@ static int msm_jpegdma_s_crop(struct file *file, void *fh,
	if (crop->c.top % formats[ctx->format_idx].v_align)
		return -EINVAL;

	mutex_lock(&ctx->lock);

	ctx->crop = crop->c;
	if (atomic_read(&ctx->active))
		ret = msm_jpegdma_update_hw_config(ctx);

	mutex_unlock(&ctx->lock);

	return ret;
}

@@ -1135,16 +1195,15 @@ void msm_jpegdma_isr_processing_done(struct msm_jpegdma_device *dma)
	struct jpegdma_ctx *ctx;

	mutex_lock(&dma->lock);

	ctx = v4l2_m2m_get_curr_priv(dma->m2m_dev);
	if (ctx) {
		mutex_lock(&ctx->lock);
		ctx->plane_idx++;
		if (ctx->plane_idx >= formats[ctx->format_idx].num_planes) {
			src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
			dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
			if (src_buf == NULL || dst_buf == NULL) {
				dev_err(ctx->jdma_device->dev, "Error, buffer list empty\n");
				mutex_unlock(&ctx->lock);
				mutex_unlock(&dma->lock);
				return;
			}
@@ -1160,13 +1219,11 @@ void msm_jpegdma_isr_processing_done(struct msm_jpegdma_device *dma)
			src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
			if (src_buf == NULL || dst_buf == NULL) {
				dev_err(ctx->jdma_device->dev, "Error, buffer list empty\n");
				mutex_unlock(&ctx->lock);
				mutex_unlock(&dma->lock);
				return;
			}
			msm_jpegdma_process_buffers(ctx, src_buf, dst_buf);
		}
		mutex_unlock(&ctx->lock);
	}
	mutex_unlock(&dma->lock);
}
+5 −2
Original line number Diff line number Diff line
@@ -22,7 +22,7 @@
/* Max number of clocks defined in device tree */
#define MSM_JPEGDMA_MAX_CLK 10
/* Core clock index */
#define MSM_JPEGDMA_CORE_CLK 0
#define MSM_JPEGDMA_CORE_CLK "core_clk"
/* Max number of regulators defined in device tree */
#define MSM_JPEGDMA_MAX_REGULATOR_NUM 3
/* Max number of planes supported */
@@ -109,6 +109,8 @@ struct msm_jpegdma_size_config {
	struct msm_jpegdma_size out_size;
	struct msm_jpegdma_format format;
	unsigned int fps;
	unsigned int in_offset;
	unsigned int out_offset;
};

/*
@@ -252,7 +254,6 @@ struct msm_jpegdma_buf_handle {
 * @format_idx: Current format index.
 */
struct jpegdma_ctx {
	struct mutex lock;
	struct msm_jpegdma_device *jdma_device;
	atomic_t active;
	struct completion completion;
@@ -262,6 +263,8 @@ struct jpegdma_ctx {
	struct v4l2_format format_out;
	struct v4l2_rect crop;
	struct v4l2_fract timeperframe;
	unsigned int in_offset;
	unsigned int out_offset;

	unsigned int config_idx;
	struct msm_jpegdma_plane_config plane_config[MSM_JPEGDMA_MAX_CONFIGS];
+66 −19
Original line number Diff line number Diff line
@@ -165,6 +165,23 @@ static int msm_jpegdma_hw_get_num_pipes(struct msm_jpegdma_device *dma)
	return num_pipes;
}

/*
 * msm_jpegdma_hw_get_clock_index - Get clock index by name
 * @dma: Pointer to dma device.
 * @clk_name: clock name.
 */
int msm_jpegdma_hw_get_clock_index(struct msm_jpegdma_device *dma,
		const char *clk_name)
{
	uint32_t i = 0;

	for (i = 0; i < dma->num_clk; i++) {
		if (!strcmp(clk_name, dma->jpeg_clk_info[i].clk_name))
			return i;
	}
	return -EINVAL;
}

/*
 * msm_jpegdma_hw_reset - Reset jpeg dma core.
 * @dma: Pointer to dma device.
@@ -782,12 +799,20 @@ static int msm_jpegdma_hw_calc_speed(struct msm_jpegdma_device *dma,
	u64 height;
	u64 real_clock;
	u64 calc_rate;
	int core_clk_idx;

	width = size->in_size.width + size->in_size.left;
	height = size->in_size.height + size->in_size.top;

	calc_rate = (width * height * size->format.depth * size->fps) / 16;
	real_clock = clk_round_rate(dma->clk[MSM_JPEGDMA_CORE_CLK], calc_rate);
	core_clk_idx = msm_jpegdma_hw_get_clock_index(dma,
		MSM_JPEGDMA_CORE_CLK);
	if (core_clk_idx < 0) {
		dev_err(dma->dev, "Can get clock index for dma %s\n",
			MSM_JPEGDMA_CORE_CLK);
	}

	real_clock = clk_round_rate(dma->clk[core_clk_idx], calc_rate);
	if (real_clock < 0) {
		dev_err(dma->dev, "Can not round core clock\n");
		return -EINVAL;
@@ -817,6 +842,7 @@ static int msm_jpegdma_hw_set_speed(struct msm_jpegdma_device *dma,
	struct msm_jpegdma_speed new_sp;
	struct msm_jpegdma_size_config new_size;
	int ret;
	int core_clk_idx;

	if (dma->active_clock_rate >= speed->core_clock)
		return 0;
@@ -830,7 +856,14 @@ static int msm_jpegdma_hw_set_speed(struct msm_jpegdma_device *dma,
			return -EINVAL;
	}

	ret = clk_set_rate(dma->clk[MSM_JPEGDMA_CORE_CLK], new_sp.core_clock);
	core_clk_idx = msm_jpegdma_hw_get_clock_index(dma,
		MSM_JPEGDMA_CORE_CLK);
	if (core_clk_idx < 0) {
		dev_err(dma->dev, "Can get clock index for dma %s\n",
			MSM_JPEGDMA_CORE_CLK);
	}

	ret = clk_set_rate(dma->clk[core_clk_idx], new_sp.core_clock);
	if (ret < 0) {
		dev_err(dma->dev, "Fail Core clock rate %d\n", ret);
		return -EINVAL;
@@ -1022,13 +1055,20 @@ int msm_jpegdma_hw_set_config(struct msm_jpegdma_device *dma,
	plane_cfg->plane[0].active_pipes = dma->hw_num_pipes;
	plane_cfg->plane[0].type = size_cfg->format.planes[0];
	msm_jpegdma_hw_calc_config(size_cfg, &plane_cfg->plane[0]);

	in_offset = size_cfg->in_offset;
	out_offset = size_cfg->out_offset;

	msm_jpegdma_hw_add_plane_offset(&plane_cfg->plane[0],
		in_offset, out_offset);

	if (size_cfg->format.num_planes == 1)
		return 0;

	in_offset = size_cfg->in_size.scanline *
		size_cfg->in_size.stride;
	out_offset = size_cfg->out_size.scanline *
		size_cfg->out_size.stride;
	in_offset += (size_cfg->in_size.scanline *
		size_cfg->in_size.stride);
	out_offset += (size_cfg->out_size.scanline *
		size_cfg->out_size.stride);

	memset(&plane_size, 0x00, sizeof(plane_size));
	for (i = 1; i < size_cfg->format.num_planes; i++) {
@@ -1336,7 +1376,8 @@ int msm_jpegdma_hw_get_qos(struct msm_jpegdma_device *dma)
	unsigned int cnt;
	const void *property;

	property = of_get_property(dma->dev->of_node, "qcom,qos-regs", &cnt);
	property = of_get_property(dma->dev->of_node,
		"qcom,qos-reg-settings", &cnt);
	if (!property || !cnt) {
		dev_dbg(dma->dev, "Missing qos settings\n");
		return 0;
@@ -1347,9 +1388,9 @@ int msm_jpegdma_hw_get_qos(struct msm_jpegdma_device *dma)
	if (!dma->qos_regs)
		return -ENOMEM;

	for (i = 0; i < cnt; i++) {
	for (i = 0; i < cnt; i = i + 2) {
		ret = of_property_read_u32_index(dma->dev->of_node,
			"qcom,qos-regs", i,
			"qcom,qos-reg-settings", i,
			&dma->qos_regs[i].reg);
		if (ret < 0) {
			dev_err(dma->dev, "can not read qos reg %d\n", i);
@@ -1357,7 +1398,7 @@ int msm_jpegdma_hw_get_qos(struct msm_jpegdma_device *dma)
		}

		ret = of_property_read_u32_index(dma->dev->of_node,
			"qcom,qos-settings", i,
			"qcom,qos-reg-settings", i + 1,
			&dma->qos_regs[i].val);
		if (ret < 0) {
			dev_err(dma->dev, "can not read qos setting %d\n", i);
@@ -1397,7 +1438,8 @@ int msm_jpegdma_hw_get_vbif(struct msm_jpegdma_device *dma)
	unsigned int cnt;
	const void *property;

	property = of_get_property(dma->dev->of_node, "qcom,vbif-regs", &cnt);
	property = of_get_property(dma->dev->of_node, "qcom,vbif-reg-settings",
		&cnt);
	if (!property || !cnt) {
		dev_dbg(dma->dev, "Missing vbif settings\n");
		return 0;
@@ -1408,9 +1450,9 @@ int msm_jpegdma_hw_get_vbif(struct msm_jpegdma_device *dma)
	if (!dma->vbif_regs)
		return -ENOMEM;

	for (i = 0; i < cnt; i++) {
	for (i = 0; i < cnt; i = i + 2) {
		ret = of_property_read_u32_index(dma->dev->of_node,
			"qcom,vbif-regs", i,
			"qcom,vbif-reg-settings", i,
			&dma->vbif_regs[i].reg);
		if (ret < 0) {
			dev_err(dma->dev, "can not read vbif reg %d\n", i);
@@ -1418,7 +1460,7 @@ int msm_jpegdma_hw_get_vbif(struct msm_jpegdma_device *dma)
		}

		ret = of_property_read_u32_index(dma->dev->of_node,
			"qcom,vbif-settings", i,
			"qcom,vbif-reg-settings", i + 1,
			&dma->vbif_regs[i].val);
		if (ret < 0) {
			dev_err(dma->dev, "can not read vbif setting %d\n", i);
@@ -1459,8 +1501,8 @@ int msm_jpegdma_hw_get_prefetch(struct msm_jpegdma_device *dma)
	unsigned int cnt;
	const void *property;

	property = of_get_property(dma->dev->of_node, "qcom,prefetch-regs",
		&cnt);
	property = of_get_property(dma->dev->of_node,
		"qcom,prefetch-reg-settings", &cnt);
	if (!property || !cnt) {
		dev_dbg(dma->dev, "Missing prefetch settings\n");
		return 0;
@@ -1472,9 +1514,9 @@ int msm_jpegdma_hw_get_prefetch(struct msm_jpegdma_device *dma)
	if (!dma->prefetch_regs)
		return -ENOMEM;

	for (i = 0; i < cnt; i++) {
	for (i = 0; i < cnt; i = i + 2) {
		ret = of_property_read_u32_index(dma->dev->of_node,
			"qcom,prefetch-regs", i,
			"qcom,prefetch-reg-settings", i,
			&dma->prefetch_regs[i].reg);
		if (ret < 0) {
			dev_err(dma->dev, "can not read prefetch reg %d\n", i);
@@ -1482,7 +1524,7 @@ int msm_jpegdma_hw_get_prefetch(struct msm_jpegdma_device *dma)
		}

		ret = of_property_read_u32_index(dma->dev->of_node,
			"qcom,prefetch-settings", i,
			"qcom,prefetch-reg-settings", i + 1,
			&dma->prefetch_regs[i].val);
		if (ret < 0) {
			dev_err(dma->dev, "can not read prefetch setting %d\n",
@@ -1598,6 +1640,9 @@ int msm_jpegdma_hw_get(struct msm_jpegdma_device *dma)
		msm_jpegdma_hw_config_qos(dma);
		msm_jpegdma_hw_config_vbif(dma);

		msm_camera_register_threaded_irq(dma->pdev, dma->irq, NULL,
			msm_jpegdma_hw_irq, IRQF_ONESHOT | IRQF_TRIGGER_RISING,
			dev_name(&dma->pdev->dev), dma);
		msm_jpegdma_hw_enable_irq(dma);

		ret = msm_jpegdma_hw_reset(dma);
@@ -1710,6 +1755,7 @@ error:
static void msm_jpegdma_hw_detach_iommu(struct msm_jpegdma_device *dma)
{
	mutex_lock(&dma->lock);

	if (dma->iommu_attached_cnt == 0) {
		dev_err(dma->dev, "There is no attached device\n");
		mutex_unlock(&dma->lock);
@@ -1720,6 +1766,7 @@ static void msm_jpegdma_hw_detach_iommu(struct msm_jpegdma_device *dma)
		cam_smmu_ops(dma->iommu_hndl, CAM_SMMU_DETACH);
		cam_smmu_destroy_handle(dma->iommu_hndl);
	}

	mutex_unlock(&dma->lock);
}