* [RFC PATCH 0/3] [media] s5p-jpeg: Add support for Exynos4x12 and 5250
@ 2013-05-14 11:53 George Joseph
2013-05-14 11:53 ` [RFC PATCH 1/3] " George Joseph
` (3 more replies)
0 siblings, 4 replies; 7+ messages in thread
From: George Joseph @ 2013-05-14 11:53 UTC (permalink / raw)
To: linux-media, linux-samsung-soc; +Cc: s.nawrocki, a.hajda, ym.song
From: George Joseph Palathingal <george.jp@samsung.com>
This patch series refactors the JPEG driver to add code to support Exynos4x12
and Exynos5250 JPEG IPs and makes the driver DT and CCF compliant.
Exynos4210 JPEG driver supports only single planar image formats.
The JPEG IP on Exynos4412 and 5250 supports multiplanar image formats as well.
So the existing JPEG driver is refactored to support the JPEG h/w on all
the three SoCs. The encoder/decoder functionalities are separated to
two different files for better modularity.
The encoder/decoder functionalities have been tested on Origen 4210, 4412 and SMDK 5250
boards. There is currently an issue with the Exynos 4210 JPEG encoder which will be
fixed in subsequent patches.
The patch series is based on linux-next tree (20130514).
George Joseph Palathingal (2):
[media] s5p-jpeg: Add support for Exynos4x12 and 5250
[media] s5p-jpeg: Add DT support to JPEG driver
Sylwester Nawrocki (1):
ARM: dts: Add documentation for Samsung JPEG driver bindings
.../devicetree/bindings/media/samsung-s5p-jpeg.txt | 21 +
drivers/media/platform/s5p-jpeg/Makefile | 4 +-
drivers/media/platform/s5p-jpeg/jpeg-core.c | 2041 +++++++++-----------
drivers/media/platform/s5p-jpeg/jpeg-core.h | 428 ++--
drivers/media/platform/s5p-jpeg/jpeg-dec.c | 489 +++++
drivers/media/platform/s5p-jpeg/jpeg-enc.c | 521 +++++
drivers/media/platform/s5p-jpeg/jpeg-hw-v1.h | 528 +++++
drivers/media/platform/s5p-jpeg/jpeg-hw-v2.c | 614 ++++++
drivers/media/platform/s5p-jpeg/jpeg-hw-v2.h | 47 +
drivers/media/platform/s5p-jpeg/jpeg-hw.h | 357 ----
drivers/media/platform/s5p-jpeg/jpeg-regs-v1.h | 171 ++
drivers/media/platform/s5p-jpeg/jpeg-regs-v2.h | 191 ++
drivers/media/platform/s5p-jpeg/jpeg-regs.h | 170 --
13 files changed, 3787 insertions(+), 1795 deletions(-)
create mode 100644 Documentation/devicetree/bindings/media/samsung-s5p-jpeg.txt
create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-dec.c
create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-enc.c
create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-hw-v1.h
create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-hw-v2.c
create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-hw-v2.h
delete mode 100644 drivers/media/platform/s5p-jpeg/jpeg-hw.h
create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-regs-v1.h
create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-regs-v2.h
delete mode 100644 drivers/media/platform/s5p-jpeg/jpeg-regs.h
--
1.7.9.5
^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC PATCH 1/3] [media] s5p-jpeg: Add support for Exynos4x12 and 5250
2013-05-14 11:53 [RFC PATCH 0/3] [media] s5p-jpeg: Add support for Exynos4x12 and 5250 George Joseph
@ 2013-05-14 11:53 ` George Joseph
2013-05-15 22:27 ` Sylwester Nawrocki
2013-05-14 11:53 ` [RFC PATCH 2/3] [media] s5p-jpeg: Add DT support to JPEG driver George Joseph
` (2 subsequent siblings)
3 siblings, 1 reply; 7+ messages in thread
From: George Joseph @ 2013-05-14 11:53 UTC (permalink / raw)
To: linux-media, linux-samsung-soc; +Cc: s.nawrocki, a.hajda, ym.song
From: George Joseph Palathingal <george.jp@samsung.com>
Refactored the s5p-jpeg driver and added support for Exynos4x12 and 5250
Signed-off-by: George Joseph Palathingal <george.jp@samsung.com>
---
drivers/media/platform/s5p-jpeg/Makefile | 4 +-
drivers/media/platform/s5p-jpeg/jpeg-core.c | 2009 ++++++++++--------------
drivers/media/platform/s5p-jpeg/jpeg-core.h | 428 +++--
drivers/media/platform/s5p-jpeg/jpeg-dec.c | 489 ++++++
drivers/media/platform/s5p-jpeg/jpeg-enc.c | 521 ++++++
drivers/media/platform/s5p-jpeg/jpeg-hw-v1.h | 528 +++++++
drivers/media/platform/s5p-jpeg/jpeg-hw-v2.c | 614 ++++++++
drivers/media/platform/s5p-jpeg/jpeg-hw-v2.h | 47 +
drivers/media/platform/s5p-jpeg/jpeg-hw.h | 357 -----
drivers/media/platform/s5p-jpeg/jpeg-regs-v1.h | 171 ++
drivers/media/platform/s5p-jpeg/jpeg-regs-v2.h | 191 +++
drivers/media/platform/s5p-jpeg/jpeg-regs.h | 170 --
12 files changed, 3734 insertions(+), 1795 deletions(-)
create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-dec.c
create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-enc.c
create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-hw-v1.h
create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-hw-v2.c
create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-hw-v2.h
delete mode 100644 drivers/media/platform/s5p-jpeg/jpeg-hw.h
create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-regs-v1.h
create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-regs-v2.h
delete mode 100644 drivers/media/platform/s5p-jpeg/jpeg-regs.h
diff --git a/drivers/media/platform/s5p-jpeg/Makefile b/drivers/media/platform/s5p-jpeg/Makefile
index ddc2900..e564fc0 100644
--- a/drivers/media/platform/s5p-jpeg/Makefile
+++ b/drivers/media/platform/s5p-jpeg/Makefile
@@ -1,2 +1,1 @@
-s5p-jpeg-objs := jpeg-core.o
-obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) := s5p-jpeg.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += jpeg-core.o jpeg-enc.o jpeg-dec.o jpeg-hw-v2.o
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 15d2396..f964566 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -1,7 +1,7 @@
/* linux/drivers/media/platform/s5p-jpeg/jpeg-core.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
+ * http://www.samsung.com
*
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
*
@@ -10,865 +10,441 @@
* published by the Free Software Foundation.
*/
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/gfp.h>
+#include <asm/page.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/string.h>
-#include <media/v4l2-mem2mem.h>
-#include <media/v4l2-ioctl.h>
-#include <media/videobuf2-core.h>
+#include <linux/err.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/signal.h>
+#include <linux/ioport.h>
+#include <linux/kmod.h>
+#include <linux/vmalloc.h>
+#include <linux/time.h>
+#include <linux/clk.h>
+#include <linux/semaphore.h>
+#include <linux/vmalloc.h>
+#include <linux/workqueue.h>
+#include <linux/pm.h>
+#include <linux/of.h>
+#include <mach/irqs.h>
#include <media/videobuf2-dma-contig.h>
+#include <media/v4l2-ioctl.h>
#include "jpeg-core.h"
-#include "jpeg-hw.h"
-
-static struct s5p_jpeg_fmt formats_enc[] = {
- {
- .name = "JPEG JFIF",
- .fourcc = V4L2_PIX_FMT_JPEG,
- .colplanes = 1,
- .types = MEM2MEM_CAPTURE,
- },
- {
- .name = "YUV 4:2:2 packed, YCbYCr",
- .fourcc = V4L2_PIX_FMT_YUYV,
- .depth = 16,
- .colplanes = 1,
- .types = MEM2MEM_OUTPUT,
- },
- {
- .name = "RGB565",
- .fourcc = V4L2_PIX_FMT_RGB565,
- .depth = 16,
- .colplanes = 1,
- .types = MEM2MEM_OUTPUT,
- },
-};
-#define NUM_FORMATS_ENC ARRAY_SIZE(formats_enc)
-
-static struct s5p_jpeg_fmt formats_dec[] = {
- {
- .name = "YUV 4:2:0 planar, YCbCr",
- .fourcc = V4L2_PIX_FMT_YUV420,
- .depth = 12,
- .colplanes = 3,
- .h_align = 4,
- .v_align = 4,
- .types = MEM2MEM_CAPTURE,
- },
- {
- .name = "YUV 4:2:2 packed, YCbYCr",
- .fourcc = V4L2_PIX_FMT_YUYV,
- .depth = 16,
- .colplanes = 1,
- .h_align = 4,
- .v_align = 3,
- .types = MEM2MEM_CAPTURE,
- },
- {
- .name = "JPEG JFIF",
- .fourcc = V4L2_PIX_FMT_JPEG,
- .colplanes = 1,
- .types = MEM2MEM_OUTPUT,
- },
-};
-#define NUM_FORMATS_DEC ARRAY_SIZE(formats_dec)
-
-static const unsigned char qtbl_luminance[4][64] = {
- {/* level 1 - high quality */
- 8, 6, 6, 8, 12, 14, 16, 17,
- 6, 6, 6, 8, 10, 13, 12, 15,
- 6, 6, 7, 8, 13, 14, 18, 24,
- 8, 8, 8, 14, 13, 19, 24, 35,
- 12, 10, 13, 13, 20, 26, 34, 39,
- 14, 13, 14, 19, 26, 34, 39, 39,
- 16, 12, 18, 24, 34, 39, 39, 39,
- 17, 15, 24, 35, 39, 39, 39, 39
- },
- {/* level 2 */
- 12, 8, 8, 12, 17, 21, 24, 23,
- 8, 9, 9, 11, 15, 19, 18, 23,
- 8, 9, 10, 12, 19, 20, 27, 36,
- 12, 11, 12, 21, 20, 28, 36, 53,
- 17, 15, 19, 20, 30, 39, 51, 59,
- 21, 19, 20, 28, 39, 51, 59, 59,
- 24, 18, 27, 36, 51, 59, 59, 59,
- 23, 23, 36, 53, 59, 59, 59, 59
- },
- {/* level 3 */
- 16, 11, 11, 16, 23, 27, 31, 30,
- 11, 12, 12, 15, 20, 23, 23, 30,
- 11, 12, 13, 16, 23, 26, 35, 47,
- 16, 15, 16, 23, 26, 37, 47, 64,
- 23, 20, 23, 26, 39, 51, 64, 64,
- 27, 23, 26, 37, 51, 64, 64, 64,
- 31, 23, 35, 47, 64, 64, 64, 64,
- 30, 30, 47, 64, 64, 64, 64, 64
- },
- {/*level 4 - low quality */
- 20, 16, 25, 39, 50, 46, 62, 68,
- 16, 18, 23, 38, 38, 53, 65, 68,
- 25, 23, 31, 38, 53, 65, 68, 68,
- 39, 38, 38, 53, 65, 68, 68, 68,
- 50, 38, 53, 65, 68, 68, 68, 68,
- 46, 53, 65, 68, 68, 68, 68, 68,
- 62, 65, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68
- }
-};
-
-static const unsigned char qtbl_chrominance[4][64] = {
- {/* level 1 - high quality */
- 9, 8, 9, 11, 14, 17, 19, 24,
- 8, 10, 9, 11, 14, 13, 17, 22,
- 9, 9, 13, 14, 13, 15, 23, 26,
- 11, 11, 14, 14, 15, 20, 26, 33,
- 14, 14, 13, 15, 20, 24, 33, 39,
- 17, 13, 15, 20, 24, 32, 39, 39,
- 19, 17, 23, 26, 33, 39, 39, 39,
- 24, 22, 26, 33, 39, 39, 39, 39
- },
- {/* level 2 */
- 13, 11, 13, 16, 20, 20, 29, 37,
- 11, 14, 14, 14, 16, 20, 26, 32,
- 13, 14, 15, 17, 20, 23, 35, 40,
- 16, 14, 17, 21, 23, 30, 40, 50,
- 20, 16, 20, 23, 30, 37, 50, 59,
- 20, 20, 23, 30, 37, 48, 59, 59,
- 29, 26, 35, 40, 50, 59, 59, 59,
- 37, 32, 40, 50, 59, 59, 59, 59
- },
- {/* level 3 */
- 17, 15, 17, 21, 20, 26, 38, 48,
- 15, 19, 18, 17, 20, 26, 35, 43,
- 17, 18, 20, 22, 26, 30, 46, 53,
- 21, 17, 22, 28, 30, 39, 53, 64,
- 20, 20, 26, 30, 39, 48, 64, 64,
- 26, 26, 30, 39, 48, 63, 64, 64,
- 38, 35, 46, 53, 64, 64, 64, 64,
- 48, 43, 53, 64, 64, 64, 64, 64
- },
- {/*level 4 - low quality */
- 21, 25, 32, 38, 54, 68, 68, 68,
- 25, 28, 24, 38, 54, 68, 68, 68,
- 32, 24, 32, 43, 66, 68, 68, 68,
- 38, 38, 43, 53, 68, 68, 68, 68,
- 54, 54, 66, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68
- }
-};
+#include "jpeg-hw-v1.h"
+#include "jpeg-hw-v2.h"
+#include "jpeg-regs-v1.h"
+#include "jpeg-regs-v2.h"
-static const unsigned char hdctbl0[16] = {
- 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
-};
-
-static const unsigned char hdctblg0[12] = {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb
-};
-static const unsigned char hactbl0[16] = {
- 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
-};
-static const unsigned char hactblg0[162] = {
- 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
- 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
- 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
- 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
- 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
- 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
- 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
- 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
- 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
- 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
- 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
- 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
- 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
- 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
- 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
- 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
- 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
- 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
- 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
- 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
- 0xf9, 0xfa
-};
-
-static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c)
+void jpeg_watchdog(unsigned long arg)
{
- return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler);
-}
-
-static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh)
-{
- return container_of(fh, struct s5p_jpeg_ctx, fh);
-}
-
-static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl,
- unsigned long tab, int len)
-{
- int i;
+ struct jpeg_dev *dev = (struct jpeg_dev *)arg;
- for (i = 0; i < len; i++)
- writel((unsigned int)qtbl[i], regs + tab + (i * 0x04));
-}
-
-static inline void jpeg_set_qtbl_lum(void __iomem *regs, int quality)
-{
- /* this driver fills quantisation table 0 with data for luma */
- jpeg_set_qtbl(regs, qtbl_luminance[quality], S5P_JPG_QTBL_CONTENT(0),
- ARRAY_SIZE(qtbl_luminance[quality]));
-}
-
-static inline void jpeg_set_qtbl_chr(void __iomem *regs, int quality)
-{
- /* this driver fills quantisation table 1 with data for chroma */
- jpeg_set_qtbl(regs, qtbl_chrominance[quality], S5P_JPG_QTBL_CONTENT(1),
- ARRAY_SIZE(qtbl_chrominance[quality]));
-}
-
-static inline void jpeg_set_htbl(void __iomem *regs, const unsigned char *htbl,
- unsigned long tab, int len)
-{
- int i;
-
- for (i = 0; i < len; i++)
- writel((unsigned int)htbl[i], regs + tab + (i * 0x04));
-}
-
-static inline void jpeg_set_hdctbl(void __iomem *regs)
-{
- /* this driver fills table 0 for this component */
- jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0), ARRAY_SIZE(hdctbl0));
-}
+ dev_dbg(&dev->plat_dev->dev, "jpeg_watchdog\n");
+ if (test_bit(0, &dev->hw_run)) {
+ atomic_inc(&dev->watchdog_cnt);
+ dev_dbg(&dev->plat_dev->dev, "jpeg_watchdog_count\n");
+ }
-static inline void jpeg_set_hdctblg(void __iomem *regs)
-{
- /* this driver fills table 0 for this component */
- jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0), ARRAY_SIZE(hdctblg0));
-}
+ if (atomic_read(&dev->watchdog_cnt) >= JPEG_WATCHDOG_CNT)
+ queue_work(dev->watchdog_workqueue, &dev->watchdog_work);
-static inline void jpeg_set_hactbl(void __iomem *regs)
-{
- /* this driver fills table 0 for this component */
- jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0), ARRAY_SIZE(hactbl0));
+ dev->watchdog_timer.expires = jiffies +
+ msecs_to_jiffies(JPEG_WATCHDOG_INTERVAL);
+ add_timer(&dev->watchdog_timer);
}
-static inline void jpeg_set_hactblg(void __iomem *regs)
-{
- /* this driver fills table 0 for this component */
- jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0), ARRAY_SIZE(hactblg0));
-}
-
-/*
- * ============================================================================
- * Device file operations
- * ============================================================================
- */
-
-static int queue_init(void *priv, struct vb2_queue *src_vq,
- struct vb2_queue *dst_vq);
-static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode,
- __u32 pixelformat);
-static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx);
-
-static int s5p_jpeg_open(struct file *file)
+static void jpeg_watchdog_worker(struct work_struct *work)
{
- struct s5p_jpeg *jpeg = video_drvdata(file);
- struct video_device *vfd = video_devdata(file);
- struct s5p_jpeg_ctx *ctx;
- struct s5p_jpeg_fmt *out_fmt;
- int ret = 0;
+ struct jpeg_dev *dev;
+ struct jpeg_ctx *ctx;
+ unsigned long flags;
+ struct vb2_buffer *src_vb, *dst_vb;
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
+ dev_dbg(&dev->plat_dev->dev, "jpeg_watch_worker\n");
+ dev = container_of(work, struct jpeg_dev, watchdog_work);
- if (mutex_lock_interruptible(&jpeg->lock)) {
- ret = -ERESTARTSYS;
- goto free;
- }
+ spin_lock_irqsave(&dev->slock, flags);
+ clear_bit(0, &dev->hw_run);
+ if (dev->mode == ENCODING)
+ ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev_enc);
+ else
+ ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev_dec);
- v4l2_fh_init(&ctx->fh, vfd);
- /* Use separate control handler per file handle */
- ctx->fh.ctrl_handler = &ctx->ctrl_handler;
- file->private_data = &ctx->fh;
- v4l2_fh_add(&ctx->fh);
+ if (ctx) {
+ src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+ dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
- ctx->jpeg = jpeg;
- if (vfd == jpeg->vfd_encoder) {
- ctx->mode = S5P_JPEG_ENCODE;
- out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_RGB565);
+ v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
+ v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
+ if (dev->mode == ENCODING)
+ v4l2_m2m_job_finish(dev->m2m_dev_enc, ctx->m2m_ctx);
+ else
+ v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
} else {
- ctx->mode = S5P_JPEG_DECODE;
- out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_JPEG);
+ dev_err(&dev->plat_dev->dev, "watchdog_ctx is NULL\n");
}
- ret = s5p_jpeg_controls_create(ctx);
- if (ret < 0)
- goto error;
-
- ctx->m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
- if (IS_ERR(ctx->m2m_ctx)) {
- ret = PTR_ERR(ctx->m2m_ctx);
- goto error;
- }
-
- ctx->out_q.fmt = out_fmt;
- ctx->cap_q.fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_YUYV);
- mutex_unlock(&jpeg->lock);
- return 0;
-
-error:
- v4l2_fh_del(&ctx->fh);
- v4l2_fh_exit(&ctx->fh);
- mutex_unlock(&jpeg->lock);
-free:
- kfree(ctx);
- return ret;
+ spin_unlock_irqrestore(&dev->slock, flags);
}
-static int s5p_jpeg_release(struct file *file)
+static int jpeg_dec_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt, unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ void *allocators[])
{
- struct s5p_jpeg *jpeg = video_drvdata(file);
- struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
-
- mutex_lock(&jpeg->lock);
- v4l2_m2m_ctx_release(ctx->m2m_ctx);
- mutex_unlock(&jpeg->lock);
- v4l2_ctrl_handler_free(&ctx->ctrl_handler);
- v4l2_fh_del(&ctx->fh);
- v4l2_fh_exit(&ctx->fh);
- kfree(ctx);
+ struct jpeg_ctx *ctx = vb2_get_drv_priv(vq);
+ int i;
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ *num_planes = ctx->param.dec_param.in_plane;
+ for (i = 0; i < ctx->param.dec_param.in_plane; i++) {
+ sizes[i] = ctx->param.dec_param.mem_size;
+ allocators[i] = ctx->dev->alloc_ctx;
+ }
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ *num_planes = ctx->param.dec_param.out_plane;
+ for (i = 0; i < ctx->param.dec_param.out_plane; i++) {
+ sizes[i] = (ctx->param.dec_param.out_width *
+ ctx->param.dec_param.out_height *
+ ctx->param.dec_param.out_depth[i]) / 8;
+ allocators[i] = ctx->dev->alloc_ctx;
+ }
+ }
return 0;
}
-static unsigned int s5p_jpeg_poll(struct file *file,
- struct poll_table_struct *wait)
+static int jpeg_dec_buf_prepare(struct vb2_buffer *vb)
{
- struct s5p_jpeg *jpeg = video_drvdata(file);
- struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
- unsigned int res;
-
- mutex_lock(&jpeg->lock);
- res = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
- mutex_unlock(&jpeg->lock);
- return res;
-}
+ int i;
+ int num_plane = 0;
+ struct jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ num_plane = ctx->param.dec_param.in_plane;
+ if (ctx->input_cacheable == 1)
+ ctx->dev->vb2->cache_flush(vb, num_plane);
+ } else if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ num_plane = ctx->param.dec_param.out_plane;
+ if (ctx->output_cacheable == 1)
+ ctx->dev->vb2->cache_flush(vb, num_plane);
+ }
-static int s5p_jpeg_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct s5p_jpeg *jpeg = video_drvdata(file);
- struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
- int ret;
+ for (i = 0; i < num_plane; i++)
+ vb2_set_plane_payload(vb, i, ctx->payload[i]);
- if (mutex_lock_interruptible(&jpeg->lock))
- return -ERESTARTSYS;
- ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
- mutex_unlock(&jpeg->lock);
- return ret;
+ return 0;
}
-static const struct v4l2_file_operations s5p_jpeg_fops = {
- .owner = THIS_MODULE,
- .open = s5p_jpeg_open,
- .release = s5p_jpeg_release,
- .poll = s5p_jpeg_poll,
- .unlocked_ioctl = video_ioctl2,
- .mmap = s5p_jpeg_mmap,
-};
-
-/*
- * ============================================================================
- * video ioctl operations
- * ============================================================================
- */
-
-static int get_byte(struct s5p_jpeg_buffer *buf)
+static void jpeg_dec_buf_queue(struct vb2_buffer *vb)
{
- if (buf->curr >= buf->size)
- return -1;
+ struct jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
- return ((unsigned char *)buf->data)[buf->curr++];
+ if (ctx->m2m_ctx)
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
}
-static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word)
+static void jpeg_dec_lock(struct vb2_queue *vq)
{
- unsigned int temp;
- int byte;
-
- byte = get_byte(buf);
- if (byte == -1)
- return -1;
- temp = byte << 8;
- byte = get_byte(buf);
- if (byte == -1)
- return -1;
- *word = (unsigned int)byte | temp;
- return 0;
+ struct jpeg_ctx *ctx = vb2_get_drv_priv(vq);
+ mutex_lock(&ctx->dev->lock);
}
-static void skip(struct s5p_jpeg_buffer *buf, long len)
+static void jpeg_dec_unlock(struct vb2_queue *vq)
{
- if (len <= 0)
- return;
-
- while (len--)
- get_byte(buf);
+ struct jpeg_ctx *ctx = vb2_get_drv_priv(vq);
+ mutex_unlock(&ctx->dev->lock);
}
-static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
- unsigned long buffer, unsigned long size)
+static int jpeg_enc_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt, unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ void *allocators[])
{
- int c, components, notfound;
- unsigned int height, width, word;
- long length;
- struct s5p_jpeg_buffer jpeg_buffer;
-
- jpeg_buffer.size = size;
- jpeg_buffer.data = buffer;
- jpeg_buffer.curr = 0;
-
- notfound = 1;
- while (notfound) {
- c = get_byte(&jpeg_buffer);
- if (c == -1)
- break;
- if (c != 0xff)
- continue;
- do
- c = get_byte(&jpeg_buffer);
- while (c == 0xff);
- if (c == -1)
- break;
- if (c == 0)
- continue;
- length = 0;
- switch (c) {
- /* SOF0: baseline JPEG */
- case SOF0:
- if (get_word_be(&jpeg_buffer, &word))
- break;
- if (get_byte(&jpeg_buffer) == -1)
- break;
- if (get_word_be(&jpeg_buffer, &height))
- break;
- if (get_word_be(&jpeg_buffer, &width))
- break;
- components = get_byte(&jpeg_buffer);
- if (components == -1)
- break;
- notfound = 0;
-
- skip(&jpeg_buffer, components * 3);
- break;
+ struct jpeg_ctx *ctx = vb2_get_drv_priv(vq);
- /* skip payload-less markers */
- case RST ... RST + 7:
- case SOI:
- case EOI:
- case TEM:
- break;
+ int i;
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ *num_planes = ctx->param.enc_param.in_plane;
+ for (i = 0; i < ctx->param.enc_param.in_plane; i++) {
+ sizes[i] = (ctx->param.enc_param.in_width *
+ ctx->param.enc_param.in_height *
+ ctx->param.enc_param.in_depth[i]) / 8;
+ allocators[i] = ctx->dev->alloc_ctx;
+ }
- /* skip uninteresting payload markers */
- default:
- if (get_word_be(&jpeg_buffer, &word))
- break;
- length = (long)word - 2;
- skip(&jpeg_buffer, length);
- break;
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ *num_planes = ctx->param.enc_param.out_plane;
+ for (i = 0; i < ctx->param.enc_param.in_plane; i++) {
+ sizes[i] = (ctx->param.enc_param.out_width *
+ ctx->param.enc_param.out_height *
+ ctx->param.enc_param.out_depth) / 8;
+ allocators[i] = ctx->dev->alloc_ctx;
}
}
- result->w = width;
- result->h = height;
- result->size = components;
- return !notfound;
-}
-
-static int s5p_jpeg_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
- if (ctx->mode == S5P_JPEG_ENCODE) {
- strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder",
- sizeof(cap->driver));
- strlcpy(cap->card, S5P_JPEG_M2M_NAME " encoder",
- sizeof(cap->card));
- } else {
- strlcpy(cap->driver, S5P_JPEG_M2M_NAME " decoder",
- sizeof(cap->driver));
- strlcpy(cap->card, S5P_JPEG_M2M_NAME " decoder",
- sizeof(cap->card));
- }
- cap->bus_info[0] = 0;
- /*
- * This is only a mem-to-mem video device. The capture and output
- * device capability flags are left only for backward compatibility
- * and are scheduled for removal.
- */
- cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M |
- V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT;
return 0;
}
-static int enum_fmt(struct s5p_jpeg_fmt *formats, int n,
- struct v4l2_fmtdesc *f, u32 type)
+static int jpeg_enc_buf_prepare(struct vb2_buffer *vb)
{
- int i, num = 0;
-
- for (i = 0; i < n; ++i) {
- if (formats[i].types & type) {
- /* index-th format of type type found ? */
- if (num == f->index)
- break;
- /* Correct type but haven't reached our index yet,
- * just increment per-type index */
- ++num;
- }
+ int i;
+ int num_plane = 0;
+
+ struct jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ num_plane = ctx->param.enc_param.in_plane;
+ if (ctx->input_cacheable == 1)
+ ctx->dev->vb2->cache_flush(vb, num_plane);
+ } else if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ num_plane = ctx->param.enc_param.out_plane;
+ if (ctx->output_cacheable == 1)
+ ctx->dev->vb2->cache_flush(vb, num_plane);
}
- /* Format not found */
- if (i >= n)
- return -EINVAL;
-
- strlcpy(f->description, formats[i].name, sizeof(f->description));
- f->pixelformat = formats[i].fourcc;
+ for (i = 0; i < num_plane; i++)
+ vb2_set_plane_payload(vb, i, ctx->payload[i]);
return 0;
}
-static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
+static void jpeg_enc_buf_queue(struct vb2_buffer *vb)
{
- struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
-
- if (ctx->mode == S5P_JPEG_ENCODE)
- return enum_fmt(formats_enc, NUM_FORMATS_ENC, f,
- MEM2MEM_CAPTURE);
-
- return enum_fmt(formats_dec, NUM_FORMATS_DEC, f, MEM2MEM_CAPTURE);
+ struct jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ if (ctx->m2m_ctx)
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
}
-static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
+static void jpeg_enc_lock(struct vb2_queue *vq)
{
- struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
-
- if (ctx->mode == S5P_JPEG_ENCODE)
- return enum_fmt(formats_enc, NUM_FORMATS_ENC, f,
- MEM2MEM_OUTPUT);
-
- return enum_fmt(formats_dec, NUM_FORMATS_DEC, f, MEM2MEM_OUTPUT);
+ struct jpeg_ctx *ctx = vb2_get_drv_priv(vq);
+ mutex_lock(&ctx->dev->lock);
}
-static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx,
- enum v4l2_buf_type type)
+static void jpeg_enc_unlock(struct vb2_queue *vq)
{
- if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
- return &ctx->out_q;
- if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return &ctx->cap_q;
-
- return NULL;
+ struct jpeg_ctx *ctx = vb2_get_drv_priv(vq);
+ mutex_unlock(&ctx->dev->lock);
}
-static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
-{
- struct vb2_queue *vq;
- struct s5p_jpeg_q_data *q_data = NULL;
- struct v4l2_pix_format *pix = &f->fmt.pix;
- struct s5p_jpeg_ctx *ct = fh_to_ctx(priv);
-
- vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type);
- if (!vq)
- return -EINVAL;
-
- if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
- ct->mode == S5P_JPEG_DECODE && !ct->hdr_parsed)
- return -EINVAL;
- q_data = get_q_data(ct, f->type);
- BUG_ON(q_data == NULL);
-
- pix->width = q_data->w;
- pix->height = q_data->h;
- pix->field = V4L2_FIELD_NONE;
- pix->pixelformat = q_data->fmt->fourcc;
- pix->bytesperline = 0;
- if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
- u32 bpl = q_data->w;
- if (q_data->fmt->colplanes == 1)
- bpl = (bpl * q_data->fmt->depth) >> 3;
- pix->bytesperline = bpl;
- }
- pix->sizeimage = q_data->size;
+static struct vb2_ops jpeg_enc_vb2_qops = {
+ .queue_setup = jpeg_enc_queue_setup,
+ .buf_prepare = jpeg_enc_buf_prepare,
+ .buf_queue = jpeg_enc_buf_queue,
+ .wait_prepare = jpeg_enc_lock,
+ .wait_finish = jpeg_enc_unlock,
+};
- return 0;
-}
+static struct vb2_ops jpeg_dec_vb2_qops = {
+ .queue_setup = jpeg_dec_queue_setup,
+ .buf_prepare = jpeg_dec_buf_prepare,
+ .buf_queue = jpeg_dec_buf_queue,
+ .wait_prepare = jpeg_dec_lock,
+ .wait_finish = jpeg_dec_unlock,
+};
-static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode,
- u32 pixelformat)
+static inline enum jpeg_node_type jpeg_get_node_type(struct file *file)
{
- unsigned int k;
- struct s5p_jpeg_fmt *formats;
- int n;
-
- if (mode == S5P_JPEG_ENCODE) {
- formats = formats_enc;
- n = NUM_FORMATS_ENC;
- } else {
- formats = formats_dec;
- n = NUM_FORMATS_DEC;
- }
+ struct video_device *vdev = video_devdata(file);
- for (k = 0; k < n; k++) {
- struct s5p_jpeg_fmt *fmt = &formats[k];
- if (fmt->fourcc == pixelformat)
- return fmt;
+ if (!vdev) {
+ jpeg_err("failed to get video_device\n");
+ return JPEG_NODE_INVALID;
}
- return NULL;
+ jpeg_dbg("video_device index: %d\n", vdev->num);
+ if (!strcmp(vdev->name, JPEG_DEC_NAME))
+ return JPEG_NODE_DECODER;
+ else if (!strcmp(vdev->name, JPEG_ENC_NAME))
+ return JPEG_NODE_ENCODER;
+ else
+ return JPEG_NODE_INVALID;
}
-static void jpeg_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
- unsigned int walign,
- u32 *h, unsigned int hmin, unsigned int hmax,
- unsigned int halign)
+static int queue_init_dec(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
{
- int width, height, w_step, h_step;
-
- width = *w;
- height = *h;
-
- w_step = 1 << walign;
- h_step = 1 << halign;
- v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
+ struct jpeg_ctx *ctx = priv;
+ int ret;
- if (*w < width && (*w + w_step) < wmax)
- *w += w_step;
- if (*h < height && (*h + h_step) < hmax)
- *h += h_step;
+ memset(src_vq, 0, sizeof(*src_vq));
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ src_vq->drv_priv = ctx;
+ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ src_vq->ops = &jpeg_dec_vb2_qops;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+ memset(dst_vq, 0, sizeof(*dst_vq));
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ dst_vq->drv_priv = ctx;
+ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->ops = &jpeg_dec_vb2_qops;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ return vb2_queue_init(dst_vq);
}
-static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
- struct s5p_jpeg_ctx *ctx, int q_type)
+static int queue_init_enc(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
{
- struct v4l2_pix_format *pix = &f->fmt.pix;
-
- if (pix->field == V4L2_FIELD_ANY)
- pix->field = V4L2_FIELD_NONE;
- else if (pix->field != V4L2_FIELD_NONE)
- return -EINVAL;
-
- /* V4L2 specification suggests the driver corrects the format struct
- * if any of the dimensions is unsupported */
- if (q_type == MEM2MEM_OUTPUT)
- jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
- S5P_JPEG_MAX_WIDTH, 0,
- &pix->height, S5P_JPEG_MIN_HEIGHT,
- S5P_JPEG_MAX_HEIGHT, 0);
- else
- jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
- S5P_JPEG_MAX_WIDTH, fmt->h_align,
- &pix->height, S5P_JPEG_MIN_HEIGHT,
- S5P_JPEG_MAX_HEIGHT, fmt->v_align);
-
- if (fmt->fourcc == V4L2_PIX_FMT_JPEG) {
- if (pix->sizeimage <= 0)
- pix->sizeimage = PAGE_SIZE;
- pix->bytesperline = 0;
- } else {
- u32 bpl = pix->bytesperline;
+ struct jpeg_ctx *ctx = priv;
+ int ret;
- if (fmt->colplanes > 1 && bpl < pix->width)
- bpl = pix->width; /* planar */
+ memset(src_vq, 0, sizeof(*src_vq));
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ src_vq->drv_priv = ctx;
+ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ src_vq->ops = &jpeg_enc_vb2_qops;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
- if (fmt->colplanes == 1 && /* packed */
- (bpl << 3) * fmt->depth < pix->width)
- bpl = (pix->width * fmt->depth) >> 3;
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
- pix->bytesperline = bpl;
- pix->sizeimage = (pix->width * pix->height * fmt->depth) >> 3;
- }
+ memset(dst_vq, 0, sizeof(*dst_vq));
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ dst_vq->drv_priv = ctx;
+ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->ops = &jpeg_enc_vb2_qops;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
- return 0;
+ return vb2_queue_init(dst_vq);
}
-static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+static int s5p_jpeg_controls_create(struct jpeg_ctx *ctx);
+
+static int jpeg_m2m_open(struct file *file)
{
- struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
- struct s5p_jpeg_fmt *fmt;
-
- fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat);
- if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) {
- v4l2_err(&ctx->jpeg->v4l2_dev,
- "Fourcc format (0x%08x) invalid.\n",
- f->fmt.pix.pixelformat);
- return -EINVAL;
- }
+ struct jpeg_dev *dev = video_drvdata(file);
+ struct jpeg_ctx *ctx = NULL;
+ int ret = 0;
+ enum jpeg_node_type node;
- return vidioc_try_fmt(f, fmt, ctx, MEM2MEM_CAPTURE);
-}
+ node = jpeg_get_node_type(file);
-static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
- struct s5p_jpeg_fmt *fmt;
-
- fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat);
- if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) {
- v4l2_err(&ctx->jpeg->v4l2_dev,
- "Fourcc format (0x%08x) invalid.\n",
- f->fmt.pix.pixelformat);
- return -EINVAL;
+ if (node == JPEG_NODE_INVALID) {
+ jpeg_err("cannot specify node type\n");
+ ret = -ENOENT;
+ goto err_node_type;
}
- return vidioc_try_fmt(f, fmt, ctx, MEM2MEM_OUTPUT);
-}
-
-static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
-{
- struct vb2_queue *vq;
- struct s5p_jpeg_q_data *q_data = NULL;
- struct v4l2_pix_format *pix = &f->fmt.pix;
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
- vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type);
- if (!vq)
- return -EINVAL;
+ file->private_data = ctx;
+ ctx->dev = dev;
- q_data = get_q_data(ct, f->type);
- BUG_ON(q_data == NULL);
+ spin_lock_init(&ctx->slock);
- if (vb2_is_busy(vq)) {
- v4l2_err(&ct->jpeg->v4l2_dev, "%s queue busy\n", __func__);
- return -EBUSY;
+ ret = s5p_jpeg_controls_create(ctx);
+ if (ret < 0) {
+ dev_err(&dev->plat_dev->dev, "Failed to create jpeg controls\n");
+ return ret;
}
- q_data->fmt = s5p_jpeg_find_format(ct->mode, pix->pixelformat);
- q_data->w = pix->width;
- q_data->h = pix->height;
- if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG)
- q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3;
+ if (node == JPEG_NODE_DECODER)
+ ctx->m2m_ctx =
+ v4l2_m2m_ctx_init(dev->m2m_dev_dec, ctx,
+ queue_init_dec);
else
- q_data->size = pix->sizeimage;
-
- return 0;
-}
+ ctx->m2m_ctx =
+ v4l2_m2m_ctx_init(dev->m2m_dev_enc, ctx,
+ queue_init_enc);
-static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- int ret;
+ if (IS_ERR(ctx->m2m_ctx)) {
+ ret = PTR_ERR(ctx->m2m_ctx);
+ goto err_node_type;
+ }
+ clk_enable(dev->clk);
- ret = s5p_jpeg_try_fmt_vid_cap(file, priv, f);
- if (ret)
- return ret;
+ return 0;
- return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
+err_node_type:
+ kfree(ctx);
+ return ret;
}
-static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
- struct v4l2_format *f)
+static int jpeg_m2m_release(struct file *file)
{
- int ret;
+ struct jpeg_ctx *ctx = file->private_data;
- ret = s5p_jpeg_try_fmt_vid_out(file, priv, f);
- if (ret)
- return ret;
+ if (test_bit(0, &ctx->dev->hw_run) == 0)
+ del_timer_sync(&ctx->dev->watchdog_timer);
- return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
-}
-
-static int s5p_jpeg_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *reqbufs)
-{
- struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+ v4l2_m2m_ctx_release(ctx->m2m_ctx);
+ v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+ clk_disable(ctx->dev->clk);
+ kfree(ctx);
- return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+ return 0;
}
-static int s5p_jpeg_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
+static unsigned int jpeg_m2m_poll(struct file *file,
+ struct poll_table_struct *wait)
{
- struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
-
- return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+ struct jpeg_ctx *ctx = file->private_data;
+ return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
}
-static int s5p_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
-
- return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
-}
-static int s5p_jpeg_dqbuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
+static int jpeg_m2m_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
-
- return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+ struct jpeg_ctx *ctx = file->private_data;
+ return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
}
-static int s5p_jpeg_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
-
- return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
-}
+static const struct v4l2_file_operations jpeg_fops = {
+ .owner = THIS_MODULE,
+ .open = jpeg_m2m_open,
+ .release = jpeg_m2m_release,
+ .poll = jpeg_m2m_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = jpeg_m2m_mmap,
+};
-static int s5p_jpeg_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+static struct video_device jpeg_enc_videodev = {
+ .name = JPEG_ENC_NAME,
+ .fops = &jpeg_fops,
+ .release = video_device_release,
+ .vfl_dir = VFL_DIR_M2M,
+ .vfl_type = VFL_TYPE_GRABBER,
+};
- return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
-}
+static struct video_device jpeg_dec_videodev = {
+ .name = JPEG_DEC_NAME,
+ .fops = &jpeg_fops,
+ .release = video_device_release,
+ .vfl_dir = VFL_DIR_M2M,
+ .vfl_type = VFL_TYPE_GRABBER,
+};
-static int s5p_jpeg_g_selection(struct file *file, void *priv,
- struct v4l2_selection *s)
+static inline struct jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c)
{
- struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
-
- if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
- s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- /* For JPEG blob active == default == bounds */
- switch (s->target) {
- case V4L2_SEL_TGT_CROP:
- case V4L2_SEL_TGT_CROP_BOUNDS:
- case V4L2_SEL_TGT_CROP_DEFAULT:
- case V4L2_SEL_TGT_COMPOSE:
- case V4L2_SEL_TGT_COMPOSE_DEFAULT:
- s->r.width = ctx->out_q.w;
- s->r.height = ctx->out_q.h;
- break;
- case V4L2_SEL_TGT_COMPOSE_BOUNDS:
- case V4L2_SEL_TGT_COMPOSE_PADDED:
- s->r.width = ctx->cap_q.w;
- s->r.height = ctx->cap_q.h;
- break;
- default:
- return -EINVAL;
- }
- s->r.left = 0;
- s->r.top = 0;
- return 0;
+ return container_of(c->handler, struct jpeg_ctx, ctrl_handler);
}
/*
@@ -877,8 +453,8 @@ static int s5p_jpeg_g_selection(struct file *file, void *priv,
static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
- struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
- struct s5p_jpeg *jpeg = ctx->jpeg;
+ struct jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
+ struct jpeg_dev *jpeg = ctx->dev;
unsigned long flags;
switch (ctrl->id) {
@@ -899,14 +475,14 @@ static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
+ struct jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
unsigned long flags;
- spin_lock_irqsave(&ctx->jpeg->slock, flags);
+ spin_lock_irqsave(&ctx->dev->slock, flags);
switch (ctrl->id) {
case V4L2_CID_JPEG_COMPRESSION_QUALITY:
- ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - ctrl->val;
+ ctx->compr_quality = QUALITY_LEVEL_4 - ctrl->val;
break;
case V4L2_CID_JPEG_RESTART_INTERVAL:
ctx->restart_interval = ctrl->val;
@@ -916,7 +492,7 @@ static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
break;
}
- spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
+ spin_unlock_irqrestore(&ctx->dev->slock, flags);
return 0;
}
@@ -925,14 +501,14 @@ static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
.s_ctrl = s5p_jpeg_s_ctrl,
};
-static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
+static int s5p_jpeg_controls_create(struct jpeg_ctx *ctx)
{
unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */
struct v4l2_ctrl *ctrl;
v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
- if (ctx->mode == S5P_JPEG_ENCODE) {
+ if (ctx->dev->mode == ENCODING) {
v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
V4L2_CID_JPEG_COMPRESSION_QUALITY,
0, 3, 1, 3);
@@ -951,49 +527,17 @@ static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
if (ctx->ctrl_handler.error)
return ctx->ctrl_handler.error;
- if (ctx->mode == S5P_JPEG_DECODE)
+ if (ctx->dev->mode == DECODING)
ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
V4L2_CTRL_FLAG_READ_ONLY;
return 0;
}
-static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
- .vidioc_querycap = s5p_jpeg_querycap,
-
- .vidioc_enum_fmt_vid_cap = s5p_jpeg_enum_fmt_vid_cap,
- .vidioc_enum_fmt_vid_out = s5p_jpeg_enum_fmt_vid_out,
-
- .vidioc_g_fmt_vid_cap = s5p_jpeg_g_fmt,
- .vidioc_g_fmt_vid_out = s5p_jpeg_g_fmt,
-
- .vidioc_try_fmt_vid_cap = s5p_jpeg_try_fmt_vid_cap,
- .vidioc_try_fmt_vid_out = s5p_jpeg_try_fmt_vid_out,
-
- .vidioc_s_fmt_vid_cap = s5p_jpeg_s_fmt_vid_cap,
- .vidioc_s_fmt_vid_out = s5p_jpeg_s_fmt_vid_out,
- .vidioc_reqbufs = s5p_jpeg_reqbufs,
- .vidioc_querybuf = s5p_jpeg_querybuf,
-
- .vidioc_qbuf = s5p_jpeg_qbuf,
- .vidioc_dqbuf = s5p_jpeg_dqbuf,
-
- .vidioc_streamon = s5p_jpeg_streamon,
- .vidioc_streamoff = s5p_jpeg_streamoff,
-
- .vidioc_g_selection = s5p_jpeg_g_selection,
-};
-
-/*
- * ============================================================================
- * mem2mem callbacks
- * ============================================================================
- */
-
-static void s5p_jpeg_device_run(void *priv)
+static void jpeg_device_enc_run_v1(void *priv)
{
- struct s5p_jpeg_ctx *ctx = priv;
- struct s5p_jpeg *jpeg = ctx->jpeg;
+ struct jpeg_ctx *ctx = priv;
+ struct jpeg_dev *dev = ctx->dev;
struct vb2_buffer *src_buf, *dst_buf;
unsigned long src_addr, dst_addr;
@@ -1002,260 +546,349 @@ static void s5p_jpeg_device_run(void *priv)
src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
- jpeg_reset(jpeg->regs);
- jpeg_poweron(jpeg->regs);
- jpeg_proc_mode(jpeg->regs, ctx->mode);
- if (ctx->mode == S5P_JPEG_ENCODE) {
- if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565)
- jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_565);
+ dev->mode = ENCODING;
+
+ jpeg_reset(dev->reg_base);
+ jpeg_poweron(dev->reg_base);
+ jpeg_proc_mode(dev->reg_base, S5P_PROC_MODE_COMPR);
+
+ if (ctx->param.enc_param.in_fmt == YCBYCR_422_1P)
+ jpeg_input_raw_mode(dev->reg_base, S5P_JPEG_RAW_IN_422);
else
- jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_422);
- jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
- jpeg_dri(jpeg->regs, ctx->restart_interval);
- jpeg_x(jpeg->regs, ctx->out_q.w);
- jpeg_y(jpeg->regs, ctx->out_q.h);
- jpeg_imgadr(jpeg->regs, src_addr);
- jpeg_jpgadr(jpeg->regs, dst_addr);
+ jpeg_input_raw_mode(dev->reg_base, S5P_JPEG_RAW_IN_565);
+
+ jpeg_subsampling_mode(dev->reg_base, ctx->subsampling);
+
+ jpeg_dri(dev->reg_base, ctx->restart_interval);
+ jpeg_x(dev->reg_base, ctx->param.enc_param.in_width);
+ jpeg_y(dev->reg_base, ctx->param.enc_param.in_height);
+ jpeg_imgadr(dev->reg_base, src_addr);
+ jpeg_jpgadr(dev->reg_base, dst_addr);
/* ultimately comes from sizeimage from userspace */
- jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size);
+ jpeg_enc_stream_int(dev->reg_base, ctx->param.enc_param.size);
/* JPEG RGB to YCbCr conversion matrix */
- jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11);
- jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12);
- jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13);
- jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21);
- jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22);
- jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23);
- jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31);
- jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32);
- jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33);
+ jpeg_coef(dev->reg_base, 1, 1, S5P_JPEG_COEF11);
+ jpeg_coef(dev->reg_base, 1, 2, S5P_JPEG_COEF12);
+ jpeg_coef(dev->reg_base, 1, 3, S5P_JPEG_COEF13);
+ jpeg_coef(dev->reg_base, 2, 1, S5P_JPEG_COEF21);
+ jpeg_coef(dev->reg_base, 2, 2, S5P_JPEG_COEF22);
+ jpeg_coef(dev->reg_base, 2, 3, S5P_JPEG_COEF23);
+ jpeg_coef(dev->reg_base, 3, 1, S5P_JPEG_COEF31);
+ jpeg_coef(dev->reg_base, 3, 2, S5P_JPEG_COEF32);
+ jpeg_coef(dev->reg_base, 3, 3, S5P_JPEG_COEF33);
/*
* JPEG IP allows storing 4 quantization tables
* We fill table 0 for luma and table 1 for chroma
*/
- jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
- jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
+ jpeg_set_qtbl_lum(dev->reg_base, ctx->compr_quality);
+ jpeg_set_qtbl_chr(dev->reg_base, ctx->compr_quality);
+
/* use table 0 for Y */
- jpeg_qtbl(jpeg->regs, 1, 0);
+ jpeg_qtbl(dev->reg_base, 1, 0);
/* use table 1 for Cb and Cr*/
- jpeg_qtbl(jpeg->regs, 2, 1);
- jpeg_qtbl(jpeg->regs, 3, 1);
+ jpeg_qtbl(dev->reg_base, 2, 1);
+ jpeg_qtbl(dev->reg_base, 3, 1);
/* Y, Cb, Cr use Huffman table 0 */
- jpeg_htbl_ac(jpeg->regs, 1);
- jpeg_htbl_dc(jpeg->regs, 1);
- jpeg_htbl_ac(jpeg->regs, 2);
- jpeg_htbl_dc(jpeg->regs, 2);
- jpeg_htbl_ac(jpeg->regs, 3);
- jpeg_htbl_dc(jpeg->regs, 3);
- } else { /* S5P_JPEG_DECODE */
- jpeg_rst_int_enable(jpeg->regs, true);
- jpeg_data_num_int_enable(jpeg->regs, true);
- jpeg_final_mcu_num_int_enable(jpeg->regs, true);
- if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
- jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
- else
- jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420);
- jpeg_jpgadr(jpeg->regs, src_addr);
- jpeg_imgadr(jpeg->regs, dst_addr);
- }
-
- jpeg_start(jpeg->regs);
+ jpeg_htbl_ac(dev->reg_base, 1);
+ jpeg_htbl_dc(dev->reg_base, 1);
+ jpeg_htbl_ac(dev->reg_base, 2);
+ jpeg_htbl_dc(dev->reg_base, 2);
+ jpeg_htbl_ac(dev->reg_base, 3);
+ jpeg_htbl_dc(dev->reg_base, 3);
+
+ jpeg_start(dev->reg_base);
}
-static int s5p_jpeg_job_ready(void *priv)
+static void jpeg_device_dec_run_v1(void *priv)
{
- struct s5p_jpeg_ctx *ctx = priv;
-
- if (ctx->mode == S5P_JPEG_DECODE)
- return ctx->hdr_parsed;
- return 1;
-}
+ struct jpeg_ctx *ctx = priv;
+ struct jpeg_dev *dev = ctx->dev;
+ struct vb2_buffer *src_buf, *dst_buf;
+ unsigned long src_addr, dst_addr;
-static void s5p_jpeg_job_abort(void *priv)
-{
-}
+ dev->mode = DECODING;
-static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = {
- .device_run = s5p_jpeg_device_run,
- .job_ready = s5p_jpeg_job_ready,
- .job_abort = s5p_jpeg_job_abort,
-};
+ src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+ src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+ dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
-/*
- * ============================================================================
- * Queue operations
- * ============================================================================
- */
+ jpeg_reset(dev->reg_base);
+ jpeg_poweron(dev->reg_base);
+ jpeg_proc_mode(dev->reg_base, S5P_PROC_MODE_DECOMPR);
-static int s5p_jpeg_queue_setup(struct vb2_queue *vq,
- const struct v4l2_format *fmt,
- unsigned int *nbuffers, unsigned int *nplanes,
- unsigned int sizes[], void *alloc_ctxs[])
-{
- struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
- struct s5p_jpeg_q_data *q_data = NULL;
- unsigned int size, count = *nbuffers;
+ jpeg_rst_int_enable(dev->reg_base, true);
+ jpeg_data_num_int_enable(dev->reg_base, true);
+ jpeg_final_mcu_num_int_enable(dev->reg_base, true);
+ if (ctx->param.dec_param.out_fmt == YCBYCR_422_1P)
+ jpeg_outform_raw(dev->reg_base, S5P_JPEG_RAW_OUT_422);
+ else
+ jpeg_outform_raw(dev->reg_base, S5P_JPEG_RAW_OUT_420);
+ jpeg_jpgadr(dev->reg_base, src_addr);
+ jpeg_imgadr(dev->reg_base, dst_addr);
- q_data = get_q_data(ctx, vq->type);
- BUG_ON(q_data == NULL);
+ jpeg_start(dev->reg_base);
+}
- size = q_data->size;
- /*
- * header is parsed during decoding and parsed information stored
- * in the context so we do not allow another buffer to overwrite it
- */
- if (ctx->mode == S5P_JPEG_DECODE)
- count = 1;
+static void jpeg_device_enc_run_v2(void *priv)
+{
+ struct jpeg_ctx *ctx = priv;
+ struct jpeg_dev *dev = ctx->dev;
+ struct jpeg_enc_param enc_param;
+ struct vb2_buffer *vb = NULL;
+ unsigned long src_addr = 0, dst_addr = 0, src_addr2 = 0, src_addr3 = 0;
+ unsigned long flags;
- *nbuffers = count;
- *nplanes = 1;
- sizes[0] = size;
- alloc_ctxs[0] = ctx->jpeg->alloc_ctx;
+ dev = ctx->dev;
+ spin_lock_irqsave(&ctx->slock, flags);
+
+ dev->mode = ENCODING;
+ enc_param = ctx->param.enc_param;
+
+ jpeg_sw_reset(dev->reg_base);
+ jpeg_set_interrupt(dev->reg_base);
+ jpeg_set_huf_table_enable(dev->reg_base, 1);
+ jpeg_set_enc_tbl(dev->reg_base);
+ jpeg_set_encode_tbl_select(dev->reg_base, enc_param.quality);
+ jpeg_set_stream_size(dev->reg_base,
+ enc_param.in_width, enc_param.in_height);
+ jpeg_set_enc_out_fmt(dev->reg_base, enc_param.out_fmt);
+ jpeg_set_enc_in_fmt(dev->reg_base, enc_param.in_fmt);
+ vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+ dst_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+ jpeg_set_stream_buf_address(dev->reg_base, dst_addr);
+
+ vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+ src_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+ if (enc_param.in_plane == 1) {
+ src_addr2 = src_addr + enc_param.in_width*enc_param.in_height;
+ /*Here src_addr2 is the start address of U/V-component
+ of 420_1P image. Because JPEGv2x supports only 420_2P
+ and 420_3P, We are processing 420_1P as a 420_2P image.
+ Address of U/V-component will go as the
+ Address of 2nd Plane*/
+ jpeg_set_frame_buf_address(dev->reg_base,
+ enc_param.in_fmt, src_addr, src_addr2, 0);
+ } else if (enc_param.in_plane == 2) {
+ src_addr2 = vb2_dma_contig_plane_dma_addr(vb, 1);
+ jpeg_set_frame_buf_address(dev->reg_base,
+ enc_param.in_fmt, src_addr, src_addr2, 0);
+ } else if (enc_param.in_plane == 3) {
+ src_addr2 = vb2_dma_contig_plane_dma_addr(vb, 1);
+ src_addr3 = vb2_dma_contig_plane_dma_addr(vb, 2);
+ jpeg_set_frame_buf_address(dev->reg_base,
+ enc_param.in_fmt, src_addr, src_addr2, src_addr3);
+ }
- return 0;
+ jpeg_set_encode_hoff_cnt(dev->reg_base, enc_param.out_fmt);
+ jpeg_set_enc_dec_mode(dev->reg_base, ENCODING);
+ spin_unlock_irqrestore(&ctx->slock, flags);
}
-static int s5p_jpeg_buf_prepare(struct vb2_buffer *vb)
+static void jpeg_device_dec_run_v2(void *priv)
{
- struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
- struct s5p_jpeg_q_data *q_data = NULL;
+ struct jpeg_ctx *ctx = priv;
+ struct jpeg_dev *dev = ctx->dev;
+ struct jpeg_dec_param dec_param;
+ struct vb2_buffer *vb = NULL;
+ unsigned long flags;
- q_data = get_q_data(ctx, vb->vb2_queue->type);
- BUG_ON(q_data == NULL);
+ dev = ctx->dev;
+ spin_lock_irqsave(&ctx->slock, flags);
+ dev_dbg(&dev->plat_dev->dev, "dec_run.\n");
- if (vb2_plane_size(vb, 0) < q_data->size) {
- pr_err("%s data will not fit into plane (%lu < %lu)\n",
- __func__, vb2_plane_size(vb, 0),
- (long)q_data->size);
- return -EINVAL;
+ if (timer_pending(&ctx->dev->watchdog_timer) == 0) {
+ ctx->dev->watchdog_timer.expires = jiffies +
+ msecs_to_jiffies(JPEG_WATCHDOG_INTERVAL);
+ add_timer(&ctx->dev->watchdog_timer);
+ }
+ set_bit(0, &ctx->dev->hw_run);
+
+ dev->mode = DECODING;
+ dec_param = ctx->param.dec_param;
+
+ jpeg_sw_reset(dev->reg_base);
+ jpeg_set_interrupt(dev->reg_base);
+
+ jpeg_set_encode_tbl_select(dev->reg_base, 0);
+
+ vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+ jpeg_set_stream_buf_address(dev->reg_base, dev->vb2->plane_addr(vb, 0));
+
+ vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+ if (dec_param.out_plane == 1)
+ jpeg_set_frame_buf_address(dev->reg_base,
+ dec_param.out_fmt, dev->vb2->plane_addr(vb, 0), 0, 0);
+ else if (dec_param.out_plane == 2)
+ jpeg_set_frame_buf_address(dev->reg_base,
+ dec_param.out_fmt, dev->vb2->plane_addr(vb, 0),
+ dev->vb2->plane_addr(vb, 1), 0);
+ else if (dec_param.out_plane == 3)
+ jpeg_set_frame_buf_address(dev->reg_base,
+ dec_param.out_fmt, dev->vb2->plane_addr(vb, 0),
+ dev->vb2->plane_addr(vb, 1),
+ dev->vb2->plane_addr(vb, 2));
+
+ if (dec_param.out_width > 0 && dec_param.out_height > 0) {
+ if ((dec_param.out_width * 2 == dec_param.in_width) &&
+ (dec_param.out_height * 2 == dec_param.in_height))
+ jpeg_set_dec_scaling(dev->reg_base, JPEG_SCALE_2,
+ JPEG_SCALE_2);
+ else if ((dec_param.out_width * 4 == dec_param.in_width) &&
+ (dec_param.out_height * 4 == dec_param.in_height))
+ jpeg_set_dec_scaling(dev->reg_base, JPEG_SCALE_4,
+ JPEG_SCALE_4);
+ else
+ jpeg_set_dec_scaling(dev->reg_base,
+ JPEG_SCALE_NORMAL, JPEG_SCALE_NORMAL);
}
- vb2_set_plane_payload(vb, 0, q_data->size);
+ jpeg_set_dec_out_fmt(dev->reg_base, dec_param.out_fmt);
- return 0;
+ jpeg_set_dec_bitstream_size(dev->reg_base, dec_param.size);
+
+ jpeg_set_enc_dec_mode(dev->reg_base, DECODING);
+
+ spin_unlock_irqrestore(&ctx->slock, flags);
}
-static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
+static void jpeg_job_enc_abort(void *priv)
{
- struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-
- if (ctx->mode == S5P_JPEG_DECODE &&
- vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- struct s5p_jpeg_q_data tmp, *q_data;
- ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp,
- (unsigned long)vb2_plane_vaddr(vb, 0),
- min((unsigned long)ctx->out_q.size,
- vb2_get_plane_payload(vb, 0)));
- if (!ctx->hdr_parsed) {
- vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
- return;
- }
+}
- q_data = &ctx->out_q;
- q_data->w = tmp.w;
- q_data->h = tmp.h;
+static void jpeg_job_dec_abort(void *priv)
+{
+}
- q_data = &ctx->cap_q;
- q_data->w = tmp.w;
- q_data->h = tmp.h;
- jpeg_bound_align_image(&q_data->w, S5P_JPEG_MIN_WIDTH,
- S5P_JPEG_MAX_WIDTH, q_data->fmt->h_align,
- &q_data->h, S5P_JPEG_MIN_HEIGHT,
- S5P_JPEG_MAX_HEIGHT, q_data->fmt->v_align
- );
- q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3;
- }
- if (ctx->m2m_ctx)
- v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
-}
+static struct v4l2_m2m_ops *jpeg_m2m_enc_ops;
-static void s5p_jpeg_wait_prepare(struct vb2_queue *vq)
-{
- struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
+static struct v4l2_m2m_ops *jpeg_m2m_dec_ops;
- mutex_unlock(&ctx->jpeg->lock);
-}
+static struct v4l2_m2m_ops jpeg_m2m_enc_ops_v1 = {
+ .device_run = jpeg_device_enc_run_v1,
+ .job_abort = jpeg_job_enc_abort,
+};
-static void s5p_jpeg_wait_finish(struct vb2_queue *vq)
-{
- struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
+static struct v4l2_m2m_ops jpeg_m2m_dec_ops_v1 = {
+ .device_run = jpeg_device_dec_run_v1,
+ .job_abort = jpeg_job_dec_abort,
+};
+
+static struct v4l2_m2m_ops jpeg_m2m_enc_ops_v2 = {
+ .device_run = jpeg_device_enc_run_v2,
+ .job_abort = jpeg_job_enc_abort,
+};
- mutex_lock(&ctx->jpeg->lock);
+static struct v4l2_m2m_ops jpeg_m2m_dec_ops_v2 = {
+ .device_run = jpeg_device_dec_run_v2,
+ .job_abort = jpeg_job_dec_abort,
+};
+
+void s5p_jpeg_init_hw_ops(struct jpeg_dev *dev)
+{
+ if (dev->variant->version == JPEG_V2) {
+ jpeg_m2m_dec_ops = &jpeg_m2m_dec_ops_v2;
+ jpeg_m2m_enc_ops = &jpeg_m2m_enc_ops_v2;
+ } else {
+ jpeg_m2m_dec_ops = &jpeg_m2m_dec_ops_v1;
+ jpeg_m2m_enc_ops = &jpeg_m2m_enc_ops_v1;
+ }
}
-static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
+int jpeg_int_pending(struct jpeg_dev *ctrl)
{
- struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
- int ret;
+ unsigned int int_status;
- ret = pm_runtime_get_sync(ctx->jpeg->dev);
+ int_status = jpeg_get_int_status(ctrl->reg_base);
+ jpeg_dbg("state(%d)\n", int_status);
- return ret > 0 ? 0 : ret;
+ return int_status;
}
-static int s5p_jpeg_stop_streaming(struct vb2_queue *q)
+static irqreturn_t jpeg_irq_v2(int irq, void *priv)
{
- struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
+ unsigned int int_status;
+ struct vb2_buffer *src_vb, *dst_vb;
+ struct jpeg_dev *ctrl = priv;
+ struct jpeg_ctx *ctx;
+ unsigned long payload_size = 0;
- pm_runtime_put(ctx->jpeg->dev);
+ spin_lock(&ctrl->slock);
- return 0;
-}
+ if (ctrl->mode == ENCODING)
+ ctx = v4l2_m2m_get_curr_priv(ctrl->m2m_dev_enc);
+ else
+ ctx = v4l2_m2m_get_curr_priv(ctrl->m2m_dev_dec);
-static struct vb2_ops s5p_jpeg_qops = {
- .queue_setup = s5p_jpeg_queue_setup,
- .buf_prepare = s5p_jpeg_buf_prepare,
- .buf_queue = s5p_jpeg_buf_queue,
- .wait_prepare = s5p_jpeg_wait_prepare,
- .wait_finish = s5p_jpeg_wait_finish,
- .start_streaming = s5p_jpeg_start_streaming,
- .stop_streaming = s5p_jpeg_stop_streaming,
-};
+ if (ctx == 0) {
+ dev_err(&ctrl->plat_dev->dev, "ctx is null.\n");
+ int_status = jpeg_int_pending(ctrl);
+ jpeg_sw_reset(ctrl->reg_base);
+ goto ctx_err;
+ }
-static int queue_init(void *priv, struct vb2_queue *src_vq,
- struct vb2_queue *dst_vq)
-{
- struct s5p_jpeg_ctx *ctx = priv;
- int ret;
+ src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+ dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
- src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
- src_vq->drv_priv = ctx;
- src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
- src_vq->ops = &s5p_jpeg_qops;
- src_vq->mem_ops = &vb2_dma_contig_memops;
- src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ int_status = jpeg_int_pending(ctrl);
- ret = vb2_queue_init(src_vq);
- if (ret)
- return ret;
+ if (int_status) {
+ switch (int_status & 0x1f) {
+ case 0x1:
+ ctrl->irq_ret = ERR_PROT;
+ break;
+ case 0x2:
+ ctrl->irq_ret = OK_ENC_OR_DEC;
+ break;
+ case 0x4:
+ ctrl->irq_ret = ERR_DEC_INVALID_FORMAT;
+ break;
+ case 0x8:
+ ctrl->irq_ret = ERR_MULTI_SCAN;
+ break;
+ case 0x10:
+ ctrl->irq_ret = ERR_FRAME;
+ break;
+ default:
+ ctrl->irq_ret = ERR_UNKNOWN;
+ break;
+ }
+ } else {
+ ctrl->irq_ret = ERR_UNKNOWN;
+ }
- dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
- dst_vq->drv_priv = ctx;
- dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
- dst_vq->ops = &s5p_jpeg_qops;
- dst_vq->mem_ops = &vb2_dma_contig_memops;
- dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ if (ctrl->irq_ret == OK_ENC_OR_DEC) {
+ if (ctrl->mode == ENCODING) {
+ payload_size = jpeg_get_stream_size(ctrl->reg_base);
+ vb2_set_plane_payload(dst_vb, 0, payload_size);
+ }
+ v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
+ v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
+ } else {
+ v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
+ v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
+ }
- return vb2_queue_init(dst_vq);
+ clear_bit(0, &ctx->dev->hw_run);
+ if (ctrl->mode == ENCODING)
+ v4l2_m2m_job_finish(ctrl->m2m_dev_enc, ctx->m2m_ctx);
+ else
+ v4l2_m2m_job_finish(ctrl->m2m_dev_dec, ctx->m2m_ctx);
+ctx_err:
+ spin_unlock(&ctrl->slock);
+ return IRQ_HANDLED;
}
-/*
- * ============================================================================
- * ISR
- * ============================================================================
- */
-
-static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
+static irqreturn_t jpeg_irq_v1(int irq, void *dev_id)
{
- struct s5p_jpeg *jpeg = dev_id;
- struct s5p_jpeg_ctx *curr_ctx;
+ struct jpeg_dev *jpeg = dev_id;
+ struct jpeg_ctx *curr_ctx;
struct vb2_buffer *src_buf, *dst_buf;
unsigned long payload_size = 0;
enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
@@ -1265,267 +898,355 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
spin_lock(&jpeg->slock);
- curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
+ if (jpeg->mode == ENCODING)
+ curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev_dec);
+
+ else
+ curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev_dec);
+
+
+ if (curr_ctx == 0) {
+ dev_err(&jpeg->plat_dev->dev, "The ctx is null\n");
+ goto ctx_err;
+ }
+
src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
- if (curr_ctx->mode == S5P_JPEG_ENCODE)
- enc_jpeg_too_large = jpeg_enc_stream_stat(jpeg->regs);
- timer_elapsed = jpeg_timer_stat(jpeg->regs);
- op_completed = jpeg_result_stat_ok(jpeg->regs);
- if (curr_ctx->mode == S5P_JPEG_DECODE)
- op_completed = op_completed && jpeg_stream_stat_ok(jpeg->regs);
+ if (jpeg->mode == ENCODING)
+ enc_jpeg_too_large = jpeg_enc_stream_stat(jpeg->reg_base);
+ timer_elapsed = jpeg_timer_stat(jpeg->reg_base);
+ op_completed = jpeg_result_stat_ok(jpeg->reg_base);
+ if (jpeg->mode == DECODING)
+ op_completed =
+ op_completed && jpeg_stream_stat_ok(jpeg->reg_base);
if (enc_jpeg_too_large) {
state = VB2_BUF_STATE_ERROR;
- jpeg_clear_enc_stream_stat(jpeg->regs);
+ jpeg_clear_enc_stream_stat(jpeg->reg_base);
} else if (timer_elapsed) {
state = VB2_BUF_STATE_ERROR;
- jpeg_clear_timer_stat(jpeg->regs);
+ jpeg_clear_timer_stat(jpeg->reg_base);
} else if (!op_completed) {
state = VB2_BUF_STATE_ERROR;
} else {
- payload_size = jpeg_compressed_size(jpeg->regs);
+ payload_size = jpeg_compressed_size(jpeg->reg_base);
}
- dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
- dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
-
v4l2_m2m_buf_done(src_buf, state);
- if (curr_ctx->mode == S5P_JPEG_ENCODE)
+ if (jpeg->mode == ENCODING)
vb2_set_plane_payload(dst_buf, 0, payload_size);
v4l2_m2m_buf_done(dst_buf, state);
- v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->m2m_ctx);
- curr_ctx->subsampling = jpeg_get_subsampling_mode(jpeg->regs);
+ if (jpeg->mode == ENCODING)
+ v4l2_m2m_job_finish(jpeg->m2m_dev_enc, curr_ctx->m2m_ctx);
+ else
+ v4l2_m2m_job_finish(jpeg->m2m_dev_dec, curr_ctx->m2m_ctx);
+
+ curr_ctx->subsampling = jpeg_get_subsampling_mode(jpeg->reg_base);
spin_unlock(&jpeg->slock);
- jpeg_clear_int(jpeg->regs);
+ jpeg_clear_int(jpeg->reg_base);
return IRQ_HANDLED;
+ctx_err:
+ spin_unlock(&jpeg->slock);
+ return IRQ_HANDLED;
}
-/*
- * ============================================================================
- * Driver basic infrastructure
- * ============================================================================
- */
+static int jpeg_setup_controller(struct jpeg_dev *ctrl)
+{
+ mutex_init(&ctrl->lock);
+ init_waitqueue_head(&ctrl->wq);
+
+ return 0;
+}
-static int s5p_jpeg_probe(struct platform_device *pdev)
+const struct jpeg_vb2 jpeg_vb2_dma = {
+ .ops = &vb2_dma_contig_memops,
+ .init = vb2_dma_contig_init_ctx,
+ .cleanup = vb2_dma_contig_cleanup_ctx,
+ .plane_addr = vb2_dma_contig_plane_dma_addr,
+};
+
+static int jpeg_probe(struct platform_device *pdev)
{
- struct s5p_jpeg *jpeg;
+ struct jpeg_dev *dev;
+ struct video_device *vfd;
struct resource *res;
int ret;
-
- /* JPEG IP abstraction struct */
- jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL);
- if (!jpeg)
+ /* global structure */
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
return -ENOMEM;
- mutex_init(&jpeg->lock);
- spin_lock_init(&jpeg->slock);
- jpeg->dev = &pdev->dev;
+ dev->plat_dev = pdev;
+ dev->variant = (struct s5p_jpeg_variant *)
+ platform_get_device_id(pdev)->driver_data;
+ spin_lock_init(&dev->slock);
- /* memory-mapped registers */
+ /* setup jpeg control */
+ ret = jpeg_setup_controller(dev);
+ if (ret) {
+ jpeg_err("failed to setup controller\n");
+ goto err_setup;
+ }
+
+ /* memory region */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ jpeg_err("failed to get jpeg memory region resource\n");
+ ret = -ENOENT;
+ goto err_res;
+ }
- jpeg->regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(jpeg->regs))
- return PTR_ERR(jpeg->regs);
+ /* ioremap */
+ dev->reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (!dev->reg_base) {
+ jpeg_err("failed to remap jpeg io region\n");
+ ret = -ENOENT;
+ goto err_map;
+ }
- /* interrupt service routine registration */
- jpeg->irq = ret = platform_get_irq(pdev, 0);
- if (ret < 0) {
- dev_err(&pdev->dev, "cannot find IRQ\n");
- return ret;
+ /* irq */
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ jpeg_err("failed to request jpeg irq resource\n");
+ ret = -ENOENT;
+ goto err_irq;
}
- ret = devm_request_irq(&pdev->dev, jpeg->irq, s5p_jpeg_irq, 0,
- dev_name(&pdev->dev), jpeg);
- if (ret) {
- dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
- return ret;
+ dev->irq_no = res->start;
+ ret = devm_request_irq(&pdev->dev, dev->irq_no,
+ (void *)dev->variant->jpeg_irq, IRQF_DISABLED,
+ pdev->name, dev);
+ if (ret != 0) {
+ jpeg_err("failed to jpeg request irq\n");
+ ret = -ENOENT;
+ goto err_irq;
}
- /* clocks */
- jpeg->clk = clk_get(&pdev->dev, "jpeg");
- if (IS_ERR(jpeg->clk)) {
- dev_err(&pdev->dev, "cannot get clock\n");
- ret = PTR_ERR(jpeg->clk);
- return ret;
+ /* clock */
+ dev->clk = clk_get(&pdev->dev, "jpeg");
+ if (IS_ERR(dev->clk)) {
+ jpeg_err("failed to find jpeg clock source\n");
+ ret = -ENXIO;
+ goto err_clk;
}
- dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk);
- clk_prepare_enable(jpeg->clk);
- /* v4l2 device */
- ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
+ /* clock enable */
+ ret = clk_prepare_enable(dev->clk);
if (ret) {
- dev_err(&pdev->dev, "Failed to register v4l2 device\n");
- goto clk_get_rollback;
+ jpeg_err("failed to enable jpeg clock source\n");
+ ret = -ENOENT;
+ goto err_clk;
}
- /* mem2mem device */
- jpeg->m2m_dev = v4l2_m2m_init(&s5p_jpeg_m2m_ops);
- if (IS_ERR(jpeg->m2m_dev)) {
- v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
- ret = PTR_ERR(jpeg->m2m_dev);
- goto device_register_rollback;
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to register v4l2 device\n");
+ goto err_v4l2;
}
- jpeg->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
- if (IS_ERR(jpeg->alloc_ctx)) {
- v4l2_err(&jpeg->v4l2_dev, "Failed to init memory allocator\n");
- ret = PTR_ERR(jpeg->alloc_ctx);
- goto m2m_init_rollback;
- }
+ s5p_jpeg_init_hw_ops(dev);
- /* JPEG encoder /dev/videoX node */
- jpeg->vfd_encoder = video_device_alloc();
- if (!jpeg->vfd_encoder) {
- v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
+ /* encoder */
+ vfd = video_device_alloc();
+ if (!vfd) {
+ v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
ret = -ENOMEM;
- goto vb2_allocator_rollback;
+ goto err_vd_alloc_enc;
}
- strlcpy(jpeg->vfd_encoder->name, S5P_JPEG_M2M_NAME,
- sizeof(jpeg->vfd_encoder->name));
- jpeg->vfd_encoder->fops = &s5p_jpeg_fops;
- jpeg->vfd_encoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
- jpeg->vfd_encoder->minor = -1;
- jpeg->vfd_encoder->release = video_device_release;
- jpeg->vfd_encoder->lock = &jpeg->lock;
- jpeg->vfd_encoder->v4l2_dev = &jpeg->v4l2_dev;
- jpeg->vfd_encoder->vfl_dir = VFL_DIR_M2M;
-
- ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
+
+ *vfd = jpeg_enc_videodev;
+ vfd->ioctl_ops = get_jpeg_enc_v4l2_ioctl_ops();
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
if (ret) {
- v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
- goto enc_vdev_alloc_rollback;
+ v4l2_err(&dev->v4l2_dev,
+ "%s(): failed to register video device\n", __func__);
+ video_device_release(vfd);
+ goto err_vd_alloc_enc;
}
+ v4l2_info(&dev->v4l2_dev,
+ "JPEG encoder is registered to /dev/video%d\n", vfd->num);
+
+ dev->vfd_enc = vfd;
+ dev->m2m_dev_enc = v4l2_m2m_init(jpeg_m2m_enc_ops);
+ if (IS_ERR(dev->m2m_dev_enc)) {
+ v4l2_err(&dev->v4l2_dev,
+ "failed to initialize v4l2-m2m device\n");
+ ret = PTR_ERR(dev->m2m_dev_enc);
+ goto err_m2m_init_enc;
+ }
+ video_set_drvdata(vfd, dev);
- video_set_drvdata(jpeg->vfd_encoder, jpeg);
- v4l2_info(&jpeg->v4l2_dev,
- "encoder device registered as /dev/video%d\n",
- jpeg->vfd_encoder->num);
-
- /* JPEG decoder /dev/videoX node */
- jpeg->vfd_decoder = video_device_alloc();
- if (!jpeg->vfd_decoder) {
- v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
+ /* decoder */
+ vfd = video_device_alloc();
+ if (!vfd) {
+ v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
ret = -ENOMEM;
- goto enc_vdev_register_rollback;
+ goto err_vd_alloc_dec;
}
- strlcpy(jpeg->vfd_decoder->name, S5P_JPEG_M2M_NAME,
- sizeof(jpeg->vfd_decoder->name));
- jpeg->vfd_decoder->fops = &s5p_jpeg_fops;
- jpeg->vfd_decoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
- jpeg->vfd_decoder->minor = -1;
- jpeg->vfd_decoder->release = video_device_release;
- jpeg->vfd_decoder->lock = &jpeg->lock;
- jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev;
-
- ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
+
+ *vfd = jpeg_dec_videodev;
+ vfd->ioctl_ops = get_jpeg_dec_v4l2_ioctl_ops();
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
if (ret) {
- v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
- goto dec_vdev_alloc_rollback;
+ v4l2_err(&dev->v4l2_dev,
+ "%s(): failed to register video device\n", __func__);
+ video_device_release(vfd);
+ goto err_vd_alloc_dec;
}
- video_set_drvdata(jpeg->vfd_decoder, jpeg);
- v4l2_info(&jpeg->v4l2_dev,
- "decoder device registered as /dev/video%d\n",
- jpeg->vfd_decoder->num);
+ v4l2_info(&dev->v4l2_dev,
+ "JPEG decoder is registered to /dev/video%d\n", vfd->num);
- /* final statements & power management */
- platform_set_drvdata(pdev, jpeg);
+ dev->vfd_dec = vfd;
+ dev->m2m_dev_dec = v4l2_m2m_init(jpeg_m2m_dec_ops);
+ if (IS_ERR(dev->m2m_dev_dec)) {
+ v4l2_err(&dev->v4l2_dev,
+ "failed to initialize v4l2-m2m device\n");
+ ret = PTR_ERR(dev->m2m_dev_dec);
+ goto err_m2m_init_dec;
+ }
+ video_set_drvdata(vfd, dev);
- pm_runtime_enable(&pdev->dev);
+ platform_set_drvdata(pdev, dev);
- v4l2_info(&jpeg->v4l2_dev, "Samsung S5P JPEG codec\n");
+ dev->vb2 = &jpeg_vb2_dma;
- return 0;
+ dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
-dec_vdev_alloc_rollback:
- video_device_release(jpeg->vfd_decoder);
+ if (IS_ERR(dev->alloc_ctx)) {
+ ret = PTR_ERR(dev->alloc_ctx);
+ goto err_video_reg;
+ }
-enc_vdev_register_rollback:
- video_unregister_device(jpeg->vfd_encoder);
+ dev->watchdog_workqueue = create_singlethread_workqueue(JPEG_NAME);
+ INIT_WORK(&dev->watchdog_work, jpeg_watchdog_worker);
+ atomic_set(&dev->watchdog_cnt, 0);
+ init_timer(&dev->watchdog_timer);
+ dev->watchdog_timer.data = (unsigned long)dev;
+ dev->watchdog_timer.function = jpeg_watchdog;
+ clk_disable(dev->clk);
-enc_vdev_alloc_rollback:
- video_device_release(jpeg->vfd_encoder);
+ return 0;
-vb2_allocator_rollback:
- vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
+err_video_reg:
+ v4l2_m2m_release(dev->m2m_dev_dec);
+err_m2m_init_dec:
+ video_unregister_device(dev->vfd_dec);
+ video_device_release(dev->vfd_dec);
+err_vd_alloc_dec:
+ v4l2_m2m_release(dev->m2m_dev_enc);
+err_m2m_init_enc:
+ video_unregister_device(dev->vfd_enc);
+ video_device_release(dev->vfd_enc);
+err_vd_alloc_enc:
+ v4l2_device_unregister(&dev->v4l2_dev);
+err_v4l2:
+ clk_disable_unprepare(dev->clk);
+err_clk:
+ free_irq(dev->irq_no, NULL);
+err_irq:
+ iounmap(dev->reg_base);
+err_map:
+ kfree(res);
+err_res:
+ mutex_destroy(&dev->lock);
+err_setup:
+ kfree(dev);
+ return ret;
+}
-m2m_init_rollback:
- v4l2_m2m_release(jpeg->m2m_dev);
+static int jpeg_remove(struct platform_device *pdev)
+{
+ struct jpeg_dev *dev = platform_get_drvdata(pdev);
-device_register_rollback:
- v4l2_device_unregister(&jpeg->v4l2_dev);
+ del_timer_sync(&dev->watchdog_timer);
+ flush_workqueue(dev->watchdog_workqueue);
+ destroy_workqueue(dev->watchdog_workqueue);
-clk_get_rollback:
- clk_disable_unprepare(jpeg->clk);
- clk_put(jpeg->clk);
+ v4l2_m2m_release(dev->m2m_dev_enc);
+ video_unregister_device(dev->vfd_enc);
- return ret;
-}
+ v4l2_m2m_release(dev->m2m_dev_dec);
+ video_unregister_device(dev->vfd_dec);
-static int s5p_jpeg_remove(struct platform_device *pdev)
-{
- struct s5p_jpeg *jpeg = platform_get_drvdata(pdev);
+ v4l2_device_unregister(&dev->v4l2_dev);
- pm_runtime_disable(jpeg->dev);
+ dev->vb2->cleanup(dev->alloc_ctx);
- video_unregister_device(jpeg->vfd_decoder);
- video_device_release(jpeg->vfd_decoder);
- video_unregister_device(jpeg->vfd_encoder);
- video_device_release(jpeg->vfd_encoder);
- vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
- v4l2_m2m_release(jpeg->m2m_dev);
- v4l2_device_unregister(&jpeg->v4l2_dev);
+ free_irq(dev->irq_no, pdev);
+ mutex_destroy(&dev->lock);
+ iounmap(dev->reg_base);
- clk_disable_unprepare(jpeg->clk);
- clk_put(jpeg->clk);
+ clk_disable_unprepare(dev->clk);
+ clk_put(dev->clk);
+ kfree(dev);
return 0;
}
-static int s5p_jpeg_runtime_suspend(struct device *dev)
+static int jpeg_suspend(struct platform_device *pdev, pm_message_t state)
{
+ struct jpeg_dev *dev = platform_get_drvdata(pdev);
+
+ /* clock disable */
+ clk_disable(dev->clk);
return 0;
}
-static int s5p_jpeg_runtime_resume(struct device *dev)
+static int jpeg_resume(struct platform_device *pdev)
{
- struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
- /*
- * JPEG IP allows storing two Huffman tables for each component
- * We fill table 0 for each component
- */
- jpeg_set_hdctbl(jpeg->regs);
- jpeg_set_hdctblg(jpeg->regs);
- jpeg_set_hactbl(jpeg->regs);
- jpeg_set_hactblg(jpeg->regs);
+ struct jpeg_dev *dev = platform_get_drvdata(pdev);
+
+ /* clock enable */
+ clk_enable(dev->clk);
return 0;
}
-static const struct dev_pm_ops s5p_jpeg_pm_ops = {
- .runtime_suspend = s5p_jpeg_runtime_suspend,
- .runtime_resume = s5p_jpeg_runtime_resume,
+static struct s5p_jpeg_variant jpeg_drvdata_v1 = {
+ .version = JPEG_V1,
+ .jpeg_irq = jpeg_irq_v1,
+};
+
+static struct s5p_jpeg_variant jpeg_drvdata_v2 = {
+ .version = JPEG_V2,
+ .jpeg_irq = jpeg_irq_v2,
+};
+
+static struct platform_device_id jpeg_driver_ids[] = {
+ {
+ .name = "s5p-jpeg", /*For backward compatibility*/
+ .driver_data = (unsigned long)&jpeg_drvdata_v1,
+ }, {
+ .name = "s5pv210-jpeg",
+ .driver_data = (unsigned long)&jpeg_drvdata_v1,
+ }, {
+ .name = "exynos4212-jpeg",
+ .driver_data = (unsigned long)&jpeg_drvdata_v2,
+ }
};
-static struct platform_driver s5p_jpeg_driver = {
- .probe = s5p_jpeg_probe,
- .remove = s5p_jpeg_remove,
- .driver = {
- .owner = THIS_MODULE,
- .name = S5P_JPEG_M2M_NAME,
- .pm = &s5p_jpeg_pm_ops,
+MODULE_DEVICE_TABLE(platform, jpeg_driver_ids);
+
+static struct platform_driver jpeg_driver = {
+ .probe = jpeg_probe,
+ .remove = jpeg_remove,
+ .suspend = jpeg_suspend,
+ .resume = jpeg_resume,
+ .id_table = jpeg_driver_ids,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = JPEG_NAME,
+ .pm = NULL,
},
};
-module_platform_driver(s5p_jpeg_driver);
+module_platform_driver(jpeg_driver);
MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
MODULE_DESCRIPTION("Samsung JPEG codec driver");
MODULE_LICENSE("GPL");
-
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h
index 8a4013e..50dc2c9 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.h
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h
@@ -1,7 +1,7 @@
/* linux/drivers/media/platform/s5p-jpeg/jpeg-core.h
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
+ * http://www.samsung.com
*
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
*
@@ -10,141 +10,324 @@
* published by the Free Software Foundation.
*/
-#ifndef JPEG_CORE_H_
-#define JPEG_CORE_H_
+#ifndef __JPEG_CORE_H__
+#define __JPEG_CORE_H__
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+
+#include <linux/videodev2.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-fh.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-core.h>
+
+#define INT_TIMEOUT 1000
+#define JPEG_NAME "s5p-jpeg"
+#define JPEG_ENC_NAME "s5p-jpeg-enc"
+#define JPEG_DEC_NAME "s5p-jpeg-dec"
+
+#define JPEG_WATCHDOG_CNT 10
+#define JPEG_WATCHDOG_INTERVAL 1000
-#define S5P_JPEG_M2M_NAME "s5p-jpeg"
+#define JPEG_NUM_INST 4
+#define JPEG_MAX_PLANE 3
-/* JPEG compression quality setting */
-#define S5P_JPEG_COMPR_QUAL_BEST 0
-#define S5P_JPEG_COMPR_QUAL_WORST 3
+#define MAX_JPEG_WIDTH 3264
+#define MAX_JPEG_HEIGHT 2448
/* JPEG RGB to YCbCr conversion matrix coefficients */
-#define S5P_JPEG_COEF11 0x4d
-#define S5P_JPEG_COEF12 0x97
-#define S5P_JPEG_COEF13 0x1e
-#define S5P_JPEG_COEF21 0x2c
-#define S5P_JPEG_COEF22 0x57
-#define S5P_JPEG_COEF23 0x83
-#define S5P_JPEG_COEF31 0x83
-#define S5P_JPEG_COEF32 0x6e
-#define S5P_JPEG_COEF33 0x13
+#define S5P_JPEG_COEF11 0x4d
+#define S5P_JPEG_COEF12 0x97
+#define S5P_JPEG_COEF13 0x1e
+#define S5P_JPEG_COEF21 0x2c
+#define S5P_JPEG_COEF22 0x57
+#define S5P_JPEG_COEF23 0x83
+#define S5P_JPEG_COEF31 0x83
+#define S5P_JPEG_COEF32 0x6e
+#define S5P_JPEG_COEF33 0x13
/* a selection of JPEG markers */
-#define TEM 0x01
-#define SOF0 0xc0
-#define RST 0xd0
-#define SOI 0xd8
-#define EOI 0xd9
-#define DHP 0xde
-
-/* Flags that indicate a format can be used for capture/output */
-#define MEM2MEM_CAPTURE (1 << 0)
-#define MEM2MEM_OUTPUT (1 << 1)
-
-/**
- * struct s5p_jpeg - JPEG IP abstraction
- * @lock: the mutex protecting this structure
- * @slock: spinlock protecting the device contexts
- * @v4l2_dev: v4l2 device for mem2mem mode
- * @vfd_encoder: video device node for encoder mem2mem mode
- * @vfd_decoder: video device node for decoder mem2mem mode
- * @m2m_dev: v4l2 mem2mem device data
- * @regs: JPEG IP registers mapping
- * @irq: JPEG IP irq
- * @clk: JPEG IP clock
- * @dev: JPEG IP struct device
- * @alloc_ctx: videobuf2 memory allocator's context
- */
-struct s5p_jpeg {
- struct mutex lock;
- spinlock_t slock;
+#define TEM 0x01
+#define SOF0 0xc0
+#define RST 0xd0
+#define SOI 0xd8
+#define EOI 0xd9
+#define DHP 0xde
- struct v4l2_device v4l2_dev;
- struct video_device *vfd_encoder;
- struct video_device *vfd_decoder;
- struct v4l2_m2m_dev *m2m_dev;
+/* JPEG specific V4L2 formats */
- void __iomem *regs;
- unsigned int irq;
- struct clk *clk;
- struct device *dev;
- void *alloc_ctx;
-};
-
-/**
- * struct jpeg_fmt - driver's internal color format data
- * @name: format descritpion
- * @fourcc: the fourcc code, 0 if not applicable
- * @depth: number of bits per pixel
- * @colplanes: number of color planes (1 for packed formats)
- * @h_align: horizontal alignment order (align to 2^h_align)
- * @v_align: vertical alignment order (align to 2^v_align)
- * @types: types of queue this format is applicable to
- */
-struct s5p_jpeg_fmt {
- char *name;
- u32 fourcc;
- int depth;
- int colplanes;
- int h_align;
- int v_align;
- u32 types;
-};
-
-/**
- * s5p_jpeg_q_data - parameters of one queue
- * @fmt: driver-specific format of this queue
- * @w: image width
- * @h: image height
- * @size: image buffer size in bytes
- */
-struct s5p_jpeg_q_data {
- struct s5p_jpeg_fmt *fmt;
- u32 w;
- u32 h;
- u32 size;
-};
-
-/**
- * s5p_jpeg_ctx - the device context data
- * @jpeg: JPEG IP device for this context
- * @mode: compression (encode) operation or decompression (decode)
- * @compr_quality: destination image quality in compression (encode) mode
- * @m2m_ctx: mem2mem device context
- * @out_q: source (output) queue information
- * @cap_fmt: destination (capture) queue queue information
- * @hdr_parsed: set if header has been parsed during decompression
- * @ctrl_handler: controls handler
- */
-struct s5p_jpeg_ctx {
- struct s5p_jpeg *jpeg;
- unsigned int mode;
- unsigned short compr_quality;
- unsigned short restart_interval;
- unsigned short subsampling;
+/* yuv444 of JFIF JPEG */
+#define V4L2_PIX_FMT_JPEG_444 v4l2_fourcc('J', 'P', 'G', '4')
+
+/* yuv422 of JFIF JPEG */
+#define V4L2_PIX_FMT_JPEG_422 v4l2_fourcc('J', 'P', 'G', '2')
+
+/* yuv420 of JFIF JPEG */
+#define V4L2_PIX_FMT_JPEG_420 v4l2_fourcc('J', 'P', 'G', '0')
+
+/* grey of JFIF JPEG */
+#define V4L2_PIX_FMT_JPEG_GRAY v4l2_fourcc('J', 'P', 'G', 'G')
+
+/* two planes -- one Y, one Cr + Cb interleaved */
+#define V4L2_PIX_FMT_YUV444_2P v4l2_fourcc('Y', 'U', '2', 'P') /* 24 Y/CbCr */
+#define V4L2_PIX_FMT_YVU444_2P v4l2_fourcc('Y', 'V', '2', 'P') /* 24 Y/CrCb */
+
+/* three planes -- one Y, one Cr, one Cb */
+#define V4L2_PIX_FMT_YUV444_3P v4l2_fourcc('Y', 'U', '3', 'P') /* 24 Y/Cb/Cr */
+
+/*Version numbers*/
+#define JPEG_V1 1
+#define JPEG_V2 2
+
+enum jpeg_state {
+ JPEG_IDLE,
+ JPEG_SRC_ADDR,
+ JPEG_DST_ADDR,
+ JPEG_ISR,
+ JPEG_STREAM,
+};
+
+enum jpeg_mode {
+ ENCODING,
+ DECODING,
+};
+
+enum jpeg_result {
+ OK_ENC_OR_DEC,
+ ERR_PROT,
+ ERR_DEC_INVALID_FORMAT,
+ ERR_MULTI_SCAN,
+ ERR_FRAME,
+ ERR_UNKNOWN,
+};
+
+enum jpeg_img_quality_level {
+ QUALITY_LEVEL_1 = 0, /* high */
+ QUALITY_LEVEL_2,
+ QUALITY_LEVEL_3,
+ QUALITY_LEVEL_4, /* low */
+};
+
+/* raw data image format */
+enum jpeg_frame_format {
+ YCRCB_444_2P,
+ YCBCR_444_2P,
+ YCBCR_444_3P,
+ YCBYCR_422_1P,
+ YCRYCB_422_1P,
+ CBYCRY_422_1P,
+ CRYCBY_422_1P,
+ YCBCR_422_2P,
+ YCRCB_422_2P,
+ YCBYCR_422_3P,
+ YCBCR_420_3P,
+ YCBCR_420_2P,
+ YCRCB_420_2P,
+ YCBCR_420_2P_M,
+ YCRCB_420_2P_M,
+ RGB_565,
+ RGB_888,
+ GRAY,
+ YCBCR_420_1P,
+ YCRCB_420_1P,
+};
+
+/* jpeg data format */
+enum jpeg_stream_format {
+ JPEG_422, /* decode input, encode output */
+ JPEG_420, /* decode input, encode output */
+ JPEG_444, /* decode input*/
+ JPEG_GRAY, /* decode input*/
+ JPEG_RESERVED,
+};
+
+enum jpeg_scale_value {
+ JPEG_SCALE_NORMAL,
+ JPEG_SCALE_2,
+ JPEG_SCALE_4,
+};
+
+enum jpeg_interface {
+ M2M_OUTPUT,
+ M2M_CAPTURE,
+};
+
+enum jpeg_node_type {
+ JPEG_NODE_INVALID = -1,
+ JPEG_NODE_DECODER = 15,
+ JPEG_NODE_ENCODER = 14,
+};
+
+struct jpeg_fmt {
+ char *name;
+ unsigned int fourcc;
+ int depth[JPEG_MAX_PLANE];
+ int color;
+ int memplanes;
+ int colplanes;
+ enum jpeg_interface types;
+};
+
+struct jpeg_dec_param {
+ unsigned int in_width;
+ unsigned int in_height;
+ unsigned int out_width;
+ unsigned int out_height;
+ unsigned int size;
+ unsigned int mem_size;
+ unsigned int in_plane;
+ unsigned int out_plane;
+ unsigned int in_depth;
+ unsigned int out_depth[JPEG_MAX_PLANE];
+
+ enum jpeg_stream_format in_fmt;
+ enum jpeg_frame_format out_fmt;
+};
+
+struct jpeg_enc_param {
+ unsigned int in_width;
+ unsigned int in_height;
+ unsigned int out_width;
+ unsigned int out_height;
+ unsigned int size;
+ unsigned int in_plane;
+ unsigned int out_plane;
+ unsigned int in_depth[JPEG_MAX_PLANE];
+ unsigned int out_depth;
+
+ enum jpeg_frame_format in_fmt;
+ enum jpeg_stream_format out_fmt;
+ enum jpeg_img_quality_level quality;
+};
+
+struct jpeg_ctx {
+ spinlock_t slock;
+ struct jpeg_dev *dev;
struct v4l2_m2m_ctx *m2m_ctx;
- struct s5p_jpeg_q_data out_q;
- struct s5p_jpeg_q_data cap_q;
- struct v4l2_fh fh;
- bool hdr_parsed;
+
+ union {
+ struct jpeg_dec_param dec_param;
+ struct jpeg_enc_param enc_param;
+ } param;
+
+ unsigned short compr_quality;
+ unsigned short restart_interval;
+ unsigned short subsampling;
struct v4l2_ctrl_handler ctrl_handler;
+
+ int index;
+ unsigned long payload[VIDEO_MAX_PLANES];
+ bool input_cacheable;
+ bool output_cacheable;
};
-/**
- * s5p_jpeg_buffer - description of memory containing input JPEG data
- * @size: buffer size
- * @curr: current position in the buffer
- * @data: pointer to the data
- */
-struct s5p_jpeg_buffer {
- unsigned long size;
- unsigned long curr;
- unsigned long data;
+struct jpeg_vb2 {
+ const struct vb2_mem_ops *ops;
+ void *(*init)(struct device *dev);
+ void (*cleanup)(void *alloc_ctx);
+
+ dma_addr_t (*plane_addr)(struct vb2_buffer *vb, u32 plane_no);
+
+ void (*resume)(void *alloc_ctx);
+ void (*suspend)(void *alloc_ctx);
+
+ int (*cache_flush)(struct vb2_buffer *vb, u32 num_planes);
+ void (*set_cacheable)(void *alloc_ctx, bool cacheable);
+};
+
+struct jpeg_dev {
+ spinlock_t slock;
+ struct v4l2_device v4l2_dev;
+ struct video_device *vfd_enc;
+ struct video_device *vfd_dec;
+ struct v4l2_m2m_dev *m2m_dev_enc;
+ struct v4l2_m2m_dev *m2m_dev_dec;
+ struct jpeg_ctx *ctx;
+ struct vb2_alloc_ctx *alloc_ctx;
+
+ struct platform_device *plat_dev;
+
+ struct clk *clk;
+
+ struct mutex lock;
+
+ int irq_no;
+ enum jpeg_result irq_ret;
+ wait_queue_head_t wq;
+ void __iomem *reg_base; /* register i/o */
+ enum jpeg_mode mode;
+ const struct jpeg_vb2 *vb2;
+
+ unsigned long hw_run;
+ atomic_t watchdog_cnt;
+ struct timer_list watchdog_timer;
+ struct workqueue_struct *watchdog_workqueue;
+ struct work_struct watchdog_work;
+ struct device *bus_dev;
+ struct s5p_jpeg_variant *variant;
+};
+
+enum jpeg_log {
+ JPEG_LOG_DEBUG = 0x1000,
+ JPEG_LOG_INFO = 0x0100,
+ JPEG_LOG_WARN = 0x0010,
+ JPEG_LOG_ERR = 0x0001,
+};
+
+struct s5p_jpeg_variant {
+ unsigned int version;
+ irqreturn_t (*jpeg_irq)(int irq, void *priv);
};
-#endif /* JPEG_CORE_H */
+/* debug macro */
+#define JPEG_LOG_DEFAULT (JPEG_LOG_WARN | JPEG_LOG_ERR)
+
+#define JPEG_DEBUG(fmt, ...) \
+ do { \
+ if (JPEG_LOG_DEFAULT & JPEG_LOG_DEBUG) \
+ pr_debug("%s: " \
+ fmt, __func__, ##__VA_ARGS__); \
+ } while (0)
+
+#define JPEG_INFO(fmt, ...) \
+ do { \
+ if (JPEG_LOG_DEFAULT & JPEG_LOG_INFO) \
+ pr_debug("%s: " \
+ fmt, __func__, ##__VA_ARGS__); \
+ } while (0)
+
+#define JPEG_WARN(fmt, ...) \
+ do { \
+ if (JPEG_LOG_DEFAULT & JPEG_LOG_WARN) \
+ pr_debug("%s: " \
+ fmt, __func__, ##__VA_ARGS__); \
+ } while (0)
+
+
+#define JPEG_ERROR(fmt, ...) \
+ do { \
+ if (JPEG_LOG_DEFAULT & JPEG_LOG_ERR) \
+ pr_debug("%s: " \
+ fmt, __func__, ##__VA_ARGS__); \
+ } while (0)
+
+
+#define jpeg_dbg(fmt, ...) JPEG_DEBUG(fmt, ##__VA_ARGS__)
+#define jpeg_info(fmt, ...) JPEG_INFO(fmt, ##__VA_ARGS__)
+#define jpeg_warn(fmt, ...) JPEG_WARN(fmt, ##__VA_ARGS__)
+#define jpeg_err(fmt, ...) JPEG_ERROR(fmt, ##__VA_ARGS__)
+
+/*=====================================================================*/
+const struct v4l2_ioctl_ops *get_jpeg_dec_v4l2_ioctl_ops(void);
+const struct v4l2_ioctl_ops *get_jpeg_enc_v4l2_ioctl_ops(void);
+
+int jpeg_int_pending(struct jpeg_dev *ctrl);
+
+#endif /*__JPEG_CORE_H__*/
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-dec.c b/drivers/media/platform/s5p-jpeg/jpeg-dec.c
new file mode 100644
index 0000000..7c42eb85
--- /dev/null
+++ b/drivers/media/platform/s5p-jpeg/jpeg-dec.c
@@ -0,0 +1,489 @@
+/* Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Decoder core file for Samsung JPEG Interface 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 <asm/page.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/signal.h>
+#include <linux/ioport.h>
+#include <linux/kmod.h>
+#include <linux/vmalloc.h>
+#include <linux/time.h>
+#include <linux/clk.h>
+#include <linux/semaphore.h>
+#include <linux/vmalloc.h>
+#include <linux/workqueue.h>
+#include <linux/videodev2.h>
+#include <mach/irqs.h>
+#include <media/v4l2-ioctl.h>
+
+#include "jpeg-core.h"
+#include "jpeg-hw-v2.h"
+#include "jpeg-regs-v2.h"
+
+static struct jpeg_fmt formats[] = {
+ {
+ .name = "JPEG compressed format",
+ .fourcc = V4L2_PIX_FMT_JPEG_444,
+ .depth = {8},
+ .color = JPEG_444,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "JPEG compressed format",
+ .fourcc = V4L2_PIX_FMT_JPEG_422,
+ .depth = {8},
+ .color = JPEG_422,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "JPEG compressed format",
+ .fourcc = V4L2_PIX_FMT_JPEG_420,
+ .depth = {8},
+ .color = JPEG_420,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "JPEG compressed format",
+ .fourcc = V4L2_PIX_FMT_JPEG_GRAY,
+ .depth = {8},
+ .color = JPEG_GRAY,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "RGB565",
+ .fourcc = V4L2_PIX_FMT_RGB565X,
+ .depth = {16},
+ .color = RGB_565,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "XRGB-8-8-8-8, 32 bpp",
+ .fourcc = V4L2_PIX_FMT_RGB32,
+ .depth = {32},
+ .color = RGB_888,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:4:4 packed, Y/CbCr",
+ .fourcc = V4L2_PIX_FMT_YUV444_2P,
+ .depth = {8, 16},
+ .color = YCBCR_444_2P,
+ .memplanes = 2,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:4:4 packed, Y/CrCb",
+ .fourcc = V4L2_PIX_FMT_YVU444_2P,
+ .depth = {8, 16},
+ .color = YCRCB_444_2P,
+ .memplanes = 2,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:4:4 packed, Y/Cb/Cr",
+ .fourcc = V4L2_PIX_FMT_YUV444_3P,
+ .depth = {8, 8, 8},
+ .color = YCBCR_444_3P,
+ .memplanes = 3,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:2:2 packed, YCbYCr",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = {16},
+ .color = YCBYCR_422_1P,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:2:2 planar, Y/CrCb",
+ .fourcc = V4L2_PIX_FMT_NV61,
+ .depth = {8, 8},
+ .color = YCRCB_422_2P,
+ .memplanes = 2,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:2:2 planar, Y/CbCr",
+ .fourcc = V4L2_PIX_FMT_NV16,
+ .depth = {8, 8},
+ .color = YCBCR_422_2P,
+ .memplanes = 2,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:2:0 planar, Y/CbCr",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .depth = {8, 4},
+ .color = YCBCR_420_2P,
+ .memplanes = 2,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:2:0 planar, Y/CrCb",
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .depth = {8, 4},
+ .color = YCRCB_420_2P,
+ .memplanes = 2,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:2:0 contiguous 3-planar, Y/Cr/Cb",
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .depth = {8, 2, 2},
+ .color = YCBCR_420_3P,
+ .memplanes = 3,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "Gray",
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .depth = {8},
+ .color = GRAY,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ },
+};
+
+static struct jpeg_fmt *find_format(struct v4l2_format *f)
+{
+ struct jpeg_fmt *fmt;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+ fmt = &formats[i];
+ if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
+ break;
+ }
+
+ return (i == ARRAY_SIZE(formats)) ? NULL : fmt;
+}
+
+static int jpeg_dec_vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct jpeg_ctx *ctx = file->private_data;
+ struct jpeg_dev *dev = ctx->dev;
+
+ strncpy(cap->driver, dev->plat_dev->name, sizeof(cap->driver) - 1);
+ strncpy(cap->card, dev->plat_dev->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 |
+ V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+ return 0;
+}
+
+int jpeg_dec_vidioc_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct jpeg_fmt *fmt;
+
+ if (f->index >= ARRAY_SIZE(formats))
+ return -EINVAL;
+
+ fmt = &formats[f->index];
+ strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+ f->pixelformat = fmt->color;
+
+ return 0;
+}
+
+int jpeg_dec_vidioc_g_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct jpeg_ctx *ctx = priv;
+ struct v4l2_pix_format_mplane *pixm;
+ struct jpeg_dec_param *dec_param = &ctx->param.dec_param;
+ unsigned int width, height;
+
+ pixm = &f->fmt.pix_mp;
+
+ pixm->field = V4L2_FIELD_NONE;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ pixm->pixelformat = dec_param->in_fmt;
+ pixm->num_planes = dec_param->in_plane;
+
+ pixm->width = dec_param->in_width;
+ pixm->height = dec_param->in_height;
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+
+ jpeg_get_frame_size(ctx->dev->reg_base, &width, &height);
+ pixm->pixelformat =
+ dec_param->out_fmt;
+ pixm->num_planes = dec_param->out_plane;
+ pixm->width = width;
+ pixm->height = height;
+ } else {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "Wrong buffer/video queue type (%d)\n", f->type);
+ }
+
+ return 0;
+}
+
+static int jpeg_dec_vidioc_try_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct jpeg_fmt *fmt;
+ struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+ struct jpeg_ctx *ctx = priv;
+ int i;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
+ f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
+ fmt = find_format(f);
+
+ if (!fmt) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "Fourcc format (0x%08x) invalid.\n",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ if (pix->field == V4L2_FIELD_ANY)
+ pix->field = V4L2_FIELD_NONE;
+ else if (V4L2_FIELD_NONE != pix->field)
+ return -EINVAL;
+
+ pix->num_planes = fmt->memplanes;
+
+ for (i = 0; i < pix->num_planes; ++i) {
+ int bpl = pix->plane_fmt[i].bytesperline;
+
+ jpeg_dbg("[%d] bpl: %d, depth: %d, w: %d, h: %d",
+ i, bpl, fmt->depth[i], pix->width, pix->height);
+ if (!bpl || (bpl * 8 / fmt->depth[i]) > pix->width)
+ bpl = (pix->width * fmt->depth[i]) >> 3;
+
+ if (!pix->plane_fmt[i].sizeimage)
+ pix->plane_fmt[i].sizeimage = pix->height * bpl;
+
+ pix->plane_fmt[i].bytesperline = bpl;
+
+ jpeg_dbg("[%d]: bpl: %d, sizeimage: %d",
+ i, pix->plane_fmt[i].bytesperline,
+ pix->plane_fmt[i].sizeimage);
+ }
+
+ if (f->fmt.pix.height > MAX_JPEG_HEIGHT)
+ f->fmt.pix.height = MAX_JPEG_HEIGHT;
+
+ if (f->fmt.pix.width > MAX_JPEG_WIDTH)
+ f->fmt.pix.width = MAX_JPEG_WIDTH;
+
+ return 0;
+}
+
+static int jpeg_dec_vidioc_s_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct jpeg_ctx *ctx = priv;
+ struct vb2_queue *vq;
+ struct v4l2_pix_format_mplane *pix;
+ struct jpeg_fmt *fmt;
+ int ret;
+ int i;
+
+ ret = jpeg_dec_vidioc_try_fmt(file, priv, f);
+ if (ret)
+ return ret;
+
+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ if (vb2_is_busy(vq)) {
+ v4l2_err(&ctx->dev->v4l2_dev, "queue (%d) busy\n", f->type);
+ return -EBUSY;
+ }
+
+ pix = &f->fmt.pix_mp;
+ fmt = find_format(f);
+ if (!fmt) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "Fourcc format (0x%08x) invalid.\n",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < fmt->memplanes; i++) {
+ ctx->payload[i] =
+ pix->plane_fmt[i].bytesperline * pix->height;
+ ctx->param.dec_param.out_depth[i] = fmt->depth[i];
+ }
+
+ ctx->param.dec_param.out_width = pix->width;
+ ctx->param.dec_param.out_height = pix->height;
+ ctx->param.dec_param.out_plane = fmt->memplanes;
+ ctx->param.dec_param.out_fmt = fmt->color;
+
+ return 0;
+}
+
+static int jpeg_dec_vidioc_s_fmt_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct jpeg_ctx *ctx = priv;
+ struct vb2_queue *vq;
+ struct v4l2_pix_format_mplane *pix;
+ struct jpeg_fmt *fmt;
+ int ret;
+ int i;
+
+ ret = jpeg_dec_vidioc_try_fmt(file, priv, f);
+ if (ret)
+ return ret;
+
+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ if (vb2_is_busy(vq)) {
+ v4l2_err(&ctx->dev->v4l2_dev, "queue (%d) busy\n", f->type);
+ return -EBUSY;
+ }
+
+ pix = &f->fmt.pix_mp;
+ fmt = find_format(f);
+ if (!fmt) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "Fourcc format (0x%08x) invalid.\n",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < fmt->memplanes; i++)
+ ctx->payload[i] =
+ pix->plane_fmt[i].bytesperline * pix->height;
+
+ ctx->param.dec_param.in_width = pix->width;
+ ctx->param.dec_param.in_height = pix->height;
+ ctx->param.dec_param.in_plane = fmt->memplanes;
+ ctx->param.dec_param.in_depth = fmt->depth[0];
+ ctx->param.dec_param.in_fmt = fmt->color;
+
+ if ((pix->plane_fmt[0].sizeimage % 32) == 0)
+ ctx->param.dec_param.size = (pix->plane_fmt[0].sizeimage / 32);
+ else
+ ctx->param.dec_param.size =
+ (pix->plane_fmt[0].sizeimage / 32) + 1;
+ ctx->param.dec_param.mem_size = pix->plane_fmt[0].sizeimage;
+
+ return 0;
+}
+
+static int jpeg_dec_m2m_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct jpeg_ctx *ctx = priv;
+ struct vb2_queue *vq;
+
+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, reqbufs->type);
+ return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int jpeg_dec_m2m_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct jpeg_ctx *ctx = priv;
+ return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int jpeg_dec_m2m_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct jpeg_ctx *ctx = priv;
+ return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int jpeg_dec_m2m_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct jpeg_ctx *ctx = priv;
+ return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int jpeg_dec_m2m_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct jpeg_ctx *ctx = priv;
+ return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int jpeg_dec_m2m_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct jpeg_ctx *ctx = priv;
+ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static int vidioc_dec_s_jpegcomp(struct file *file, void *priv,
+ const struct v4l2_jpegcompression *jpegcomp)
+{
+ struct jpeg_ctx *ctx = priv;
+ ctx->param.enc_param.quality = jpegcomp->quality;
+ return 0;
+}
+
+static int jpeg_dec_vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct jpeg_ctx *ctx = priv;
+/*
+* 0 : input/output noncacheable
+* 1 : input/output cacheable
+* 2 : input cacheable / output noncacheable
+* 3 : input noncacheable / output cacheable
+*/
+ switch (ctrl->id) {
+ default:
+ v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
+ break;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops jpeg_dec_ioctl_ops = {
+ .vidioc_querycap = jpeg_dec_vidioc_querycap,
+
+ .vidioc_enum_fmt_vid_cap_mplane = jpeg_dec_vidioc_enum_fmt,
+ .vidioc_enum_fmt_vid_out_mplane = jpeg_dec_vidioc_enum_fmt,
+
+ .vidioc_g_fmt_vid_cap_mplane = jpeg_dec_vidioc_g_fmt,
+ .vidioc_g_fmt_vid_out_mplane = jpeg_dec_vidioc_g_fmt,
+
+ .vidioc_try_fmt_vid_cap_mplane = jpeg_dec_vidioc_try_fmt,
+ .vidioc_try_fmt_vid_out_mplane = jpeg_dec_vidioc_try_fmt,
+ .vidioc_s_fmt_vid_cap_mplane = jpeg_dec_vidioc_s_fmt_cap,
+ .vidioc_s_fmt_vid_out_mplane = jpeg_dec_vidioc_s_fmt_out,
+
+ .vidioc_reqbufs = jpeg_dec_m2m_reqbufs,
+ .vidioc_querybuf = jpeg_dec_m2m_querybuf,
+ .vidioc_qbuf = jpeg_dec_m2m_qbuf,
+ .vidioc_dqbuf = jpeg_dec_m2m_dqbuf,
+ .vidioc_streamon = jpeg_dec_m2m_streamon,
+ .vidioc_streamoff = jpeg_dec_m2m_streamoff,
+ .vidioc_s_jpegcomp = vidioc_dec_s_jpegcomp,
+ .vidioc_s_ctrl = jpeg_dec_vidioc_s_ctrl,
+};
+const struct v4l2_ioctl_ops *get_jpeg_dec_v4l2_ioctl_ops(void)
+{
+ return &jpeg_dec_ioctl_ops;
+}
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-enc.c b/drivers/media/platform/s5p-jpeg/jpeg-enc.c
new file mode 100644
index 0000000..436a18a
--- /dev/null
+++ b/drivers/media/platform/s5p-jpeg/jpeg-enc.c
@@ -0,0 +1,521 @@
+/* Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Encoder Core file for Samsung JPEG Interface 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/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/signal.h>
+#include <linux/ioport.h>
+#include <linux/kmod.h>
+#include <linux/vmalloc.h>
+#include <linux/time.h>
+#include <linux/clk.h>
+#include <linux/semaphore.h>
+#include <linux/vmalloc.h>
+#include <linux/workqueue.h>
+#include <linux/videodev2.h>
+#include <mach/irqs.h>
+
+#include <media/v4l2-ioctl.h>
+#include <asm/page.h>
+
+#include "jpeg-core.h"
+#include "jpeg-hw-v2.h"
+#include "jpeg-regs-v2.h"
+
+static struct jpeg_fmt formats[] = {
+ {
+ .name = "JPEG compressed format",
+ .fourcc = V4L2_PIX_FMT_JPEG_444,
+ .depth = {8},
+ .color = JPEG_444,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "JPEG compressed format",
+ .fourcc = V4L2_PIX_FMT_JPEG_422,
+ .depth = {8},
+ .color = JPEG_422,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "JPEG compressed format",
+ .fourcc = V4L2_PIX_FMT_JPEG_420,
+ .depth = {8},
+ .color = JPEG_420,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "JPEG compressed format",
+ .fourcc = V4L2_PIX_FMT_JPEG_GRAY,
+ .depth = {8},
+ .color = JPEG_GRAY,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "RGB565",
+ .fourcc = V4L2_PIX_FMT_RGB565X,
+ .depth = {16},
+ .color = RGB_565,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:4:4 packed, Y/CbCr",
+ .fourcc = V4L2_PIX_FMT_YUV444_2P,
+ .depth = {8, 16},
+ .color = YCBCR_444_2P,
+ .memplanes = 2,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:4:4 packed, Y/CrCb",
+ .fourcc = V4L2_PIX_FMT_YVU444_2P,
+ .depth = {8, 16},
+ .color = YCRCB_444_2P,
+ .memplanes = 2,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:4:4 packed, Y/Cb/Cr",
+ .fourcc = V4L2_PIX_FMT_YUV444_3P,
+ .depth = {8, 8, 8},
+ .color = YCBCR_444_3P,
+ .memplanes = 2,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "XRGB-8-8-8-8, 32 bpp",
+ .fourcc = V4L2_PIX_FMT_RGB32,
+ .depth = {32},
+ .color = RGB_888,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:2:2 packed, YCbYCr",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = {16},
+ .color = YCBYCR_422_1P,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:2:2 planar, Y/CrCb",
+ .fourcc = V4L2_PIX_FMT_NV61,
+ .depth = {8, 8},
+ .color = YCRCB_422_2P,
+ .memplanes = 2,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:2:2 planar, Y/CbCr",
+ .fourcc = V4L2_PIX_FMT_NV16,
+ .depth = {8, 8},
+ .color = YCBCR_422_2P,
+ .memplanes = 2,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:2:0 planar, Y/CbCr",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .depth = {8, 4},
+ .color = YCBCR_420_2P,
+ .memplanes = 2,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:2:0 planar, Y/CrCb",
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .depth = {8, 4},
+ .color = YCRCB_420_2P,
+ .memplanes = 2,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:2:0 contiguous 3-planar, Y/Cb/Cr",
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .depth = {8, 2, 2},
+ .color = YCBCR_420_3P,
+ .memplanes = 3,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "Gray",
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .depth = {8},
+ .color = GRAY,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ },
+};
+
+static struct jpeg_fmt *find_format(struct v4l2_format *f)
+{
+ struct jpeg_fmt *fmt;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+ fmt = &formats[i];
+ if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
+ break;
+ }
+
+ return (i == ARRAY_SIZE(formats)) ? NULL : fmt;
+}
+
+static int jpeg_enc_vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct jpeg_ctx *ctx = file->private_data;
+ struct jpeg_dev *dev = ctx->dev;
+
+ strncpy(cap->driver, dev->plat_dev->name, sizeof(cap->driver) - 1);
+ strncpy(cap->card, dev->plat_dev->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 |
+ V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+ return 0;
+}
+
+int jpeg_enc_vidioc_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct jpeg_fmt *fmt;
+
+ if (f->index >= ARRAY_SIZE(formats))
+ return -EINVAL;
+
+ fmt = &formats[f->index];
+ strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+ f->pixelformat = fmt->fourcc;
+
+ return 0;
+}
+
+int jpeg_enc_vidioc_g_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct jpeg_ctx *ctx = priv;
+ struct v4l2_pix_format_mplane *pixm;
+ struct jpeg_enc_param *enc_param = &ctx->param.enc_param;
+
+ pixm = &f->fmt.pix_mp;
+
+ pixm->field = V4L2_FIELD_NONE;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ pixm->pixelformat =
+ enc_param->in_fmt;
+ pixm->num_planes =
+ enc_param->in_plane;
+ pixm->width =
+ enc_param->in_width;
+ pixm->height =
+ enc_param->in_height;
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ pixm->pixelformat =
+ enc_param->out_fmt;
+ pixm->num_planes =
+ enc_param->out_plane;
+ pixm->width =
+ enc_param->out_width;
+ pixm->height =
+ enc_param->out_height;
+ } else {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "Wrong buffer/video queue type (%d)\n", f->type);
+ }
+
+ return 0;
+}
+
+static int jpeg_enc_vidioc_try_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct jpeg_fmt *fmt;
+ struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+ struct jpeg_ctx *ctx = priv;
+ int i;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
+ f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+ f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+ f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ fmt = find_format(f);
+
+ if (!fmt) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "Fourcc format (0x%08x) invalid.\n",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ if (pix->field == V4L2_FIELD_ANY)
+ pix->field = V4L2_FIELD_NONE;
+ else if (V4L2_FIELD_NONE != pix->field)
+ return -EINVAL;
+
+
+ pix->num_planes = fmt->memplanes;
+
+ for (i = 0; i < pix->num_planes; ++i) {
+ int bpl = pix->plane_fmt[i].bytesperline;
+
+ jpeg_dbg("[%d] bpl: %d, depth: %d, w: %d, h: %d",
+ i, bpl, fmt->depth[i], pix->width, pix->height);
+
+ if (!bpl || (bpl * 8 / fmt->depth[i]) > pix->width)
+ bpl = (pix->width * fmt->depth[i]) >> 3;
+
+ if (!pix->plane_fmt[i].sizeimage)
+ pix->plane_fmt[i].sizeimage = pix->height * bpl;
+
+ pix->plane_fmt[i].bytesperline = bpl;
+
+ jpeg_dbg("[%d]: bpl: %d, sizeimage: %d",
+ i, pix->plane_fmt[i].bytesperline,
+ pix->plane_fmt[i].sizeimage);
+ }
+
+ if (f->fmt.pix.height > MAX_JPEG_HEIGHT)
+ f->fmt.pix.height = MAX_JPEG_HEIGHT;
+
+ if (f->fmt.pix.width > MAX_JPEG_WIDTH)
+ f->fmt.pix.width = MAX_JPEG_WIDTH;
+
+ return 0;
+}
+
+static int jpeg_enc_vidioc_s_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct jpeg_ctx *ctx = priv;
+ struct vb2_queue *vq;
+ struct v4l2_pix_format_mplane *pix;
+ struct jpeg_fmt *fmt;
+ int ret;
+ int i;
+
+ ret = jpeg_enc_vidioc_try_fmt(file, priv, f);
+ if (ret)
+ return ret;
+
+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ if (vb2_is_busy(vq)) {
+ v4l2_err(&ctx->dev->v4l2_dev, "queue (%d) busy\n", f->type);
+ return -EBUSY;
+ }
+
+ pix = &f->fmt.pix_mp;
+ fmt = find_format(f);
+ if (!fmt) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "Fourcc format (0x%08x) invalid.\n",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+
+ for (i = 0; i < fmt->memplanes; i++)
+ ctx->payload[i] =
+ pix->plane_fmt[i].bytesperline * pix->height;
+
+ ctx->param.enc_param.out_width = pix->height;
+ ctx->param.enc_param.out_height = pix->width;
+ ctx->param.enc_param.out_plane = fmt->memplanes;
+ ctx->param.enc_param.out_depth = fmt->depth[0];
+ ctx->param.enc_param.out_fmt = fmt->color;
+ ctx->param.enc_param.size = pix->plane_fmt[0].sizeimage;
+ return 0;
+}
+
+static int jpeg_enc_vidioc_s_fmt_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct jpeg_ctx *ctx = priv;
+ struct vb2_queue *vq;
+ struct v4l2_pix_format_mplane *pix;
+ struct jpeg_fmt *fmt;
+ int ret;
+ int i;
+
+ ret = jpeg_enc_vidioc_try_fmt(file, priv, f);
+ if (ret)
+ return ret;
+
+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ if (vb2_is_busy(vq)) {
+ v4l2_err(&ctx->dev->v4l2_dev, "queue (%d) busy\n", f->type);
+ return -EBUSY;
+ }
+
+ pix = &f->fmt.pix_mp;
+ fmt = find_format(f);
+ if (!fmt) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "Fourcc format (0x%08x) invalid.\n",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+
+ for (i = 0; i < fmt->memplanes; i++) {
+ ctx->payload[i] =
+ pix->plane_fmt[i].bytesperline * pix->height;
+ ctx->param.enc_param.in_depth[i] = fmt->depth[i];
+ }
+ ctx->param.enc_param.in_width = pix->width;
+ ctx->param.enc_param.in_height = pix->height;
+ ctx->param.enc_param.in_plane = fmt->memplanes;
+ ctx->param.enc_param.in_fmt = fmt->color;
+
+ return 0;
+}
+
+static int jpeg_enc_m2m_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct jpeg_ctx *ctx = priv;
+
+ return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int jpeg_enc_m2m_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct jpeg_ctx *ctx = priv;
+ return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int jpeg_enc_m2m_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct jpeg_ctx *ctx = priv;
+
+ return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int jpeg_enc_m2m_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct jpeg_ctx *ctx = priv;
+ return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int jpeg_enc_m2m_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct jpeg_ctx *ctx = priv;
+ return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int jpeg_enc_m2m_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct jpeg_ctx *ctx = priv;
+ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static int jpeg_enc_vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ switch (ctrl->id) {
+ default:
+ break;
+ }
+ return ctrl->value;
+}
+
+static int vidioc_enc_s_jpegcomp(struct file *file, void *priv,
+ const struct v4l2_jpegcompression *jpegcomp)
+{
+ struct jpeg_ctx *ctx = priv;
+
+ ctx->param.enc_param.quality = jpegcomp->quality;
+ return 0;
+}
+
+static int vidioc_enc_g_jpegcomp(struct file *file, void *priv,
+ struct v4l2_jpegcompression *jpegcomp)
+{
+ struct jpeg_ctx *ctx = priv;
+
+ jpegcomp->quality = ctx->param.enc_param.quality;
+ return 0;
+}
+
+static int jpeg_enc_vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct jpeg_ctx *ctx = priv;
+/*
+* 0 : input/output noncacheable
+* 1 : input/output cacheable
+* 2 : input cacheable / output noncacheable
+* 3 : input noncacheable / output cacheable
+*/
+ switch (ctrl->id) {
+ default:
+ v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
+ break;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops jpeg_enc_ioctl_ops = {
+ .vidioc_querycap = jpeg_enc_vidioc_querycap,
+
+ .vidioc_enum_fmt_vid_cap_mplane = jpeg_enc_vidioc_enum_fmt,
+ .vidioc_enum_fmt_vid_cap = jpeg_enc_vidioc_enum_fmt,
+ .vidioc_enum_fmt_vid_out_mplane = jpeg_enc_vidioc_enum_fmt,
+ .vidioc_enum_fmt_vid_out = jpeg_enc_vidioc_enum_fmt,
+
+ .vidioc_g_fmt_vid_cap_mplane = jpeg_enc_vidioc_g_fmt,
+ .vidioc_g_fmt_vid_cap = jpeg_enc_vidioc_g_fmt,
+ .vidioc_g_fmt_vid_out_mplane = jpeg_enc_vidioc_g_fmt,
+ .vidioc_g_fmt_vid_out = jpeg_enc_vidioc_g_fmt,
+
+ .vidioc_try_fmt_vid_cap_mplane = jpeg_enc_vidioc_try_fmt,
+ .vidioc_try_fmt_vid_cap = jpeg_enc_vidioc_try_fmt,
+ .vidioc_try_fmt_vid_out_mplane = jpeg_enc_vidioc_try_fmt,
+ .vidioc_try_fmt_vid_out = jpeg_enc_vidioc_try_fmt,
+ .vidioc_s_fmt_vid_cap_mplane = jpeg_enc_vidioc_s_fmt_cap,
+ .vidioc_s_fmt_vid_cap = jpeg_enc_vidioc_s_fmt_cap,
+ .vidioc_s_fmt_vid_out_mplane = jpeg_enc_vidioc_s_fmt_out,
+ .vidioc_s_fmt_vid_out = jpeg_enc_vidioc_s_fmt_out,
+
+ .vidioc_reqbufs = jpeg_enc_m2m_reqbufs,
+ .vidioc_querybuf = jpeg_enc_m2m_querybuf,
+ .vidioc_qbuf = jpeg_enc_m2m_qbuf,
+ .vidioc_dqbuf = jpeg_enc_m2m_dqbuf,
+ .vidioc_streamon = jpeg_enc_m2m_streamon,
+ .vidioc_streamoff = jpeg_enc_m2m_streamoff,
+ .vidioc_g_ctrl = jpeg_enc_vidioc_g_ctrl,
+ .vidioc_g_jpegcomp = vidioc_enc_g_jpegcomp,
+ .vidioc_s_jpegcomp = vidioc_enc_s_jpegcomp,
+ .vidioc_s_ctrl = jpeg_enc_vidioc_s_ctrl,
+};
+const struct v4l2_ioctl_ops *get_jpeg_enc_v4l2_ioctl_ops(void)
+{
+ return &jpeg_enc_ioctl_ops;
+}
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-v1.h b/drivers/media/platform/s5p-jpeg/jpeg-hw-v1.h
new file mode 100644
index 0000000..893c4fb
--- /dev/null
+++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-v1.h
@@ -0,0 +1,528 @@
+/* linux/drivers/media/platform/s5p-jpeg/jpeg-hw-v1.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * 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 JPEG_HW_H_
+#define JPEG_HW_H_
+
+#include <linux/io.h>
+#include <linux/videodev2.h>
+
+#include "jpeg-regs-v1.h"
+
+#define S5P_JPEG_MIN_WIDTH 32
+#define S5P_JPEG_MIN_HEIGHT 32
+#define S5P_JPEG_MAX_WIDTH 8192
+#define S5P_JPEG_MAX_HEIGHT 8192
+#define S5P_JPEG_RAW_IN_565 0
+#define S5P_JPEG_RAW_IN_422 1
+#define S5P_JPEG_RAW_OUT_422 0
+#define S5P_JPEG_RAW_OUT_420 1
+
+/* Quantization and Huffman tables for S5P-JPEG-V1(Exynos 4210) IP */
+static const unsigned char qtbl_luminance[4][64] = {
+ {/* level 1 - high quality */
+ 8, 6, 6, 8, 12, 14, 16, 17,
+ 6, 6, 6, 8, 10, 13, 12, 15,
+ 6, 6, 7, 8, 13, 14, 18, 24,
+ 8, 8, 8, 14, 13, 19, 24, 35,
+ 12, 10, 13, 13, 20, 26, 34, 39,
+ 14, 13, 14, 19, 26, 34, 39, 39,
+ 16, 12, 18, 24, 34, 39, 39, 39,
+ 17, 15, 24, 35, 39, 39, 39, 39
+ },
+ {/* level 2 */
+ 12, 8, 8, 12, 17, 21, 24, 23,
+ 8, 9, 9, 11, 15, 19, 18, 23,
+ 8, 9, 10, 12, 19, 20, 27, 36,
+ 12, 11, 12, 21, 20, 28, 36, 53,
+ 17, 15, 19, 20, 30, 39, 51, 59,
+ 21, 19, 20, 28, 39, 51, 59, 59,
+ 24, 18, 27, 36, 51, 59, 59, 59,
+ 23, 23, 36, 53, 59, 59, 59, 59
+ },
+ {/* level 3 */
+ 16, 11, 11, 16, 23, 27, 31, 30,
+ 11, 12, 12, 15, 20, 23, 23, 30,
+ 11, 12, 13, 16, 23, 26, 35, 47,
+ 16, 15, 16, 23, 26, 37, 47, 64,
+ 23, 20, 23, 26, 39, 51, 64, 64,
+ 27, 23, 26, 37, 51, 64, 64, 64,
+ 31, 23, 35, 47, 64, 64, 64, 64,
+ 30, 30, 47, 64, 64, 64, 64, 64
+ },
+ {/*level 4 - low quality */
+ 20, 16, 25, 39, 50, 46, 62, 68,
+ 16, 18, 23, 38, 38, 53, 65, 68,
+ 25, 23, 31, 38, 53, 65, 68, 68,
+ 39, 38, 38, 53, 65, 68, 68, 68,
+ 50, 38, 53, 65, 68, 68, 68, 68,
+ 46, 53, 65, 68, 68, 68, 68, 68,
+ 62, 65, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68
+ }
+};
+
+static const unsigned char qtbl_chrominance[4][64] = {
+ {/* level 1 - high quality */
+ 9, 8, 9, 11, 14, 17, 19, 24,
+ 8, 10, 9, 11, 14, 13, 17, 22,
+ 9, 9, 13, 14, 13, 15, 23, 26,
+ 11, 11, 14, 14, 15, 20, 26, 33,
+ 14, 14, 13, 15, 20, 24, 33, 39,
+ 17, 13, 15, 20, 24, 32, 39, 39,
+ 19, 17, 23, 26, 33, 39, 39, 39,
+ 24, 22, 26, 33, 39, 39, 39, 39
+ },
+ {/* level 2 */
+ 13, 11, 13, 16, 20, 20, 29, 37,
+ 11, 14, 14, 14, 16, 20, 26, 32,
+ 13, 14, 15, 17, 20, 23, 35, 40,
+ 16, 14, 17, 21, 23, 30, 40, 50,
+ 20, 16, 20, 23, 30, 37, 50, 59,
+ 20, 20, 23, 30, 37, 48, 59, 59,
+ 29, 26, 35, 40, 50, 59, 59, 59,
+ 37, 32, 40, 50, 59, 59, 59, 59
+ },
+ {/* level 3 */
+ 17, 15, 17, 21, 20, 26, 38, 48,
+ 15, 19, 18, 17, 20, 26, 35, 43,
+ 17, 18, 20, 22, 26, 30, 46, 53,
+ 21, 17, 22, 28, 30, 39, 53, 64,
+ 20, 20, 26, 30, 39, 48, 64, 64,
+ 26, 26, 30, 39, 48, 63, 64, 64,
+ 38, 35, 46, 53, 64, 64, 64, 64,
+ 48, 43, 53, 64, 64, 64, 64, 64
+ },
+ {/*level 4 - low quality */
+ 21, 25, 32, 38, 54, 68, 68, 68,
+ 25, 28, 24, 38, 54, 68, 68, 68,
+ 32, 24, 32, 43, 66, 68, 68, 68,
+ 38, 38, 43, 53, 68, 68, 68, 68,
+ 54, 54, 66, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68
+ }
+};
+
+static const unsigned char hdctbl0[16] = {
+ 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const unsigned char hdctblg0[12] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb
+};
+static const unsigned char hactbl0[16] = {
+ 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
+};
+static const unsigned char hactblg0[162] = {
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+};
+
+
+static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl,
+ unsigned long tab, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ writel((unsigned int)qtbl[i], regs + tab + (i * 0x04));
+}
+
+static inline void jpeg_set_qtbl_lum(void __iomem *regs, int quality)
+{
+ /* this driver fills quantisation table 0 with data for luma */
+ jpeg_set_qtbl(regs, qtbl_luminance[quality], S5P_JPG_QTBL_CONTENT(0),
+ ARRAY_SIZE(qtbl_luminance[quality]));
+}
+
+static inline void jpeg_set_qtbl_chr(void __iomem *regs, int quality)
+{
+ /* this driver fills quantisation table 1 with data for chroma */
+ jpeg_set_qtbl(regs, qtbl_chrominance[quality], S5P_JPG_QTBL_CONTENT(1),
+ ARRAY_SIZE(qtbl_chrominance[quality]));
+}
+
+static inline void jpeg_set_htbl(void __iomem *regs, const unsigned char *htbl,
+ unsigned long tab, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ writel((unsigned int)htbl[i], regs + tab + (i * 0x04));
+}
+
+static inline void jpeg_set_hdctbl(void __iomem *regs)
+{
+ /* this driver fills table 0 for this component */
+ jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0), ARRAY_SIZE(hdctbl0));
+}
+
+static inline void jpeg_set_hdctblg(void __iomem *regs)
+{
+ /* this driver fills table 0 for this component */
+ jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0), ARRAY_SIZE(hdctblg0));
+}
+
+static inline void jpeg_set_hactbl(void __iomem *regs)
+{
+ /* this driver fills table 0 for this component */
+ jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0), ARRAY_SIZE(hactbl0));
+}
+
+static inline void jpeg_set_hactblg(void __iomem *regs)
+{
+ /* this driver fills table 0 for this component */
+ jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0), ARRAY_SIZE(hactblg0));
+}
+
+static inline void jpeg_reset(void __iomem *regs)
+{
+ unsigned long reg;
+
+ writel(1, regs + S5P_JPG_SW_RESET);
+ reg = readl(regs + S5P_JPG_SW_RESET);
+ /* no other way but polling for when JPEG IP becomes operational */
+ while (reg != 0) {
+ cpu_relax();
+ reg = readl(regs + S5P_JPG_SW_RESET);
+ }
+}
+
+static inline void jpeg_poweron(void __iomem *regs)
+{
+ writel(S5P_POWER_ON, regs + S5P_JPGCLKCON);
+}
+
+static inline void jpeg_input_raw_mode(void __iomem *regs, unsigned long mode)
+{
+ unsigned long reg, m;
+
+ m = S5P_MOD_SEL_565;
+ if (mode == S5P_JPEG_RAW_IN_565)
+ m = S5P_MOD_SEL_565;
+ else if (mode == S5P_JPEG_RAW_IN_422)
+ m = S5P_MOD_SEL_422;
+
+ reg = readl(regs + S5P_JPGCMOD);
+ reg &= ~S5P_MOD_SEL_MASK;
+ reg |= m;
+ writel(reg, regs + S5P_JPGCMOD);
+}
+
+static inline void jpeg_input_raw_y16(void __iomem *regs, bool y16)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPGCMOD);
+ if (y16)
+ reg |= S5P_MODE_Y16;
+ else
+ reg &= ~S5P_MODE_Y16_MASK;
+ writel(reg, regs + S5P_JPGCMOD);
+}
+
+static inline void jpeg_proc_mode(void __iomem *regs, unsigned long mode)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPGMOD);
+ reg &= ~S5P_PROC_MODE_MASK;
+ reg |= mode;
+ writel(reg, regs + S5P_JPGMOD);
+}
+
+static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned int mode)
+{
+ unsigned long reg, m;
+
+ if (mode == V4L2_JPEG_CHROMA_SUBSAMPLING_420)
+ m = S5P_SUBSAMPLING_MODE_420;
+ else
+ m = S5P_SUBSAMPLING_MODE_422;
+
+ reg = readl(regs + S5P_JPGMOD);
+ reg &= ~S5P_SUBSAMPLING_MODE_MASK;
+ reg |= m;
+ writel(reg, regs + S5P_JPGMOD);
+}
+
+static inline unsigned int jpeg_get_subsampling_mode(void __iomem *regs)
+{
+ return readl(regs + S5P_JPGMOD) & S5P_SUBSAMPLING_MODE_MASK;
+}
+
+static inline void jpeg_dri(void __iomem *regs, unsigned int dri)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPGDRI_U);
+ reg &= ~0xff;
+ reg |= (dri >> 8) & 0xff;
+ writel(reg, regs + S5P_JPGDRI_U);
+
+ reg = readl(regs + S5P_JPGDRI_L);
+ reg &= ~0xff;
+ reg |= dri & 0xff;
+ writel(reg, regs + S5P_JPGDRI_L);
+}
+
+static inline void jpeg_qtbl(void __iomem *regs, unsigned int t, unsigned int n)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPG_QTBL);
+ reg &= ~S5P_QT_NUMt_MASK(t);
+ reg |= (n << S5P_QT_NUMt_SHIFT(t)) & S5P_QT_NUMt_MASK(t);
+ writel(reg, regs + S5P_JPG_QTBL);
+}
+
+static inline void jpeg_htbl_ac(void __iomem *regs, unsigned int t)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPG_HTBL);
+ reg &= ~S5P_HT_NUMt_AC_MASK(t);
+ /* this driver uses table 0 for all color components */
+ reg |= (0 << S5P_HT_NUMt_AC_SHIFT(t)) & S5P_HT_NUMt_AC_MASK(t);
+ writel(reg, regs + S5P_JPG_HTBL);
+}
+
+static inline void jpeg_htbl_dc(void __iomem *regs, unsigned int t)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPG_HTBL);
+ reg &= ~S5P_HT_NUMt_DC_MASK(t);
+ /* this driver uses table 0 for all color components */
+ reg |= (0 << S5P_HT_NUMt_DC_SHIFT(t)) & S5P_HT_NUMt_DC_MASK(t);
+ writel(reg, regs + S5P_JPG_HTBL);
+}
+
+static inline void jpeg_y(void __iomem *regs, unsigned int y)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPGY_U);
+ reg &= ~0xff;
+ reg |= (y >> 8) & 0xff;
+ writel(reg, regs + S5P_JPGY_U);
+
+ reg = readl(regs + S5P_JPGY_L);
+ reg &= ~0xff;
+ reg |= y & 0xff;
+ writel(reg, regs + S5P_JPGY_L);
+}
+
+static inline void jpeg_x(void __iomem *regs, unsigned int x)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPGX_U);
+ reg &= ~0xff;
+ reg |= (x >> 8) & 0xff;
+ writel(reg, regs + S5P_JPGX_U);
+
+ reg = readl(regs + S5P_JPGX_L);
+ reg &= ~0xff;
+ reg |= x & 0xff;
+ writel(reg, regs + S5P_JPGX_L);
+}
+
+static inline void jpeg_rst_int_enable(void __iomem *regs, bool enable)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPGINTSE);
+ reg &= ~S5P_RSTm_INT_EN_MASK;
+ if (enable)
+ reg |= S5P_RSTm_INT_EN;
+ writel(reg, regs + S5P_JPGINTSE);
+}
+
+static inline void jpeg_data_num_int_enable(void __iomem *regs, bool enable)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPGINTSE);
+ reg &= ~S5P_DATA_NUM_INT_EN_MASK;
+ if (enable)
+ reg |= S5P_DATA_NUM_INT_EN;
+ writel(reg, regs + S5P_JPGINTSE);
+}
+
+static inline void jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPGINTSE);
+ reg &= ~S5P_FINAL_MCU_NUM_INT_EN_MASK;
+ if (enbl)
+ reg |= S5P_FINAL_MCU_NUM_INT_EN;
+ writel(reg, regs + S5P_JPGINTSE);
+}
+
+static inline void jpeg_timer_enable(void __iomem *regs, unsigned long val)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPG_TIMER_SE);
+ reg |= S5P_TIMER_INT_EN;
+ reg &= ~S5P_TIMER_INIT_MASK;
+ reg |= val & S5P_TIMER_INIT_MASK;
+ writel(reg, regs + S5P_JPG_TIMER_SE);
+}
+
+static inline void jpeg_timer_disable(void __iomem *regs)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPG_TIMER_SE);
+ reg &= ~S5P_TIMER_INT_EN_MASK;
+ writel(reg, regs + S5P_JPG_TIMER_SE);
+}
+
+static inline int jpeg_timer_stat(void __iomem *regs)
+{
+ return (int)((readl(regs + S5P_JPG_TIMER_ST) & S5P_TIMER_INT_STAT_MASK)
+ >> S5P_TIMER_INT_STAT_SHIFT);
+}
+
+static inline void jpeg_clear_timer_stat(void __iomem *regs)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPG_TIMER_SE);
+ reg &= ~S5P_TIMER_INT_STAT_MASK;
+ writel(reg, regs + S5P_JPG_TIMER_SE);
+}
+
+static inline void jpeg_enc_stream_int(void __iomem *regs, unsigned long size)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPG_ENC_STREAM_INTSE);
+ reg &= ~S5P_ENC_STREAM_BOUND_MASK;
+ reg |= S5P_ENC_STREAM_INT_EN;
+ reg |= size & S5P_ENC_STREAM_BOUND_MASK;
+ writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE);
+}
+
+static inline int jpeg_enc_stream_stat(void __iomem *regs)
+{
+ return (int)(readl(regs + S5P_JPG_ENC_STREAM_INTST) &
+ S5P_ENC_STREAM_INT_STAT_MASK);
+}
+
+static inline void jpeg_clear_enc_stream_stat(void __iomem *regs)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPG_ENC_STREAM_INTSE);
+ reg &= ~S5P_ENC_STREAM_INT_MASK;
+ writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE);
+}
+
+static inline void jpeg_outform_raw(void __iomem *regs, unsigned long format)
+{
+ unsigned long reg, f;
+
+ f = S5P_DEC_OUT_FORMAT_422;
+ if (format == S5P_JPEG_RAW_OUT_422)
+ f = S5P_DEC_OUT_FORMAT_422;
+ else if (format == S5P_JPEG_RAW_OUT_420)
+ f = S5P_DEC_OUT_FORMAT_420;
+ reg = readl(regs + S5P_JPG_OUTFORM);
+ reg &= ~S5P_DEC_OUT_FORMAT_MASK;
+ reg |= f;
+ writel(reg, regs + S5P_JPG_OUTFORM);
+}
+
+static inline void jpeg_jpgadr(void __iomem *regs, unsigned long addr)
+{
+ writel(addr, regs + S5P_JPG_JPGADR);
+}
+
+static inline void jpeg_imgadr(void __iomem *regs, unsigned long addr)
+{
+ writel(addr, regs + S5P_JPG_IMGADR);
+}
+
+static inline void jpeg_coef(void __iomem *regs, unsigned int i,
+ unsigned int j, unsigned int coef)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPG_COEF(i));
+ reg &= ~S5P_COEFn_MASK(j);
+ reg |= (coef << S5P_COEFn_SHIFT(j)) & S5P_COEFn_MASK(j);
+ writel(reg, regs + S5P_JPG_COEF(i));
+}
+
+static inline void jpeg_start(void __iomem *regs)
+{
+ writel(1, regs + S5P_JSTART);
+}
+
+static inline int jpeg_result_stat_ok(void __iomem *regs)
+{
+ return (int)((readl(regs + S5P_JPGINTST) & S5P_RESULT_STAT_MASK)
+ >> S5P_RESULT_STAT_SHIFT);
+}
+
+static inline int jpeg_stream_stat_ok(void __iomem *regs)
+{
+ return !(int)((readl(regs + S5P_JPGINTST) & S5P_STREAM_STAT_MASK)
+ >> S5P_STREAM_STAT_SHIFT);
+}
+
+static inline void jpeg_clear_int(void __iomem *regs)
+{
+ unsigned long reg;
+
+ reg = readl(regs + S5P_JPGINTST);
+ writel(S5P_INT_RELEASE, regs + S5P_JPGCOM);
+ reg = readl(regs + S5P_JPGOPR);
+}
+
+static inline unsigned int jpeg_compressed_size(void __iomem *regs)
+{
+ unsigned long jpeg_size = 0;
+
+ jpeg_size |= (readl(regs + S5P_JPGCNT_U) & 0xff) << 16;
+ jpeg_size |= (readl(regs + S5P_JPGCNT_M) & 0xff) << 8;
+ jpeg_size |= (readl(regs + S5P_JPGCNT_L) & 0xff);
+
+ return (unsigned int)jpeg_size;
+}
+
+#endif /* JPEG_HW_H_ */
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-v2.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-v2.c
new file mode 100644
index 0000000..61f6fda
--- /dev/null
+++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-v2.c
@@ -0,0 +1,614 @@
+/* Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Register interface file for JPEG driver on Exynos4x12 and 5250.
+ *
+ * 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 "jpeg-hw-v2.h"
+#include "jpeg-regs-v2.h"
+
+/* Q-table for S5P-JPEG-V2*/
+/* ITU standard Q-table */
+const unsigned int ITU_Q_tbl[4][16] = {
+ {
+ 0x100a0b10, 0x3d332818, 0x130e0c0c, 0x373c3a1a, /* table 0 */
+ 0x18100d0e, 0x38453928, 0x1d16110e, 0x3e505733,
+ 0x38251612, 0x4d676d44, 0x40372318, 0x5c716851,
+ 0x574e4031, 0x65787967, 0x625f5c48, 0x63676470
+ } , {
+ 0x2f181211, 0x63636363, 0x421a1512, 0x63636363, /* table 1 */
+ 0x63381a18, 0x63636363, 0x6363422f, 0x63636363,
+ 0x63636363, 0x63636363, 0x63636363, 0x63636363,
+ 0x63636363, 0x63636363, 0x63636363, 0x63636363
+ } , {
+ 0x100a0b10, 0x3d332818, 0x130e0c0c, 0x373c3a1a, /* table 2 */
+ 0x18100d0e, 0x38453928, 0x1d16110e, 0x3e505733,
+ 0x38251612, 0x4d676d44, 0x40372318, 0x5c716851,
+ 0x574e4031, 0x65787967, 0x625f5c48, 0x63676470
+ } , {
+ 0x2f181211, 0x63636363, 0x421a1512, 0x63636363, /* table 3 */
+ 0x63381a18, 0x63636363, 0x6363422f, 0x63636363,
+ 0x63636363, 0x63636363, 0x63636363, 0x63636363,
+ 0x63636363, 0x63636363, 0x63636363, 0x63636363
+ }
+};
+
+/* ITU Luminace Huffman Table */
+static unsigned int itu_h_tbl_len_dc_luminance[4] = {
+ 0x00000000, 0x00000000, 0x00000000, 0x00000c00
+};
+static unsigned int itu_h_tbl_val_dc_luminance[3] = {
+ 0x03020100, 0x07060504, 0x0b0a0908
+};
+
+/* ITU Chrominace Huffman Table */
+static unsigned int itu_h_tbl_len_dc_chrominance[4] = {
+ 0x00000000, 0x00000000, 0x00000000, 0x000c0000
+};
+static unsigned int itu_h_tbl_val_dc_chrominance[3] = {
+ 0x03020100, 0x07060504, 0x0b0a0908
+};
+static unsigned int itu_h_tbl_len_ac_luminance[4] = {
+ 0x00000000, 0x00000000, 0x00000000, 0xa2000000
+};
+
+static unsigned int itu_h_tbl_val_ac_luminance[41] = {
+ 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
+};
+
+static u32 itu_h_tbl_len_ac_chrominance[4] = {
+ 0x00000000, 0x00000000, 0x51000000, 0x00000051
+};
+static u32 itu_h_tbl_val_ac_chrominance[41] = {
+ 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
+};
+
+void jpeg_sw_reset(void __iomem *base)
+{
+ unsigned int reg;
+
+ reg = readl(base + S5P_JPEG_CNTL_REG);
+ writel(reg & ~S5P_JPEG_SOFT_RESET_HI,
+ base + S5P_JPEG_CNTL_REG);
+
+ ndelay(100000);
+
+ writel(reg | S5P_JPEG_SOFT_RESET_HI,
+ base + S5P_JPEG_CNTL_REG);
+}
+
+void jpeg_set_enc_dec_mode(void __iomem *base, enum jpeg_mode mode)
+{
+ unsigned int reg;
+
+ reg = readl(base + S5P_JPEG_CNTL_REG);
+ /* set jpeg mod register */
+ if (mode == DECODING) {
+ writel((reg & S5P_JPEG_ENC_DEC_MODE_MASK) | S5P_JPEG_DEC_MODE,
+ base + S5P_JPEG_CNTL_REG);
+ } else {/* encode */
+ writel((reg & S5P_JPEG_ENC_DEC_MODE_MASK) | S5P_JPEG_ENC_MODE,
+ base + S5P_JPEG_CNTL_REG);
+ }
+}
+
+void jpeg_set_dec_out_fmt(void __iomem *base,
+ enum jpeg_frame_format out_fmt)
+{
+ unsigned int reg = 0;
+
+ writel(0, base + S5P_JPEG_IMG_FMT_REG); /* clear */
+
+ /* set jpeg deocde ouput format register */
+ switch (out_fmt) {
+ case GRAY:
+ reg = S5P_JPEG_DEC_GRAY_IMG |
+ S5P_JPEG_GRAY_IMG_IP;
+ break;
+
+ case RGB_888:
+ reg = S5P_JPEG_DEC_RGB_IMG |
+ S5P_JPEG_RGB_IP_RGB_32BIT_IMG;
+ break;
+
+ case RGB_565:
+ reg = S5P_JPEG_DEC_RGB_IMG |
+ S5P_JPEG_RGB_IP_RGB_16BIT_IMG;
+ break;
+
+ case YCRCB_444_2P:
+ reg = S5P_JPEG_DEC_YUV_444_IMG |
+ S5P_JPEG_YUV_444_IP_YUV_444_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CrCb;
+ break;
+
+ case YCBCR_444_2P:
+ reg = S5P_JPEG_DEC_YUV_444_IMG |
+ S5P_JPEG_YUV_444_IP_YUV_444_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CbCr;
+ break;
+
+ case YCBCR_444_3P:
+ reg = S5P_JPEG_DEC_YUV_444_IMG |
+ S5P_JPEG_YUV_444_IP_YUV_444_3P_IMG;
+ break;
+
+ case YCRYCB_422_1P:
+ reg = S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_1P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CrCb;
+ break;
+
+ case YCBYCR_422_1P:
+ reg = S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_1P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CbCr;
+ break;
+
+ case YCRCB_422_2P:
+ reg = S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CrCb;
+ break;
+
+ case YCBCR_422_2P:
+ reg = S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CbCr;
+ break;
+
+ case YCBYCR_422_3P:
+ reg = S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_3P_IMG;
+ break;
+
+ case YCRCB_420_1P:
+ case YCRCB_420_2P:
+ reg = S5P_JPEG_DEC_YUV_420_IMG |
+ S5P_JPEG_YUV_420_IP_YUV_420_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CrCb;
+ break;
+
+ case YCBCR_420_1P:
+ case YCBCR_420_2P:
+ reg = S5P_JPEG_DEC_YUV_420_IMG |
+ S5P_JPEG_YUV_420_IP_YUV_420_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CbCr;
+ break;
+
+ case YCBCR_420_3P:
+ reg = S5P_JPEG_DEC_YUV_420_IMG |
+ S5P_JPEG_YUV_420_IP_YUV_420_3P_IMG;
+ break;
+
+ default:
+ break;
+ }
+
+ writel(reg, base + S5P_JPEG_IMG_FMT_REG);
+}
+
+void jpeg_set_enc_in_fmt(void __iomem *base,
+ enum jpeg_frame_format in_fmt)
+{
+ unsigned int reg;
+
+ reg = readl(base + S5P_JPEG_IMG_FMT_REG) &
+ S5P_JPEG_ENC_IN_FMT_MASK; /* clear except enc format */
+
+ switch (in_fmt) {
+ case GRAY:
+ reg = reg | S5P_JPEG_ENC_GRAY_IMG | S5P_JPEG_GRAY_IMG_IP;
+ break;
+
+ case RGB_888:
+ reg = reg | S5P_JPEG_ENC_RGB_IMG |
+ S5P_JPEG_RGB_IP_RGB_32BIT_IMG;
+ break;
+
+ case RGB_565:
+ reg = reg | S5P_JPEG_ENC_RGB_IMG |
+ S5P_JPEG_RGB_IP_RGB_16BIT_IMG;
+ break;
+
+ case YCRCB_444_2P:
+ reg = reg | S5P_JPEG_ENC_YUV_444_IMG |
+ S5P_JPEG_YUV_444_IP_YUV_444_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CrCb;
+ break;
+
+ case YCBCR_444_2P:
+ reg = reg | S5P_JPEG_ENC_YUV_444_IMG |
+ S5P_JPEG_YUV_444_IP_YUV_444_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CbCr;
+ break;
+
+ case YCBCR_444_3P:
+ reg = reg | S5P_JPEG_ENC_YUV_444_IMG |
+ S5P_JPEG_YUV_444_IP_YUV_444_3P_IMG;
+ break;
+
+ case YCRYCB_422_1P:
+ reg = reg | S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_1P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CrCb;
+ break;
+
+ case YCBYCR_422_1P:
+ reg = reg | S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_1P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CbCr;
+ break;
+
+ case YCRCB_422_2P:
+ reg = reg | S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CrCb;
+ break;
+
+ case YCBCR_422_2P:
+ reg = reg | S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CbCr;
+ break;
+
+ case YCBYCR_422_3P:
+ reg = reg | S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_3P_IMG;
+ break;
+
+ case YCRCB_420_1P:
+ case YCRCB_420_2P:
+ reg = reg | S5P_JPEG_DEC_YUV_420_IMG |
+ S5P_JPEG_YUV_420_IP_YUV_420_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CrCb;
+ break;
+
+ case YCBCR_420_1P:
+ case YCBCR_420_2P:
+ reg = reg | S5P_JPEG_DEC_YUV_420_IMG |
+ S5P_JPEG_YUV_420_IP_YUV_420_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CbCr;
+ break;
+
+ case YCBCR_420_3P:
+ reg = reg | S5P_JPEG_DEC_YUV_420_IMG |
+ S5P_JPEG_YUV_420_IP_YUV_420_3P_IMG;
+ break;
+
+ default:
+ break;
+
+ }
+
+ writel(reg, base + S5P_JPEG_IMG_FMT_REG);
+
+}
+
+void jpeg_set_enc_out_fmt(void __iomem *base,
+ enum jpeg_stream_format out_fmt)
+{
+ unsigned int reg;
+
+ reg = readl(base + S5P_JPEG_IMG_FMT_REG) &
+ ~S5P_JPEG_ENC_FMT_MASK; /* clear enc format */
+
+ switch (out_fmt) {
+ case JPEG_GRAY:
+ reg = reg | S5P_JPEG_ENC_FMT_GRAY;
+ break;
+
+ case JPEG_444:
+ reg = reg | S5P_JPEG_ENC_FMT_YUV_444;
+ break;
+
+ case JPEG_422:
+ reg = reg | S5P_JPEG_ENC_FMT_YUV_422;
+ break;
+
+ case JPEG_420:
+ reg = reg | S5P_JPEG_ENC_FMT_YUV_420;
+ break;
+
+ default:
+ break;
+ }
+
+ writel(reg, base + S5P_JPEG_IMG_FMT_REG);
+}
+
+void jpeg_set_enc_tbl(void __iomem *base)
+{
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[0][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG + (i*0x04));
+ }
+
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[1][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG + 0x40 + (i*0x04));
+ }
+
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[2][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG + 0x80 + (i*0x04));
+ }
+
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[3][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG + 0xc0 + (i*0x04));
+ }
+
+ for (i = 0; i < 4; i++) {
+ writel((unsigned int)itu_h_tbl_len_dc_luminance[i],
+ base + S5P_JPEG_HUFF_TBL_ENTRY_REG + (i*0x04));
+ }
+
+ for (i = 0; i < 3; i++) {
+ writel((unsigned int)itu_h_tbl_val_dc_luminance[i],
+ base + S5P_JPEG_HUFF_TBL_ENTRY_REG + 0x10 + (i*0x04));
+ }
+
+ for (i = 0; i < 4; i++) {
+ writel((unsigned int)itu_h_tbl_len_dc_chrominance[i],
+ base + S5P_JPEG_HUFF_TBL_ENTRY_REG + 0x20 + (i*0x04));
+ }
+
+ for (i = 0; i < 3; i++) {
+ writel((unsigned int)itu_h_tbl_val_dc_chrominance[i],
+ base + S5P_JPEG_HUFF_TBL_ENTRY_REG + 0x30 + (i*0x04));
+ }
+
+ for (i = 0; i < 4; i++) {
+ writel((unsigned int)itu_h_tbl_len_ac_luminance[i],
+ base + S5P_JPEG_HUFF_TBL_ENTRY_REG + 0x40 + (i*0x04));
+ }
+
+ for (i = 0; i < 41; i++) {
+ writel((unsigned int)itu_h_tbl_val_ac_luminance[i],
+ base + S5P_JPEG_HUFF_TBL_ENTRY_REG + 0x50 + (i*0x04));
+ }
+
+ for (i = 0; i < 4; i++) {
+ writel((unsigned int)itu_h_tbl_len_ac_chrominance[i],
+ base + S5P_JPEG_HUFF_TBL_ENTRY_REG + 0x100 + (i*0x04));
+ }
+
+ for (i = 0; i < 41; i++) {
+ writel((unsigned int)itu_h_tbl_val_ac_chrominance[i],
+ base + S5P_JPEG_HUFF_TBL_ENTRY_REG + 0x110 + (i*0x04));
+ }
+
+}
+
+void jpeg_set_interrupt(void __iomem *base)
+{
+ unsigned int reg;
+
+ reg = readl(base + S5P_JPEG_INT_EN_REG) & ~S5P_JPEG_INT_EN_MASK;
+ writel(S5P_JPEG_INT_EN_ALL, base + S5P_JPEG_INT_EN_REG);
+}
+
+unsigned int jpeg_get_int_status(void __iomem *base)
+{
+ unsigned int int_status;
+
+ int_status = readl(base + S5P_JPEG_INT_STATUS_REG);
+
+ return int_status;
+}
+
+void jpeg_set_huf_table_enable(void __iomem *base, int value)
+{
+ unsigned int reg;
+
+ reg = readl(base + S5P_JPEG_CNTL_REG) & ~S5P_JPEG_HUF_TBL_EN;
+
+ if (value == 1)
+ writel(reg | S5P_JPEG_HUF_TBL_EN, base + S5P_JPEG_CNTL_REG);
+ else
+ writel(reg | ~S5P_JPEG_HUF_TBL_EN, base + S5P_JPEG_CNTL_REG);
+}
+
+void jpeg_set_dec_scaling(void __iomem *base,
+ enum jpeg_scale_value x_value, enum jpeg_scale_value y_value)
+{
+ unsigned int reg;
+
+ reg = readl(base + S5P_JPEG_CNTL_REG) &
+ ~(S5P_JPEG_HOR_SCALING_MASK |
+ S5P_JPEG_VER_SCALING_MASK);
+
+ writel(reg | S5P_JPEG_HOR_SCALING(x_value) |
+ S5P_JPEG_VER_SCALING(y_value),
+ base + S5P_JPEG_CNTL_REG);
+}
+
+void jpeg_set_sys_int_enable(void __iomem *base, int value)
+{
+ unsigned int reg;
+
+ reg = readl(base + S5P_JPEG_CNTL_REG) & ~(S5P_JPEG_SYS_INT_EN);
+
+ if (value == 1)
+ writel(S5P_JPEG_SYS_INT_EN, base + S5P_JPEG_CNTL_REG);
+ else
+ writel(~S5P_JPEG_SYS_INT_EN, base + S5P_JPEG_CNTL_REG);
+}
+
+void jpeg_set_stream_buf_address(void __iomem *base, unsigned int address)
+{
+ writel(address, base + S5P_JPEG_OUT_MEM_BASE_REG);
+}
+
+void jpeg_set_stream_size(void __iomem *base,
+ unsigned int x_value, unsigned int y_value)
+{
+ writel(0x0, base + S5P_JPEG_IMG_SIZE_REG); /* clear */
+ writel(S5P_JPEG_X_SIZE(x_value) | S5P_JPEG_Y_SIZE(y_value),
+ base + S5P_JPEG_IMG_SIZE_REG);
+}
+
+void jpeg_set_frame_buf_address(void __iomem *base,
+ enum jpeg_frame_format fmt, unsigned int address_1p,
+ unsigned int address_2p, unsigned int address_3p)
+{
+ switch (fmt) {
+ case GRAY:
+ case RGB_565:
+ case RGB_888:
+ case YCRYCB_422_1P:
+ case YCBYCR_422_1P:
+ writel(address_1p, base + S5P_JPEG_IMG_BA_PLANE_1_REG);
+ writel(0, base + S5P_JPEG_IMG_BA_PLANE_2_REG);
+ writel(0, base + S5P_JPEG_IMG_BA_PLANE_3_REG);
+ break;
+ case YCBCR_444_2P:
+ case YCRCB_444_2P:
+ case YCRCB_422_2P:
+ case YCBCR_422_2P:
+ case YCBCR_420_2P:
+ case YCRCB_420_2P:
+ case YCBCR_420_1P:
+ case YCRCB_420_1P:
+ writel(address_1p, base + S5P_JPEG_IMG_BA_PLANE_1_REG);
+ writel(address_2p, base + S5P_JPEG_IMG_BA_PLANE_2_REG);
+ writel(0, base + S5P_JPEG_IMG_BA_PLANE_3_REG);
+ break;
+ case YCBCR_444_3P:
+ writel(address_1p, base + S5P_JPEG_IMG_BA_PLANE_1_REG);
+ writel(address_2p, base + S5P_JPEG_IMG_BA_PLANE_2_REG);
+ writel(address_3p, base + S5P_JPEG_IMG_BA_PLANE_3_REG);
+ break;
+ case YCBYCR_422_3P:
+ writel(address_1p, base + S5P_JPEG_IMG_BA_PLANE_1_REG);
+ writel(address_2p, base + S5P_JPEG_IMG_BA_PLANE_2_REG);
+ writel(address_3p, base + S5P_JPEG_IMG_BA_PLANE_3_REG);
+ break;
+ case YCBCR_420_3P:
+ writel(address_1p, base + S5P_JPEG_IMG_BA_PLANE_1_REG);
+ writel(address_2p, base + S5P_JPEG_IMG_BA_PLANE_2_REG);
+ writel(address_3p, base + S5P_JPEG_IMG_BA_PLANE_3_REG);
+ break;
+ default:
+ break;
+ }
+}
+void jpeg_set_encode_tbl_select(void __iomem *base,
+ enum jpeg_img_quality_level level)
+{
+ unsigned int reg;
+
+ switch (level) {
+ case QUALITY_LEVEL_1:
+ reg = S5P_JPEG_Q_TBL_COMP1_0 | S5P_JPEG_Q_TBL_COMP2_0 |
+ S5P_JPEG_Q_TBL_COMP3_0 |
+ S5P_JPEG_HUFF_TBL_COMP1_AC_0_DC_1 |
+ S5P_JPEG_HUFF_TBL_COMP2_AC_0_DC_0 |
+ S5P_JPEG_HUFF_TBL_COMP3_AC_1_DC_1;
+ break;
+ case QUALITY_LEVEL_2:
+ reg = S5P_JPEG_Q_TBL_COMP1_1 | S5P_JPEG_Q_TBL_COMP2_1 |
+ S5P_JPEG_Q_TBL_COMP3_1 |
+ S5P_JPEG_HUFF_TBL_COMP1_AC_0_DC_1 |
+ S5P_JPEG_HUFF_TBL_COMP2_AC_0_DC_0 |
+ S5P_JPEG_HUFF_TBL_COMP3_AC_1_DC_1;
+ break;
+ case QUALITY_LEVEL_3:
+ reg = S5P_JPEG_Q_TBL_COMP1_2 | S5P_JPEG_Q_TBL_COMP2_2 |
+ S5P_JPEG_Q_TBL_COMP3_2 |
+ S5P_JPEG_HUFF_TBL_COMP1_AC_0_DC_1 |
+ S5P_JPEG_HUFF_TBL_COMP2_AC_0_DC_0 |
+ S5P_JPEG_HUFF_TBL_COMP3_AC_1_DC_1;
+ break;
+ case QUALITY_LEVEL_4:
+ reg = S5P_JPEG_Q_TBL_COMP1_3 | S5P_JPEG_Q_TBL_COMP2_3 |
+ S5P_JPEG_Q_TBL_COMP3_3 |
+ S5P_JPEG_HUFF_TBL_COMP1_AC_0_DC_1 |
+ S5P_JPEG_HUFF_TBL_COMP2_AC_0_DC_0 |
+ S5P_JPEG_HUFF_TBL_COMP3_AC_1_DC_1;
+ break;
+ default:
+ reg = S5P_JPEG_Q_TBL_COMP1_0 | S5P_JPEG_Q_TBL_COMP2_0 |
+ S5P_JPEG_Q_TBL_COMP3_1 |
+ S5P_JPEG_HUFF_TBL_COMP1_AC_0_DC_1 |
+ S5P_JPEG_HUFF_TBL_COMP2_AC_0_DC_0 |
+ S5P_JPEG_HUFF_TBL_COMP3_AC_1_DC_1;
+ break;
+ }
+ writel(reg, base + S5P_JPEG_TBL_SEL_REG);
+}
+
+void jpeg_set_encode_hoff_cnt(void __iomem *base, enum jpeg_stream_format fmt)
+{
+ if (fmt == JPEG_GRAY)
+ writel(0xd2, base + S5P_JPEG_HUFF_CNT_REG);
+ else
+ writel(0x1a2, base + S5P_JPEG_HUFF_CNT_REG);
+}
+
+unsigned int jpeg_get_stream_size(void __iomem *base)
+{
+ unsigned int size;
+
+ size = readl(base + S5P_JPEG_BITSTREAM_SIZE_REG);
+ return size;
+}
+
+void jpeg_set_dec_bitstream_size(void __iomem *base, unsigned int size)
+{
+ writel(size, base + S5P_JPEG_BITSTREAM_SIZE_REG);
+}
+
+void jpeg_get_frame_size(void __iomem *base,
+ unsigned int *width, unsigned int *height)
+{
+ *width = (readl(base + S5P_JPEG_DECODE_XY_SIZE_REG) &
+ S5P_JPEG_DECODED_SIZE_MASK);
+ *height = (readl(base + S5P_JPEG_DECODE_XY_SIZE_REG) >> 16) &
+ S5P_JPEG_DECODED_SIZE_MASK;
+}
+
+enum jpeg_stream_format jpeg_get_frame_fmt(void __iomem *base)
+{
+ unsigned int reg;
+ enum jpeg_stream_format out_format;
+
+ reg = readl(base + S5P_JPEG_DECODE_IMG_FMT_REG);
+
+ out_format =
+ ((reg & 0x03) == 0x01) ? JPEG_444 :
+ ((reg & 0x03) == 0x02) ? JPEG_422 :
+ ((reg & 0x03) == 0x03) ? JPEG_420 :
+ ((reg & 0x03) == 0x00) ? JPEG_GRAY : JPEG_RESERVED;
+
+ return out_format;
+}
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-v2.h b/drivers/media/platform/s5p-jpeg/jpeg-hw-v2.h
new file mode 100644
index 0000000..4e36061
--- /dev/null
+++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-v2.h
@@ -0,0 +1,47 @@
+/* Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Header file of the register interface for JPEG driver on Exynos4x12 and 5250.
+ *
+ * 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 __JPEG_REGS_H__
+#define __JPEG_REGS_H__
+
+#include "jpeg-core.h"
+
+void jpeg_sw_reset(void __iomem *base);
+void jpeg_set_enc_dec_mode(void __iomem *base, enum jpeg_mode mode);
+void jpeg_set_dec_out_fmt(void __iomem *base,
+ enum jpeg_frame_format out_fmt);
+void jpeg_set_enc_in_fmt(void __iomem *base,
+ enum jpeg_frame_format in_fmt);
+void jpeg_set_enc_out_fmt(void __iomem *base,
+ enum jpeg_stream_format out_fmt);
+void jpeg_set_enc_tbl(void __iomem *base);
+void jpeg_set_interrupt(void __iomem *base);
+unsigned int jpeg_get_int_status(void __iomem *base);
+void jpeg_set_huf_table_enable(void __iomem *base, int value);
+void jpeg_set_dec_scaling(void __iomem *base,
+ enum jpeg_scale_value x_value, enum jpeg_scale_value y_value);
+void jpeg_set_sys_int_enable(void __iomem *base, int value);
+void jpeg_set_stream_buf_address(void __iomem *base, unsigned int address);
+void jpeg_set_stream_size(void __iomem *base,
+ unsigned int x_value, unsigned int y_value);
+void jpeg_set_frame_buf_address(void __iomem *base,
+ enum jpeg_frame_format fmt, unsigned int address,
+ unsigned int address_2p, unsigned int address_3p);
+void jpeg_set_encode_tbl_select(void __iomem *base,
+ enum jpeg_img_quality_level level);
+void jpeg_set_encode_hoff_cnt(void __iomem *base, enum jpeg_stream_format fmt);
+void jpeg_set_dec_bitstream_size(void __iomem *base, unsigned int size);
+unsigned int jpeg_get_stream_size(void __iomem *base);
+void jpeg_get_frame_size(void __iomem *base,
+ unsigned int *width, unsigned int *height);
+
+enum jpeg_stream_format jpeg_get_frame_fmt(void __iomem *base);
+
+#endif /* __JPEG_REGS_H__ */
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw.h b/drivers/media/platform/s5p-jpeg/jpeg-hw.h
deleted file mode 100644
index b47e887..0000000
--- a/drivers/media/platform/s5p-jpeg/jpeg-hw.h
+++ /dev/null
@@ -1,357 +0,0 @@
-/* linux/drivers/media/platform/s5p-jpeg/jpeg-hw.h
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
- *
- * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
- *
- * 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 JPEG_HW_H_
-#define JPEG_HW_H_
-
-#include <linux/io.h>
-#include <linux/videodev2.h>
-
-#include "jpeg-hw.h"
-#include "jpeg-regs.h"
-
-#define S5P_JPEG_MIN_WIDTH 32
-#define S5P_JPEG_MIN_HEIGHT 32
-#define S5P_JPEG_MAX_WIDTH 8192
-#define S5P_JPEG_MAX_HEIGHT 8192
-#define S5P_JPEG_ENCODE 0
-#define S5P_JPEG_DECODE 1
-#define S5P_JPEG_RAW_IN_565 0
-#define S5P_JPEG_RAW_IN_422 1
-#define S5P_JPEG_RAW_OUT_422 0
-#define S5P_JPEG_RAW_OUT_420 1
-
-static inline void jpeg_reset(void __iomem *regs)
-{
- unsigned long reg;
-
- writel(1, regs + S5P_JPG_SW_RESET);
- reg = readl(regs + S5P_JPG_SW_RESET);
- /* no other way but polling for when JPEG IP becomes operational */
- while (reg != 0) {
- cpu_relax();
- reg = readl(regs + S5P_JPG_SW_RESET);
- }
-}
-
-static inline void jpeg_poweron(void __iomem *regs)
-{
- writel(S5P_POWER_ON, regs + S5P_JPGCLKCON);
-}
-
-static inline void jpeg_input_raw_mode(void __iomem *regs, unsigned long mode)
-{
- unsigned long reg, m;
-
- m = S5P_MOD_SEL_565;
- if (mode == S5P_JPEG_RAW_IN_565)
- m = S5P_MOD_SEL_565;
- else if (mode == S5P_JPEG_RAW_IN_422)
- m = S5P_MOD_SEL_422;
-
- reg = readl(regs + S5P_JPGCMOD);
- reg &= ~S5P_MOD_SEL_MASK;
- reg |= m;
- writel(reg, regs + S5P_JPGCMOD);
-}
-
-static inline void jpeg_input_raw_y16(void __iomem *regs, bool y16)
-{
- unsigned long reg;
-
- reg = readl(regs + S5P_JPGCMOD);
- if (y16)
- reg |= S5P_MODE_Y16;
- else
- reg &= ~S5P_MODE_Y16_MASK;
- writel(reg, regs + S5P_JPGCMOD);
-}
-
-static inline void jpeg_proc_mode(void __iomem *regs, unsigned long mode)
-{
- unsigned long reg, m;
-
- m = S5P_PROC_MODE_DECOMPR;
- if (mode == S5P_JPEG_ENCODE)
- m = S5P_PROC_MODE_COMPR;
- else
- m = S5P_PROC_MODE_DECOMPR;
- reg = readl(regs + S5P_JPGMOD);
- reg &= ~S5P_PROC_MODE_MASK;
- reg |= m;
- writel(reg, regs + S5P_JPGMOD);
-}
-
-static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned int mode)
-{
- unsigned long reg, m;
-
- if (mode == V4L2_JPEG_CHROMA_SUBSAMPLING_420)
- m = S5P_SUBSAMPLING_MODE_420;
- else
- m = S5P_SUBSAMPLING_MODE_422;
-
- reg = readl(regs + S5P_JPGMOD);
- reg &= ~S5P_SUBSAMPLING_MODE_MASK;
- reg |= m;
- writel(reg, regs + S5P_JPGMOD);
-}
-
-static inline unsigned int jpeg_get_subsampling_mode(void __iomem *regs)
-{
- return readl(regs + S5P_JPGMOD) & S5P_SUBSAMPLING_MODE_MASK;
-}
-
-static inline void jpeg_dri(void __iomem *regs, unsigned int dri)
-{
- unsigned long reg;
-
- reg = readl(regs + S5P_JPGDRI_U);
- reg &= ~0xff;
- reg |= (dri >> 8) & 0xff;
- writel(reg, regs + S5P_JPGDRI_U);
-
- reg = readl(regs + S5P_JPGDRI_L);
- reg &= ~0xff;
- reg |= dri & 0xff;
- writel(reg, regs + S5P_JPGDRI_L);
-}
-
-static inline void jpeg_qtbl(void __iomem *regs, unsigned int t, unsigned int n)
-{
- unsigned long reg;
-
- reg = readl(regs + S5P_JPG_QTBL);
- reg &= ~S5P_QT_NUMt_MASK(t);
- reg |= (n << S5P_QT_NUMt_SHIFT(t)) & S5P_QT_NUMt_MASK(t);
- writel(reg, regs + S5P_JPG_QTBL);
-}
-
-static inline void jpeg_htbl_ac(void __iomem *regs, unsigned int t)
-{
- unsigned long reg;
-
- reg = readl(regs + S5P_JPG_HTBL);
- reg &= ~S5P_HT_NUMt_AC_MASK(t);
- /* this driver uses table 0 for all color components */
- reg |= (0 << S5P_HT_NUMt_AC_SHIFT(t)) & S5P_HT_NUMt_AC_MASK(t);
- writel(reg, regs + S5P_JPG_HTBL);
-}
-
-static inline void jpeg_htbl_dc(void __iomem *regs, unsigned int t)
-{
- unsigned long reg;
-
- reg = readl(regs + S5P_JPG_HTBL);
- reg &= ~S5P_HT_NUMt_DC_MASK(t);
- /* this driver uses table 0 for all color components */
- reg |= (0 << S5P_HT_NUMt_DC_SHIFT(t)) & S5P_HT_NUMt_DC_MASK(t);
- writel(reg, regs + S5P_JPG_HTBL);
-}
-
-static inline void jpeg_y(void __iomem *regs, unsigned int y)
-{
- unsigned long reg;
-
- reg = readl(regs + S5P_JPGY_U);
- reg &= ~0xff;
- reg |= (y >> 8) & 0xff;
- writel(reg, regs + S5P_JPGY_U);
-
- reg = readl(regs + S5P_JPGY_L);
- reg &= ~0xff;
- reg |= y & 0xff;
- writel(reg, regs + S5P_JPGY_L);
-}
-
-static inline void jpeg_x(void __iomem *regs, unsigned int x)
-{
- unsigned long reg;
-
- reg = readl(regs + S5P_JPGX_U);
- reg &= ~0xff;
- reg |= (x >> 8) & 0xff;
- writel(reg, regs + S5P_JPGX_U);
-
- reg = readl(regs + S5P_JPGX_L);
- reg &= ~0xff;
- reg |= x & 0xff;
- writel(reg, regs + S5P_JPGX_L);
-}
-
-static inline void jpeg_rst_int_enable(void __iomem *regs, bool enable)
-{
- unsigned long reg;
-
- reg = readl(regs + S5P_JPGINTSE);
- reg &= ~S5P_RSTm_INT_EN_MASK;
- if (enable)
- reg |= S5P_RSTm_INT_EN;
- writel(reg, regs + S5P_JPGINTSE);
-}
-
-static inline void jpeg_data_num_int_enable(void __iomem *regs, bool enable)
-{
- unsigned long reg;
-
- reg = readl(regs + S5P_JPGINTSE);
- reg &= ~S5P_DATA_NUM_INT_EN_MASK;
- if (enable)
- reg |= S5P_DATA_NUM_INT_EN;
- writel(reg, regs + S5P_JPGINTSE);
-}
-
-static inline void jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl)
-{
- unsigned long reg;
-
- reg = readl(regs + S5P_JPGINTSE);
- reg &= ~S5P_FINAL_MCU_NUM_INT_EN_MASK;
- if (enbl)
- reg |= S5P_FINAL_MCU_NUM_INT_EN;
- writel(reg, regs + S5P_JPGINTSE);
-}
-
-static inline void jpeg_timer_enable(void __iomem *regs, unsigned long val)
-{
- unsigned long reg;
-
- reg = readl(regs + S5P_JPG_TIMER_SE);
- reg |= S5P_TIMER_INT_EN;
- reg &= ~S5P_TIMER_INIT_MASK;
- reg |= val & S5P_TIMER_INIT_MASK;
- writel(reg, regs + S5P_JPG_TIMER_SE);
-}
-
-static inline void jpeg_timer_disable(void __iomem *regs)
-{
- unsigned long reg;
-
- reg = readl(regs + S5P_JPG_TIMER_SE);
- reg &= ~S5P_TIMER_INT_EN_MASK;
- writel(reg, regs + S5P_JPG_TIMER_SE);
-}
-
-static inline int jpeg_timer_stat(void __iomem *regs)
-{
- return (int)((readl(regs + S5P_JPG_TIMER_ST) & S5P_TIMER_INT_STAT_MASK)
- >> S5P_TIMER_INT_STAT_SHIFT);
-}
-
-static inline void jpeg_clear_timer_stat(void __iomem *regs)
-{
- unsigned long reg;
-
- reg = readl(regs + S5P_JPG_TIMER_SE);
- reg &= ~S5P_TIMER_INT_STAT_MASK;
- writel(reg, regs + S5P_JPG_TIMER_SE);
-}
-
-static inline void jpeg_enc_stream_int(void __iomem *regs, unsigned long size)
-{
- unsigned long reg;
-
- reg = readl(regs + S5P_JPG_ENC_STREAM_INTSE);
- reg &= ~S5P_ENC_STREAM_BOUND_MASK;
- reg |= S5P_ENC_STREAM_INT_EN;
- reg |= size & S5P_ENC_STREAM_BOUND_MASK;
- writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE);
-}
-
-static inline int jpeg_enc_stream_stat(void __iomem *regs)
-{
- return (int)(readl(regs + S5P_JPG_ENC_STREAM_INTST) &
- S5P_ENC_STREAM_INT_STAT_MASK);
-}
-
-static inline void jpeg_clear_enc_stream_stat(void __iomem *regs)
-{
- unsigned long reg;
-
- reg = readl(regs + S5P_JPG_ENC_STREAM_INTSE);
- reg &= ~S5P_ENC_STREAM_INT_MASK;
- writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE);
-}
-
-static inline void jpeg_outform_raw(void __iomem *regs, unsigned long format)
-{
- unsigned long reg, f;
-
- f = S5P_DEC_OUT_FORMAT_422;
- if (format == S5P_JPEG_RAW_OUT_422)
- f = S5P_DEC_OUT_FORMAT_422;
- else if (format == S5P_JPEG_RAW_OUT_420)
- f = S5P_DEC_OUT_FORMAT_420;
- reg = readl(regs + S5P_JPG_OUTFORM);
- reg &= ~S5P_DEC_OUT_FORMAT_MASK;
- reg |= f;
- writel(reg, regs + S5P_JPG_OUTFORM);
-}
-
-static inline void jpeg_jpgadr(void __iomem *regs, unsigned long addr)
-{
- writel(addr, regs + S5P_JPG_JPGADR);
-}
-
-static inline void jpeg_imgadr(void __iomem *regs, unsigned long addr)
-{
- writel(addr, regs + S5P_JPG_IMGADR);
-}
-
-static inline void jpeg_coef(void __iomem *regs, unsigned int i,
- unsigned int j, unsigned int coef)
-{
- unsigned long reg;
-
- reg = readl(regs + S5P_JPG_COEF(i));
- reg &= ~S5P_COEFn_MASK(j);
- reg |= (coef << S5P_COEFn_SHIFT(j)) & S5P_COEFn_MASK(j);
- writel(reg, regs + S5P_JPG_COEF(i));
-}
-
-static inline void jpeg_start(void __iomem *regs)
-{
- writel(1, regs + S5P_JSTART);
-}
-
-static inline int jpeg_result_stat_ok(void __iomem *regs)
-{
- return (int)((readl(regs + S5P_JPGINTST) & S5P_RESULT_STAT_MASK)
- >> S5P_RESULT_STAT_SHIFT);
-}
-
-static inline int jpeg_stream_stat_ok(void __iomem *regs)
-{
- return !(int)((readl(regs + S5P_JPGINTST) & S5P_STREAM_STAT_MASK)
- >> S5P_STREAM_STAT_SHIFT);
-}
-
-static inline void jpeg_clear_int(void __iomem *regs)
-{
- unsigned long reg;
-
- reg = readl(regs + S5P_JPGINTST);
- writel(S5P_INT_RELEASE, regs + S5P_JPGCOM);
- reg = readl(regs + S5P_JPGOPR);
-}
-
-static inline unsigned int jpeg_compressed_size(void __iomem *regs)
-{
- unsigned long jpeg_size = 0;
-
- jpeg_size |= (readl(regs + S5P_JPGCNT_U) & 0xff) << 16;
- jpeg_size |= (readl(regs + S5P_JPGCNT_M) & 0xff) << 8;
- jpeg_size |= (readl(regs + S5P_JPGCNT_L) & 0xff);
-
- return (unsigned int)jpeg_size;
-}
-
-#endif /* JPEG_HW_H_ */
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-regs-v1.h b/drivers/media/platform/s5p-jpeg/jpeg-regs-v1.h
new file mode 100644
index 0000000..54a0925
--- /dev/null
+++ b/drivers/media/platform/s5p-jpeg/jpeg-regs-v1.h
@@ -0,0 +1,169 @@
+/* linux/drivers/media/platform/s5p-jpeg/jpeg-regs-v1.h
+ *
+ * Register definition file for Samsung JPEG codec driver on Exynos4210.
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * 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 JPEG_REGS_H_
+#define JPEG_REGS_H_
+
+/* JPEG mode register */
+#define S5P_JPGMOD 0x00
+#define S5P_PROC_MODE_MASK (0x1 << 3)
+#define S5P_PROC_MODE_DECOMPR (0x1 << 3)
+#define S5P_PROC_MODE_COMPR (0x0 << 3)
+#define S5P_SUBSAMPLING_MODE_MASK 0x7
+#define S5P_SUBSAMPLING_MODE_444 (0x0 << 0)
+#define S5P_SUBSAMPLING_MODE_422 (0x1 << 0)
+#define S5P_SUBSAMPLING_MODE_420 (0x2 << 0)
+#define S5P_SUBSAMPLING_MODE_GRAY (0x3 << 0)
+
+/* JPEG operation status register */
+#define S5P_JPGOPR 0x04
+
+/* Quantization tables*/
+#define S5P_JPG_QTBL 0x08
+#define S5P_QT_NUMt_SHIFT(t) (((t) - 1) << 1)
+#define S5P_QT_NUMt_MASK(t) (0x3 << S5P_QT_NUMt_SHIFT(t))
+
+/* Huffman tables */
+#define S5P_JPG_HTBL 0x0c
+#define S5P_HT_NUMt_AC_SHIFT(t) (((t) << 1) - 1)
+#define S5P_HT_NUMt_AC_MASK(t) (0x1 << S5P_HT_NUMt_AC_SHIFT(t))
+
+#define S5P_HT_NUMt_DC_SHIFT(t) (((t) - 1) << 1)
+#define S5P_HT_NUMt_DC_MASK(t) (0x1 << S5P_HT_NUMt_DC_SHIFT(t))
+
+/* JPEG restart interval register upper byte */
+#define S5P_JPGDRI_U 0x10
+
+/* JPEG restart interval register lower byte */
+#define S5P_JPGDRI_L 0x14
+
+/* JPEG vertical resolution register upper byte */
+#define S5P_JPGY_U 0x18
+
+/* JPEG vertical resolution register lower byte */
+#define S5P_JPGY_L 0x1c
+
+/* JPEG horizontal resolution register upper byte */
+#define S5P_JPGX_U 0x20
+
+/* JPEG horizontal resolution register lower byte */
+#define S5P_JPGX_L 0x24
+
+/* JPEG byte count register upper byte */
+#define S5P_JPGCNT_U 0x28
+
+/* JPEG byte count register middle byte */
+#define S5P_JPGCNT_M 0x2c
+
+/* JPEG byte count register lower byte */
+#define S5P_JPGCNT_L 0x30
+
+/* JPEG interrupt setting register */
+#define S5P_JPGINTSE 0x34
+#define S5P_RSTm_INT_EN_MASK (0x1 << 7)
+#define S5P_RSTm_INT_EN (0x1 << 7)
+#define S5P_DATA_NUM_INT_EN_MASK (0x1 << 6)
+#define S5P_DATA_NUM_INT_EN (0x1 << 6)
+#define S5P_FINAL_MCU_NUM_INT_EN_MASK (0x1 << 5)
+#define S5P_FINAL_MCU_NUM_INT_EN (0x1 << 5)
+
+/* JPEG interrupt status register */
+#define S5P_JPGINTST 0x38
+#define S5P_RESULT_STAT_SHIFT 6
+#define S5P_RESULT_STAT_MASK (0x1 << S5P_RESULT_STAT_SHIFT)
+#define S5P_STREAM_STAT_SHIFT 5
+#define S5P_STREAM_STAT_MASK (0x1 << S5P_STREAM_STAT_SHIFT)
+
+/* JPEG command register */
+#define S5P_JPGCOM 0x4c
+#define S5P_INT_RELEASE (0x1 << 2)
+
+/* Raw image data r/w address register */
+#define S5P_JPG_IMGADR 0x50
+
+/* JPEG file r/w address register */
+#define S5P_JPG_JPGADR 0x58
+
+/* Coefficient for RGB-to-YCbCr converter register */
+#define S5P_JPG_COEF(n) (0x5c + (((n) - 1) << 2))
+#define S5P_COEFn_SHIFT(j) ((3 - (j)) << 3)
+#define S5P_COEFn_MASK(j) (0xff << S5P_COEFn_SHIFT(j))
+
+/* JPEG color mode register */
+#define S5P_JPGCMOD 0x68
+#define S5P_MOD_SEL_MASK (0x7 << 5)
+#define S5P_MOD_SEL_422 (0x1 << 5)
+#define S5P_MOD_SEL_565 (0x2 << 5)
+#define S5P_MODE_Y16_MASK (0x1 << 1)
+#define S5P_MODE_Y16 (0x1 << 1)
+
+/* JPEG clock control register */
+#define S5P_JPGCLKCON 0x6c
+#define S5P_CLK_DOWN_READY (0x1 << 1)
+#define S5P_POWER_ON (0x1 << 0)
+
+/* JPEG start register */
+#define S5P_JSTART 0x70
+
+/* JPEG SW reset register */
+#define S5P_JPG_SW_RESET 0x78
+
+/* JPEG timer setting register */
+#define S5P_JPG_TIMER_SE 0x7c
+#define S5P_TIMER_INT_EN_MASK (0x1 << 31)
+#define S5P_TIMER_INT_EN (0x1 << 31)
+#define S5P_TIMER_INIT_MASK 0x7fffffff
+
+/* JPEG timer status register */
+#define S5P_JPG_TIMER_ST 0x80
+#define S5P_TIMER_INT_STAT_SHIFT 31
+#define S5P_TIMER_INT_STAT_MASK (0x1 << S5P_TIMER_INT_STAT_SHIFT)
+#define S5P_TIMER_CNT_SHIFT 0
+#define S5P_TIMER_CNT_MASK 0x7fffffff
+
+/* JPEG decompression output format register */
+#define S5P_JPG_OUTFORM 0x88
+#define S5P_DEC_OUT_FORMAT_MASK (0x1 << 0)
+#define S5P_DEC_OUT_FORMAT_422 (0x0 << 0)
+#define S5P_DEC_OUT_FORMAT_420 (0x1 << 0)
+
+/* JPEG version register */
+#define S5P_JPG_VERSION 0x8c
+
+/* JPEG compressed stream size interrupt setting register */
+#define S5P_JPG_ENC_STREAM_INTSE 0x98
+#define S5P_ENC_STREAM_INT_MASK (0x1 << 24)
+#define S5P_ENC_STREAM_INT_EN (0x1 << 24)
+#define S5P_ENC_STREAM_BOUND_MASK 0xffffff
+
+/* JPEG compressed stream size interrupt status register */
+#define S5P_JPG_ENC_STREAM_INTST 0x9c
+#define S5P_ENC_STREAM_INT_STAT_MASK 0x1
+
+/* JPEG quantizer table register */
+#define S5P_JPG_QTBL_CONTENT(n) (0x400 + (n) * 0x100)
+
+/* JPEG DC Huffman table register */
+#define S5P_JPG_HDCTBL(n) (0x800 + (n) * 0x400)
+
+/* JPEG DC Huffman table register */
+#define S5P_JPG_HDCTBLG(n) (0x840 + (n) * 0x400)
+
+/* JPEG AC Huffman table register */
+#define S5P_JPG_HACTBL(n) (0x880 + (n) * 0x400)
+
+/* JPEG AC Huffman table register */
+#define S5P_JPG_HACTBLG(n) (0x8c0 + (n) * 0x400)
+
+#endif /* JPEG_REGS_H_ */
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-regs-v2.h b/drivers/media/platform/s5p-jpeg/jpeg-regs-v2.h
new file mode 100644
index 0000000..00ff2f7
--- /dev/null
+++ b/drivers/media/platform/s5p-jpeg/jpeg-regs-v2.h
@@ -0,0 +1,191 @@
+/* Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Register definition file for Samsung JPEG driver on Exynos4x12 and 5250.
+ *
+ * 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 __ASM_ARM_REGS_S5P_JPEG_H
+#define __ASM_ARM_REGS_S5P_JPEG_H
+
+/* JPEG Registers part */
+
+/* JPEG Codec Control Registers */
+#define S5P_JPEG_CNTL_REG 0x00
+#define S5P_JPEG_INT_EN_REG 0x04
+/*#define S5P_JPEG_QTBL_REG 0x08*Reserved*/
+#define S5P_JPEG_INT_STATUS_REG 0x0c
+#define S5P_JPEG_OUT_MEM_BASE_REG 0x10
+#define S5P_JPEG_IMG_SIZE_REG 0x14
+#define S5P_JPEG_IMG_BA_PLANE_1_REG 0x18
+#define S5P_JPEG_IMG_SO_PLANE_1_REG 0x1c
+#define S5P_JPEG_IMG_PO_PLANE_1_REG 0x20
+#define S5P_JPEG_IMG_BA_PLANE_2_REG 0x24
+#define S5P_JPEG_IMG_SO_PLANE_2_REG 0x28
+#define S5P_JPEG_IMG_PO_PLANE_2_REG 0x2c
+#define S5P_JPEG_IMG_BA_PLANE_3_REG 0x30
+#define S5P_JPEG_IMG_SO_PLANE_3_REG 0x34
+#define S5P_JPEG_IMG_PO_PLANE_3_REG 0x38
+
+#define S5P_JPEG_TBL_SEL_REG 0x3c
+
+#define S5P_JPEG_IMG_FMT_REG 0x40
+
+#define S5P_JPEG_BITSTREAM_SIZE_REG 0x44
+#define S5P_JPEG_PADDING_REG 0x48
+#define S5P_JPEG_HUFF_CNT_REG 0x4c
+#define S5P_JPEG_FIFO_STATUS_REG 0x50
+#define S5P_JPEG_DECODE_XY_SIZE_REG 0x54
+#define S5P_JPEG_DECODE_IMG_FMT_REG 0x58
+
+#define S5P_JPEG_QUAN_TBL_ENTRY_REG 0x100
+#define S5P_JPEG_HUFF_TBL_ENTRY_REG 0x200
+
+
+/****************************************************************/
+/* Bit definition part */
+/****************************************************************/
+
+/* JPEG CNTL Register bit */
+#define S5P_JPEG_ENC_DEC_MODE_MASK (0xfffffffc << 0)
+#define S5P_JPEG_DEC_MODE (1 << 0)
+#define S5P_JPEG_ENC_MODE (1 << 1)
+#define S5P_JPEG_AUTO_RST_MARKER (1 << 2)
+#define S5P_JPEG_RST_INTERVAL_SHIFT 3
+#define S5P_JPEG_RST_INTERVAL(x) (((x) & 0xffff) << S5P_JPEG_RST_INTERVAL_SHIFT)
+#define S5P_JPEG_HUF_TBL_EN (1 << 19)
+#define S5P_JPEG_HOR_SCALING_SHIFT 20
+#define S5P_JPEG_HOR_SCALING_MASK (3 << S5P_JPEG_HOR_SCALING_SHIFT)
+#define S5P_JPEG_HOR_SCALING(x) (((x) & 0x3) << S5P_JPEG_HOR_SCALING_SHIFT)
+#define S5P_JPEG_VER_SCALING_SHIFT 22
+#define S5P_JPEG_VER_SCALING_MASK (3 << S5P_JPEG_VER_SCALING_SHIFT)
+#define S5P_JPEG_VER_SCALING(x) (((x) & 0x3) << S5P_JPEG_VER_SCALING_SHIFT)
+#define S5P_JPEG_PADDING (1 << 27)
+#define S5P_JPEG_SYS_INT_EN (1 << 28)
+#define S5P_JPEG_SOFT_RESET_HI (1 << 29)
+
+/* JPEG INT Register bit */
+#define S5P_JPEG_INT_EN_MASK (0x1f << 0)
+#define S5P_JPEG_PROT_ERR_INT_EN (1 << 0)
+#define S5P_JPEG_IMG_COMPLETION_INT_EN (1 << 1)
+#define S5P_JPEG_DEC_INVALID_FORMAT_EN (1 << 2)
+#define S5P_JPEG_MULTI_SCAN_ERROR_EN (1 << 3)
+#define S5P_JPEG_FRAME_ERR_EN (1 << 4)
+#define S5P_JPEG_INT_EN_ALL (0x1f << 0)
+
+#define S5P_JPEG_MOD_REG_PROC_ENC (0 << 3)
+#define S5P_JPEG_MOD_REG_PROC_DEC (1 << 3)
+
+#define S5P_JPEG_MOD_REG_SUBSAMPLE_444 (0 << 0)
+#define S5P_JPEG_MOD_REG_SUBSAMPLE_422 (1 << 0)
+#define S5P_JPEG_MOD_REG_SUBSAMPLE_420 (2 << 0)
+#define S5P_JPEG_MOD_REG_SUBSAMPLE_GRAY (3 << 0)
+
+
+/* JPEG IMAGE SIZE Register bit */
+#define S5P_JPEG_X_SIZE_SHIFT 0
+#define S5P_JPEG_X_SIZE_MASK (0xffff << S5P_JPEG_X_SIZE_SHIFT)
+#define S5P_JPEG_X_SIZE(x) (((x) & 0xffff) << S5P_JPEG_X_SIZE_SHIFT)
+#define S5P_JPEG_Y_SIZE_SHIFT 16
+#define S5P_JPEG_Y_SIZE_MASK (0xffff << S5P_JPEG_Y_SIZE_SHIFT)
+#define S5P_JPEG_Y_SIZE(x) (((x) & 0xffff) << S5P_JPEG_Y_SIZE_SHIFT)
+
+/* JPEG IMAGE FORMAT Register bit */
+#define S5P_JPEG_ENC_IN_FMT_MASK 0xffff0000
+#define S5P_JPEG_ENC_GRAY_IMG (0 << 0)
+#define S5P_JPEG_ENC_RGB_IMG (1 << 0)
+#define S5P_JPEG_ENC_YUV_444_IMG (2 << 0)
+#define S5P_JPEG_ENC_YUV_422_IMG (3 << 0)
+#define S5P_JPEG_ENC_YUV_440_IMG (4 << 0)
+
+#define S5P_JPEG_DEC_GRAY_IMG (0 << 0)
+#define S5P_JPEG_DEC_RGB_IMG (1 << 0)
+#define S5P_JPEG_DEC_YUV_444_IMG (2 << 0)
+#define S5P_JPEG_DEC_YUV_422_IMG (3 << 0)
+#define S5P_JPEG_DEC_YUV_420_IMG (4 << 0)
+
+#define S5P_JPEG_GRAY_IMG_IP_SHIFT 3
+#define S5P_JPEG_GRAY_IMG_IP_MASK (7 << S5P_JPEG_GRAY_IMG_IP_SHIFT)
+#define S5P_JPEG_GRAY_IMG_IP (4 << S5P_JPEG_GRAY_IMG_IP_SHIFT)
+
+#define S5P_JPEG_RGB_IP_SHIFT 6
+#define S5P_JPEG_RGB_IP_MASK (7 << S5P_JPEG_RGB_IP_SHIFT)
+#define S5P_JPEG_RGB_IP_RGB_16BIT_IMG (4 << S5P_JPEG_RGB_IP_SHIFT)
+#define S5P_JPEG_RGB_IP_RGB_32BIT_IMG (5 << S5P_JPEG_RGB_IP_SHIFT)
+
+#define S5P_JPEG_YUV_444_IP_SHIFT 9
+#define S5P_JPEG_YUV_444_IP_MASK (7 << S5P_JPEG_YUV_444_IP_SHIFT)
+#define S5P_JPEG_YUV_444_IP_YUV_444_2P_IMG (4 << S5P_JPEG_YUV_444_IP_SHIFT)
+#define S5P_JPEG_YUV_444_IP_YUV_444_3P_IMG (5 << S5P_JPEG_YUV_444_IP_SHIFT)
+
+#define S5P_JPEG_YUV_422_IP_SHIFT 12
+#define S5P_JPEG_YUV_422_IP_MASK (7 << S5P_JPEG_YUV_422_IP_SHIFT)
+#define S5P_JPEG_YUV_422_IP_YUV_422_1P_IMG (4 << S5P_JPEG_YUV_422_IP_SHIFT)
+#define S5P_JPEG_YUV_422_IP_YUV_422_2P_IMG (5 << S5P_JPEG_YUV_422_IP_SHIFT)
+#define S5P_JPEG_YUV_422_IP_YUV_422_3P_IMG (6 << S5P_JPEG_YUV_422_IP_SHIFT)
+
+#define S5P_JPEG_YUV_420_IP_SHIFT 15
+#define S5P_JPEG_YUV_420_IP_MASK (7 << S5P_JPEG_YUV_420_IP_SHIFT)
+#define S5P_JPEG_YUV_420_IP_YUV_420_2P_IMG (4 << S5P_JPEG_YUV_420_IP_SHIFT)
+#define S5P_JPEG_YUV_420_IP_YUV_420_3P_IMG (5 << S5P_JPEG_YUV_420_IP_SHIFT)
+
+#define S5P_JPEG_ENC_FMT_SHIFT 24
+#define S5P_JPEG_ENC_FMT_MASK (3 << S5P_JPEG_ENC_FMT_SHIFT)
+#define S5P_JPEG_ENC_FMT_GRAY (0 << S5P_JPEG_ENC_FMT_SHIFT)
+#define S5P_JPEG_ENC_FMT_YUV_444 (1 << S5P_JPEG_ENC_FMT_SHIFT)
+#define S5P_JPEG_ENC_FMT_YUV_422 (2 << S5P_JPEG_ENC_FMT_SHIFT)
+#define S5P_JPEG_ENC_FMT_YUV_420 (3 << S5P_JPEG_ENC_FMT_SHIFT)
+
+#define S5P_JPEG_SWAP_CHROMA_CrCb (1 << 26)
+#define S5P_JPEG_SWAP_CHROMA_CbCr (0 << 26)
+
+/* JPEG HUFF count Register bit */
+#define S5P_JPEG_HUFF_COUNT_MASK 0xffff
+
+/* JPEG Decoded_img_x_y_size Register bit */
+#define S5P_JPEG_DECODED_SIZE_MASK 0x0000ffff
+
+/* JPEG Decoded image format Register bit */
+#define S5P_JPEG_DECODED_IMG_FMT_MASK 0x3
+
+/* JPEG TBL SEL Register bit */
+#define S5P_JPEG_Q_TBL_COMP1_SHIFT 0
+#define S5P_JPEG_Q_TBL_COMP1_0 (0 << S5P_JPEG_Q_TBL_COMP1_SHIFT)
+#define S5P_JPEG_Q_TBL_COMP1_1 (1 << S5P_JPEG_Q_TBL_COMP1_SHIFT)
+#define S5P_JPEG_Q_TBL_COMP1_2 (2 << S5P_JPEG_Q_TBL_COMP1_SHIFT)
+#define S5P_JPEG_Q_TBL_COMP1_3 (3 << S5P_JPEG_Q_TBL_COMP1_SHIFT)
+
+#define S5P_JPEG_Q_TBL_COMP2_SHIFT 2
+#define S5P_JPEG_Q_TBL_COMP2_0 (0 << S5P_JPEG_Q_TBL_COMP2_SHIFT)
+#define S5P_JPEG_Q_TBL_COMP2_1 (1 << S5P_JPEG_Q_TBL_COMP2_SHIFT)
+#define S5P_JPEG_Q_TBL_COMP2_2 (2 << S5P_JPEG_Q_TBL_COMP2_SHIFT)
+#define S5P_JPEG_Q_TBL_COMP2_3 (3 << S5P_JPEG_Q_TBL_COMP2_SHIFT)
+
+#define S5P_JPEG_Q_TBL_COMP3_SHIFT 4
+#define S5P_JPEG_Q_TBL_COMP3_0 (0 << S5P_JPEG_Q_TBL_COMP3_SHIFT)
+#define S5P_JPEG_Q_TBL_COMP3_1 (1 << S5P_JPEG_Q_TBL_COMP2_SHIFT)
+#define S5P_JPEG_Q_TBL_COMP3_2 (2 << S5P_JPEG_Q_TBL_COMP2_SHIFT)
+#define S5P_JPEG_Q_TBL_COMP3_3 (3 << S5P_JPEG_Q_TBL_COMP2_SHIFT)
+
+#define S5P_JPEG_HUFF_TBL_COMP1_SHIFT 6
+#define S5P_JPEG_HUFF_TBL_COMP1_AC_0_DC_0 (0 << S5P_JPEG_HUFF_TBL_COMP1_SHIFT)
+#define S5P_JPEG_HUFF_TBL_COMP1_AC_0_DC_1 (1 << S5P_JPEG_HUFF_TBL_COMP1_SHIFT)
+#define S5P_JPEG_HUFF_TBL_COMP1_AC_1_DC_0 (2 << S5P_JPEG_HUFF_TBL_COMP1_SHIFT)
+#define S5P_JPEG_HUFF_TBL_COMP1_AC_1_DC_1 (3 << S5P_JPEG_HUFF_TBL_COMP1_SHIFT)
+
+#define S5P_JPEG_HUFF_TBL_COMP2_SHIFT 8
+#define S5P_JPEG_HUFF_TBL_COMP2_AC_0_DC_0 (0 << S5P_JPEG_HUFF_TBL_COMP2_SHIFT)
+#define S5P_JPEG_HUFF_TBL_COMP2_AC_0_DC_1 (1 << S5P_JPEG_HUFF_TBL_COMP2_SHIFT)
+#define S5P_JPEG_HUFF_TBL_COMP2_AC_1_DC_0 (2 << S5P_JPEG_HUFF_TBL_COMP2_SHIFT)
+#define S5P_JPEG_HUFF_TBL_COMP2_AC_1_DC_1 (3 << S5P_JPEG_HUFF_TBL_COMP2_SHIFT)
+
+#define S5P_JPEG_HUFF_TBL_COMP3_SHIFT 10
+#define S5P_JPEG_HUFF_TBL_COMP3_AC_0_DC_0 (0 << S5P_JPEG_HUFF_TBL_COMP3_SHIFT)
+#define S5P_JPEG_HUFF_TBL_COMP3_AC_0_DC_1 (1 << S5P_JPEG_HUFF_TBL_COMP3_SHIFT)
+#define S5P_JPEG_HUFF_TBL_COMP3_AC_1_DC_0 (2 << S5P_JPEG_HUFF_TBL_COMP3_SHIFT)
+#define S5P_JPEG_HUFF_TBL_COMP3_AC_1_DC_1 (3 << S5P_JPEG_HUFF_TBL_COMP3_SHIFT)
+
+#endif /* __ASM_ARM_REGS_S5P_JPEG_H */
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-regs.h b/drivers/media/platform/s5p-jpeg/jpeg-regs.h
deleted file mode 100644
index 38e5081..0000000
--- a/drivers/media/platform/s5p-jpeg/jpeg-regs.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/* linux/drivers/media/platform/s5p-jpeg/jpeg-regs.h
- *
- * Register definition file for Samsung JPEG codec driver
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
- *
- * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
- *
- * 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 JPEG_REGS_H_
-#define JPEG_REGS_H_
-
-/* JPEG mode register */
-#define S5P_JPGMOD 0x00
-#define S5P_PROC_MODE_MASK (0x1 << 3)
-#define S5P_PROC_MODE_DECOMPR (0x1 << 3)
-#define S5P_PROC_MODE_COMPR (0x0 << 3)
-#define S5P_SUBSAMPLING_MODE_MASK 0x7
-#define S5P_SUBSAMPLING_MODE_444 (0x0 << 0)
-#define S5P_SUBSAMPLING_MODE_422 (0x1 << 0)
-#define S5P_SUBSAMPLING_MODE_420 (0x2 << 0)
-#define S5P_SUBSAMPLING_MODE_GRAY (0x3 << 0)
-
-/* JPEG operation status register */
-#define S5P_JPGOPR 0x04
-
-/* Quantization tables*/
-#define S5P_JPG_QTBL 0x08
-#define S5P_QT_NUMt_SHIFT(t) (((t) - 1) << 1)
-#define S5P_QT_NUMt_MASK(t) (0x3 << S5P_QT_NUMt_SHIFT(t))
-
-/* Huffman tables */
-#define S5P_JPG_HTBL 0x0c
-#define S5P_HT_NUMt_AC_SHIFT(t) (((t) << 1) - 1)
-#define S5P_HT_NUMt_AC_MASK(t) (0x1 << S5P_HT_NUMt_AC_SHIFT(t))
-
-#define S5P_HT_NUMt_DC_SHIFT(t) (((t) - 1) << 1)
-#define S5P_HT_NUMt_DC_MASK(t) (0x1 << S5P_HT_NUMt_DC_SHIFT(t))
-
-/* JPEG restart interval register upper byte */
-#define S5P_JPGDRI_U 0x10
-
-/* JPEG restart interval register lower byte */
-#define S5P_JPGDRI_L 0x14
-
-/* JPEG vertical resolution register upper byte */
-#define S5P_JPGY_U 0x18
-
-/* JPEG vertical resolution register lower byte */
-#define S5P_JPGY_L 0x1c
-
-/* JPEG horizontal resolution register upper byte */
-#define S5P_JPGX_U 0x20
-
-/* JPEG horizontal resolution register lower byte */
-#define S5P_JPGX_L 0x24
-
-/* JPEG byte count register upper byte */
-#define S5P_JPGCNT_U 0x28
-
-/* JPEG byte count register middle byte */
-#define S5P_JPGCNT_M 0x2c
-
-/* JPEG byte count register lower byte */
-#define S5P_JPGCNT_L 0x30
-
-/* JPEG interrupt setting register */
-#define S5P_JPGINTSE 0x34
-#define S5P_RSTm_INT_EN_MASK (0x1 << 7)
-#define S5P_RSTm_INT_EN (0x1 << 7)
-#define S5P_DATA_NUM_INT_EN_MASK (0x1 << 6)
-#define S5P_DATA_NUM_INT_EN (0x1 << 6)
-#define S5P_FINAL_MCU_NUM_INT_EN_MASK (0x1 << 5)
-#define S5P_FINAL_MCU_NUM_INT_EN (0x1 << 5)
-
-/* JPEG interrupt status register */
-#define S5P_JPGINTST 0x38
-#define S5P_RESULT_STAT_SHIFT 6
-#define S5P_RESULT_STAT_MASK (0x1 << S5P_RESULT_STAT_SHIFT)
-#define S5P_STREAM_STAT_SHIFT 5
-#define S5P_STREAM_STAT_MASK (0x1 << S5P_STREAM_STAT_SHIFT)
-
-/* JPEG command register */
-#define S5P_JPGCOM 0x4c
-#define S5P_INT_RELEASE (0x1 << 2)
-
-/* Raw image data r/w address register */
-#define S5P_JPG_IMGADR 0x50
-
-/* JPEG file r/w address register */
-#define S5P_JPG_JPGADR 0x58
-
-/* Coefficient for RGB-to-YCbCr converter register */
-#define S5P_JPG_COEF(n) (0x5c + (((n) - 1) << 2))
-#define S5P_COEFn_SHIFT(j) ((3 - (j)) << 3)
-#define S5P_COEFn_MASK(j) (0xff << S5P_COEFn_SHIFT(j))
-
-/* JPEG color mode register */
-#define S5P_JPGCMOD 0x68
-#define S5P_MOD_SEL_MASK (0x7 << 5)
-#define S5P_MOD_SEL_422 (0x1 << 5)
-#define S5P_MOD_SEL_565 (0x2 << 5)
-#define S5P_MODE_Y16_MASK (0x1 << 1)
-#define S5P_MODE_Y16 (0x1 << 1)
-
-/* JPEG clock control register */
-#define S5P_JPGCLKCON 0x6c
-#define S5P_CLK_DOWN_READY (0x1 << 1)
-#define S5P_POWER_ON (0x1 << 0)
-
-/* JPEG start register */
-#define S5P_JSTART 0x70
-
-/* JPEG SW reset register */
-#define S5P_JPG_SW_RESET 0x78
-
-/* JPEG timer setting register */
-#define S5P_JPG_TIMER_SE 0x7c
-#define S5P_TIMER_INT_EN_MASK (0x1 << 31)
-#define S5P_TIMER_INT_EN (0x1 << 31)
-#define S5P_TIMER_INIT_MASK 0x7fffffff
-
-/* JPEG timer status register */
-#define S5P_JPG_TIMER_ST 0x80
-#define S5P_TIMER_INT_STAT_SHIFT 31
-#define S5P_TIMER_INT_STAT_MASK (0x1 << S5P_TIMER_INT_STAT_SHIFT)
-#define S5P_TIMER_CNT_SHIFT 0
-#define S5P_TIMER_CNT_MASK 0x7fffffff
-
-/* JPEG decompression output format register */
-#define S5P_JPG_OUTFORM 0x88
-#define S5P_DEC_OUT_FORMAT_MASK (0x1 << 0)
-#define S5P_DEC_OUT_FORMAT_422 (0x0 << 0)
-#define S5P_DEC_OUT_FORMAT_420 (0x1 << 0)
-
-/* JPEG version register */
-#define S5P_JPG_VERSION 0x8c
-
-/* JPEG compressed stream size interrupt setting register */
-#define S5P_JPG_ENC_STREAM_INTSE 0x98
-#define S5P_ENC_STREAM_INT_MASK (0x1 << 24)
-#define S5P_ENC_STREAM_INT_EN (0x1 << 24)
-#define S5P_ENC_STREAM_BOUND_MASK 0xffffff
-
-/* JPEG compressed stream size interrupt status register */
-#define S5P_JPG_ENC_STREAM_INTST 0x9c
-#define S5P_ENC_STREAM_INT_STAT_MASK 0x1
-
-/* JPEG quantizer table register */
-#define S5P_JPG_QTBL_CONTENT(n) (0x400 + (n) * 0x100)
-
-/* JPEG DC Huffman table register */
-#define S5P_JPG_HDCTBL(n) (0x800 + (n) * 0x400)
-
-/* JPEG DC Huffman table register */
-#define S5P_JPG_HDCTBLG(n) (0x840 + (n) * 0x400)
-
-/* JPEG AC Huffman table register */
-#define S5P_JPG_HACTBL(n) (0x880 + (n) * 0x400)
-
-/* JPEG AC Huffman table register */
-#define S5P_JPG_HACTBLG(n) (0x8c0 + (n) * 0x400)
-
-#endif /* JPEG_REGS_H_ */
-
--
1.7.9.5
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [RFC PATCH 2/3] [media] s5p-jpeg: Add DT support to JPEG driver
2013-05-14 11:53 [RFC PATCH 0/3] [media] s5p-jpeg: Add support for Exynos4x12 and 5250 George Joseph
2013-05-14 11:53 ` [RFC PATCH 1/3] " George Joseph
@ 2013-05-14 11:53 ` George Joseph
2013-05-15 22:32 ` Sylwester Nawrocki
2013-05-14 11:53 ` [RFC PATCH 3/3] ARM: dts: Add documentation for Samsung JPEG driver bindings George Joseph
2013-06-29 19:12 ` [RFC PATCH 0/3] [media] s5p-jpeg: Add support for Exynos4x12 and 5250 Sylwester Nawrocki
3 siblings, 1 reply; 7+ messages in thread
From: George Joseph @ 2013-05-14 11:53 UTC (permalink / raw)
To: linux-media, linux-samsung-soc; +Cc: s.nawrocki, a.hajda, ym.song
From: George Joseph Palathingal <george.jp@samsung.com>
Adding DT support to the driver. Driver supports Exynos 4210, 4412 and 5250.
Signed-off-by: George Joseph Palathingal <george.jp@samsung.com>
Cc: devicetree-discuss@lists.ozlabs.org
---
drivers/media/platform/s5p-jpeg/jpeg-core.c | 36 +++++++++++++++++++++++++--
1 file changed, 34 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index f964566..b2bf412 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -970,6 +970,8 @@ const struct jpeg_vb2 jpeg_vb2_dma = {
.plane_addr = vb2_dma_contig_plane_dma_addr,
};
+static void *jpeg_get_drv_data(struct platform_device *pdev);
+
static int jpeg_probe(struct platform_device *pdev)
{
struct jpeg_dev *dev;
@@ -982,8 +984,7 @@ static int jpeg_probe(struct platform_device *pdev)
return -ENOMEM;
dev->plat_dev = pdev;
- dev->variant = (struct s5p_jpeg_variant *)
- platform_get_device_id(pdev)->driver_data;
+ dev->variant = (struct s5p_jpeg_variant *)jpeg_get_drv_data(pdev);
spin_lock_init(&dev->slock);
/* setup jpeg control */
@@ -1232,6 +1233,36 @@ static struct platform_device_id jpeg_driver_ids[] = {
MODULE_DEVICE_TABLE(platform, jpeg_driver_ids);
+static const struct of_device_id exynos_jpeg_match[] = {
+ {
+ .compatible = "samsung,s5pv210-jpeg",
+ .data = &jpeg_drvdata_v1,
+ }, {
+ .compatible = "samsung,exynos4212-jpeg",
+ .data = &jpeg_drvdata_v2,
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, exynos_jpeg_match);
+
+static void *jpeg_get_drv_data(struct platform_device *pdev)
+{
+ struct s5p_jpeg_variant *driver_data = NULL;
+
+ if (pdev->dev.of_node) {
+ const struct of_device_id *match;
+ match = of_match_node(of_match_ptr(exynos_jpeg_match),
+ pdev->dev.of_node);
+ if (match)
+ driver_data = (struct s5p_jpeg_variant *)match->data;
+ } else {
+ driver_data = (struct s5p_jpeg_variant *)
+ platform_get_device_id(pdev)->driver_data;
+ }
+ return driver_data;
+}
+
static struct platform_driver jpeg_driver = {
.probe = jpeg_probe,
.remove = jpeg_remove,
@@ -1241,6 +1272,7 @@ static struct platform_driver jpeg_driver = {
.driver = {
.owner = THIS_MODULE,
.name = JPEG_NAME,
+ .of_match_table = exynos_jpeg_match,
.pm = NULL,
},
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [RFC PATCH 3/3] ARM: dts: Add documentation for Samsung JPEG driver bindings
2013-05-14 11:53 [RFC PATCH 0/3] [media] s5p-jpeg: Add support for Exynos4x12 and 5250 George Joseph
2013-05-14 11:53 ` [RFC PATCH 1/3] " George Joseph
2013-05-14 11:53 ` [RFC PATCH 2/3] [media] s5p-jpeg: Add DT support to JPEG driver George Joseph
@ 2013-05-14 11:53 ` George Joseph
2013-06-29 19:12 ` [RFC PATCH 0/3] [media] s5p-jpeg: Add support for Exynos4x12 and 5250 Sylwester Nawrocki
3 siblings, 0 replies; 7+ messages in thread
From: George Joseph @ 2013-05-14 11:53 UTC (permalink / raw)
To: linux-media, linux-samsung-soc; +Cc: s.nawrocki, a.hajda, ym.song
From: Sylwester Nawrocki <s.nawrocki@samsung.com>
Added documentation for Samsung JPEG driver DT bindings.
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: George Joseph Palathingal <george.jp@samsung.com>
Cc: devicetree-discuss@lists.ozlabs.org
---
.../devicetree/bindings/media/samsung-s5p-jpeg.txt | 21 ++++++++++++++++++++
1 file changed, 21 insertions(+)
create mode 100644 Documentation/devicetree/bindings/media/samsung-s5p-jpeg.txt
diff --git a/Documentation/devicetree/bindings/media/samsung-s5p-jpeg.txt b/Documentation/devicetree/bindings/media/samsung-s5p-jpeg.txt
new file mode 100644
index 0000000..e44c4da
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/samsung-s5p-jpeg.txt
@@ -0,0 +1,21 @@
+Samsung S5P/EXYNOS SoC series JPEG codec
+
+Required properties:
+
+- compatible : "samsung,<soc_name>-jpeg", must be one of:
+ "samsung,s5pv210-jpeg", "samsung,exynos4212-jpeg";
+- reg : address and length of the JPEG codec register set;
+- interrupts : should contain the JPEG codec interrupt; format of the
+ interrupt specifier depends on the interrupt controller;
+- clocks : jpeg clock specifier, as covered by common clock bindings.
+- clock-names : must contain "jpeg" entry.
+
+Example:
+
+jpeg@11840000 {
+ compatible = "samsung,s5pv210-jpeg";
+ reg = <0x11840000 0x3FF>;
+ interrupts = <0 88 0>;
+ clocks = <&clock 262>;
+ clock-names = "jpeg";
+};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [RFC PATCH 1/3] [media] s5p-jpeg: Add support for Exynos4x12 and 5250
2013-05-14 11:53 ` [RFC PATCH 1/3] " George Joseph
@ 2013-05-15 22:27 ` Sylwester Nawrocki
0 siblings, 0 replies; 7+ messages in thread
From: Sylwester Nawrocki @ 2013-05-15 22:27 UTC (permalink / raw)
To: George Joseph
Cc: linux-media, linux-samsung-soc, s.nawrocki, a.hajda, ym.song,
Andrzej Pietrasiewicz
Hi George,
Thanks for the patches. Sorry, I can't review the $subject patch in detail
as is, there is way too many things done in this single patch. It looks more
like a driver replacement. It is even hard to edit due to its size in my
e-mail client.
Hence, may I ask you to split it into several patches, each possibly
including
single logical change, with an explanation what the patch does and why,
e.g.:
- encoder/decoder code split into different files (I'm not 100% sure
it is
needed),
- multiplanar format support addition,
- software watchdog addition,
- the quantization/Huffman tables modification,
- device tree support addition,
- ...
The reason I'm asking for it is also there seems to be some unrelated
or unnecessary changes, like, e.g. introducing several JPEG fourccs for
different YCbCr subsampling or adding unused v4l2 control ioctls (
jpeg_enc_vidioc_g/s_ctrl, jpeg_enc_vidioc_g/s_ctrl).
It should be also be easier to test and bisect set of smaller changes when
needed. I know it means more work for you, but maybe the exynos4210
regression described in your cover letter could be avoided that way.
A general note, please don't remove "s5p_" prefix from functions that are
not static. "jpeg_" sounds a bit to generic prefix for symbols in this
single driver.
Also please make sure indentation is not broken, it looks like you are
using TAB size different than 8 characters.
It might be worth testing the driver as a loadable module, it doesn't
appear it has been tested, looking at the Makefile modifications. And
it doesn't even build currently:
drivers/media/platform/s5p-jpeg/jpeg-core: struct platform_device_id is
24 bytes. The last of 3 is:
0x65 0x78 0x79 0x6e 0x6f 0x73 0x34 0x32 0x31 0x32 0x2d 0x6a 0x70 0x65
0x67 0x00 0x00 0x00 0x00 0x00 0x44 0x01 0x00 0x00
FATAL: drivers/media/platform/s5p-jpeg/jpeg-core: struct
platform_device_id is not terminated with a NULL entry!
make[1]: *** [__modpost] Error 1
When I fix that there are errors due to your incorrect Makefile changes
(separate module for each file ??):
ERROR: "jpeg_get_frame_size"
[drivers/media/platform/s5p-jpeg/jpeg-dec.ko] undefined!
ERROR: "jpeg_set_dec_bitstream_size"
[drivers/media/platform/s5p-jpeg/jpeg-core.ko] undefined!
ERROR: "jpeg_set_dec_out_fmt"
[drivers/media/platform/s5p-jpeg/jpeg-core.ko] undefined!
ERROR: "jpeg_set_dec_scaling"
[drivers/media/platform/s5p-jpeg/jpeg-core.ko] undefined!
ERROR: "jpeg_set_frame_buf_address"
[drivers/media/platform/s5p-jpeg/jpeg-core.ko] undefined!
ERROR: "jpeg_set_enc_dec_mode"
[drivers/media/platform/s5p-jpeg/jpeg-core.ko] undefined!
ERROR: "jpeg_set_encode_hoff_cnt"
[drivers/media/platform/s5p-jpeg/jpeg-core.ko] undefined!
ERROR: "jpeg_set_stream_buf_address"
[drivers/media/platform/s5p-jpeg/jpeg-core.ko] undefined!
ERROR: "jpeg_set_enc_in_fmt"
[drivers/media/platform/s5p-jpeg/jpeg-core.ko] undefined!
ERROR: "jpeg_set_enc_out_fmt"
[drivers/media/platform/s5p-jpeg/jpeg-core.ko] undefined!
ERROR: "jpeg_set_stream_size"
[drivers/media/platform/s5p-jpeg/jpeg-core.ko] undefined!
ERROR: "jpeg_set_encode_tbl_select"
[drivers/media/platform/s5p-jpeg/jpeg-core.ko] undefined!
ERROR: "jpeg_set_enc_tbl" [drivers/media/platform/s5p-jpeg/jpeg-core.ko]
undefined!
ERROR: "jpeg_set_huf_table_enable"
[drivers/media/platform/s5p-jpeg/jpeg-core.ko] undefined!
ERROR: "jpeg_set_interrupt"
[drivers/media/platform/s5p-jpeg/jpeg-core.ko] undefined!
ERROR: "jpeg_sw_reset" [drivers/media/platform/s5p-jpeg/jpeg-core.ko]
undefined!
ERROR: "jpeg_get_stream_size"
[drivers/media/platform/s5p-jpeg/jpeg-core.ko] undefined!
ERROR: "jpeg_get_int_status"
[drivers/media/platform/s5p-jpeg/jpeg-core.ko] undefined!
ERROR: "get_jpeg_dec_v4l2_ioctl_ops"
[drivers/media/platform/s5p-jpeg/jpeg-core.ko] undefined!
ERROR: "get_jpeg_enc_v4l2_ioctl_ops"
[drivers/media/platform/s5p-jpeg/jpeg-core.ko] undefined!
make[1]: *** [__modpost] Error 1
make: *** [modules] Error 2
Could you please add Andrzej Pietrasiewicz to Cc next time ? He might be
busy with other things, nevertheless I wouldn't like to miss any comments/
remarks from his side.
Thanks,
Sylwester
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [RFC PATCH 2/3] [media] s5p-jpeg: Add DT support to JPEG driver
2013-05-14 11:53 ` [RFC PATCH 2/3] [media] s5p-jpeg: Add DT support to JPEG driver George Joseph
@ 2013-05-15 22:32 ` Sylwester Nawrocki
0 siblings, 0 replies; 7+ messages in thread
From: Sylwester Nawrocki @ 2013-05-15 22:32 UTC (permalink / raw)
To: George Joseph
Cc: linux-media, linux-samsung-soc, s.nawrocki, a.hajda, ym.song,
Andrzej Pietrasiewicz
On 05/14/2013 01:53 PM, George Joseph wrote:
> From: George Joseph Palathingal<george.jp@samsung.com>
>
> Adding DT support to the driver. Driver supports Exynos 4210, 4412 and 5250.
>
> Signed-off-by: George Joseph Palathingal<george.jp@samsung.com>
> Cc: devicetree-discuss@lists.ozlabs.org
> ---
> drivers/media/platform/s5p-jpeg/jpeg-core.c | 36 +++++++++++++++++++++++++--
> 1 file changed, 34 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
> index f964566..b2bf412 100644
> --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
> +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
> @@ -970,6 +970,8 @@ const struct jpeg_vb2 jpeg_vb2_dma = {
> .plane_addr = vb2_dma_contig_plane_dma_addr,
> };
>
> +static void *jpeg_get_drv_data(struct platform_device *pdev);
How about putting definition of the jpeg_get_drv_data() function and
the exynos_jpeg_match array above jpeg_probe() to avoid this forward
declaration ?
> static int jpeg_probe(struct platform_device *pdev)
> {
> struct jpeg_dev *dev;
> @@ -982,8 +984,7 @@ static int jpeg_probe(struct platform_device *pdev)
> return -ENOMEM;
>
> dev->plat_dev = pdev;
> - dev->variant = (struct s5p_jpeg_variant *)
> - platform_get_device_id(pdev)->driver_data;
> + dev->variant = (struct s5p_jpeg_variant *)jpeg_get_drv_data(pdev);
Casting is not needed here.
> spin_lock_init(&dev->slock);
>
> /* setup jpeg control */
> @@ -1232,6 +1233,36 @@ static struct platform_device_id jpeg_driver_ids[] = {
>
> MODULE_DEVICE_TABLE(platform, jpeg_driver_ids);
>
> +static const struct of_device_id exynos_jpeg_match[] = {
> + {
> + .compatible = "samsung,s5pv210-jpeg",
> + .data =&jpeg_drvdata_v1,
> + }, {
> + .compatible = "samsung,exynos4212-jpeg",
> + .data =&jpeg_drvdata_v2,
> + },
> + {},
> +};
> +
> +MODULE_DEVICE_TABLE(of, exynos_jpeg_match);
> +
> +static void *jpeg_get_drv_data(struct platform_device *pdev)
> +{
> + struct s5p_jpeg_variant *driver_data = NULL;
Unnecessary NULL assignment.
> + if (pdev->dev.of_node) {
> + const struct of_device_id *match;
> + match = of_match_node(of_match_ptr(exynos_jpeg_match),
> + pdev->dev.of_node);
> + if (match)
> + driver_data = (struct s5p_jpeg_variant *)match->data;
> + } else {
Indentation is wrong here.
> + driver_data = (struct s5p_jpeg_variant *)
> + platform_get_device_id(pdev)->driver_data;
> + }
> + return driver_data;
> +}
How about rewriting this function to something like:
static const void *jpeg_get_drv_data(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
const struct of_device_id *match;
if (node) {
match = of_match_node(exynos_jpeg_match, node);
return match ? match->data : NULL;
}
return (void *)platform_get_device_id(pdev)->driver_data;
}
?
> static struct platform_driver jpeg_driver = {
> .probe = jpeg_probe,
> .remove = jpeg_remove,
> @@ -1241,6 +1272,7 @@ static struct platform_driver jpeg_driver = {
> .driver = {
> .owner = THIS_MODULE,
> .name = JPEG_NAME,
> + .of_match_table = exynos_jpeg_match,
> .pm = NULL,
> },
> };
Thanks,
Sylwester
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [RFC PATCH 0/3] [media] s5p-jpeg: Add support for Exynos4x12 and 5250
2013-05-14 11:53 [RFC PATCH 0/3] [media] s5p-jpeg: Add support for Exynos4x12 and 5250 George Joseph
` (2 preceding siblings ...)
2013-05-14 11:53 ` [RFC PATCH 3/3] ARM: dts: Add documentation for Samsung JPEG driver bindings George Joseph
@ 2013-06-29 19:12 ` Sylwester Nawrocki
3 siblings, 0 replies; 7+ messages in thread
From: Sylwester Nawrocki @ 2013-06-29 19:12 UTC (permalink / raw)
To: George Joseph, Sachin Kamat
Cc: linux-media, linux-samsung-soc, s.nawrocki, a.hajda, ym.song
On 05/14/2013 01:53 PM, George Joseph wrote:
> From: George Joseph Palathingal<george.jp@samsung.com>
>
> This patch series refactors the JPEG driver to add code to support Exynos4x12
> and Exynos5250 JPEG IPs and makes the driver DT and CCF compliant.
>
> Exynos4210 JPEG driver supports only single planar image formats.
> The JPEG IP on Exynos4412 and 5250 supports multiplanar image formats as well.
> So the existing JPEG driver is refactored to support the JPEG h/w on all
> the three SoCs. The encoder/decoder functionalities are separated to
> two different files for better modularity.
>
> The encoder/decoder functionalities have been tested on Origen 4210, 4412 and SMDK 5250
> boards. There is currently an issue with the Exynos 4210 JPEG encoder which will be
> fixed in subsequent patches.
>
> The patch series is based on linux-next tree (20130514).
Hi,
Are you still working on it ? Are you planning to address my review
comments or are these works now abandoned ? I refrained from merging
my patch [1] that would at least allow to use the JPEG codec on
exynos4210 SoCs in mainline v3.11, as you guys indicated that you
were working on full support for the exynos4x12 and exynos5250 SoCs.
Now it's about v3.11 merge window and we are left with nothing. I'm
not happy. Please let me know if you're going to carry on with that
effort, if not someone from our team will complete that.
You seem to have already done most of the hard work, and I'm really
surprised it hasn't been completed, there was plenty time...
[1] https://patchwork.linuxtv.org/patch/18345/
Thanks,
Sylwester
> George Joseph Palathingal (2):
> [media] s5p-jpeg: Add support for Exynos4x12 and 5250
> [media] s5p-jpeg: Add DT support to JPEG driver
>
> Sylwester Nawrocki (1):
> ARM: dts: Add documentation for Samsung JPEG driver bindings
>
> .../devicetree/bindings/media/samsung-s5p-jpeg.txt | 21 +
> drivers/media/platform/s5p-jpeg/Makefile | 4 +-
> drivers/media/platform/s5p-jpeg/jpeg-core.c | 2041 +++++++++-----------
> drivers/media/platform/s5p-jpeg/jpeg-core.h | 428 ++--
> drivers/media/platform/s5p-jpeg/jpeg-dec.c | 489 +++++
> drivers/media/platform/s5p-jpeg/jpeg-enc.c | 521 +++++
> drivers/media/platform/s5p-jpeg/jpeg-hw-v1.h | 528 +++++
> drivers/media/platform/s5p-jpeg/jpeg-hw-v2.c | 614 ++++++
> drivers/media/platform/s5p-jpeg/jpeg-hw-v2.h | 47 +
> drivers/media/platform/s5p-jpeg/jpeg-hw.h | 357 ----
> drivers/media/platform/s5p-jpeg/jpeg-regs-v1.h | 171 ++
> drivers/media/platform/s5p-jpeg/jpeg-regs-v2.h | 191 ++
> drivers/media/platform/s5p-jpeg/jpeg-regs.h | 170 --
> 13 files changed, 3787 insertions(+), 1795 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/media/samsung-s5p-jpeg.txt
> create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-dec.c
> create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-enc.c
> create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-hw-v1.h
> create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-hw-v2.c
> create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-hw-v2.h
> delete mode 100644 drivers/media/platform/s5p-jpeg/jpeg-hw.h
> create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-regs-v1.h
> create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-regs-v2.h
> delete mode 100644 drivers/media/platform/s5p-jpeg/jpeg-regs.h
>
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2013-06-29 19:12 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-05-14 11:53 [RFC PATCH 0/3] [media] s5p-jpeg: Add support for Exynos4x12 and 5250 George Joseph
2013-05-14 11:53 ` [RFC PATCH 1/3] " George Joseph
2013-05-15 22:27 ` Sylwester Nawrocki
2013-05-14 11:53 ` [RFC PATCH 2/3] [media] s5p-jpeg: Add DT support to JPEG driver George Joseph
2013-05-15 22:32 ` Sylwester Nawrocki
2013-05-14 11:53 ` [RFC PATCH 3/3] ARM: dts: Add documentation for Samsung JPEG driver bindings George Joseph
2013-06-29 19:12 ` [RFC PATCH 0/3] [media] s5p-jpeg: Add support for Exynos4x12 and 5250 Sylwester Nawrocki
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).