[COMMON] media: smfc: add basic function of compression by H/W
authorCho KyongHo <pullip.cho@samsung.com>
Mon, 30 Mar 2015 10:51:59 +0000 (19:51 +0900)
committerCosmin Tanislav <demonsingur@gmail.com>
Mon, 22 Apr 2024 17:22:18 +0000 (20:22 +0300)
Now it is able to compress an image with H/W.

Change-Id: I420e4908b1e3c36818ae4be0b548d8c51ddb3fcc
Signed-off-by: Cho KyongHo <pullip.cho@samsung.com>
drivers/media/platform/exynos/smfc/Makefile
drivers/media/platform/exynos/smfc/smfc-regs.c [new file with mode: 0644]
drivers/media/platform/exynos/smfc/smfc-regs.h
drivers/media/platform/exynos/smfc/smfc.c
drivers/media/platform/exynos/smfc/smfc.h

index 966637807901c6813697e8fd050f453ae896403b..3b802490fe8eada587cc9635c6b34364eaceca61 100644 (file)
@@ -3,4 +3,4 @@
 #              http://www.samsung.com
 #
 
-obj-$(CONFIG_VIDEO_EXYNOS_SMFC) += smfc.o
+obj-$(CONFIG_VIDEO_EXYNOS_SMFC) += smfc.o smfc-regs.o
diff --git a/drivers/media/platform/exynos/smfc/smfc-regs.c b/drivers/media/platform/exynos/smfc/smfc-regs.c
new file mode 100644 (file)
index 0000000..dd37a8b
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * The H/W handling file of Samsung Exynos SMFC Driver
+ *
+ * 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/kernel.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-sg.h>
+
+#include "smfc.h"
+
+void smfc_hwconfigure_reset(struct smfc_dev *smfc)
+{
+       u32 cfg = __raw_readl(smfc->reg + REG_JPEG_CNTL) & ~((1 << 29) | 3);
+       __raw_writel(cfg, smfc->reg + REG_JPEG_CNTL);
+       __raw_writel(cfg | (1 << 29), smfc->reg + REG_JPEG_CNTL);
+}
+
+/*
+ * Quantization tables in ZIG-ZAG order provided by IOC/IEC 10918-1 K.1 and K.2
+ * for YUV420 and YUV422
+ */
+static const unsigned char default_luma_qtbl[SMFC_MCU_SIZE] __aligned(64) = {
+        16,  11,  12,  14,  12,  10,  16,  14,
+        13,  14,  18,  17,  16,  19,  24,  40,
+        26,  24,  22,  22,  24,  49,  35,  37,
+        29,  40,  58,  51,  61,  60,  57,  51,
+        56,  55,  64,  72,  92,  78,  64,  68,
+        87,  69,  55,  56,  80, 109,  81,  87,
+        95,  98, 103, 104, 103,  62,  77, 113,
+       121, 112, 100, 120,  92, 101, 103,  99,
+};
+
+static const unsigned char default_chroma_qtbl[SMFC_MCU_SIZE] __aligned(64) = {
+       17,  18,  18,  24,  21,  24,  47,  26,
+       26,  47,  99,  66,  56,  66,  99,  99,
+       99,  99,  99,  99,  99,  99,  99,  99,
+       99,  99,  99,  99,  99,  99,  99,  99,
+       99,  99,  99,  99,  99,  99,  99,  99,
+       99,  99,  99,  99,  99,  99,  99,  99,
+       99,  99,  99,  99,  99,  99,  99,  99,
+       99,  99,  99,  99,  99,  99,  99,  99,
+};
+
+/* ITU Luminace Huffman Table */
+static unsigned int ITU_H_TBL_LEN_DC_LUMINANCE[] = {
+       0x01050100, 0x01010101, 0x00000001, 0x00000000
+};
+static unsigned int ITU_H_TBL_VAL_DC_LUMINANCE[] = {
+       0x03020100, 0x07060504, 0x0b0a0908, 0x00000000
+};
+
+/* ITU Chrominace Huffman Table */
+static unsigned int ITU_H_TBL_LEN_DC_CHROMINANCE[] = {
+       0x01010300, 0x01010101, 0x00010101, 0x00000000
+};
+static unsigned int ITU_H_TBL_VAL_DC_CHROMINANCE[] = {
+       0x03020100, 0x07060504, 0x0b0a0908, 0x00000000
+};
+
+/* ITU Luminace Huffman Table */
+static unsigned int ITU_H_TBL_LEN_AC_LUMINANCE[] = {
+       0x03010200, 0x03040203, 0x04040505, 0x7d010000
+};
+
+static unsigned int ITU_H_TBL_VAL_AC_LUMINANCE[] = {
+       0x00030201, 0x12051104, 0x06413121, 0x07615113,
+       0x32147122, 0x08a19181, 0xc1b14223, 0xf0d15215,
+       0x72623324, 0x160a0982, 0x1a191817, 0x28272625,
+       0x35342a29, 0x39383736, 0x4544433a, 0x49484746,
+       0x5554534a, 0x59585756, 0x6564635a, 0x69686766,
+       0x7574736a, 0x79787776, 0x8584837a, 0x89888786,
+       0x9493928a, 0x98979695, 0xa3a29a99, 0xa7a6a5a4,
+       0xb2aaa9a8, 0xb6b5b4b3, 0xbab9b8b7, 0xc5c4c3c2,
+       0xc9c8c7c6, 0xd4d3d2ca, 0xd8d7d6d5, 0xe2e1dad9,
+       0xe6e5e4e3, 0xeae9e8e7, 0xf4f3f2f1, 0xf8f7f6f5,
+       0x0000faf9
+};
+
+/* ITU Chrominace Huffman Table */
+static u32 ITU_H_TBL_LEN_AC_CHROMINANCE[] = {
+       0x02010200, 0x04030404, 0x04040507, 0x77020100
+};
+static u32 ITU_H_TBL_VAL_AC_CHROMINANCE[] = {
+       0x03020100, 0x21050411, 0x41120631, 0x71610751,
+       0x81322213, 0x91421408, 0x09c1b1a1, 0xf0523323,
+       0xd1726215, 0x3424160a, 0x17f125e1, 0x261a1918,
+       0x2a292827, 0x38373635, 0x44433a39, 0x48474645,
+       0x54534a49, 0x58575655, 0x64635a59, 0x68676665,
+       0x74736a69, 0x78777675, 0x83827a79, 0x87868584,
+       0x928a8988, 0x96959493, 0x9a999897, 0xa5a4a3a2,
+       0xa9a8a7a6, 0xb4b3b2aa, 0xb8b7b6b5, 0xc3c2bab9,
+       0xc7c6c5c4, 0xd2cac9c8, 0xd6d5d4d3, 0xdad9d8d7,
+       0xe5e4e3e2, 0xe9e8e7e6, 0xf4f3f2ea, 0xf8f7f6f5,
+       0x0000faf9
+};
+
+/* to suppress warning or error message about out-of-aaray-bound */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
+/* tables and qunatization tables configuration to H/W for compression */
+static inline u32 smfc_calc_quantizers(unsigned int idx, unsigned int factor,
+                                       const unsigned char tbl[])
+{
+       u32 val = max(min((tbl[idx] * factor + 50) / 100, 255U), 1U);
+       val |= max(min((tbl[idx + 1] * factor + 50) / 100, 255U), 1U) << 8;
+       val |= max(min((tbl[idx + 2] * factor + 50) / 100, 255U), 1U) << 16;
+       val |= max(min((tbl[idx + 3] * factor + 50) / 100, 255U), 1U) << 24;
+       return val;
+}
+#pragma GCC diagnostic pop
+
+void smfc_hwconfigure_tables(struct smfc_ctx *ctx)
+{
+       size_t i;
+       void __iomem *base = ctx->smfc->reg;
+       unsigned int factor = ctx->quality_factor;
+       factor = (factor < 50) ? 5000 / factor : 200 - factor * 2;
+
+       /* Quantizer table 0 */
+       for (i = 0; i < SMFC_MCU_SIZE; i += 4) {
+               __raw_writel(smfc_calc_quantizers(i, factor, default_luma_qtbl),
+                       base + REG_QTBL_BASE + i);
+               __raw_writel(
+                       smfc_calc_quantizers(i, factor, default_chroma_qtbl),
+                       base + REG_QTBL_BASE + SMFC_MCU_SIZE + i);
+       }
+
+       /* Huffman tables */
+       for (i = 0; i < 4; i++) {
+               __raw_writel(ITU_H_TBL_LEN_DC_LUMINANCE[i],
+                               base + REG_HTBL_LUMA_DCLEN + i * sizeof(u32));
+               __raw_writel(ITU_H_TBL_VAL_DC_LUMINANCE[i],
+                               base + REG_HTBL_LUMA_DCVAL + i * sizeof(u32));
+               __raw_writel(ITU_H_TBL_LEN_DC_CHROMINANCE[i],
+                               base + REG_HTBL_CHROMA_DCLEN + i * sizeof(u32));
+               __raw_writel(ITU_H_TBL_VAL_DC_CHROMINANCE[i],
+                               base + REG_HTBL_CHROMA_DCVAL + i * sizeof(u32));
+               __raw_writel(ITU_H_TBL_LEN_AC_LUMINANCE[i],
+                               base + REG_HTBL_LUMA_ACLEN + i * sizeof(u32));
+               __raw_writel(ITU_H_TBL_LEN_AC_CHROMINANCE[i],
+                               base + REG_HTBL_CHROMA_ACLEN + i * sizeof(u32));
+       }
+
+       for (i = 0; i < ARRAY_SIZE(ITU_H_TBL_VAL_AC_LUMINANCE); i++)
+               __raw_writel(ITU_H_TBL_VAL_AC_LUMINANCE[i],
+                               base + REG_HTBL_LUMA_ACVAL + i * sizeof(u32));
+
+       for (i = 0; i < ARRAY_SIZE(ITU_H_TBL_VAL_AC_CHROMINANCE); i++)
+               __raw_writel(ITU_H_TBL_VAL_AC_CHROMINANCE[i],
+                               base + REG_HTBL_CHROMA_ACVAL + i * sizeof(u32));
+
+       __raw_writel(VAL_TABLE_SELECT, base + REG_TABLE_SELECT);
+       __raw_writel(SMFC_DHT_LEN, base + REG_DHT_LEN);
+}
+
+
+static void smfc_hwconfigure_image_base(struct smfc_ctx *ctx,
+                                       struct vb2_buffer *vb2buf)
+{
+       dma_addr_t addr;
+       unsigned int i;
+       bool multiplane =
+               (ctx->img_fmt->num_buffers == ctx->img_fmt->num_planes);
+
+       if (multiplane) {
+               /* Note that this includes a single-plane format such as YUYV */
+               for (i = 0; i < ctx->img_fmt->num_buffers; i++) {
+                       addr = vb2_dma_sg_plane_dma_addr(vb2buf, i);
+                       __raw_writel((u32)addr,
+                               ctx->smfc->reg + REG_MAIN_IMAGE_BASE(i));
+               }
+       } else {
+               addr = vb2_dma_sg_plane_dma_addr(vb2buf, i);
+
+               for (i = 0; i < ctx->img_fmt->num_planes; i++) {
+                       __raw_writel((u32)addr,
+                               ctx->smfc->reg + REG_MAIN_IMAGE_BASE(i));
+                       addr += (ctx->width * ctx->height *
+                                               ctx->img_fmt->bpp_pix[i]) / 8;
+               }
+       }
+}
+
+static u32 smfc_hwconfigure_jpeg_base(struct smfc_ctx *ctx,
+                                       struct vb2_buffer *vb2buf)
+{
+       dma_addr_t addr;
+
+       BUG_ON(vb2buf->num_planes != 1);
+       addr = vb2_dma_sg_plane_dma_addr(vb2buf, 0);
+       __raw_writel((u32)addr, ctx->smfc->reg + REG_MAIN_JPEG_BASE);
+       return (u32)addr;
+}
+
+/* [hfactor - 1][vfactor - 1]: 444, 422V, 422, 420 */
+static u32 smfc_get_jpeg_format(unsigned int hfactor, unsigned int vfactor)
+{
+       static unsigned char jpeg_regfmt[2][2] = { {1, 4}, {2, 3} };
+       return jpeg_regfmt[hfactor - 1][vfactor - 1] << 24;
+}
+
+void smfc_hwconfigure_image(struct smfc_ctx *ctx)
+{
+       struct vb2_v4l2_buffer *vb2buf_img, *vb2buf_jpg;
+       u32 stream_address;
+       u32 format = ctx->img_fmt->regcfg;
+
+       __raw_writel(ctx->width | (ctx->height << 16),
+                       ctx->smfc->reg + REG_MAIN_IMAGE_SIZE);
+
+       if (!(ctx->flags & SMFC_CTX_COMPRESS)) {
+               vb2buf_img = v4l2_m2m_next_dst_buf(ctx->m2mctx);
+               vb2buf_jpg = v4l2_m2m_next_src_buf(ctx->m2mctx);
+       } else {
+               vb2buf_img = v4l2_m2m_next_src_buf(ctx->m2mctx);
+               vb2buf_jpg = v4l2_m2m_next_dst_buf(ctx->m2mctx);
+               /*
+                * H/W JPEG does not allow upscaling of chroma components
+                * during compression
+                */
+               format |= smfc_get_jpeg_format(
+                       max(ctx->chroma_hfactor, ctx->img_fmt->chroma_hfactor),
+                       max(ctx->chroma_vfactor, ctx->img_fmt->chroma_vfactor));
+       }
+
+       smfc_hwconfigure_image_base(ctx, &vb2buf_img->vb2_buf);
+       stream_address = smfc_hwconfigure_jpeg_base(ctx, &vb2buf_jpg->vb2_buf);
+
+       __raw_writel(format, ctx->smfc->reg + REG_MAIN_IMAGE_FORMAT);
+       __raw_writel(vb2_plane_size(&vb2buf_jpg->vb2_buf, 0) -
+                                       (stream_address & SMFC_ADDR_ALIGN_MASK),
+                       ctx->smfc->reg + REG_MAIN_MAX_STREAM_SIZE);
+}
+
+void smfc_hwconfigure_start(struct smfc_ctx *ctx)
+{
+       u32 cfg;
+       void __iomem *base = ctx->smfc->reg;
+
+       /* configure "Error max compressed size" interrupt */
+       cfg = __raw_readl(base + REG_INT_EN);
+       __raw_writel(cfg | (1 << 11), base + REG_INT_EN);
+
+       cfg = __raw_readl(base + REG_JPEG_CNTL) & ~3;
+       cfg |= !(ctx->flags & SMFC_CTX_COMPRESS) ? 1 : 2;
+       cfg |= 1 << 19; /* update huffman table from SFR */
+       cfg |= 1 << 28; /* enables interrupt */
+       cfg |= 1 << 29; /* Release reset */
+
+       writel(cfg, base + REG_JPEG_CNTL);
+}
+
+bool smfc_hwstatus_okay(struct smfc_dev *smfc)
+{
+       u32 val = __raw_readl(smfc->reg + REG_INT_STATUS);
+       if (!val) {
+               dev_err(smfc->dev, "Interrupt with no status change\n");
+               return false;
+       }
+
+       if ((val & ~2)) {
+               dev_err(smfc->dev, "Error interrupt %#010x\n", val);
+               return false;
+       }
+
+       return true;
+}
index 03e8982b5b8014387be426189373361cf50d2b2e..6c4edd601e846b1aa717f00e383dddc9d022a06c 100644 (file)
 #ifndef _MEDIA_EXYNOS_SMFC_REGS_H_
 #define _MEDIA_EXYNOS_SMFC_REGS_H_
 
