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: 1001324
Change-Id: Ice15afd63e006401a469376277b50a129ef177b4
Signed-off-by: Ashwini Rao <ashwinik@codeaurora.org>
This commit is contained in:
Ashwini Rao 2016-03-15 13:09:55 -07:00 committed by Jeevan Shriram
parent f4515051a9
commit a302531f3e
5 changed files with 180 additions and 58 deletions

View file

@ -19,13 +19,18 @@ Required properties:
- clocks : clocks required for the device.
- qcom,clock-rates: should specify clock rates in Hz to each clocks
property defined.
- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
below optional properties:
- qcom,msm-bus,name
- qcom,msm-bus,num-cases
- qcom,msm-bus,num-paths
- qcom,msm-bus,vectors-KBps
Optional properties:
- qcom,qos-regs: relative address offsets of QoS registers.
- qcom,qos-settings: QoS values to be written to QoS registers.
- qcom,vbif-regs: relative address offsets of VBIF registers.
- qcom,vbif-settings: VBIF values to be written to VBIF registers.
- qcom,prefetch-regs: relative address offsets of MMU prefetch registers.
- qcom,prefetch-settings: values to be written to MMU Prefetch registers.
- qcom,vbif-reg-settings: relative address offsets and value pairs for VBIF registers.
- qcom,qos-reg-settings: relative address offsets and value pairs for QoS registers.
- qcom,prefetch-reg-settings: relative address offsets and value pairs for
MMU prefetch registers.
Example:
qcom,jpegdma@aa0000 {
@ -53,10 +58,14 @@ Example:
<&clock_gcc clk_mmssnoc_axi_clk>,
<&clock_mmss clk_mmagic_camss_axi_clk>;
qcom,clock-rates = <266670000 0 0 0 0 0 0 0 0>,
<400000000 0 0 0 0 0 0 0 0>;
qcom,vbif-regs = <0x4 0xDC 0x124 0x160>;
qcom,vbif-settings = <0x1 0x7 0x1 0x22222222>;
qcom,prefetch-regs = <0x18C 0x1A0 0x1B0>;
qcom,prefetch-settings = <0x11 0x31 0x31>;
qcom,vbif-reg-settings = <0x4 0x1>;
qcom,prefetch-reg-settings = <0x18c 0x11>,
<0x1a0 0x31>,
<0x1b0 0x31>;
qcom,msm-bus,name = "msm_camera_jpeg_dma";
qcom,msm-bus,num-cases = <2>;
qcom,msm-bus,num-paths = <1>;
qcom,msm-bus,vectors-KBps = <62 512 0 0>,
<62 512 666675 666675>;
status = "ok";
};

View file

@ -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);
@ -364,7 +383,9 @@ static void msm_jpegdma_stop_streaming(struct vb2_queue *q)
dev_err(ctx->jdma_device->dev, "Ctx wait timeout\n");
ret = -ETIME;
}
msm_jpegdma_hw_put(ctx->jdma_device);
if (ctx->jdma_device->ref_count > 0)
msm_jpegdma_hw_put(ctx->jdma_device);
}
/* Videobuf2 queue callbacks. */
@ -388,13 +409,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;
@ -482,7 +519,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 */
@ -531,7 +567,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 */
msm_jpegdma_hw_put(ctx->jdma_device);
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);
@ -774,16 +812,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;
}
@ -816,14 +884,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;
}
@ -954,14 +1018,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;
}
@ -1004,7 +1064,7 @@ static int msm_jpegdma_s_parm(struct file *file, void *fh,
return -EINVAL;
if (!a->parm.output.timeperframe.numerator ||
!a->parm.output.timeperframe.denominator)
!a->parm.output.timeperframe.denominator)
return -EINVAL;
/* Frame rate is not supported during streaming */
@ -1138,16 +1198,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;
}
@ -1163,13 +1222,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);
}

View file

@ -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];

View file

@ -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);
}

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -18,4 +18,10 @@
/* msm jpeg dma control ID's */
#define V4L2_CID_JPEG_DMA_SPEED (V4L2_CID_PRIVATE_BASE)
/* msm_jpeg_dma_buf */
struct msm_jpeg_dma_buff {
int32_t fd;
uint32_t offset;
};
#endif /* __UAPI_MSM_JPEG_DMA__ */