Hi Ben, Thank you for the review. > -----Original Message----- > From: linux-samsung-soc-owner@xxxxxxxxxxxxxxx [mailto:linux-samsung- > soc-owner@xxxxxxxxxxxxxxx] On Behalf Of Ben Dooks > Sent: Thursday, May 06, 2010 8:26 AM > To: Sylwester Nawrocki > Cc: linux-media@xxxxxxxxxxxxxxx; linux-samsung-soc@xxxxxxxxxxxxxxx; > linux-arm-kernel@xxxxxxxxxxxxxxxxxxx; p.osciak@xxxxxxxxxxx; > m.szyprowski@xxxxxxxxxxx; kyungmin.park@xxxxxxxxxxx > Subject: Re: [PATCH v1 3/3] ARM: S5P: Add Camera interface (video > postprocessor) driver > > On Mon, Apr 19, 2010 at 12:30:00PM +0200, Sylwester Nawrocki wrote: > > The purpose of this driver is to expose, as an initial stage, > > memory to memory operations, including color conversion, > > image resizing, flipping and rotation. > > > > Signed-off-by: Sylwester Nawrocki <s.nawrocki@xxxxxxxxxxx> > > Reviewed-by: Pawel Osciak <p.osciak@xxxxxxxxxxx> > > Reviewed-by: Marek Szyprowski <m.szyprowski@xxxxxxxxxxx> > > Reviewed-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx> > > --- > > drivers/media/video/Kconfig | 9 + > > drivers/media/video/Makefile | 1 + > > drivers/media/video/samsung-fimc/Makefile | 3 + > > drivers/media/video/samsung-fimc/s5p_fimc.c | 1491 > +++++++++++++++++++++++ > > drivers/media/video/samsung-fimc/s5p_fimc.h | 331 +++++ > > drivers/media/video/samsung-fimc/s5p_fimc_reg.c | 559 +++++++++ > > include/linux/videodev2.h | 1 + > > 7 files changed, 2395 insertions(+), 0 deletions(-) > > create mode 100644 drivers/media/video/samsung-fimc/Makefile > > create mode 100644 drivers/media/video/samsung-fimc/s5p_fimc.c > > create mode 100644 drivers/media/video/samsung-fimc/s5p_fimc.h > > create mode 100644 drivers/media/video/samsung-fimc/s5p_fimc_reg.c > > are these also contained in the s3c64xx? yes, s3c64xx are equipped with similar device, just an older revision, so with a little work the driver could be adapted to s3c64xx too. I'm going to rename the files to something less single SOC specific then. > > > diff --git a/drivers/media/video/Kconfig > b/drivers/media/video/Kconfig > > index f8fc865..1560de8 100644 > > --- a/drivers/media/video/Kconfig > > +++ b/drivers/media/video/Kconfig > > @@ -949,6 +949,15 @@ config VIDEO_OMAP2 > > ---help--- > > This is a v4l2 driver for the TI OMAP2 camera capture interface > > > > +config VIDEO_SAMSUNG_FIMC > > + tristate "Samsung S5P Camera Interface (video postprocessor) > driver" > > + depends on VIDEO_DEV && VIDEO_V4L2 > > + select VIDEOBUF_DMA_CONTIG > > + select V4L2_MEM2MEM_DEV > > + default n > > + help > > + This is a v4l2 driver the Samsung S5P camera capture interface > > + > > # > > # USB Multimedia device configuration > > # > > diff --git a/drivers/media/video/Makefile > b/drivers/media/video/Makefile > > index b88b617..c176a34 100644 > > --- a/drivers/media/video/Makefile > > +++ b/drivers/media/video/Makefile > > @@ -159,6 +159,7 @@ obj-$(CONFIG_VIDEO_MX1) += > mx1_camera.o > > obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o > > obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o > > obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o > > +obj-$(CONFIG_VIDEO_SAMSUNG_FIMC) += samsung-fimc/ > > > > obj-$(CONFIG_ARCH_DAVINCI) += davinci/ > > > > diff --git a/drivers/media/video/samsung-fimc/Makefile > b/drivers/media/video/samsung-fimc/Makefile > > new file mode 100644 > > index 0000000..564d7c4 > > --- /dev/null > > +++ b/drivers/media/video/samsung-fimc/Makefile > > @@ -0,0 +1,3 @@ > > + > > +obj-$(CONFIG_VIDEO_SAMSUNG_FIMC) := s5px_fimc.o > > +s5px_fimc-y := s5p_fimc.o s5p_fimc_reg.o > > diff --git a/drivers/media/video/samsung-fimc/s5p_fimc.c > b/drivers/media/video/samsung-fimc/s5p_fimc.c > > new file mode 100644 > > index 0000000..47e6765 > > --- /dev/null > > +++ b/drivers/media/video/samsung-fimc/s5p_fimc.c > > @@ -0,0 +1,1491 @@ > > +/* linux/drivers/media/video/samsung-fimc/s5p_fimc.c > > + * > > + * S5P camera interface (postprocessor) driver > > + * > > + * Copyright (c) 2010 Samsung Electronics > > + * > > + * Sylwester Nawrocki, s.nawrocki@xxxxxxxxxxx > > + * > > + * This program is free software; you can redistribute it and/or > modify > > + * it under the terms of the GNU General Public License as published > > + * by the Free Software Foundiation. either version 2 of the > License, > > + * or (at your option) any later version > > + */ > > + > > +#include <linux/module.h> > > +#include <linux/kernel.h> > > +#include <linux/version.h> > > +#include <linux/types.h> > > +#include <linux/errno.h> > > +#include <linux/clk.h> > > +#include <linux/wait.h> > > +#include <linux/fs.h> > > +#include <linux/irq.h> > > +#include <linux/mm.h> > > +#include <linux/interrupt.h> > > +#include <linux/device.h> > > +#include <linux/platform_device.h> > > +#include <linux/io.h> > > +#include <linux/delay.h> > > +#include <linux/timer.h> > > +#include <linux/proc_fs.h> > > +#include <linux/list.h> > > +#include <linux/io.h> > > +#include <linux/bug.h> > > +#include <linux/memory.h> > > +#include <plat/clock.h> > > do you really need plat/clock.h > <linux/clk.h> should be enough. indeed, I have reviewed this include list and will remove also few other ones which are irrelevant > > +#include <plat/regs-fimc.h> > > +#include <linux/videodev2.h> > > +#include <media/v4l2-device.h> > > +#include <media/v4l2-ioctl.h> > > +#include <media/v4l2-mem2mem.h> > > +#include <media/videobuf-core.h> > > +#include <media/videobuf-dma-contig.h> > > +#include "s5p_fimc.h" > > some spacing between the different include groups would be nice. I wasn't sure about that, will do > > > + > > + > > +#define ctx_get_frame(frame, ctx, type) do { \ > > + if (V4L2_BUF_TYPE_VIDEO_OUTPUT == (type)) \ > > + frame = &(ctx)->s_frame; \ > > + else if (V4L2_BUF_TYPE_VIDEO_CAPTURE == (type)) \ > > + frame = &(ctx)->d_frame; \ > > + else { \ > > + v4l2_err(&(ctx)->fimc_dev->v4l2_dev, \ > > + "Wrong buffer/video queue type (%d)\n", type); \ > > + return -EINVAL; \ > > + } \ > > +} while (0) > > + > > + > > +static int s5p_fimc_prepare_addr(struct fimc_ctx *ctx, > > + struct fimc_vid_buffer *buf, enum v4l2_buf_type type); > > +static void queue_init(void *priv, struct videobuf_queue *vq, > > + enum v4l2_buf_type type); > > +static int s5p_fimc_prepare_config(struct fimc_ctx *ctx, u32 flags); > > + > > + > > +static struct videobuf_queue_ops s5p_fimc_qops; > > + > > +static struct s5p_fimc_fmt formats[] = { > > + { > > + .name = "RGB565", > > + .fourcc = V4L2_PIX_FMT_RGB565X, > > + .depth = 16, > > + .color = S5P_FIMC_RGB565, > > + .buff_cnt = 1, > > + .planes_cnt = 1 > > + }, { > > + .name = "RGB666", > > + .fourcc = V4L2_PIX_FMT_RGB666, > > + .depth = 32, > > + .color = S5P_FIMC_RGB666, > > + .buff_cnt = 1, > > + .planes_cnt = 1 > > + }, { > > + .name = "XRGB-8-8-8-8, 24 bpp", > > + .fourcc = V4L2_PIX_FMT_RGB24, > > + .depth = 32, > > + .color = S5P_FIMC_RGB888, > > + .buff_cnt = 1, > > + .planes_cnt = 1 > > + }, { > > + .name = "YUV 4:2:2 packed, YCbYCr", > > + .fourcc = V4L2_PIX_FMT_YUYV, > > + .depth = 16, > > + .color = S5P_FIMC_YCBYCR422, > > + .buff_cnt = 1, > > + .planes_cnt = 1 > > + }, { > > + .name = "YUV 4:2:2 packed, CbYCrY", > > + .fourcc = V4L2_PIX_FMT_UYVY, > > + .depth = 16, > > + .color = S5P_FIMC_CBYCRY422, > > + .buff_cnt = 1, > > + .planes_cnt = 1 > > + }, { > > + .name = "YUV 4:2:2 packed, CrYCbY", > > + .fourcc = V4L2_PIX_FMT_VYUY, > > + .depth = 16, > > + .color = S5P_FIMC_CRYCBY422, > > + .buff_cnt = 1, > > + .planes_cnt = 1 > > + }, { > > + .name = "YUV 4:2:2 packed, YCrYCb", > > + .fourcc = V4L2_PIX_FMT_YVYU, > > + .depth = 16, > > + .color = S5P_FIMC_YCRYCB422, > > + .buff_cnt = 1, > > + .planes_cnt = 1 > > + }, { > > + .name = "YUV 4:2:2 planar, Y/Cb/Cr", > > + .fourcc = V4L2_PIX_FMT_YUV422P, > > + .depth = 12, > > + .color = S5P_FIMC_YCBCR422, > > + .buff_cnt = 1, > > + .planes_cnt = 3 > > + }, { > > + .name = "YUV 4:2:2 planar, Y/CbCr", > > + .fourcc = V4L2_PIX_FMT_NV16, > > + .depth = 16, > > + .color = S5P_FIMC_YCBCR422, > > + .buff_cnt = 1, > > + .planes_cnt = 2 > > + }, { > > + .name = "YUV 4:2:2 planar, Y/CrCb", > > + .fourcc = V4L2_PIX_FMT_NV61, > > + .depth = 16, > > + .color = S5P_FIMC_RGB565, > > + .buff_cnt = 1, > > + .planes_cnt = 2 > > + }, { > > + .name = "YUV 4:2:0 planar, YCbCr", > > + .fourcc = V4L2_PIX_FMT_YUV420, > > + .depth = 12, > > + .color = S5P_FIMC_YCBCR420, > > + .buff_cnt = 1, > > + .planes_cnt = 3 > > + }, { > > + .name = "YUV 4:2:0 planar, Y/CbCr", > > + .fourcc = V4L2_PIX_FMT_NV12, > > + .depth = 12, > > + .color = S5P_FIMC_YCBCR420, > > + .buff_cnt = 1, > > + .planes_cnt = 2 > > + } > > + }; > > + > > +#define NUM_FORMATS ARRAY_SIZE(formats) > > is this really necessary? ok, will get rid of it > > > +static struct v4l2_queryctrl s5p_fimc_ctrls[] = { > > + { > > + .id = V4L2_CID_HFLIP, > > + .type = V4L2_CTRL_TYPE_BOOLEAN, > > + .name = "Horizontal flip", > > + .minimum = 0, > > + .maximum = 1, > > + .default_value = 0, > > + }, > > + { > > + .id = V4L2_CID_VFLIP, > > + .type = V4L2_CTRL_TYPE_BOOLEAN, > > + .name = "Vertical flip", > > + .minimum = 0, > > + .maximum = 1, > > + .default_value = 0, > > + }, > > + { > > + .id = V4L2_CID_ROTATE, > > + .type = V4L2_CTRL_TYPE_INTEGER, > > + .name = "Rotation (CCW)", > > + .minimum = 0, > > + .maximum = 270, > > + .step = 90, > > + .default_value = 0, > > + }, > > +}; > > + > > + > > +static struct v4l2_queryctrl *get_ctrl(int id) > > +{ > > + int i; > > + > > + for (i = 0; i < ARRAY_SIZE(s5p_fimc_ctrls); ++i) > > + if (id == s5p_fimc_ctrls[i].id) > > + return &s5p_fimc_ctrls[i]; > > + return NULL; > > +} > > + > > +static int s5p_fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, > u32 *shift) > > +{ > > + if (src >= tar * 64) { > > + return -EINVAL; > > + } else if (src >= tar * 32) { > > + *ratio = 32; > > + *shift = 5; > > + } else if (src >= tar * 16) { > > + *ratio = 16; > > + *shift = 4; > > + } else if (src >= tar * 8) { > > + *ratio = 8; > > + *shift = 3; > > + } else if (src >= tar * 4) { > > + *ratio = 4; > > + *shift = 2; > > + } else if (src >= tar * 2) { > > + *ratio = 2; > > + *shift = 1; > > + } else { > > + *ratio = 1; > > + *shift = 0; > > + } > > + > > + return 0; > > +} > > + > > +int s5p_fimc_set_scaler_info(struct fimc_ctx *ctx) > > +{ > > + struct fimc_scaler *sc = &ctx->scaler; > > + struct fimc_dma_offset *d_ofs = &ctx->s_frame.dma_offset; > > + int tx, ty, sx, sy; > > + int width, height, h_ofs, v_ofs; > > + int ret; > > + struct fimc_frame *src_frame = &ctx->s_frame; > > + struct fimc_frame *dst_frame = &ctx->d_frame; > > + > > + if (ctx->in_path == S5P_FIMC_DMA) { > > + if ((90 == ctx->rotation || 270 == ctx->rotation) > > don't like if (const == var) a lot. all right, I don't mind changing that the other way around > > > + && ctx->out_path == S5P_FIMC_LCDFIFO) { > > + /* here we are using only the input rotator */ > > + width = src_frame->height; > > + height = src_frame->width; > > + h_ofs = d_ofs->y_v; > > + v_ofs = d_ofs->y_h; > > + } else { > > + width = src_frame->width; > > + height = src_frame->height; > > + h_ofs = d_ofs->y_h; > > + v_ofs = d_ofs->y_v; > > + } > > + } else { > > + width = src_frame->width; > > + height = src_frame->height; > > + h_ofs = d_ofs->y_h; > > + v_ofs = d_ofs->y_v; > > + } > > + > > + tx = dst_frame->width; > > + ty = dst_frame->height; > > + > > + if (tx <= 0 || ty <= 0) { > > + v4l2_err(&ctx->fimc_dev->v4l2_dev, > > + "invalid target size: %d %d", tx, ty); > > + return -EINVAL; > > + } > > + > > + sx = width; > > + sy = height; > > + > > + sc->real_width = width; > > + sc->real_height = height; > > + > > + if (sx <= 0 || sy <= 0) { > > + err("invalid source size: s: %d %d, t: %d %d", sx, sy, tx, > ty); > > + return -EINVAL; > > + } > > + > > + dbg("sx= %d, sy= %d, tx= %d, ty= %d", sx, sy, tx, ty); > > + > > + ret = s5p_fimc_get_scaler_factor(sx, tx, > > + &sc->pre_hratio, &sc->hfactor); > > + if (ret) > > + return ret; > > + > > + ret = s5p_fimc_get_scaler_factor(sy, ty, > > + &sc->pre_vratio, &sc->vfactor); > > + if (ret) > > + return ret; > > + > > + sc->pre_dst_width = sx/sc->pre_hratio; > > + sc->pre_dst_height = sy/sc->pre_vratio; > > + > > + sc->main_hratio = (sx << 8) / (tx << sc->hfactor); > > + sc->main_vratio = (sy << 8) / (ty << sc->vfactor); > > + > > + dbg("sc->main_hratio= %d, sc->main_vratio= %d", > > + sc->main_hratio, sc->main_vratio); > > + dbg("sc->hfactor= %d, sc->vfactor= %d", sc->hfactor, sc- > >vfactor); > > + > > + sc->scaleup_h = (tx >= sx) ? 1 : 0; > > + sc->scaleup_v = (ty >= sy) ? 1 : 0; > > + > > + /* check to see if input and output size/format differ */ > > + if (src_frame->fmt->color == dst_frame->fmt->color > > + && src_frame->width == dst_frame->width > > + && src_frame->height == dst_frame->height) > > + sc->copy_mode = 1; > > + else > > + sc->copy_mode = 0; > > + > > + return 0; > > +} > > + > > +static void s5p_fimc_clear_irq(struct fimc_dev *dev) > > +{ > > + u32 cfg = readl(dev->regs + S5P_CIGCTRL); > > + cfg |= S5P_CIGCTRL_IRQ_CLR; > > + writel(cfg, dev->regs + S5P_CIGCTRL); > > +} > > + > > +static irqreturn_t s5p_fimc_isr(int irq, void *priv) > > +{ > > + struct fimc_ctx *ctx; > > + struct fimc_vid_buffer *src_buf, *dst_buf; > > + struct fimc_dev *dev = (struct fimc_dev *)priv; > > + > > + BUG_ON(NULL == dev); > > + > > + s5p_fimc_clear_irq(dev); > > + s5p_fimc_check_fifo(dev); > > + > > + ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); > > + if (NULL == ctx) > > + return IRQ_HANDLED; > > + > > + src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); > > + dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); > > + spin_lock(&dev->irqlock); > > + src_buf->vb.state = dst_buf->vb.state = VIDEOBUF_DONE; > > + wake_up(&src_buf->vb.done); > > + wake_up(&dst_buf->vb.done); > > + spin_unlock(&dev->irqlock); > > + v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx); > > + > > + return IRQ_HANDLED; > > +} > > + > > +/* > > + * Rewrite context data to the registers as required and start > > + * the transaction in hardware. > > + */ > > +static void s5p_fimc_dma_run(void *priv) > > +{ > > + struct fimc_ctx *ctx = priv; > > + struct fimc_dev *dev = ctx->fimc_dev; > > + struct fimc_frame *frame; > > + u32 ret; > > + > > + if (NULL == ctx || S5P_FIMC_DMA != ctx->out_path) > > + return; > > !ctx would be sufficient for the first test. will change that, just wanted to emphasize we are dealing with a pointer > > > + > > + ctx->updated |= S5P_FIMC_SRC_ADDR | S5P_FIMC_DST_ADDR; > > + ret = s5p_fimc_prepare_config(ctx, ctx->updated); > > + if (ret) { > > + err("Wrong configuration"); > > + return; > > + } > > + > > + frame = &ctx->s_frame; > > + dbg("SRC: width= %d, height= %d, f_width= %d, f_height= %d " \ > > + "offs_h= %d, offs_v= %d", > > + frame->width, frame->height, > > + frame->f_width, frame->f_height, > > + frame->offs_h, frame->offs_v); > > + > > + frame = &ctx->d_frame; > > + dbg("DST: width= %d, height= %d, f_width= %d, f_height= %d " \ > > + "offs_h= %d, offs_v= %d", > > + frame->width, frame->height, > > + frame->f_width, frame->f_height, > > + frame->offs_h, frame->offs_v); > > + > > + s5p_fimc_set_input_addr(ctx); > > + > > + if (ctx->updated&S5P_FIMC_PARAMS) { > > + s5p_fimc_set_input_path(ctx); > > + > > + if (ctx->in_path == S5P_FIMC_DMA) > > + s5p_fimc_set_in_dma(ctx); > > + > > + if (s5p_fimc_set_scaler_info(ctx)) { > > + err("scaler configuration error"); > > + return; > > + } > > + s5p_fimc_set_prescaler(ctx); > > + s5p_fimc_set_scaler(ctx); > > + s5p_fimc_set_target_format(ctx); > > + s5p_fimc_set_effect(ctx); > > + } > > + > > + s5p_fimc_set_output_path(ctx); > > + if (ctx->updated & (S5P_FIMC_DST_ADDR | S5P_FIMC_PARAMS)) > > + s5p_fimc_set_output_addr(ctx); > > + > > + if (ctx->updated & S5P_FIMC_PARAMS) > > + s5p_fimc_set_out_dma(ctx); > > + > > + if (ctx->scaler.enabled) > > + s5p_fimc_start_scaler(ctx); > > + > > + s5p_fimc_en_capture(ctx); > > + > > + if (ctx->in_path == S5P_FIMC_DMA) > > + s5p_fimc_start_in_dma(dev); > > + > > + ctx->updated = 0; > > +} > > + > > +static void s5p_fimc_job_abort(void *priv) > > +{ > > + > > +} > > + > > +/* set order for 1 and 2 plane YCBCR 4:2:2 formats */ > > +static void s5p_fimc_set_yuv_order(struct fimc_ctx *ctx) > > +{ > > + /* the one only mode supported in SoC */ > > + ctx->in_order_2p = S5P_FIMC_LSB_CRCB; > > + ctx->out_order_2p = S5P_FIMC_LSB_CRCB; > > + > > + /* set order for 1 plane input formats */ > > + switch (ctx->s_frame.fmt->color) { > > + case S5P_FIMC_YCRYCB422: > > + ctx->in_order_1p = S5P_FIMC_IN_YCRYCB; > > + break; > > + case S5P_FIMC_CBYCRY422: > > + ctx->in_order_1p = S5P_FIMC_IN_CBYCRY; > > + break; > > + case S5P_FIMC_CRYCBY422: > > + ctx->in_order_1p = S5P_FIMC_IN_CRYCBY; > > + break; > > + case S5P_FIMC_YCBYCR422: /* fall through */ > > + default: > > + ctx->in_order_1p = S5P_FIMC_IN_YCBYCR; > > + break; > > + } > > + dbg("ctx->in_order_1p= %d", ctx->in_order_1p); > > + > > + switch (ctx->d_frame.fmt->color) { > > + case S5P_FIMC_YCRYCB422: > > + ctx->out_order_1p = S5P_FIMC_OUT_YCRYCB; > > + break; > > + case S5P_FIMC_CBYCRY422: > > + ctx->out_order_1p = S5P_FIMC_OUT_CBYCRY; > > + break; > > + case S5P_FIMC_CRYCBY422: > > + ctx->out_order_1p = S5P_FIMC_OUT_CRYCBY; > > + break; > > + case S5P_FIMC_YCBYCR422: /* fall through */ > > + default: > > + ctx->out_order_1p = S5P_FIMC_OUT_YCBYCR; > > + break; > > + } > > + dbg("ctx->out_order_1p= %d", ctx->out_order_1p); > > +} > > + > > +/** > > + * @name s5p_fimc_prepare_config > > + * Check dimensions, operation and color mode > > + * @return 0 if dimensions are valid, non zero otherwise > > + */ > > +static int s5p_fimc_prepare_config(struct fimc_ctx *ctx, u32 flags) > > +{ > > + struct fimc_frame *src_frame, *dst_frame; > > + struct fimc_vid_buffer *buf = NULL; > > + int ret = 0; > > + u32 tmp; > > + > > + dbg("flags= 0x%X", flags); > > + > > + src_frame = &ctx->s_frame; > > + dst_frame = &ctx->d_frame; > > + > > + if (flags & S5P_FIMC_PARAMS) { > > + if ((S5P_FIMC_DMA == ctx->out_path) && > > + (90 == ctx->rotation || 270 == ctx->rotation)) { > > + tmp = dst_frame->f_width; > > + dst_frame->f_width = dst_frame->f_height; > > + dst_frame->f_height = tmp; > > + tmp = dst_frame->width; > > + dst_frame->width = dst_frame->height; > > + dst_frame->height = tmp; > > + } > > + > > + /* prepare the output offset related attributes for scaler > */ > > + dst_frame->dma_offset.y_h = dst_frame->offs_h > > + * (dst_frame->fmt->depth >> 3); > > + dst_frame->dma_offset.y_v = dst_frame->offs_v; > > + > > + dst_frame->dma_offset.cb_h = dst_frame->offs_h; > > + dst_frame->dma_offset.cb_v = dst_frame->offs_v; > > + > > + dst_frame->dma_offset.cr_h = dst_frame->offs_h; > > + dst_frame->dma_offset.cr_v = dst_frame->offs_v; > > + > > + if (3 == dst_frame->fmt->planes_cnt) { > > + dst_frame->dma_offset.cb_h /= 2; > > + dst_frame->dma_offset.cb_v /= 2; > > + dst_frame->dma_offset.cr_h /= 2; > > + dst_frame->dma_offset.cr_v /= 2; > > + } > > + > > + dbg("OUT OFFSET: color= %d, y_h= %d, y_v= %d", > > + dst_frame->fmt->color, > > + dst_frame->dma_offset.y_h, dst_frame- > >dma_offset.y_v); > > + > > + /* prepare the input offset related attributes for scaler > */ > > + src_frame->dma_offset.y_h = src_frame->offs_h > > + * (src_frame->fmt->depth >> 3); > > + src_frame->dma_offset.y_v = src_frame->offs_v; > > + > > + src_frame->dma_offset.cb_h = src_frame->offs_h; > > + src_frame->dma_offset.cb_v = src_frame->offs_v; > > + > > + src_frame->dma_offset.cr_h = src_frame->offs_h; > > + src_frame->dma_offset.cr_v = src_frame->offs_v; > > + > > + if (3 == src_frame->fmt->planes_cnt) { > > + src_frame->dma_offset.cb_h /= 2; > > + src_frame->dma_offset.cb_v /= 2; > > + src_frame->dma_offset.cr_h /= 2; > > + src_frame->dma_offset.cr_v /= 2; > > + } > > + > > + dbg("IN OFFSET: color= %d, y_h= %d, y_v= %d", > > + src_frame->fmt->color, src_frame->dma_offset.y_h, > > + src_frame->dma_offset.y_v); > > + > > + s5p_fimc_set_yuv_order(ctx); > > + > > + /* Check against the scaler ratio */ > > + if (src_frame->height > SCALER_MAX_VRATIO*dst_frame->height > || > > + src_frame->width > SCALER_MAX_HRATIO*dst_frame- > >width) { > > + err("Out of the scaler range"); > > + return -EINVAL; > > + } > > + } /* if (flags & S5P_FIMC_PARAMS) */ > > + > > + /* input DMA mode is not allowed when the scaler is disabled */ > > + ctx->scaler.enabled = 1; > > + > > + if (flags & (S5P_FIMC_SRC_ADDR)) { > > + buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); > > + ret = s5p_fimc_prepare_addr(ctx, buf, > > + V4L2_BUF_TYPE_VIDEO_OUTPUT); > > + if (ret) > > + return ret; > > + } > > + > > + if (flags & (S5P_FIMC_DST_ADDR)) { > > + buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); > > + ret = s5p_fimc_prepare_addr(ctx, buf, > > + V4L2_BUF_TYPE_VIDEO_CAPTURE); > > + } > > + > > + return ret; > > +} > > + > > +/* the color format (planes_cnt, buff_cnt) must be already > configured */ > > +static int s5p_fimc_prepare_addr(struct fimc_ctx *ctx, > > + struct fimc_vid_buffer *buf, enum v4l2_buf_type type) > > +{ > > + int ret = 0; > > + struct fimc_frame *frame; > > + u32 pix_size; > > + > > + ctx_get_frame(frame, ctx, type); > > + > > + if (!buf) > > + return -EINVAL; > > + > > + pix_size = frame->width * frame->height; > > + > > + dbg("%d buff_cnt, planes_cnt= %d, frame->size= %d, pix_size= %d", > > + frame->fmt->buff_cnt, frame->fmt->planes_cnt, > > + frame->size, pix_size); > > + > > + > > + if (frame->fmt->buff_cnt == 1) { > > + frame->addr_y = videobuf_to_dma_contig(&buf->vb); > > + switch (frame->fmt->planes_cnt) { > > + case 1: > > + frame->addr_cb = 0; > > + frame->addr_cr = 0; > > + break; > > + case 2: > > + /* decompose Y into Y/Cb */ > > + frame->addr_cb = (u32)(frame->addr_y + pix_size); > > + frame->addr_cr = 0; > > + break; > > + case 3: > > + frame->addr_cb = (u32)(frame->addr_y + pix_size); > > + /* decompose Y into Y/Cb/Cr */ > > + if (S5P_FIMC_YCBCR420 == frame->fmt->color) > > + frame->addr_cr = (u32)(frame->addr_cb > > + + (pix_size >> 2)); > > + else /* 422 */ > > + frame->addr_cr = (u32)(frame->addr_cb > > + + (pix_size >> 1)); > > + break; > > + default: > > + return -EINVAL; > > + } > > + } > > + > > + dbg("PHYS_ADDR: type= %d, y= 0x%X cb= 0x%X cr= 0x%X ret= %d", > > + type, frame->addr_y, frame->addr_cb, frame->addr_cr, ret); > > + > > + return ret; > > +} > > + > > +static void s5p_fimc_buf_release(struct videobuf_queue *vq, > > + struct videobuf_buffer *vb) > > +{ > > + videobuf_dma_contig_free(vq, vb); > > + vb->state = VIDEOBUF_NEEDS_INIT; > > +} > > + > > +static int s5p_fimc_buf_setup(struct videobuf_queue *vq, unsigned > int *count, > > + unsigned int *size) > > +{ > > + struct fimc_ctx *ctx = vq->priv_data; > > + struct fimc_frame *frame; > > + > > + ctx_get_frame(frame, ctx, vq->type); > > + > > + *size = (frame->width * frame->height * frame->fmt->depth) >> 3; > > + if (0 == *count) > > + *count = 1; > > + return 0; > > +} > > + > > +static int s5p_fimc_buf_prepare(struct videobuf_queue *vq, > > + struct videobuf_buffer *vb, > > + enum v4l2_field field) > > +{ > > + struct fimc_ctx *ctx = vq->priv_data; > > + struct fimc_frame *frame; > > + int ret; > > + > > + ctx_get_frame(frame, ctx, vq->type); > > + > > + if (vb->baddr) { > > + if (vb->bsize < frame->size) { > > + v4l2_err(&ctx->fimc_dev->v4l2_dev, > > + "User-provided buffer too small (%d < %d)\n", > > + vb->bsize, frame->size); > > + WARN_ON(1); > > + return -EINVAL; > > + } > > + } else if (vb->state != VIDEOBUF_NEEDS_INIT > > + && vb->bsize < frame->size) { > > + return -EINVAL; > > + } > > + > > + vb->width = frame->width; > > + vb->height = frame->height; > > + vb->bytesperline = (frame->width * frame->fmt->depth) >> 3; > > + vb->size = frame->size; > > + vb->field = field; > > + > > + if (VIDEOBUF_NEEDS_INIT == vb->state) { > > + ret = videobuf_iolock(vq, vb, NULL); > > + if (ret) { > > + v4l2_err(&ctx->fimc_dev->v4l2_dev, > > + "Iolock failed\n"); > > + goto fail; > > + } > > + } > > + vb->state = VIDEOBUF_PREPARED; > > + > > + return 0; > > +fail: > > + s5p_fimc_buf_release(vq, vb); > > + return ret; > > +} > > + > > +static void s5p_fimc_buf_queue(struct videobuf_queue *vq, > > + struct videobuf_buffer *vb) > > +{ > > + struct fimc_ctx *ctx = vq->priv_data; > > + v4l2_m2m_buf_queue(ctx->m2m_ctx, vq, vb); > > +} > > + > > + > > +static struct videobuf_queue_ops s5p_fimc_qops = { > > + .buf_setup = s5p_fimc_buf_setup, > > + .buf_prepare = s5p_fimc_buf_prepare, > > + .buf_queue = s5p_fimc_buf_queue, > > + .buf_release = s5p_fimc_buf_release, > > +}; > > + > > +static int s5p_fimc_querycap(struct file *file, void *priv, > > + struct v4l2_capability *cap) > > +{ > > + struct fimc_ctx *ctx = file->private_data; > > + struct fimc_dev *dev = ctx->fimc_dev; > > + > > + strncpy(cap->driver, dev->pdev->name, sizeof(cap->driver) - 1); > > + strncpy(cap->card, dev->pdev->name, sizeof(cap->card) - 1); > > + cap->bus_info[0] = 0; > > + cap->version = KERNEL_VERSION(1, 0, 0); > > + cap->capabilities = V4L2_CAP_STREAMING | > > + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT; > > + > > + return 0; > > +} > > + > > +static int s5p_fimc_enum_fmt(struct file *file, void *priv, > > + struct v4l2_fmtdesc *f) > > +{ > > + struct s5p_fimc_fmt *fmt; > > + > > + if (f->index >= NUM_FORMATS) > > + return -EINVAL; > > + > > + fmt = &formats[f->index]; > > + strncpy(f->description, fmt->name, sizeof(f->description) - 1); > > + f->pixelformat = fmt->fourcc; > > + return 0; > > +} > > + > > +static int s5p_fimc_g_fmt(struct file *file, void *priv, struct > v4l2_format *f) > > +{ > > + struct fimc_ctx *ctx = priv; > > + struct fimc_frame *frame; > > + > > + ctx_get_frame(frame, ctx, f->type); > > + > > + f->fmt.pix.width = frame->width; > > + f->fmt.pix.height = frame->height; > > + f->fmt.pix.field = V4L2_FIELD_NONE; > > + f->fmt.pix.pixelformat = frame->fmt->fourcc; > > + > > + return 0; > > +} > > + > > +static struct s5p_fimc_fmt *find_format(struct v4l2_format *f) > > +{ > > + struct s5p_fimc_fmt *fmt; > > + unsigned int i; > > + > > + for (i = 0; i < NUM_FORMATS; ++i) { > > + fmt = &formats[i]; > > + if (fmt->fourcc == f->fmt.pix.pixelformat) > > + break; > > + } > > + if (i == NUM_FORMATS) > > + return NULL; > > + > > + return fmt; > > +} > > + > > +static int s5p_fimc_try_fmt(struct file *file, void *priv, > > + struct v4l2_format *f) > > +{ > > + struct s5p_fimc_fmt *fmt; > > + struct fimc_ctx *ctx = priv; > > + struct fimc_dev *dev = ctx->fimc_dev; > > + struct v4l2_pix_format *pix = &f->fmt.pix; > > + u32 max_width, max_height; > > + u32 mod_x = 1; /* defaults for non-DMA mode */ > > + u32 mod_y = 1; > > + > > + > > + fmt = find_format(f); > > + if (!fmt) { > > + v4l2_err(&dev->v4l2_dev, "Fourcc format (0x%08x) > invalid.\n", > > + pix->pixelformat); > > + return -EINVAL; > > + } > > + > > + if (pix->field == V4L2_FIELD_ANY) > > + pix->field = V4L2_FIELD_NONE; > > + else if (V4L2_FIELD_NONE != pix->field) > > + return -EINVAL; > > + > > + if (V4L2_BUF_TYPE_VIDEO_OUTPUT == f->type) { > > + max_width = dev->pldata->scaler_dis_w; > > + max_height = dev->pldata->scaler_dis_w; > > + } else if (V4L2_BUF_TYPE_VIDEO_CAPTURE == f->type) { > > + max_width = dev->pldata->out_rot_dis_w; > > + max_height = dev->pldata->out_rot_dis_w; > > + } else { > > + err("Wrong stream type (%d)", f->type); > > + return -EINVAL; > > + } > > + > > + dbg("max_w= %d, max_h= %d", max_width, max_height); > > + > > + if (pix->height > max_height) > > + pix->height = max_height; > > + if (pix->width > max_width) > > + pix->width = max_width; > > + > > + if (S5P_FIMC_DMA == ctx->in_path > > + || V4L2_BUF_TYPE_VIDEO_CAPTURE == f->type) { > > + mod_x = (DMA_MIN_SIZE - 1); > > + mod_y = (DMA_MIN_SIZE - 1); > > + } else { > > + mod_x = 1, mod_y = 1; > > + } > > + dbg("mod_x= 0x%X, mod_y= 0x%X", mod_x, mod_y); > > + > > + pix->width &= ~mod_x; > > + pix->height &= ~mod_y; > > + if (0 == pix->width) > > + pix->width = mod_x + 1; > > + if (0 == pix->height) > > + pix->height = mod_y + 1; > > + > > + if (0 == pix->bytesperline) { > > + pix->bytesperline = (pix->width * fmt->depth) >> 3; > > + } else { > > + u32 f_width = pix->bytesperline*8/fmt->depth; > > + if (f_width > max_width) > > + pix->bytesperline = (max_width * fmt->depth) >> 3; > > + } > > + > > + if (0 == pix->sizeimage) > > + pix->sizeimage = pix->height * pix->bytesperline; > > + > > + dbg("pix->bytesperline= %d, fmt->depth= %d", > > + pix->bytesperline, fmt->depth); > > + > > + return 0; > > +} > > + > > +static int s5p_fimc_s_fmt(struct file *file, void *priv, struct > v4l2_format *f) > > +{ > > + struct fimc_frame *frame; > > + struct v4l2_pix_format *pix; > > + struct videobuf_queue *src_vq = NULL, > > + *dst_vq = NULL; > > + struct fimc_ctx *ctx = priv; > > + int ret = 0; > > + > > + BUG_ON(NULL == ctx); > > + > > + ret = s5p_fimc_try_fmt(file, priv, f); > > + if (ret) > > + return ret; > > + > > + mutex_lock(&ctx->lock); > > + > > + src_vq = v4l2_m2m_get_src_vq(ctx->m2m_ctx); > > + dst_vq = v4l2_m2m_get_dst_vq(ctx->m2m_ctx); > > + > > + mutex_lock(&src_vq->vb_lock); > > + mutex_lock(&dst_vq->vb_lock); > > + > > + if (videobuf_queue_is_busy(src_vq)) { > > + v4l2_err(&ctx->fimc_dev->v4l2_dev, "%s queue busy\n", > __func__); > > + ret = -EBUSY; > > + goto s_fmt_out; > > + } > > + > > + if (videobuf_queue_is_busy(dst_vq)) { > > + v4l2_err(&ctx->fimc_dev->v4l2_dev, "%s queue busy\n", > __func__); > > + ret = -EBUSY; > > + goto s_fmt_out; > > + } > > + > > + ctx_get_frame(frame, ctx, f->type); > > + > > + pix = &f->fmt.pix; > > + frame->fmt = find_format(f); > > + if (!frame->fmt) { > > + ret = -EINVAL; > > + goto s_fmt_out; > > + } > > + > > + dbg("depth=%d, bytesperline=%d", frame->fmt->depth, pix- > >bytesperline); > > + > > + frame->width = pix->width; > > + frame->height = pix->height; > > + > > + frame->f_width = pix->bytesperline*8/frame->fmt->depth; > > + frame->f_height = pix->sizeimage/pix->bytesperline; > > + > > + frame->o_width = pix->width; > > + frame->o_height = pix->height; > > + frame->offs_h = 0; > > + frame->offs_v = 0; > > + frame->size = (pix->width * pix->height * frame->fmt->depth) >> > 3; > > + ctx->updated |= S5P_FIMC_PARAMS; > > + src_vq->field = dst_vq->field = pix->field; > > + dbg("f_width= %d, f_height= %d", frame->f_width, frame- > >f_height); > > + > > +s_fmt_out: > > + mutex_unlock(&dst_vq->vb_lock); > > + mutex_unlock(&src_vq->vb_lock); > > + mutex_unlock(&ctx->lock); > > + return ret; > > +} > > + > > +static int s5p_fimc_reqbufs(struct file *file, void *priv, > > + struct v4l2_requestbuffers *reqbufs) > > +{ > > + struct fimc_ctx *ctx = priv; > > + return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); > > +} > > + > > +static int s5p_fimc_querybuf(struct file *file, void *priv, > > + struct v4l2_buffer *buf) > > +{ > > + struct fimc_ctx *ctx = priv; > > + return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); > > +} > > + > > +static int s5p_fimc_qbuf(struct file *file, void *priv, > > + struct v4l2_buffer *buf) > > +{ > > + struct fimc_ctx *ctx = priv; > > + return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); > > +} > > + > > +static int s5p_fimc_dqbuf(struct file *file, void *priv, > > + struct v4l2_buffer *buf) > > +{ > > + struct fimc_ctx *ctx = priv; > > + return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); > > +} > > + > > +static int s5p_fimc_streamon(struct file *file, void *priv, > > + enum v4l2_buf_type type) > > +{ > > + struct fimc_ctx *ctx = priv; > > + return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); > > +} > > + > > +static int s5p_fimc_streamoff(struct file *file, void *priv, > > + enum v4l2_buf_type type) > > +{ > > + struct fimc_ctx *ctx = priv; > > + return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); > > +} > > + > > +static int s5p_fimc_queryctrl(struct file *file, void *priv, > > + struct v4l2_queryctrl *qc) > > +{ > > + struct v4l2_queryctrl *c; > > + c = get_ctrl(qc->id); > > + if (!c) > > + return -EINVAL; > > + *qc = *c; > > + return 0; > > +} > > + > > +static int s5p_fimc_g_ctrl(struct file *file, void *priv, > > + struct v4l2_control *ctrl) > > +{ > > + struct fimc_ctx *ctx = priv; > > + > > + switch (ctrl->id) { > > + case V4L2_CID_HFLIP: > > + ctrl->value = (FLIP_X_AXIS & ctx->flip) ? 1 : 0; > > + break; > > + case V4L2_CID_VFLIP: > > + ctrl->value = (FLIP_Y_AXIS & ctx->flip) ? 1 : 0; > > + break; > > + case V4L2_CID_ROTATE: > > + ctrl->value = ctx->rotation; > > + break; > > + default: > > + v4l2_err(&ctx->fimc_dev->v4l2_dev, "Invalid control\n"); > > + return -EINVAL; > > + } > > + dbg("ctrl->value= %d", ctrl->value); > > + return 0; > > +} > > + > > +static int check_ctrl_val(struct fimc_ctx *ctx, > > + struct v4l2_control *ctrl) > > +{ > > + struct v4l2_queryctrl *c; > > + c = get_ctrl(ctrl->id); > > + if (!c) > > + return -EINVAL; > > + > > + if (ctrl->value < c->minimum || ctrl->value > c->maximum > > + || (c->step != 0 && ctrl->value % c->step != 0)) { > > + v4l2_err(&ctx->fimc_dev->v4l2_dev, "Invalid control > value\n"); > > + return -ERANGE; > > + } > > + > > + return 0; > > +} > > + > > +static int s5p_fimc_s_ctrl(struct file *file, void *priv, > > + struct v4l2_control *ctrl) > > +{ > > + struct fimc_ctx *ctx = priv; > > + struct s5p_platform_fimc *pldata = ctx->fimc_dev->pldata; > > + int ret = 0; > > + > > + ret = check_ctrl_val(ctx, ctrl); > > + if (ret != 0) > > + return ret; > > + > > + > > + switch (ctrl->id) { > > + case V4L2_CID_HFLIP: > > + if (ctrl->value) > > + ctx->flip |= FLIP_X_AXIS; > > + else > > + ctx->flip &= ~FLIP_X_AXIS; > > + break; > > + > > + case V4L2_CID_VFLIP: > > + if (ctrl->value) > > + ctx->flip |= FLIP_Y_AXIS; > > + else > > + ctx->flip &= ~FLIP_Y_AXIS; > > + break; > > + > > + case V4L2_CID_ROTATE: > > + if (90 == ctrl->value || 270 == ctrl->value) { > > + /* use input rotator in LCDFIFO output mode only */ > > + if (S5P_FIMC_LCDFIFO == ctx->out_path) { > > + if (!(pldata->capability & S5P_FIMC_IN_ROT)) > > + return -EINVAL; > > + } /* in DMA/ out DMA case */ > > + else if (S5P_FIMC_DMA == ctx->in_path && > > + !(pldata->capability & S5P_FIMC_OUT_ROT)) > > + return -EINVAL; > > + } > > + > > + ctx->rotation = ctrl->value; > > + if (180 == ctrl->value) > > + ctx->flip = FLIP_XY_AXIS; > > + break; > > + > > + default: > > + v4l2_err(&ctx->fimc_dev->v4l2_dev, "Invalid control\n"); > > + return -EINVAL; > > + } > > + > > + ctx->updated |= S5P_FIMC_PARAMS; > > + return 0; > > +} > > + > > + > > +static int s5p_fimc_cropcap(struct file *file, void *fh, > > + struct v4l2_cropcap *cr) > > +{ > > + struct fimc_frame *frame; > > + struct fimc_ctx *ctx = fh; > > + if (!ctx) { > > + WARN_ON(1); > > + return -ENOENT; > > + } > > + > > + ctx_get_frame(frame, ctx, cr->type); > > + > > + cr->bounds.left = 0; > > + cr->bounds.top = 0; > > + cr->bounds.width = frame->f_width; > > + cr->bounds.height = frame->f_height; > > + cr->defrect.left = frame->offs_h; > > + cr->defrect.top = frame->offs_v; > > + cr->defrect.width = frame->o_width; > > + cr->defrect.height = frame->o_height; > > + return 0; > > +} > > + > > +static int s5p_fimc_g_crop(struct file *file, void *fh, struct > v4l2_crop *cr) > > +{ > > + struct fimc_frame *frame; > > + struct fimc_ctx *ctx = file->private_data; > > + > > + if (!ctx) { > > + WARN_ON(1); > > + return -ENOENT; > > + } > > + > > + ctx_get_frame(frame, ctx, cr->type); > > + > > + cr->c.left = frame->offs_h; > > + cr->c.top = frame->offs_v; > > + cr->c.width = frame->width; > > + cr->c.height = frame->height; > > + > > + return 0; > > +} > > + > > +static int s5p_fimc_s_crop(struct file *file, void *fh, struct > v4l2_crop *cr) > > +{ > > + struct fimc_frame *f; > > + struct fimc_ctx *ctx = file->private_data; > > + struct fimc_dev *dev = ctx->fimc_dev; > > + > > + if (cr->c.top < 0 || cr->c.left < 0) { > > + v4l2_err(&dev->v4l2_dev, > > + "doesn't support negative values for top & left\n"); > > + return -EINVAL; > > + } > > + > > + ctx_get_frame(f, ctx, cr->type); > > + > > + dbg("%d %d %d %d f_w= %d, f_h= %d", > > + cr->c.left, cr->c.top, cr->c.width, cr->c.height, > > + f->f_width, f->f_height); > > + > > + /* adjust to pixel boundary */ > > + cr->c.width = cr->c.width & ~PIX_ALIGN_MASK; > > + cr->c.height = cr->c.height & ~PIX_ALIGN_MASK; > > + if (0 == cr->c.width) > > + cr->c.width = DMA_MIN_SIZE; > > + if (0 == cr->c.height) > > + cr->c.height = DMA_MIN_SIZE; > > + cr->c.left = ((cr->c.left + PIX_ALIGN_MASK - 1) & > ~PIX_ALIGN_MASK); > > + cr->c.top = ((cr->c.top + PIX_ALIGN_MASK - 1) & ~PIX_ALIGN_MASK); > > + > > + if ((cr->c.left + cr->c.width > f->o_width) > > + || (cr->c.top + cr->c.height > f->o_height)) { > > + v4l2_err(&dev->v4l2_dev, "Error in S_CROP params\n"); > > + dbg("%d %d %d %d. %d %d", > > + cr->c.left, cr->c.top, cr->c.width, cr->c.height, > > + f->o_width, f->o_height); > > + return -EINVAL; > > + } > > + > > + /* check for the pixel scaling ratio when cropping input image */ > > + if (V4L2_BUF_TYPE_VIDEO_OUTPUT == cr->type) { > > + if (f->width > (SCALER_MAX_HRATIO*ctx->d_frame.width) || > > + f->height > (SCALER_MAX_VRATIO*ctx->d_frame.height)) > { > > + v4l2_err(&dev->v4l2_dev, "Out of the scaler range"); > > + return -EINVAL; > > + } > > + } > > + > > + f->offs_h = cr->c.left; > > + f->offs_v = cr->c.top; > > + f->width = cr->c.width; > > + f->height = cr->c.height; > > + return 0; > > +} > > + > > +static const struct v4l2_ioctl_ops s5p_fimc_ioctl_ops = { > > + .vidioc_querycap = s5p_fimc_querycap, > > + > > + .vidioc_enum_fmt_vid_cap = s5p_fimc_enum_fmt, > > + .vidioc_enum_fmt_vid_out = s5p_fimc_enum_fmt, > > + > > + .vidioc_g_fmt_vid_cap = s5p_fimc_g_fmt, > > + .vidioc_g_fmt_vid_out = s5p_fimc_g_fmt, > > + > > + .vidioc_try_fmt_vid_cap = s5p_fimc_try_fmt, > > + .vidioc_try_fmt_vid_out = s5p_fimc_try_fmt, > > + > > + .vidioc_s_fmt_vid_cap = s5p_fimc_s_fmt, > > + .vidioc_s_fmt_vid_out = s5p_fimc_s_fmt, > > + > > + .vidioc_reqbufs = s5p_fimc_reqbufs, > > + .vidioc_querybuf = s5p_fimc_querybuf, > > + > > + .vidioc_qbuf = s5p_fimc_qbuf, > > + .vidioc_dqbuf = s5p_fimc_dqbuf, > > + > > + .vidioc_streamon = s5p_fimc_streamon, > > + .vidioc_streamoff = s5p_fimc_streamoff, > > + > > + .vidioc_queryctrl = s5p_fimc_queryctrl, > > + .vidioc_g_ctrl = s5p_fimc_g_ctrl, > > + .vidioc_s_ctrl = s5p_fimc_s_ctrl, > > + > > + .vidioc_g_crop = s5p_fimc_g_crop, > > + .vidioc_s_crop = s5p_fimc_s_crop, > > + .vidioc_cropcap = s5p_fimc_cropcap > > + > > +}; > > + > > +static void queue_init(void *priv, struct videobuf_queue *vq, > > + enum v4l2_buf_type type) > > +{ > > + struct fimc_ctx *ctx = priv; > > + struct fimc_dev *dev = ctx->fimc_dev; > > + > > + videobuf_queue_dma_contig_init(vq, &s5p_fimc_qops, dev- > >v4l2_dev.dev, > > + &dev->irqlock, type, V4L2_FIELD_NONE, > > + sizeof(struct fimc_vid_buffer), priv); > > +} > > + > > +static int s5p_fimc_open(struct file *file) > > +{ > > + struct fimc_dev *dev = video_drvdata(file); > > + struct fimc_ctx *ctx = NULL; > > + int err; > > + > > + ctx = kzalloc(sizeof *ctx, GFP_KERNEL); > > + if (!ctx) > > + return -ENOMEM; > > + > > + file->private_data = ctx; > > + ctx->fimc_dev = dev; > > + /* default format */ > > + ctx->s_frame.fmt = &formats[0]; > > + ctx->d_frame.fmt = &formats[0]; > > + /* per user process device context initialization */ > > + ctx->updated = 0; > > + ctx->effect.type = S5P_FIMC_EFFECT_ORIGINAL; > > + ctx->flags = 0; > > + ctx->in_path = S5P_FIMC_DMA; > > + ctx->out_path = S5P_FIMC_DMA; > > + mutex_init(&ctx->lock); > > + > > + ctx->m2m_ctx = v4l2_m2m_ctx_init(ctx, dev->m2m_dev, queue_init); > > + > > + if (IS_ERR(ctx->m2m_ctx)) { > > + err = PTR_ERR(ctx->m2m_ctx); > > + kfree(ctx); > > + return err; > > + } > > + > > + return 0; > > +} > > + > > +static int s5p_fimc_release(struct file *file) > > +{ > > + struct fimc_ctx *ctx = > > + (struct fimc_ctx *)file->private_data; > > + > > + v4l2_m2m_ctx_release(ctx->m2m_ctx); > > + kfree(ctx); > > + return 0; > > +} > > + > > +static unsigned int s5p_fimc_poll(struct file *file, > > + struct poll_table_struct *wait) > > +{ > > + struct fimc_ctx *ctx = file->private_data; > > + return v4l2_m2m_poll(file, ctx->m2m_ctx, wait); > > +} > > + > > + > > +static int s5p_fimc_mmap(struct file *file, struct vm_area_struct > *vma) > > +{ > > + struct fimc_ctx *ctx = file->private_data; > > + return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); > > +} > > + > > +static const struct v4l2_file_operations s5p_fimc_fops = { > > + .owner = THIS_MODULE, > > + .open = s5p_fimc_open, > > + .release = s5p_fimc_release, > > + .poll = s5p_fimc_poll, > > + .ioctl = video_ioctl2, > > + .mmap = s5p_fimc_mmap, > > +}; > > + > > +static struct v4l2_m2m_ops m2m_ops = { > > + .device_run = s5p_fimc_dma_run, > > + .job_abort = s5p_fimc_job_abort, > > +}; > > + > > + > > +static int s5p_fimc_probe(struct platform_device *pdev) > > +{ > > + struct resource *res; > > + struct video_device *vfd; > > + struct fimc_dev *dev; > > + int ret = 0; > > + struct clk *srclk; > > + > > + dev_dbg(&pdev->dev, "probe\n"); > > + > > + if (NULL == pdev->dev.platform_data) { > > + dev_err(&pdev->dev, "platform_data is not set\n"); > > + return -ENOENT; > > + } > > + > > + dev = kzalloc(sizeof(struct fimc_dev), GFP_KERNEL); > > + if (!dev) > > + return -ENOMEM; > > + > > + dev->id = pdev->id; > > + dev->pdev = pdev; > > + dev->pldata = pdev->dev.platform_data; > > + > > + spin_lock_init(&dev->irqlock); > > + > > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > > + if (!res) { > > + dev_err(&pdev->dev, "failed to find the registers\n"); > > + ret = -ENOENT; > > + goto err_info; > > + } > > + > > + dev->regs_res = request_mem_region(res->start, > resource_size(res), > > + dev_name(&pdev->dev)); > > + if (!dev->regs_res) { > > + dev_err(&pdev->dev, "failed to obtain register region\n"); > > + ret = -ENOENT; > > + goto err_info; > > + } > > + > > + dev->regs = ioremap(res->start, resource_size(res)); > > + if (!dev->regs) { > > + dev_err(&pdev->dev, "failed to map registers\n"); > > + ret = -ENXIO; > > + goto err_req_region; > > + } > > + > > + /* FIMC parent clock */ > > + srclk = clk_get(&pdev->dev, dev->pldata->srclk_name); > > + if (IS_ERR(srclk)) { > > + dev_err(&pdev->dev, "failed to get source clock of > fimc\n"); > > + goto err_regs_unmap; > > + } > > you don't seem to clk_put this if the call exits normally? Thanks for pointing this out, that's my oversight. I consider moving all this clock selection code, except clk_enable/disable to the platform's machine_init(). Would it the right direction? > > > + /* FIMC clock */ > > + dev->clock = clk_get(&pdev->dev, "fimc"); > > + if (IS_ERR(dev->clock)) { > > + dev_err(&pdev->dev, "failed to get fimc clock source\n"); > > + goto err_clk2; > > + } > > + > > + ret = clk_set_parent(dev->clock, srclk); > > + if (ret) > > + goto err_clk; > > + > > + /* set FIMC local clock rate */ > > + clk_set_rate(dev->clock, dev->pldata->clockrate); > > + clk_enable(dev->clock); > > + > > + /* IRQ */ > > + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); > > + if (res == NULL) { > > + dev_err(&pdev->dev, "failed to get IRQ resource\n"); > > + ret = -ENXIO; > > + goto err_clk; > > + } > > + dev->irq = res->start; > > + > > + s5p_fimc_reset(dev); > > + > > + ret = request_irq(dev->irq, s5p_fimc_isr, 0, pdev->name, dev); > > + if (ret != 0) { > > + dev_err(&pdev->dev, "failed to install irq (%d)\n", ret); > > + goto err_clk; > > + } > > + > > + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); > > + if (ret) > > + goto err_irq; > > + > > + vfd = video_device_alloc(); > > + if (!vfd) { > > + v4l2_err(&dev->v4l2_dev, "Failed to allocate video > device\n"); > > + goto err_unreg_dev; > > + } > > + > > + if ((u32)dev->id >= MAX_FIMC_DEVICES) > > + goto err_unreg_dev; > > + > > + vfd->fops = &s5p_fimc_fops; > > + vfd->ioctl_ops = &s5p_fimc_ioctl_ops; > > + vfd->minor = -1; > > + vfd->release = video_device_release; > > + > > + snprintf(vfd->name, sizeof(vfd->name), "%s%d", MODULE_NAME, dev- > >id); > > + > > + ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); > > + if (ret) { > > + v4l2_err(&dev->v4l2_dev, "Failed to register video > device\n"); > > + goto err_rel_vdev; > > + } > > + video_set_drvdata(vfd, dev); > > + dev->vfd = vfd; > > + v4l2_info(&dev->v4l2_dev, "Device registered as /dev/video%d\n", > > + vfd->num); > > + > > + platform_set_drvdata(pdev, dev); > > + dev->m2m_dev = v4l2_m2m_init(&m2m_ops); > > + if (IS_ERR(dev->m2m_dev)) { > > + v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem > device\n"); > > + ret = PTR_ERR(dev->m2m_dev); > > + goto err_m2m; > > + } > > + > > + s5p_fimc_en_lastirq(dev, 1); > > + > > + dev_dbg(&pdev->dev, "installation successful\n"); > > + return 0; > > + > > +err_m2m: > > + video_unregister_device(dev->vfd); > > +err_rel_vdev: > > + video_device_release(vfd); > > +err_unreg_dev: > > + v4l2_device_unregister(&dev->v4l2_dev); > > +err_irq: > > + free_irq(dev->irq, dev); > > +err_clk: > > + clk_disable(dev->clock); > > + clk_put(dev->clock); > > +err_clk2: > > + clk_put(srclk); > > +err_regs_unmap: > > + iounmap(dev->regs); > > +err_req_region: > > + release_resource(dev->regs_res); > > + kfree(dev->regs_res); > > +err_info: > > + dev_err(&pdev->dev, "failed to install\n"); > > + return ret; > > +} > > + > > +static int __devexit s5p_fimc_remove(struct platform_device *pdev) > > +{ > > + struct fimc_dev *dev = > > + (struct fimc_dev *)platform_get_drvdata(pdev); > > no need to cast. obviously... > > > + v4l2_info(&dev->v4l2_dev, "Removing %s\n", pdev->name); > > + > > + free_irq(dev->irq, dev); > > + > > + s5p_fimc_reset(dev); > > + v4l2_m2m_release(dev->m2m_dev); > > + video_unregister_device(dev->vfd); > > + v4l2_device_unregister(&dev->v4l2_dev); > > + > > + iounmap(dev->regs); > > + release_resource(dev->regs_res); > > + kfree(dev->regs_res); > > + kfree(dev); > > + return 0; > > +} > > + > > +static int s5p_fimc_suspend(struct device *dev) > > +{ > > + return 0; > > +} > > + > > +static int s5p_fimc_resume(struct device *dev) > > +{ > > + return 0; > > +} > > + > > +static const struct dev_pm_ops s5p_fimc_pm_ops = { > > + .suspend = s5p_fimc_suspend, > > + .resume = s5p_fimc_resume, > > +}; > > > given these are null ops, is this really a good idea including > the pm ops? agreed, I will clean this up, until I really get the pm ops implemented > > +static struct platform_driver s5p_fimc_driver = { > > + .probe = s5p_fimc_probe, > > + .remove = __devexit_p(s5p_fimc_remove), > > + .driver = { > > + .name = "s5p-fimc", > > + .owner = THIS_MODULE, > > + .pm = &s5p_fimc_pm_ops > > + } > > +}; > > + > > +static char banner[] __initdata = KERN_INFO \ > > + "S5PC Camera Interface V4L2 Driver, (c) 2010 Samsung > Electronics\n"; > > + > > +static int __init s5p_fimc_init(void) > > +{ > > + u32 ret; > > + printk(banner); > > + > > + ret = platform_driver_register(&s5p_fimc_driver); > > + if (ret != 0) { > > + printk(KERN_ERR "FIMC platform driver register failed\n"); > > + return -1; > > + } > > + return 0; > > +} > > + > > +static void __exit s5p_fimc_exit(void) > > +{ > > + platform_driver_unregister(&s5p_fimc_driver); > > +} > > + > > +module_init(s5p_fimc_init); > > +module_exit(s5p_fimc_exit); > > + > > +MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@xxxxxxxxxxx>"); > > +MODULE_DESCRIPTION("S5PV210 FIMC (video postprocessor) driver"); > > +MODULE_LICENSE("GPL"); > > + > > diff --git a/drivers/media/video/samsung-fimc/s5p_fimc.h > b/drivers/media/video/samsung-fimc/s5p_fimc.h > > new file mode 100644 > > index 0000000..f4485a8 > > --- /dev/null > > +++ b/drivers/media/video/samsung-fimc/s5p_fimc.h > > @@ -0,0 +1,331 @@ > > +/* > > + * drivers/media/video/samsung-fimc/s5p_fimc.h > > + * > > + * Copyright (c) 2010 Samsung Electronics > > + * > > + * Sylwester Nawrocki, s.nawrocki@xxxxxxxxxxx > > + * > > + * This program is free software; you can redistribute it and/or > modify > > + * it under the terms of the GNU General Public License version 2 as > > + * published by the Free Software Foundation. > > + */ > > + > > +#ifndef S5P_FIMC_H_ > > +#define S5P_FIMC_H_ > > + > > +#include <linux/types.h> > > +#include <plat/fimc.h> > > +#include <media/videobuf-core.h> > > +#include <media/v4l2-device.h> > > +#include <media/v4l2-mem2mem.h> > > +#include <linux/videodev2.h> > > + > > + > > +#define err(fmt, args...) \ > > + printk(KERN_ERR "%s:%d: " fmt "\n", __func__, __LINE__, ##args) > > + > > +#ifdef DEBUG > > +#define dbg(fmt, args...) \ > > + printk(KERN_DEBUG "%s:%d: " fmt "\n", __func__, __LINE__, ##args) > > +#else > > +#define dbg(fmt, args...) > > +#endif > > + > > +#define MODULE_NAME "s5p-fimc" > > +#define MAX_FIMC_DEVICES 3 > > +#define S5P_FIMC_MAX_FRAMES 4 > > +#define DMA_MIN_SIZE 16 > > +#define SCALER_MAX_HRATIO 64 > > +#define SCALER_MAX_VRATIO 64 > > +#define PIX_ALIGN_MASK (DMA_MIN_SIZE - 1) > > + > > +#define S5P_FIMC_CHANGED_NONE 0 > > +#define S5P_FIMC_PARAMS (1 << 0) > > +#define S5P_FIMC_SRC_ADDR (1 << 1) > > +#define S5P_FIMC_DST_ADDR (1 << 2) > > + > > + > > +enum fimc_datapath { > > + S5P_FIMC_ITU_CAM_A, > > + S5P_FIMC_ITU_CAM_B, > > + S5P_FIMC_MIPI_CAM, > > + S5P_FIMC_DMA, > > + S5P_FIMC_LCDFIFO, > > + S5P_FIMC_WRITEBACK > > +}; > > + > > +enum fimc_color_fmt { > > + S5P_FIMC_RGB565, > > + S5P_FIMC_RGB666, > > + S5P_FIMC_RGB888, > > + S5P_FIMC_YCBCR420, > > + S5P_FIMC_YCBCR422, > > + S5P_FIMC_YCBYCR422, > > + S5P_FIMC_YCRYCB422, > > + S5P_FIMC_CBYCRY422, > > + S5P_FIMC_CRYCBY422, > > + S5P_FIMC_RGB30_LOCAL, > > + S5P_FIMC_YCBCR444_LOCAL, > > + S5P_FIMC_MAX_COLOR = S5P_FIMC_YCBCR444_LOCAL, > > + S5P_FIMC_COLOR_MASK = 0x0F, > > +}; > > + > > +/* Y/Cb/Cr components order at DMA output for 1 plane YCbCr 4:2:2 > formats */ > > +#define S5P_FIMC_OUT_CRYCBY S5P_CIOCTRL_ORDER422_CRYCBY > > +#define S5P_FIMC_OUT_CBYCRY S5P_CIOCTRL_ORDER422_YCRYCB > > +#define S5P_FIMC_OUT_YCRYCB S5P_CIOCTRL_ORDER422_CBYCRY > > +#define S5P_FIMC_OUT_YCBYCR S5P_CIOCTRL_ORDER422_YCBYCR > > + > > +/* Input Y/Cb/Cr components order for 1 plane YCbCr 4:2:2 color > formats */ > > +#define S5P_FIMC_IN_CRYCBY S5P_MSCTRL_ORDER422_CRYCBY > > +#define S5P_FIMC_IN_CBYCRY S5P_MSCTRL_ORDER422_YCRYCB > > +#define S5P_FIMC_IN_YCRYCB S5P_MSCTRL_ORDER422_CBYCRY > > +#define S5P_FIMC_IN_YCBYCR S5P_MSCTRL_ORDER422_YCBYCR > > + > > +/* Cb/Cr chrominance components order for 2 plane Y/CbCr 4:2:2 > formats */ > > +#define S5P_FIMC_LSB_CRCB S5P_CIOCTRL_ORDER422_2P_LSB_CRCB > > + > > +/* The embedded image effect selection */ > > +#define S5P_FIMC_EFFECT_ORIGINAL S5P_CIIMGEFF_FIN_BYPASS > > +#define S5P_FIMC_EFFECT_ARBITRARY S5P_CIIMGEFF_FIN_ARBITRARY > > +#define S5P_FIMC_EFFECT_NEGATIVE S5P_CIIMGEFF_FIN_NEGATIVE > > +#define S5P_FIMC_EFFECT_ARTFREEZE S5P_CIIMGEFF_FIN_ARTFREEZE > > +#define S5P_FIMC_EFFECT_EMBOSSING S5P_CIIMGEFF_FIN_EMBOSSING > > +#define S5P_FIMC_EFFECT_SIKHOUETTE S5P_CIIMGEFF_FIN_SILHOUETTE > > + > > + > > +/* Definitions for flags field in struct fimc_ctx */ > > +#define IN_DMA_ACCESS_LINEAR 0 /* default */ > > +#define IN_DMA_ACCESS_TILED (1 << 0) > > +#define OUT_DMA_ACCESS_LINEAR (0 << 1) > > +#define OUT_DMA_ACCESS_TILED (1 << 1) > > +#define SCAN_MODE_PROGRESSIVE (0 << 2) > > +#define SCAN_MODE_INTERLACED (1 << 2) > > +/* YCbCr data dynamic range selection for the RGB <-> YCBCR color > space > > + * conversion. Y/Cb/Cr (0 ~ 255) : Wide default */ > > +#define S5P_FIMC_COLOR_RANGE_WIDE (0 << 3) > > +/* Y (16 ~ 235), Cb/Cr (16 ~ 240) : Narrow */ > > +#define S5P_FIMC_COLOR_RANGE_NARROW (1 << 3) > > + > > +#define FLIP_ORIGINAL 0 > > +#define FLIP_X_AXIS 0x01 > > +#define FLIP_Y_AXIS 0x02 > > +#define FLIP_XY_AXIS (FLIP_X_AXIS | FLIP_Y_AXIS) > > + > > +/** > > + * struct fimc_dma_offset > > + * @y_h: y value horizontal offset > > + * @y_v: y value vertical offset > > + * @cb_h: cb value horizontal offset > > + * @cb_v: cb value vertical offset > > + * @cr_h: cr value horizontal offset > > + * @cr_v: cr value vertical offset > > + */ > > +struct fimc_dma_offset { > > + int y_h; > > + int y_v; > > + int cb_h; > > + int cb_v; > > + int cr_h; > > + int cr_v; > > +}; > > + > > +/** > > + * struct s5p_fimc_effect > > + * @type: effect type > > + * @pat_cb: cr value when type is "arbitrary" > > + * @pat_cr: cr value when type is "arbitrary" > > + */ > > +struct fimc_effect { > > + u32 type; > > + u8 pat_cb; > > + u8 pat_cr; > > +}; > > + > > +/** > > + * struct fimc_scaler > > + * @enabled: flag indicating whether the scaler is used or > not > > + * @hfactor: horizontal shift factor > > + * @vfactor: vertical shift factor > > + * @pre_hratio: prescaler horizontal ratio > > + * @pre_vratio: prescaler vertical ratio > > + * @pre_dst_width: prescaler destination width > > + * @pre_dst_height: pre-scaler destination height > > + * @scaleup_h: flag indicating scaling up horizontally > > + * @scaleup_v: flag indicating scaling up vertically > > + * @main_hratio: main scaler horizontal ratio > > + * @main_vratio: main scaler vertical ratio > > + * @real_width: src_width - offset > > + * @real_height: src_height - offset > > + * @copy_mode: flag indicating one to one mode, i.e. no > scaling > > + * and color format conversion > > + */ > > +struct fimc_scaler { > > + u32 enabled; > > + u32 hfactor; > > + u32 vfactor; > > + u32 pre_hratio; > > + u32 pre_vratio; > > + u32 pre_dst_width; > > + u32 pre_dst_height; > > + u32 scaleup_h; > > + u32 scaleup_v; > > + u32 main_hratio; > > + u32 main_vratio; > > + u32 real_width; > > + u32 real_height; > > + u32 copy_mode; > > +}; > > + > > +/** > > + * struct fimc_frame - input/output frame format properties > > + * @f_width: image full width (virtual screen size) > > + * @f_height: image full height (virtual screen size) > > + * @o_width: original image width as set by S_FMT > > + * @o_height: original image height as set by S_FMT > > + * @offs_h: image horizontal pixel offset > > + * @offs_v: image vertical pixel offset > > + * @width: image pixel width > > + * @height: image pixel weight > > + * @addr_y: RGB/Y physical address > > + * @addr_cb: CB physical address > > + * @addr_cr: CR physical addres > > + * @buf_cnt: number of buffers depending on a color format > > + * @size: image size in bytes > > + * @color: color format > > + * @dma_offset: DMA offset in bytes > > + */ > > +struct fimc_frame { > > + u32 f_width; > > + u32 f_height; > > + u32 o_width; > > + u32 o_height; > > + u32 offs_h; > > + u32 offs_v; > > + u32 width; > > + u32 height; > > + u32 addr_y; > > + u32 addr_cb; > > + u32 addr_cr; > > + u32 size; > > + struct fimc_dma_offset dma_offset; > > + struct s5p_fimc_fmt *fmt; > > +}; > > + > > + > > +struct fimc_vid_buffer { > > + struct videobuf_buffer vb; > > + int index; > > +}; > > + > > +struct s5p_fimc_fmt { > > + char *name; > > + u32 fourcc; > > + u32 color; > > + u32 depth; > > + /* Number of data planes used */ > > + u16 buff_cnt; > > + u16 planes_cnt; > > +}; > > + > > +struct fimc_ctx; > > + > > +/** > > + * struct fimc_subdev: abstraction for a FIMC entity > > + * @pdev: a pointer to the FIMC platform device > > + * @pldata: a pointer to the device platform data > > + * @id: the FIMC device index (0..2) > > + * @clock: > > + * @regs: > > + * @regs_res: > > + * @mem_res: > > + * @irq: interrupt number of the FIMC subdevice > > + * @irqlock: spinlock protecting videbuffer queue > > + * @timer: > > + * @vfd: > > + * @v4l2_dev: > > + * @m2m_dev: > > + */ > > +struct fimc_dev { > > + struct platform_device *pdev; > > + struct s5p_platform_fimc *pldata; > > + int id; > > + struct clk *clock; > > + void __iomem *regs; > > + struct resource *regs_res; > > + struct resource *mem_res; > > + int irq; > > + spinlock_t irqlock; > > + struct video_device *vfd; > > + struct v4l2_device v4l2_dev; > > + struct v4l2_m2m_dev *m2m_dev; > > +}; > > + > > + > > +/** > > + * fimc_ctx - the device context data structure > > + * @lock: mutex protecting the context data > > + * @s_frame: source frame properties > > + * @d_frame: destination frame properties > > + * @osd: osd (output) window parameters > > + * @out_order_1p: output 1-plane YCBCR order > > + * @out_order_2p: output 2-plane YCBCR order > > + * @in_order_1p input 1-plane YCBCR order > > + * @in_order_2p: input 2-plane YCBCR order > > + * @in_path: input mode > > + * @out_path: output mode > > + * @scaler: image scaler properties > > + * @effect: image effect > > + * @rotation: image clockwise rotation in degrees > > + * @flip: image flip mode > > + * @flags: device state flags > > + * @updated: flags variable to keep track of user > configurable > > + * parameters (ioctl) > > + * @fimc_dev: fimc device related to the context > > + * @m2m_ctx: memory-to-memory device context > > + */ > > +struct fimc_ctx { > > + spinlock_t slock; > > + struct mutex lock; > > + struct fimc_frame s_frame; > > + struct fimc_frame d_frame; > > + u32 out_order_1p; > > + u32 out_order_2p; > > + u32 in_order_1p; > > + u32 in_order_2p; > > + enum fimc_datapath in_path; > > + enum fimc_datapath out_path; > > + struct fimc_scaler scaler; > > + struct fimc_effect effect; > > + int rotation; > > + u32 flip; > > + u32 flags; > > + u32 updated; > > + struct fimc_dev *fimc_dev; > > + struct v4l2_m2m_ctx *m2m_ctx; > > +}; > > + > > +int s5p_fimc_set_scaler_info(struct fimc_ctx *ctx); > > +int s5p_fimc_check_fifo(struct fimc_dev *dev); > > +void s5p_fimc_reset(struct fimc_dev *dev); > > +void s5p_fimc_set_target_format(struct fimc_ctx *ctx); > > +void s5p_fimc_set_out_dma(struct fimc_ctx *ctx); > > +void s5p_fimc_en_lastirq(struct fimc_dev *dev, int enable); > > +void s5p_fimc_en_irq(struct fimc_dev *dev, int enable); > > +void s5p_fimc_en_autoload(struct fimc_ctx *ctx, int enable); > > +void s5p_fimc_set_prescaler(struct fimc_ctx *ctx); > > +void s5p_fimc_set_scaler(struct fimc_ctx *ctx); > > +void s5p_fimc_start_scaler(struct fimc_ctx *ctx); > > +void s5p_fimc_stop_scaler(struct fimc_ctx *ctx); > > +void s5p_fimc_en_capture(struct fimc_ctx *ctx); > > +void s5p_fimc_dis_capture(struct fimc_ctx *ctx); > > +void s5p_fimc_set_effect(struct fimc_ctx *ctx); > > +void s5p_fimc_set_in_dma(struct fimc_ctx *ctx); > > +void s5p_fimc_start_in_dma(struct fimc_dev *dev); > > +void s5p_fimc_stop_in_dma(struct fimc_dev *dev); > > +void s5p_fimc_set_input_path(struct fimc_ctx *ctx); > > +void s5p_fimc_set_output_path(struct fimc_ctx *ctx); > > +void s5p_fimc_set_input_addr(struct fimc_ctx *ctx); > > +void s5p_fimc_set_output_addr(struct fimc_ctx *ctx); > > + > > +#endif /* S5P_FIMC_H_ */ > > diff --git a/drivers/media/video/samsung-fimc/s5p_fimc_reg.c > b/drivers/media/video/samsung-fimc/s5p_fimc_reg.c > > new file mode 100644 > > index 0000000..a6f719e > > --- /dev/null > > +++ b/drivers/media/video/samsung-fimc/s5p_fimc_reg.c > > @@ -0,0 +1,559 @@ > > +/* > > + * Register interface file for Samsung Camera Interface (FIMC) > driver > > + * > > + * Copyright (c) 2010 Samsung Electronics > > + * > > + * Sylwester Nawrocki, s.nawrocki@xxxxxxxxxxx > > + * > > + * This program is free software; you can redistribute it and/or > modify > > + * it under the terms of the GNU General Public License version 2 as > > + * published by the Free Software Foundation. > > +*/ > > + > > +#include <linux/io.h> > > +#include <linux/delay.h> > > +#include <mach/map.h> > > +#include <plat/regs-fimc.h> > > +#include <plat/fimc.h> > > +#include "s5p_fimc.h" > > + > > + > > +int s5p_fimc_check_fifo(struct fimc_dev *ctrl) > > +{ > > + u32 cfg, status; > > + > > + status = readl(ctrl->regs + S5P_CISTATUS); > > + > > + if ((S5P_CISTATUS_OVFIY | S5P_CISTATUS_OVFICB | > S5P_CISTATUS_OVFICR) > > + & status) { > > + cfg = readl(ctrl->regs + S5P_CIWDOFST); > > + cfg |= (S5P_CIWDOFST_CLROVFIY | S5P_CIWDOFST_CLROVFICB > > + | S5P_CIWDOFST_CLROVFICR); > > + writel(cfg, ctrl->regs + S5P_CIWDOFST); > > + > > + cfg = readl(ctrl->regs + S5P_CIWDOFST); > > + cfg &= ~(S5P_CIWDOFST_CLROVFIY | S5P_CIWDOFST_CLROVFICB > > + | S5P_CIWDOFST_CLROVFICR); > > + writel(cfg, ctrl->regs + S5P_CIWDOFST); > > + } > > + > > + return 0; > > +} > > + > > +void s5p_fimc_reset(struct fimc_dev *dev) > > +{ > > + u32 cfg; > > + > > + cfg = readl(dev->regs + S5P_CISRCFMT); > > + cfg |= S5P_CISRCFMT_ITU601_8BIT; > > + writel(cfg, dev->regs + S5P_CISRCFMT); > > + > > + /* sw reset */ > > + cfg = readl(dev->regs + S5P_CIGCTRL); > > + cfg |= (S5P_CIGCTRL_SWRST | S5P_CIGCTRL_IRQ_LEVEL); > > + writel(cfg, dev->regs + S5P_CIGCTRL); > > + mdelay(1); > > + > > + cfg = readl(dev->regs + S5P_CIGCTRL); > > + cfg &= ~S5P_CIGCTRL_SWRST; > > + writel(cfg, dev->regs + S5P_CIGCTRL); > > + > > +} > > + > > +static void s5p_fimc_set_rot90(struct fimc_ctx *ctx) > > +{ > > + struct fimc_dev *dev = ctx->fimc_dev; > > + u32 cfg = readl(dev->regs + S5P_CITRGFMT); > > + > > + cfg &= ~(S5P_CITRGFMT_INROT90_CLOCKWISE | > > + S5P_CITRGFMT_OUTROT90_CLOCKWISE); > > + > > + /* The input and output rotator cannot work simultaneously, > > + in input DMA mode only the output rotator shall be used. */ > > + if (ctx->out_path == S5P_FIMC_LCDFIFO) > > + cfg |= S5P_CITRGFMT_INROT90_CLOCKWISE; > > + else > > + cfg |= S5P_CITRGFMT_OUTROT90_CLOCKWISE; > > + > > + writel(cfg, dev->regs + S5P_CITRGFMT); > > +} > > + > > +static u32 s5p_fimc_get_in_flip(struct fimc_ctx *ctx) > > +{ > > + u32 flip = S5P_MSCTRL_FLIP_NORMAL; > > + > > + switch(ctx->flip) { > > + case FLIP_X_AXIS: > > + flip = S5P_MSCTRL_FLIP_X_MIRROR; > > + break; > > + case FLIP_Y_AXIS: > > + flip = S5P_MSCTRL_FLIP_Y_MIRROR; > > + break; > > + case FLIP_XY_AXIS: > > + flip = S5P_MSCTRL_FLIP_180; > > + break; > > + } > > + > > + return flip; > > +} > > + > > +static u32 s5p_fimc_get_target_flip(struct fimc_ctx *ctx) > > +{ > > + u32 flip = S5P_CITRGFMT_FLIP_NORMAL; > > + > > + switch(ctx->flip) { > > + case FLIP_X_AXIS: > > + flip = S5P_CITRGFMT_FLIP_X_MIRROR; > > + break; > > + case FLIP_Y_AXIS: > > + flip = S5P_CITRGFMT_FLIP_Y_MIRROR; > > + break; > > + case FLIP_XY_AXIS: > > + flip = S5P_CITRGFMT_FLIP_180; > > + break; > > + } > > + return flip; > > +} > > + > > +void s5p_fimc_set_target_format(struct fimc_ctx *ctx) > > +{ > > + u32 cfg = 0; > > + struct fimc_dev *dev = ctx->fimc_dev; > > + struct fimc_frame *frame = &ctx->d_frame; > > + > > + dbg("w= %d, h= %d color: %d", frame->width, > > + frame->height, frame->fmt->color); > > + > > + switch (frame->fmt->color) { > > + case S5P_FIMC_RGB565: > > + case S5P_FIMC_RGB666: > > + case S5P_FIMC_RGB888: > > + cfg |= S5P_CITRGFMT_OUTFORMAT_RGB; > > + break; > > + case S5P_FIMC_YCBCR420: > > + cfg |= S5P_CITRGFMT_OUTFORMAT_YCBCR420; > > + break; > > + case S5P_FIMC_YCBYCR422: > > + case S5P_FIMC_YCRYCB422: > > + case S5P_FIMC_CBYCRY422: > > + case S5P_FIMC_CRYCBY422: > > + if (frame->fmt->planes_cnt == 1) > > + cfg |= S5P_CITRGFMT_OUTFORMAT_YCBCR422_1PLANE; > > + else > > + cfg |= S5P_CITRGFMT_OUTFORMAT_YCBCR422; > > + break; > > + default: > > + break; > > + } > > + > > + cfg |= S5P_CITRGFMT_TARGETHSIZE(frame->width); > > + cfg |= S5P_CITRGFMT_TARGETVSIZE(frame->height); > > + cfg |= s5p_fimc_get_target_flip(ctx); > > + writel(cfg, dev->regs + S5P_CITRGFMT); > > + > > + if (90 == ctx->rotation || 270 == ctx->rotation) > > + s5p_fimc_set_rot90(ctx); > > + > > + cfg = S5P_CITAREA_TARGET_AREA(frame->width * frame->height); > > + writel(cfg, dev->regs + S5P_CITAREA); > > +} > > + > > +static void s5p_fimc_set_out_dma_size(struct fimc_ctx *ctx) > > +{ > > + struct fimc_dev *dev = ctx->fimc_dev; > > + struct fimc_frame *frame = &ctx->d_frame; > > + u32 cfg = 0; > > + > > + dbg("h= 0x%X w= 0x%X", frame->f_width, frame->f_height); > > + > > + if (90 == ctx->rotation || 270 == ctx->rotation) { > > + cfg |= S5P_ORGOSIZE_HORIZONTAL(frame->f_height); > > + cfg |= S5P_ORGOSIZE_VERTICAL(frame->f_width); > > + } else { > > + cfg |= S5P_ORGOSIZE_HORIZONTAL(frame->f_width); > > + cfg |= S5P_ORGOSIZE_VERTICAL(frame->f_height); > > + } > > + dbg("ORGOSIZE: 0x%X", cfg); > > + writel(cfg, dev->regs + S5P_ORGOSIZE); > > +} > > + > > +void s5p_fimc_set_out_dma(struct fimc_ctx *ctx) > > +{ > > + u32 cfg; > > + struct fimc_dev *dev = ctx->fimc_dev; > > + struct fimc_frame *frame = &ctx->d_frame; > > + struct fimc_dma_offset *offset = &frame->dma_offset; > > + > > + /* input dma offsets */ > > + cfg = 0; > > + cfg |= S5P_CIOYOFF_HORIZONTAL(offset->y_h); > > + cfg |= S5P_CIOYOFF_VERTICAL(offset->y_v); > > + writel(cfg, dev->regs + S5P_CIOYOFF); > > + > > + cfg = 0; > > + cfg |= S5P_CIOCBOFF_HORIZONTAL(offset->cb_h); > > + cfg |= S5P_CIOCBOFF_VERTICAL(offset->cb_v); > > + writel(cfg, dev->regs + S5P_CIOCBOFF); > > + > > + cfg = 0; > > + cfg |= S5P_CIOCROFF_HORIZONTAL(offset->cr_h); > > + cfg |= S5P_CIOCROFF_VERTICAL(offset->cr_v); > > + writel(cfg, dev->regs + S5P_CIOCROFF); > > + > > + s5p_fimc_set_out_dma_size(ctx); > > + > > + /* configure chroma components order */ > > + cfg = readl(dev->regs + S5P_CIOCTRL); > > + > > + cfg &= ~(S5P_CIOCTRL_ORDER2P_MASK | S5P_CIOCTRL_ORDER422_MASK | > > + S5P_CIOCTRL_YCBCR_PLANE_MASK); > > + > > + if (frame->fmt->planes_cnt == 1) > > + cfg |= ctx->out_order_1p; > > + else if (frame->fmt->planes_cnt == 2) > > + cfg |= ctx->out_order_2p | S5P_CIOCTRL_YCBCR_2PLANE; > > + else if (frame->fmt->planes_cnt == 3) > > + cfg |= S5P_CIOCTRL_YCBCR_3PLANE; > > + > > + writel(cfg, dev->regs + S5P_CIOCTRL); > > +} > > + > > +void s5p_fimc_en_autoload(struct fimc_ctx *ctx, int enable) > > +{ > > + struct fimc_dev *dev = ctx->fimc_dev; > > + u32 cfg = readl(dev->regs + S5P_ORGISIZE); > > + if (enable) > > + cfg |= S5P_CIREAL_ISIZE_AUTOLOAD_ENABLE; > > + else > > + cfg &= ~S5P_CIREAL_ISIZE_AUTOLOAD_ENABLE; > > + writel(cfg, dev->regs + S5P_ORGISIZE); > > +} > > + > > +void s5p_fimc_en_lastirq(struct fimc_dev *dev, int enable) > > +{ > > + unsigned long flags; > > + u32 cfg; > > + local_irq_save(flags); > > + > > + cfg = readl(dev->regs + S5P_CIOCTRL); > > + if (enable) > > + cfg |= S5P_CIOCTRL_LASTIRQ_ENABLE; > > + else > > + cfg &= ~S5P_CIOCTRL_LASTIRQ_ENABLE; > > + writel(cfg, dev->regs + S5P_CIOCTRL); > > + > > + local_irq_restore(flags); > > +} > > + > > +void s5p_fimc_set_prescaler(struct fimc_ctx *ctx) > > +{ > > + struct fimc_dev *dev = ctx->fimc_dev; > > + struct fimc_scaler *sc = &ctx->scaler; > > + u32 cfg = 0, shfactor; > > + > > + shfactor = 10 - (sc->hfactor + sc->vfactor); > > + > > + cfg |= S5P_CISCPRERATIO_SHFACTOR(shfactor); > > + cfg |= S5P_CISCPRERATIO_PREHORRATIO(sc->pre_hratio); > > + cfg |= S5P_CISCPRERATIO_PREVERRATIO(sc->pre_vratio); > > + > > + writel(cfg, dev->regs + S5P_CISCPRERATIO); > > + > > + cfg = 0; > > + cfg |= S5P_CISCPREDST_PREDSTWIDTH(sc->pre_dst_width); > > + cfg |= S5P_CISCPREDST_PREDSTHEIGHT(sc->pre_dst_height); > > + > > + writel(cfg, dev->regs + S5P_CISCPREDST); > > +} > > + > > +void s5p_fimc_set_scaler(struct fimc_ctx *ctx) > > +{ > > + struct fimc_dev *dev = ctx->fimc_dev; > > + struct fimc_scaler *sc = &ctx->scaler; > > + struct fimc_frame *src_frame = &ctx->s_frame; > > + struct fimc_frame *dst_frame = &ctx->d_frame; > > + u32 cfg; > > + > > + if (ctx->flags & S5P_FIMC_COLOR_RANGE_NARROW) > > + cfg = > (S5P_CISCCTRL_CSCR2Y_NARROW|S5P_CISCCTRL_CSCY2R_NARROW); > > + else > > + cfg = (S5P_CISCCTRL_CSCR2Y_WIDE|S5P_CISCCTRL_CSCY2R_WIDE); > > + > > + if (!sc->enabled) > > + cfg |= S5P_CISCCTRL_SCALERBYPASS; > > + > > + if (sc->scaleup_h) > > + cfg |= S5P_CISCCTRL_SCALEUP_H; > > + > > + if (sc->scaleup_v) > > + cfg |= S5P_CISCCTRL_SCALEUP_V; > > + > > + if (sc->copy_mode) > > + cfg |= S5P_CISCCTRL_ONE2ONE; > > + > > + > > + if (ctx->in_path == S5P_FIMC_DMA) { > > + if (src_frame->fmt->color == S5P_FIMC_RGB565) > > + cfg |= S5P_CISCCTRL_INRGB_FMT_RGB565; > > + else if (src_frame->fmt->color == S5P_FIMC_RGB666) > > + cfg |= S5P_CISCCTRL_INRGB_FMT_RGB666; > > + else if (src_frame->fmt->color == S5P_FIMC_RGB888) > > + cfg |= S5P_CISCCTRL_INRGB_FMT_RGB888; > > + } > > + > > + if (ctx->out_path == S5P_FIMC_DMA) { > > + if (dst_frame->fmt->color == S5P_FIMC_RGB565) > > + cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB565; > > + else if (dst_frame->fmt->color == S5P_FIMC_RGB666) > > + cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB666; > > + else if (dst_frame->fmt->color == S5P_FIMC_RGB888) > > + cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888; > > + } else { > > + cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888; > > + > > + if (ctx->flags&SCAN_MODE_INTERLACED) > > + cfg |= S5P_CISCCTRL_INTERLACE; > > + else > > + cfg |= S5P_CISCCTRL_PROGRESSIVE; > > + } > > + > > + dbg("main_hratio= 0x%X main_vratio= 0x%X", > > + sc->main_hratio, sc->main_vratio); > > + > > + cfg |= S5P_CISCCTRL_MAINHORRATIO(sc->main_hratio); > > + cfg |= S5P_CISCCTRL_MAINVERRATIO(sc->main_vratio); > > + > > + writel(cfg, dev->regs + S5P_CISCCTRL); > > +} > > + > > +void s5p_fimc_start_scaler(struct fimc_ctx *ctx) > > +{ > > + struct fimc_dev *dev = ctx->fimc_dev; > > + u32 cfg = readl(dev->regs + S5P_CISCCTRL); > > + > > + cfg |= S5P_CISCCTRL_SCALERSTART; > > + writel(cfg, dev->regs + S5P_CISCCTRL); > > +} > > + > > +void s5p_fimc_stop_scaler(struct fimc_ctx *ctx) > > +{ > > + struct fimc_dev *dev = ctx->fimc_dev; > > + u32 cfg = readl(dev->regs + S5P_CISCCTRL); > > + > > + cfg &= ~S5P_CISCCTRL_SCALERSTART; > > + writel(cfg, dev->regs + S5P_CISCCTRL); > > +} > > + > > +void s5p_fimc_en_capture(struct fimc_ctx *ctx) > > +{ > > + struct fimc_dev *dev = ctx->fimc_dev; > > + u32 cfg = readl(dev->regs + S5P_CIIMGCPT); > > + > > + if (S5P_FIMC_DMA == ctx->out_path) { > > + /* one shot mode */ > > + cfg |= S5P_CIIMGCPT_CPT_FREN_ENABLE | S5P_CIIMGCPT_IMGCPTEN > > + | S5P_CIIMGCPT_CPT_FRMOD_EN; > > + } else { > > + /* freerun */ > > + cfg &= ~(S5P_CIIMGCPT_CPT_FREN_ENABLE | > > + S5P_CIIMGCPT_CPT_FRMOD_EN); > > + cfg |= S5P_CIIMGCPT_IMGCPTEN; > > + } > > + > > + if (ctx->scaler.enabled) > > + cfg |= S5P_CIIMGCPT_IMGCPTEN_SC; > > + > > + writel(cfg, dev->regs + S5P_CIIMGCPT); > > +} > > + > > +void s5p_fimc_dis_capture(struct fimc_ctx *ctx) > > +{ > > + struct fimc_dev *dev = ctx->fimc_dev; > > + u32 cfg = readl(dev->regs + S5P_CIIMGCPT); > > + cfg &= ~(S5P_CIIMGCPT_IMGCPTEN | S5P_CIIMGCPT_IMGCPTEN_SC); > > + writel(cfg, dev->regs + S5P_CIIMGCPT); > > +} > > + > > +void s5p_fimc_set_effect(struct fimc_ctx *ctx) > > +{ > > + struct fimc_dev *dev = ctx->fimc_dev; > > + struct fimc_effect *effect = &ctx->effect; > > + u32 cfg = (S5P_CIIMGEFF_IE_ENABLE | S5P_CIIMGEFF_IE_SC_AFTER); > > + > > + cfg |= effect->type; > > + > > + if (effect->type == S5P_FIMC_EFFECT_ARBITRARY) { > > + cfg |= S5P_CIIMGEFF_PAT_CB(effect->pat_cb); > > + cfg |= S5P_CIIMGEFF_PAT_CR(effect->pat_cr); > > + } > > + > > + writel(cfg, dev->regs + S5P_CIIMGEFF); > > +} > > + > > +static void s5p_fimc_set_in_dma_size(struct fimc_ctx *ctx) > > +{ > > + struct fimc_dev *dev = ctx->fimc_dev; > > + struct fimc_frame *frame = &ctx->s_frame; > > + u32 cfg_o = 0; > > + u32 cfg_r = 0; > > + > > + if (S5P_FIMC_LCDFIFO == ctx->out_path) > > + cfg_r |= S5P_CIREAL_ISIZE_AUTOLOAD_ENABLE; > > + > > + cfg_o |= S5P_ORGISIZE_HORIZONTAL(frame->f_width); > > + cfg_o |= S5P_ORGISIZE_VERTICAL(frame->f_height); > > + cfg_r |= S5P_CIREAL_ISIZE_WIDTH(frame->width); > > + cfg_r |= S5P_CIREAL_ISIZE_HEIGHT(frame->height); > > + > > + writel(cfg_o, dev->regs + S5P_ORGISIZE); > > + writel(cfg_r, dev->regs + S5P_CIREAL_ISIZE); > > +} > > + > > +void s5p_fimc_set_in_dma(struct fimc_ctx *ctx) > > +{ > > + struct fimc_dev *dev = ctx->fimc_dev; > > + struct fimc_frame *frame = &ctx->s_frame; > > + struct fimc_dma_offset *offset = &frame->dma_offset; > > + u32 cfg = 0; > > + > > + /* offsets */ > > + cfg |= S5P_CIIYOFF_HORIZONTAL(offset->y_h); > > + cfg |= S5P_CIIYOFF_VERTICAL(offset->y_v); > > + writel(cfg, dev->regs + S5P_CIIYOFF); > > + > > + cfg = 0; > > + cfg |= S5P_CIICBOFF_HORIZONTAL(offset->cb_h); > > + cfg |= S5P_CIICBOFF_VERTICAL(offset->cb_v); > > + writel(cfg, dev->regs + S5P_CIICBOFF); > > + > > + cfg = 0; > > + cfg |= S5P_CIICROFF_HORIZONTAL(offset->cr_h); > > + cfg |= S5P_CIICROFF_VERTICAL(offset->cr_v); > > + writel(cfg, dev->regs + S5P_CIICROFF); > > + > > + /* original & real size */ > > + s5p_fimc_set_in_dma_size(ctx); > > + > > + /* autoload is used currently only in FIFO mode */ > > + s5p_fimc_en_autoload(ctx, S5P_FIMC_LCDFIFO == ctx->out_path); > > + > > + /* input dma set to process single frame only */ > > + cfg = (S5P_MSCTRL_SUCCESSIVE_COUNT(1) | S5P_MSCTRL_INPUT_MEMORY); > > + > > + switch (frame->fmt->color) { > > + case S5P_FIMC_RGB565: > > + case S5P_FIMC_RGB666: > > + case S5P_FIMC_RGB888: > > + cfg |= S5P_MSCTRL_INFORMAT_RGB; > > + break; > > + case S5P_FIMC_YCBCR420: > > + cfg |= S5P_MSCTRL_INFORMAT_YCBCR420; > > + > > + if (frame->fmt->planes_cnt == 2) > > + cfg |= ctx->in_order_2p | S5P_MSCTRL_C_INT_IN_2PLANE; > > + else > > + cfg |= S5P_MSCTRL_C_INT_IN_3PLANE; > > + > > + break; > > + case S5P_FIMC_YCBYCR422: > > + case S5P_FIMC_YCRYCB422: > > + case S5P_FIMC_CBYCRY422: > > + case S5P_FIMC_CRYCBY422: > > + if (frame->fmt->planes_cnt == 1) { > > + cfg |= ctx->in_order_1p > > + | S5P_MSCTRL_INFORMAT_YCBCR422_1PLANE; > > + } else { > > + cfg |= S5P_MSCTRL_INFORMAT_YCBCR422; > > + > > + if (frame->fmt->planes_cnt == 2) > > + cfg |= ctx->in_order_2p > > + | S5P_MSCTRL_C_INT_IN_2PLANE; > > + else > > + cfg |= S5P_MSCTRL_C_INT_IN_3PLANE; > > + } > > + break; > > + default: > > + break; > > + } > > + > > + /* input DMA flip mode */ > > + if (ctx->out_path == S5P_FIMC_LCDFIFO) > > + cfg |= s5p_fimc_get_in_flip(ctx);; > > + > > + writel(cfg, dev->regs + S5P_MSCTRL); > > + > > + /* in/out DMA linear/tiled mode */ > > + cfg = readl(dev->regs + S5P_CIDMAPARAM); > > + cfg &= ~(S5P_CIDMAPARAM_R_MODE_64X32 | > S5P_CIDMAPARAM_W_MODE_64X32); > > + > > + writel(cfg, dev->regs + S5P_CIDMAPARAM); > > +} > > + > > +void s5p_fimc_start_in_dma(struct fimc_dev *dev) > > +{ > > + u32 cfg = readl(dev->regs + S5P_MSCTRL); > > + cfg |= S5P_MSCTRL_ENVID; > > + writel(cfg, dev->regs + S5P_MSCTRL); > > +} > > + > > +void s5p_fimc_stop_in_dma(struct fimc_dev *dev) > > +{ > > + u32 cfg = readl(dev->regs + S5P_MSCTRL); > > + cfg &= ~S5P_MSCTRL_ENVID; > > + writel(cfg, dev->regs + S5P_MSCTRL); > > +} > > + > > +void s5p_fimc_set_input_path(struct fimc_ctx *ctx) > > +{ > > + struct fimc_dev *dev = ctx->fimc_dev; > > + u32 cfg = readl(dev->regs + S5P_MSCTRL); > > + cfg &= ~S5P_MSCTRL_INPUT_MASK; > > + > > + if (ctx->in_path == S5P_FIMC_DMA) > > + cfg |= S5P_MSCTRL_INPUT_MEMORY; > > + else > > + cfg |= S5P_MSCTRL_INPUT_EXTCAM; > > + > > + writel(cfg, dev->regs + S5P_MSCTRL); > > +} > > + > > +void s5p_fimc_set_output_path(struct fimc_ctx *ctx) > > +{ > > + struct fimc_dev *dev = ctx->fimc_dev; > > + u32 cfg = readl(dev->regs + S5P_CISCCTRL); > > + cfg &= ~S5P_CISCCTRL_LCDPATHEN_FIFO; > > + > > + if (ctx->out_path == S5P_FIMC_LCDFIFO) > > + cfg |= S5P_CISCCTRL_LCDPATHEN_FIFO; > > + > > + writel(cfg, dev->regs + S5P_CISCCTRL); > > +} > > + > > +void s5p_fimc_set_input_addr(struct fimc_ctx *ctx) > > +{ > > + struct fimc_dev *dev = ctx->fimc_dev; > > + u32 cfg = 0; > > + > > + cfg = readl(dev->regs + S5P_CIREAL_ISIZE); > > + cfg |= S5P_CIREAL_ISIZE_ADDR_CH_DISABLE; > > + writel(cfg, dev->regs + S5P_CIREAL_ISIZE); > > + > > + writel(ctx->s_frame.addr_y, dev->regs + S5P_CIIYSA0); > > + writel(ctx->s_frame.addr_cb, dev->regs + S5P_CIICBSA0); > > + writel(ctx->s_frame.addr_cr, dev->regs + S5P_CIICRSA0); > > + > > + cfg &= ~S5P_CIREAL_ISIZE_ADDR_CH_DISABLE; > > + writel(cfg, dev->regs + S5P_CIREAL_ISIZE); > > +} > > + > > +void s5p_fimc_set_output_addr(struct fimc_ctx *ctx) > > +{ > > + struct fimc_dev *dev = ctx->fimc_dev; > > + int i = 0; > > + /* each of the four output register sets points to the same > buffer */ > > + for (i = 0; i < S5P_FIMC_MAX_FRAMES; i++) { > > + writel(ctx->d_frame.addr_y, dev->regs + S5P_CIOYSA(i)); > > + writel(ctx->d_frame.addr_cb, dev->regs + S5P_CIOCBSA(i)); > > + writel(ctx->d_frame.addr_cr, dev->regs + S5P_CIOCRSA(i)); > > + } > > +} > > diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h > > index 3793d16..ada05c5 100644 > > --- a/include/linux/videodev2.h > > +++ b/include/linux/videodev2.h > > @@ -287,6 +287,7 @@ struct v4l2_pix_format { > > #define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R', 'G', 'B', 'P') /* 16 > RGB-5-6-5 */ > > #define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R', 'G', 'B', 'Q') /* 16 > RGB-5-5-5 BE */ > > #define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R', 'G', 'B', 'R') /* 16 > RGB-5-6-5 BE */ > > +#define V4L2_PIX_FMT_RGB666 v4l2_fourcc('R', 'G', 'B', 'H') /* 18 > RGB-6-6-6 */ > > #define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B', 'G', 'R', '3') /* 24 > BGR-8-8-8 */ > > #define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R', 'G', 'B', '3') /* 24 > RGB-8-8-8 */ > > #define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B', 'G', 'R', '4') /* 32 > BGR-8-8-8-8 */ > > -- > > 1.6.3.3 > > > > -- > > To unsubscribe from this list: send the line "unsubscribe linux- > samsung-soc" in > > the body of a message to majordomo@xxxxxxxxxxxxxxx > > More majordomo info at http://vger.kernel.org/majordomo-info.html > I am going to update the driver to the last version of v4l2-mem2mem framework, rebase it and will post again. Regards, Sylwester > -- > -- > Ben > > Q: What's a light-year? > A: One-third less calories than a regular year. > > -- > To unsubscribe from this list: send the line "unsubscribe linux- > samsung-soc" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html