+/********** JPEG STANDARD *****************************************************/
+#define SMFC_MCU_SIZE  64
+
 /********** H/W RESTRICTIONS **************************************************/
 #define SMFC_MAX_WIDTH 16368U
 #define SMFC_MAX_HEIGHT        16368U
 #define SMFC_MIN_WIDTH 8U
 #define SMFC_MIN_HEIGHT        8U
+#define SMFC_ADDR_ALIGN_MASK (16 - 1) /* 128-bit align */
 
+/********** H/W REGISTERS and DEFAULT VALUES **********************************/
+#define REG_JPEG_CNTL                  0x000
+#define REG_INT_EN                     0x004
+#define REG_TIMER_COUNT                        0x008
+#define REG_INT_STATUS                 0x00C
+#define REG_MAIN_IMAGE_SIZE            0x014
+#define REG_MAIN_JPEG_BASE             0x010
+#define REG_MAIN_IMAGE_BASE(n)         (0x018 + (n) * 12)
 #define REG_MAIN_IMAGE_FORMAT          0x040
-#define REG_SECD_IMAGE_FORMAT          0x0B8
+#define REG_MAIN_STREAM_SIZE           0x044
+#define REG_MAIN_MAX_STREAM_SIZE       0x06C
 
 #define REG_IP_VERSION_NUMBER          0x064
 
+#define REG_SECD_IMAGE_FORMAT          0x0B8
+
+#define REG_TABLE_SELECT               0x03C
+/*
+ * Component 0: Q-table 0, AC/DC table 0
+ * Component 1 and 2: Q-table 1, AC/DC table 1
+ */
+#define VAL_TABLE_SELECT               0xF14
+/* 64 reigsters for four quantization tables are prepared */
+#define REG_QTBL_BASE                  0x100
+/*
+ * Total 112 registers for huffman tables:
+ * 0x200 - 4 DC Luma code lengths registers
+ * 0x210 - 4 DC Luma values registers
+ * 0x220 - 4 DC Chroma code lengths registers
+ * 0x230 - 4 DC Chroma values registers
+ * 0x240 - 4 AC Luma code lengths registers
+ * 0x250 - 44 AC Luma values registers
+ * 0x300 - 4 AC Chroma code lengths registers
+ * 0x310 - 44 ACChroma values registers
+ */
+#define REG_HTBL_BASE                  0x200
+#  define REG_HTBL_LUMA_DCLEN  REG_HTBL_BASE
+#  define REG_HTBL_LUMA_DCVAL  (REG_HTBL_LUMA_DCLEN + 4 * sizeof(u32))
+#  define REG_HTBL_CHROMA_DCLEN        (REG_HTBL_LUMA_DCVAL + 4 * sizeof(u32))
+#  define REG_HTBL_CHROMA_DCVAL        (REG_HTBL_CHROMA_DCLEN + 4 * sizeof(u32))
+#  define REG_HTBL_LUMA_ACLEN  (REG_HTBL_CHROMA_DCVAL + 4 * sizeof(u32))
+#  define REG_HTBL_LUMA_ACVAL  (REG_HTBL_LUMA_ACLEN + 4 * sizeof(u32))
+#  define REG_HTBL_CHROMA_ACLEN        (REG_HTBL_LUMA_ACVAL + 44 * sizeof(u32))
+#  define REG_HTBL_CHROMA_ACVAL        (REG_HTBL_CHROMA_ACLEN + 4 * sizeof(u32))
+#define REG_DHT_LEN                    0x04C
+#define SMFC_DHT_LEN                   0x1A2
+
 /* Value definitions of MAIN/SECONDARY_IMAGE_FORMAT */
 enum {
        IMGSEL_GRAY,
index 444d103b20c4f353d486ae682ee095f5080026cb..eacb32bf7b09f5361087de2ac928a368ac0b3dd0 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/slab.h>
 #include <linux/io.h>
 #include <linux/mutex.h>
+#include <linux/exynos_iovmm.h>
 
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
@@ -27,7 +28,6 @@
 #include <media/videobuf2-dma-sg.h>
 
 #include "smfc.h"
-#include "smfc-regs.h"
 
 /* SMFC SPECIFIC DEVICE CAPABILITIES */
 /* set if H/W supports for decompression */
@@ -274,6 +274,33 @@ static const char *buf_type_name(__u32 type)
 
 static irqreturn_t exynos_smfc_irq_handler(int irq, void *priv)
 {
+       struct smfc_dev *smfc = priv;
+       struct smfc_ctx *ctx = v4l2_m2m_get_curr_priv(smfc->m2mdev);
+       enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
+       struct vb2_v4l2_buffer *vb_capture;
+
+       vb_capture = v4l2_m2m_dst_buf_remove(ctx->m2mctx);
+
+       if (smfc_hwstatus_okay(smfc)) {
+               vb2_set_plane_payload(&vb_capture->vb2_buf, 0,
+                                     smfc_get_streamsize(smfc));
+       } else {
+               state = VB2_BUF_STATE_ERROR;
+               smfc_hwconfigure_reset(smfc);
+       }
+
+       if (!IS_ERR(smfc->clk_gate)) {
+               clk_disable(smfc->clk_gate);
+               if (!IS_ERR(smfc->clk_gate2))
+                       clk_disable(smfc->clk_gate2);
+       }
+
+       pm_runtime_put(smfc->dev);
+
+       v4l2_m2m_buf_done(v4l2_m2m_src_buf_remove(ctx->m2mctx), state);
+       v4l2_m2m_buf_done(vb_capture, state);
+       v4l2_m2m_job_finish(smfc->m2mdev, ctx->m2mctx);
+
        return IRQ_HANDLED;
 }
 
@@ -432,6 +459,7 @@ static int exynos_smfc_open(struct file *filp)
         * default image format: YUYV
         * default size: 16x8
         * default chroma subsampling for JPEG: YUV422
+        * default quality factor for compression: 96
         */
        ctx->img_fmt = SMFC_DEFAULT_OUTPUT_FORMAT;
        ctx->width = SMFC_MIN_WIDTH << ctx->img_fmt->chroma_hfactor;
@@ -439,6 +467,7 @@ static int exynos_smfc_open(struct file *filp)
        ctx->chroma_hfactor = ctx->img_fmt->chroma_hfactor;
        ctx->chroma_vfactor = ctx->img_fmt->chroma_vfactor;
        ctx->flags |= SMFC_CTX_COMPRESS;
+       ctx->quality_factor = 96;
 
        ctx->smfc = smfc;
 
@@ -793,27 +822,35 @@ static int smfc_v4l2_s_fmt(struct file *filp, void *fh, struct v4l2_format *f)
 static int smfc_v4l2_reqbufs(struct file *filp, void *fh,
                             struct v4l2_requestbuffers *reqbufs)
 {
-       struct smfc_ctx *ctx = v4l2_fh_to_smfc_ctx(fh);
-       return v4l2_m2m_reqbufs(filp, ctx->m2mctx, reqbufs);
+       return v4l2_m2m_reqbufs(filp, v4l2_fh_to_smfc_ctx(fh)->m2mctx, reqbufs);
 }
 
 static int smfc_v4l2_querybuf(struct file *filp, void *fh,
                              struct v4l2_buffer *buf)
 {
-       struct smfc_ctx *ctx = v4l2_fh_to_smfc_ctx(fh);
-       return v4l2_m2m_querybuf(filp, ctx->m2mctx, buf);
+       return v4l2_m2m_querybuf(filp, v4l2_fh_to_smfc_ctx(fh)->m2mctx, buf);
 }
 
 static int smfc_v4l2_qbuf(struct file *filp, void *fh, struct v4l2_buffer *buf)
 {
-       struct smfc_ctx *ctx = v4l2_fh_to_smfc_ctx(fh);
-       return v4l2_m2m_qbuf(filp, ctx->m2mctx, buf);
+       return v4l2_m2m_qbuf(filp, v4l2_fh_to_smfc_ctx(fh)->m2mctx, buf);
 }
 
 static int smfc_v4l2_dqbuf(struct file *filp, void *fh, struct v4l2_buffer *buf)
 {
-       struct smfc_ctx *ctx = v4l2_fh_to_smfc_ctx(fh);
-       return v4l2_m2m_dqbuf(filp, ctx->m2mctx, buf);
+       return v4l2_m2m_dqbuf(filp, v4l2_fh_to_smfc_ctx(fh)->m2mctx, buf);
+}
+
+static int smfc_v4l2_streamon(struct file *filp, void *fh,
+                             enum v4l2_buf_type type)
+{
+       return v4l2_m2m_streamon(filp, v4l2_fh_to_smfc_ctx(fh)->m2mctx, type);
+}
+
+static int smfc_v4l2_streamoff(struct file *filp, void *fh,
+                              enum v4l2_buf_type type)
+{
+       return v4l2_m2m_streamoff(filp, v4l2_fh_to_smfc_ctx(fh)->m2mctx, type);
 }
 
 static const struct v4l2_ioctl_ops smfc_v4l2_ioctl_ops = {
@@ -838,11 +875,41 @@ static const struct v4l2_ioctl_ops smfc_v4l2_ioctl_ops = {
        .vidioc_querybuf                = smfc_v4l2_querybuf,
        .vidioc_qbuf                    = smfc_v4l2_qbuf,
        .vidioc_dqbuf                   = smfc_v4l2_dqbuf,
+       .vidioc_streamon                = smfc_v4l2_streamon,
+       .vidioc_streamoff               = smfc_v4l2_streamoff,
 };
 
 static void smfc_m2m_device_run(void *priv)
 {
-       /* TODO: H/W initialization */
+       struct smfc_ctx *ctx = priv;
+       int ret;
+
+       ret = in_irq() ? pm_runtime_get(ctx->smfc->dev) :
+                        pm_runtime_get_sync(ctx->smfc->dev);
+       if (ret < 0) {
+               pr_err("Failed to enable power\n");
+               /* TODO: error current frame */
+       }
+
+       if (!IS_ERR(ctx->smfc->clk_gate)) {
+               ret = clk_enable(ctx->smfc->clk_gate);
+               if (!ret && !IS_ERR(ctx->smfc->clk_gate2)) {
+                       ret = clk_enable(ctx->smfc->clk_gate2);
+                       if (ret)
+                               clk_disable(ctx->smfc->clk_gate);
+               }
+       }
+
+       if (ret < 0) {
+               dev_err(ctx->smfc->dev, "Failed to enable clocks\n");
+               pm_runtime_put(ctx->smfc->dev);
+               /* TODO: error current frame */
+       }
+
+       smfc_hwconfigure_reset(ctx->smfc);
+       smfc_hwconfigure_tables(ctx);
+       smfc_hwconfigure_image(ctx);
+       smfc_hwconfigure_start(ctx);
 }
 
 static void smfc_m2m_job_abort(void *priv)
@@ -1036,6 +1103,10 @@ static int exynos_smfc_probe(struct platform_device *pdev)
        if (ret < 0)
                return ret;
 
+       ret = iovmm_activate(&pdev->dev);
+       if (ret < 0)
+               return ret;
+
        platform_set_drvdata(pdev, smfc);
 
        dev_info(&pdev->dev, "Probed H/W Version: %02x.%02x.%04x\n",
index 6ab0dfc9b21d3ef2114280c1bc7c8b125eb98e70..ba0f17382e9eb8145b5c3d164009d3c7e61255de 100644 (file)
@@ -12,6 +12,8 @@
 #ifndef _MEDIA_EXYNOS_SMFC_H_
 #define _MEDIA_EXYNOS_SMFC_H_
 
+#include "smfc-regs.h"
+
 #define MODULE_NAME    "exynos-jpeg"
 
 struct device;
@@ -62,6 +64,7 @@ struct smfc_ctx {
        /* JPEG chroma subsampling factors */
        unsigned char chroma_hfactor;
        unsigned char chroma_vfactor;
+       unsigned int quality_factor;
 };
 
 static inline struct smfc_ctx *v4l2_fh_to_smfc_ctx(struct v4l2_fh *fh)
@@ -82,4 +85,15 @@ static inline bool smfc_is_compressed_type(struct smfc_ctx *ctx, __u32 type)
        return !(ctx->flags & SMFC_CTX_COMPRESS) == V4L2_TYPE_IS_OUTPUT(type);
 }
 
+/* H/W Configuration */
+void smfc_hwconfigure_tables(struct smfc_ctx *ctx);
+void smfc_hwconfigure_image(struct smfc_ctx *ctx);
+void smfc_hwconfigure_start(struct smfc_ctx *ctx);
+bool smfc_hwstatus_okay(struct smfc_dev *smfc);
+void smfc_hwconfigure_reset(struct smfc_dev *smfc);
+static inline u32 smfc_get_streamsize(struct smfc_dev *smfc)
+{
+       return __raw_readl(smfc->reg + REG_MAIN_STREAM_SIZE);
+}
+
 #endif /* _MEDIA_EXYNOS_SMFC_H_ */