aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/s5p-jpeg
diff options
context:
space:
mode:
authorAndrzej Pietrasiewicz <andrzej.p@samsung.com>2011-11-24 09:15:23 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-01-10 20:21:52 -0500
commitbb677f3ac434cb1708938f1e76a41d9098affd05 (patch)
tree334408194135fed6b8ab7599f2dcbd46e8fb4a2f /drivers/media/video/s5p-jpeg
parentaa73ab96bebb6fb9e0ee4429f78bfa3ef8c5b6b6 (diff)
[media] Exynos4 JPEG codec v4l2 driver
Add driver for the JPEG codec IP block available in Samsung Exynos SoC series. The driver is implemented as a V4L2 mem-to-mem device. It exposes two video nodes to user space, one for the encoding part, and one for the decoding part. Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Reviewed-by: Sakari Ailus <sakari.ailus@iki.fi> Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Reviewed-by: Tomasz Stanislawski <t.stanislaws@samsung.com> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/s5p-jpeg')
-rw-r--r--drivers/media/video/s5p-jpeg/Makefile2
-rw-r--r--drivers/media/video/s5p-jpeg/jpeg-core.c1481
-rw-r--r--drivers/media/video/s5p-jpeg/jpeg-core.h143
-rw-r--r--drivers/media/video/s5p-jpeg/jpeg-hw.h353
-rw-r--r--drivers/media/video/s5p-jpeg/jpeg-regs.h170
5 files changed, 2149 insertions, 0 deletions
diff --git a/drivers/media/video/s5p-jpeg/Makefile b/drivers/media/video/s5p-jpeg/Makefile
new file mode 100644
index 000000000000..ddc2900d88a2
--- /dev/null
+++ b/drivers/media/video/s5p-jpeg/Makefile
@@ -0,0 +1,2 @@
1s5p-jpeg-objs := jpeg-core.o
2obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) := s5p-jpeg.o
diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.c b/drivers/media/video/s5p-jpeg/jpeg-core.c
new file mode 100644
index 000000000000..f841a3e9845c
--- /dev/null
+++ b/drivers/media/video/s5p-jpeg/jpeg-core.c
@@ -0,0 +1,1481 @@
1/* linux/drivers/media/video/s5p-jpeg/jpeg-core.c
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/clk.h>
14#include <linux/err.h>
15#include <linux/gfp.h>
16#include <linux/interrupt.h>
17#include <linux/io.h>
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/platform_device.h>
21#include <linux/pm_runtime.h>
22#include <linux/slab.h>
23#include <linux/spinlock.h>
24#include <linux/string.h>
25#include <media/v4l2-mem2mem.h>
26#include <media/v4l2-ioctl.h>
27#include <media/videobuf2-core.h>
28#include <media/videobuf2-dma-contig.h>
29
30#include "jpeg-core.h"
31#include "jpeg-hw.h"
32
33static struct s5p_jpeg_fmt formats_enc[] = {
34 {
35 .name = "YUV 4:2:0 planar, YCbCr",
36 .fourcc = V4L2_PIX_FMT_YUV420,
37 .depth = 12,
38 .colplanes = 3,
39 .types = MEM2MEM_CAPTURE,
40 },
41 {
42 .name = "YUV 4:2:2 packed, YCbYCr",
43 .fourcc = V4L2_PIX_FMT_YUYV,
44 .depth = 16,
45 .colplanes = 1,
46 .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
47 },
48 {
49 .name = "RGB565",
50 .fourcc = V4L2_PIX_FMT_RGB565,
51 .depth = 16,
52 .colplanes = 1,
53 .types = MEM2MEM_OUTPUT,
54 },
55};
56#define NUM_FORMATS_ENC ARRAY_SIZE(formats_enc)
57
58static struct s5p_jpeg_fmt formats_dec[] = {
59 {
60 .name = "YUV 4:2:0 planar, YCbCr",
61 .fourcc = V4L2_PIX_FMT_YUV420,
62 .depth = 12,
63 .colplanes = 3,
64 .h_align = 4,
65 .v_align = 4,
66 .types = MEM2MEM_CAPTURE,
67 },
68 {
69 .name = "YUV 4:2:2 packed, YCbYCr",
70 .fourcc = V4L2_PIX_FMT_YUYV,
71 .depth = 16,
72 .colplanes = 1,
73 .h_align = 4,
74 .v_align = 3,
75 .types = MEM2MEM_CAPTURE,
76 },
77 {
78 .name = "JPEG JFIF",
79 .fourcc = V4L2_PIX_FMT_JPEG,
80 .colplanes = 1,
81 .types = MEM2MEM_OUTPUT,
82 },
83};
84#define NUM_FORMATS_DEC ARRAY_SIZE(formats_dec)
85
86static const unsigned char qtbl_luminance[4][64] = {
87 {/* level 1 - high quality */
88 8, 6, 6, 8, 12, 14, 16, 17,
89 6, 6, 6, 8, 10, 13, 12, 15,
90 6, 6, 7, 8, 13, 14, 18, 24,
91 8, 8, 8, 14, 13, 19, 24, 35,
92 12, 10, 13, 13, 20, 26, 34, 39,
93 14, 13, 14, 19, 26, 34, 39, 39,
94 16, 12, 18, 24, 34, 39, 39, 39,
95 17, 15, 24, 35, 39, 39, 39, 39
96 },
97 {/* level 2 */
98 12, 8, 8, 12, 17, 21, 24, 23,
99 8, 9, 9, 11, 15, 19, 18, 23,
100 8, 9, 10, 12, 19, 20, 27, 36,
101 12, 11, 12, 21, 20, 28, 36, 53,
102 17, 15, 19, 20, 30, 39, 51, 59,
103 21, 19, 20, 28, 39, 51, 59, 59,
104 24, 18, 27, 36, 51, 59, 59, 59,
105 23, 23, 36, 53, 59, 59, 59, 59
106 },
107 {/* level 3 */
108 16, 11, 11, 16, 23, 27, 31, 30,
109 11, 12, 12, 15, 20, 23, 23, 30,
110 11, 12, 13, 16, 23, 26, 35, 47,
111 16, 15, 16, 23, 26, 37, 47, 64,
112 23, 20, 23, 26, 39, 51, 64, 64,
113 27, 23, 26, 37, 51, 64, 64, 64,
114 31, 23, 35, 47, 64, 64, 64, 64,
115 30, 30, 47, 64, 64, 64, 64, 64
116 },
117 {/*level 4 - low quality */
118 20, 16, 25, 39, 50, 46, 62, 68,
119 16, 18, 23, 38, 38, 53, 65, 68,
120 25, 23, 31, 38, 53, 65, 68, 68,
121 39, 38, 38, 53, 65, 68, 68, 68,
122 50, 38, 53, 65, 68, 68, 68, 68,
123 46, 53, 65, 68, 68, 68, 68, 68,
124 62, 65, 68, 68, 68, 68, 68, 68,
125 68, 68, 68, 68, 68, 68, 68, 68
126 }
127};
128
129static const unsigned char qtbl_chrominance[4][64] = {
130 {/* level 1 - high quality */
131 9, 8, 9, 11, 14, 17, 19, 24,
132 8, 10, 9, 11, 14, 13, 17, 22,
133 9, 9, 13, 14, 13, 15, 23, 26,
134 11, 11, 14, 14, 15, 20, 26, 33,
135 14, 14, 13, 15, 20, 24, 33, 39,
136 17, 13, 15, 20, 24, 32, 39, 39,
137 19, 17, 23, 26, 33, 39, 39, 39,
138 24, 22, 26, 33, 39, 39, 39, 39
139 },
140 {/* level 2 */
141 13, 11, 13, 16, 20, 20, 29, 37,
142 11, 14, 14, 14, 16, 20, 26, 32,
143 13, 14, 15, 17, 20, 23, 35, 40,
144 16, 14, 17, 21, 23, 30, 40, 50,
145 20, 16, 20, 23, 30, 37, 50, 59,
146 20, 20, 23, 30, 37, 48, 59, 59,
147 29, 26, 35, 40, 50, 59, 59, 59,
148 37, 32, 40, 50, 59, 59, 59, 59
149 },
150 {/* level 3 */
151 17, 15, 17, 21, 20, 26, 38, 48,
152 15, 19, 18, 17, 20, 26, 35, 43,
153 17, 18, 20, 22, 26, 30, 46, 53,
154 21, 17, 22, 28, 30, 39, 53, 64,
155 20, 20, 26, 30, 39, 48, 64, 64,
156 26, 26, 30, 39, 48, 63, 64, 64,
157 38, 35, 46, 53, 64, 64, 64, 64,
158 48, 43, 53, 64, 64, 64, 64, 64
159 },
160 {/*level 4 - low quality */
161 21, 25, 32, 38, 54, 68, 68, 68,
162 25, 28, 24, 38, 54, 68, 68, 68,
163 32, 24, 32, 43, 66, 68, 68, 68,
164 38, 38, 43, 53, 68, 68, 68, 68,
165 54, 54, 66, 68, 68, 68, 68, 68,
166 68, 68, 68, 68, 68, 68, 68, 68,
167 68, 68, 68, 68, 68, 68, 68, 68,
168 68, 68, 68, 68, 68, 68, 68, 68
169 }
170};
171
172static const unsigned char hdctbl0[16] = {
173 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
174};
175
176static const unsigned char hdctblg0[12] = {
177 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb
178};
179static const unsigned char hactbl0[16] = {
180 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
181};
182static const unsigned char hactblg0[162] = {
183 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
184 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
185 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
186 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
187 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
188 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
189 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
190 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
191 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
192 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
193 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
194 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
195 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
196 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
197 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
198 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
199 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
200 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
201 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
202 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
203 0xf9, 0xfa
204};
205
206static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl,
207 unsigned long tab, int len)
208{
209 int i;
210
211 for (i = 0; i < len; i++)
212 writel((unsigned int)qtbl[i], regs + tab + (i * 0x04));
213}
214
215static inline void jpeg_set_qtbl_lum(void __iomem *regs, int quality)
216{
217 /* this driver fills quantisation table 0 with data for luma */
218 jpeg_set_qtbl(regs, qtbl_luminance[quality], S5P_JPG_QTBL_CONTENT(0),
219 ARRAY_SIZE(qtbl_luminance[quality]));
220}
221
222static inline void jpeg_set_qtbl_chr(void __iomem *regs, int quality)
223{
224 /* this driver fills quantisation table 1 with data for chroma */
225 jpeg_set_qtbl(regs, qtbl_chrominance[quality], S5P_JPG_QTBL_CONTENT(1),
226 ARRAY_SIZE(qtbl_chrominance[quality]));
227}
228
229static inline void jpeg_set_htbl(void __iomem *regs, const unsigned char *htbl,
230 unsigned long tab, int len)
231{
232 int i;
233
234 for (i = 0; i < len; i++)
235 writel((unsigned int)htbl[i], regs + tab + (i * 0x04));
236}
237
238static inline void jpeg_set_hdctbl(void __iomem *regs)
239{
240 /* this driver fills table 0 for this component */
241 jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0), ARRAY_SIZE(hdctbl0));
242}
243
244static inline void jpeg_set_hdctblg(void __iomem *regs)
245{
246 /* this driver fills table 0 for this component */
247 jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0), ARRAY_SIZE(hdctblg0));
248}
249
250static inline void jpeg_set_hactbl(void __iomem *regs)
251{
252 /* this driver fills table 0 for this component */
253 jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0), ARRAY_SIZE(hactbl0));
254}
255
256static inline void jpeg_set_hactblg(void __iomem *regs)
257{
258 /* this driver fills table 0 for this component */
259 jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0), ARRAY_SIZE(hactblg0));
260}
261
262/*
263 * ============================================================================
264 * Device file operations
265 * ============================================================================
266 */
267
268static int queue_init(void *priv, struct vb2_queue *src_vq,
269 struct vb2_queue *dst_vq);
270static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode,
271 __u32 pixelformat);
272
273static int s5p_jpeg_open(struct file *file)
274{
275 struct s5p_jpeg *jpeg = video_drvdata(file);
276 struct video_device *vfd = video_devdata(file);
277 struct s5p_jpeg_ctx *ctx;
278 struct s5p_jpeg_fmt *out_fmt;
279
280 ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
281 if (!ctx)
282 return -ENOMEM;
283
284 file->private_data = ctx;
285 ctx->jpeg = jpeg;
286 if (vfd == jpeg->vfd_encoder) {
287 ctx->mode = S5P_JPEG_ENCODE;
288 out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_RGB565);
289 } else {
290 ctx->mode = S5P_JPEG_DECODE;
291 out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_JPEG);
292 }
293
294 ctx->m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
295 if (IS_ERR(ctx->m2m_ctx)) {
296 int err = PTR_ERR(ctx->m2m_ctx);
297 kfree(ctx);
298 return err;
299 }
300
301 ctx->out_q.fmt = out_fmt;
302 ctx->cap_q.fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_YUYV);
303
304 return 0;
305}
306
307static int s5p_jpeg_release(struct file *file)
308{
309 struct s5p_jpeg_ctx *ctx = file->private_data;
310
311 v4l2_m2m_ctx_release(ctx->m2m_ctx);
312 kfree(ctx);
313
314 return 0;
315}
316
317static unsigned int s5p_jpeg_poll(struct file *file,
318 struct poll_table_struct *wait)
319{
320 struct s5p_jpeg_ctx *ctx = file->private_data;
321
322 return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
323}
324
325static int s5p_jpeg_mmap(struct file *file, struct vm_area_struct *vma)
326{
327 struct s5p_jpeg_ctx *ctx = file->private_data;
328
329 return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
330}
331
332static const struct v4l2_file_operations s5p_jpeg_fops = {
333 .owner = THIS_MODULE,
334 .open = s5p_jpeg_open,
335 .release = s5p_jpeg_release,
336 .poll = s5p_jpeg_poll,
337 .unlocked_ioctl = video_ioctl2,
338 .mmap = s5p_jpeg_mmap,
339};
340
341/*
342 * ============================================================================
343 * video ioctl operations
344 * ============================================================================
345 */
346
347static int get_byte(struct s5p_jpeg_buffer *buf)
348{
349 if (buf->curr >= buf->size)
350 return -1;
351
352 return ((unsigned char *)buf->data)[buf->curr++];
353}
354
355static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word)
356{
357 unsigned int temp;
358 int byte;
359
360 byte = get_byte(buf);
361 if (byte == -1)
362 return -1;
363 temp = byte << 8;
364 byte = get_byte(buf);
365 if (byte == -1)
366 return -1;
367 *word = (unsigned int)byte | temp;
368 return 0;
369}
370
371static void skip(struct s5p_jpeg_buffer *buf, long len)
372{
373 if (len <= 0)
374 return;
375
376 while (len--)
377 get_byte(buf);
378}
379
380static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
381 unsigned long buffer, unsigned long size)
382{
383 int c, components, notfound;
384 unsigned int height, width, word;
385 long length;
386 struct s5p_jpeg_buffer jpeg_buffer;
387
388 jpeg_buffer.size = size;
389 jpeg_buffer.data = buffer;
390 jpeg_buffer.curr = 0;
391
392 notfound = 1;
393 while (notfound) {
394 c = get_byte(&jpeg_buffer);
395 if (c == -1)
396 break;
397 if (c != 0xff)
398 continue;
399 do
400 c = get_byte(&jpeg_buffer);
401 while (c == 0xff);
402 if (c == -1)
403 break;
404 if (c == 0)
405 continue;
406 length = 0;
407 switch (c) {
408 /* SOF0: baseline JPEG */
409 case SOF0:
410 if (get_word_be(&jpeg_buffer, &word))
411 break;
412 if (get_byte(&jpeg_buffer) == -1)
413 break;
414 if (get_word_be(&jpeg_buffer, &height))
415 break;
416 if (get_word_be(&jpeg_buffer, &width))
417 break;
418 components = get_byte(&jpeg_buffer);
419 if (components == -1)
420 break;
421 notfound = 0;
422
423 skip(&jpeg_buffer, components * 3);
424 break;
425
426 /* skip payload-less markers */
427 case RST ... RST + 7:
428 case SOI:
429 case EOI:
430 case TEM:
431 break;
432
433 /* skip uninteresting payload markers */
434 default:
435 if (get_word_be(&jpeg_buffer, &word))
436 break;
437 length = (long)word - 2;
438 skip(&jpeg_buffer, length);
439 break;
440 }
441 }
442 result->w = width;
443 result->h = height;
444 result->size = components;
445 return !notfound;
446}
447
448static int s5p_jpeg_querycap(struct file *file, void *priv,
449 struct v4l2_capability *cap)
450{
451 struct s5p_jpeg_ctx *ctx = priv;
452
453 if (ctx->mode == S5P_JPEG_ENCODE) {
454 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder",
455 sizeof(cap->driver));
456 strlcpy(cap->card, S5P_JPEG_M2M_NAME " encoder",
457 sizeof(cap->card));
458 } else {
459 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " decoder",
460 sizeof(cap->driver));
461 strlcpy(cap->card, S5P_JPEG_M2M_NAME " decoder",
462 sizeof(cap->card));
463 }
464 cap->bus_info[0] = 0;
465 cap->capabilities = V4L2_CAP_STREAMING |
466 V4L2_CAP_VIDEO_CAPTURE |
467 V4L2_CAP_VIDEO_OUTPUT;
468 return 0;
469}
470
471static int enum_fmt(struct s5p_jpeg_fmt *formats, int n,
472 struct v4l2_fmtdesc *f, u32 type)
473{
474 int i, num = 0;
475
476 for (i = 0; i < n; ++i) {
477 if (formats[i].types & type) {
478 /* index-th format of type type found ? */
479 if (num == f->index)
480 break;
481 /* Correct type but haven't reached our index yet,
482 * just increment per-type index */
483 ++num;
484 }
485 }
486
487 /* Format not found */
488 if (i >= n)
489 return -EINVAL;
490
491 strlcpy(f->description, formats[i].name, sizeof(f->description));
492 f->pixelformat = formats[i].fourcc;
493
494 return 0;
495}
496
497static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
498 struct v4l2_fmtdesc *f)
499{
500 struct s5p_jpeg_ctx *ctx;
501
502 ctx = priv;
503
504 if (ctx->mode == S5P_JPEG_ENCODE)
505 return enum_fmt(formats_enc, NUM_FORMATS_ENC, f,
506 MEM2MEM_CAPTURE);
507
508 return enum_fmt(formats_dec, NUM_FORMATS_DEC, f, MEM2MEM_CAPTURE);
509}
510
511static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
512 struct v4l2_fmtdesc *f)
513{
514 struct s5p_jpeg_ctx *ctx;
515
516 ctx = priv;
517
518 if (ctx->mode == S5P_JPEG_ENCODE)
519 return enum_fmt(formats_enc, NUM_FORMATS_ENC, f,
520 MEM2MEM_OUTPUT);
521
522 return enum_fmt(formats_dec, NUM_FORMATS_DEC, f, MEM2MEM_OUTPUT);
523}
524
525static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx,
526 enum v4l2_buf_type type)
527{
528 if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
529 return &ctx->out_q;
530 if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
531 return &ctx->cap_q;
532
533 return NULL;
534}
535
536static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
537{
538 struct vb2_queue *vq;
539 struct s5p_jpeg_q_data *q_data = NULL;
540 struct v4l2_pix_format *pix = &f->fmt.pix;
541 struct s5p_jpeg_ctx *ct = priv;
542
543 vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type);
544 if (!vq)
545 return -EINVAL;
546
547 if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
548 ct->mode == S5P_JPEG_DECODE && !ct->hdr_parsed)
549 return -EINVAL;
550 q_data = get_q_data(ct, f->type);
551 BUG_ON(q_data == NULL);
552
553 pix->width = q_data->w;
554 pix->height = q_data->h;
555 pix->field = V4L2_FIELD_NONE;
556 pix->pixelformat = q_data->fmt->fourcc;
557 pix->bytesperline = 0;
558 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
559 u32 bpl = q_data->w;
560 if (q_data->fmt->colplanes == 1)
561 bpl = (bpl * q_data->fmt->depth) >> 3;
562 pix->bytesperline = bpl;
563 }
564 pix->sizeimage = q_data->size;
565
566 return 0;
567}
568
569static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode,
570 u32 pixelformat)
571{
572 unsigned int k;
573 struct s5p_jpeg_fmt *formats;
574 int n;
575
576 if (mode == S5P_JPEG_ENCODE) {
577 formats = formats_enc;
578 n = NUM_FORMATS_ENC;
579 } else {
580 formats = formats_dec;
581 n = NUM_FORMATS_DEC;
582 }
583
584 for (k = 0; k < n; k++) {
585 struct s5p_jpeg_fmt *fmt = &formats[k];
586 if (fmt->fourcc == pixelformat)
587 return fmt;
588 }
589
590 return NULL;
591
592}
593
594static void jpeg_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
595 unsigned int walign,
596 u32 *h, unsigned int hmin, unsigned int hmax,
597 unsigned int halign)
598{
599 int width, height, w_step, h_step;
600
601 width = *w;
602 height = *h;
603
604 w_step = 1 << walign;
605 h_step = 1 << halign;
606 v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
607
608 if (*w < width && (*w + w_step) < wmax)
609 *w += w_step;
610 if (*h < height && (*h + h_step) < hmax)
611 *h += h_step;
612
613}
614
615static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
616 struct s5p_jpeg_ctx *ctx, int q_type)
617{
618 struct v4l2_pix_format *pix = &f->fmt.pix;
619
620 if (pix->field == V4L2_FIELD_ANY)
621 pix->field = V4L2_FIELD_NONE;
622 else if (pix->field != V4L2_FIELD_NONE)
623 return -EINVAL;
624
625 /* V4L2 specification suggests the driver corrects the format struct
626 * if any of the dimensions is unsupported */
627 if (q_type == MEM2MEM_OUTPUT)
628 jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
629 S5P_JPEG_MAX_WIDTH, 0,
630 &pix->height, S5P_JPEG_MIN_HEIGHT,
631 S5P_JPEG_MAX_HEIGHT, 0);
632 else
633 jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
634 S5P_JPEG_MAX_WIDTH, fmt->h_align,
635 &pix->height, S5P_JPEG_MIN_HEIGHT,
636 S5P_JPEG_MAX_HEIGHT, fmt->v_align);
637
638 if (fmt->fourcc == V4L2_PIX_FMT_JPEG) {
639 if (pix->sizeimage <= 0)
640 pix->sizeimage = PAGE_SIZE;
641 pix->bytesperline = 0;
642 } else {
643 u32 bpl = pix->bytesperline;
644
645 if (fmt->colplanes > 1 && bpl < pix->width)
646 bpl = pix->width; /* planar */
647
648 if (fmt->colplanes == 1 && /* packed */
649 (bpl << 3) * fmt->depth < pix->width)
650 bpl = (pix->width * fmt->depth) >> 3;
651
652 pix->bytesperline = bpl;
653 pix->sizeimage = (pix->width * pix->height * fmt->depth) >> 3;
654 }
655
656 return 0;
657}
658
659static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
660 struct v4l2_format *f)
661{
662 struct s5p_jpeg_fmt *fmt;
663 struct s5p_jpeg_ctx *ctx = priv;
664
665 fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat);
666 if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) {
667 v4l2_err(&ctx->jpeg->v4l2_dev,
668 "Fourcc format (0x%08x) invalid.\n",
669 f->fmt.pix.pixelformat);
670 return -EINVAL;
671 }
672
673 return vidioc_try_fmt(f, fmt, ctx, MEM2MEM_CAPTURE);
674}
675
676static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
677 struct v4l2_format *f)
678{
679 struct s5p_jpeg_fmt *fmt;
680 struct s5p_jpeg_ctx *ctx = priv;
681
682 fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat);
683 if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) {
684 v4l2_err(&ctx->jpeg->v4l2_dev,
685 "Fourcc format (0x%08x) invalid.\n",
686 f->fmt.pix.pixelformat);
687 return -EINVAL;
688 }
689
690 return vidioc_try_fmt(f, fmt, ctx, MEM2MEM_OUTPUT);
691}
692
693static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
694{
695 struct vb2_queue *vq;
696 struct s5p_jpeg_q_data *q_data = NULL;
697 struct v4l2_pix_format *pix = &f->fmt.pix;
698
699 vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type);
700 if (!vq)
701 return -EINVAL;
702
703 q_data = get_q_data(ct, f->type);
704 BUG_ON(q_data == NULL);
705
706 if (vb2_is_busy(vq)) {
707 v4l2_err(&ct->jpeg->v4l2_dev, "%s queue busy\n", __func__);
708 return -EBUSY;
709 }
710
711 q_data->fmt = s5p_jpeg_find_format(ct->mode, pix->pixelformat);
712 q_data->w = pix->width;
713 q_data->h = pix->height;
714 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG)
715 q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3;
716 else
717 q_data->size = pix->sizeimage;
718
719 return 0;
720}
721
722static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
723 struct v4l2_format *f)
724{
725 int ret;
726
727 ret = s5p_jpeg_try_fmt_vid_cap(file, priv, f);
728 if (ret)
729 return ret;
730
731 return s5p_jpeg_s_fmt(priv, f);
732}
733
734static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
735 struct v4l2_format *f)
736{
737 int ret;
738
739 ret = s5p_jpeg_try_fmt_vid_out(file, priv, f);
740 if (ret)
741 return ret;
742
743 return s5p_jpeg_s_fmt(priv, f);
744}
745
746static int s5p_jpeg_reqbufs(struct file *file, void *priv,
747 struct v4l2_requestbuffers *reqbufs)
748{
749 struct s5p_jpeg_ctx *ctx = priv;
750
751 return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
752}
753
754static int s5p_jpeg_querybuf(struct file *file, void *priv,
755 struct v4l2_buffer *buf)
756{
757 struct s5p_jpeg_ctx *ctx = priv;
758
759 return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
760}
761
762static int s5p_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
763{
764 struct s5p_jpeg_ctx *ctx = priv;
765
766 return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
767}
768
769static int s5p_jpeg_dqbuf(struct file *file, void *priv,
770 struct v4l2_buffer *buf)
771{
772 struct s5p_jpeg_ctx *ctx = priv;
773
774 return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
775}
776
777static int s5p_jpeg_streamon(struct file *file, void *priv,
778 enum v4l2_buf_type type)
779{
780 struct s5p_jpeg_ctx *ctx = priv;
781
782 return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
783}
784
785static int s5p_jpeg_streamoff(struct file *file, void *priv,
786 enum v4l2_buf_type type)
787{
788 struct s5p_jpeg_ctx *ctx = priv;
789
790 return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
791}
792
793int s5p_jpeg_g_selection(struct file *file, void *priv,
794 struct v4l2_selection *s)
795{
796 struct s5p_jpeg_ctx *ctx = priv;
797
798 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
799 s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
800 return -EINVAL;
801
802 /* For JPEG blob active == default == bounds */
803 switch (s->target) {
804 case V4L2_SEL_TGT_CROP_ACTIVE:
805 case V4L2_SEL_TGT_CROP_BOUNDS:
806 case V4L2_SEL_TGT_CROP_DEFAULT:
807 case V4L2_SEL_TGT_COMPOSE_ACTIVE:
808 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
809 s->r.width = ctx->out_q.w;
810 s->r.height = ctx->out_q.h;
811 break;
812 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
813 case V4L2_SEL_TGT_COMPOSE_PADDED:
814 s->r.width = ctx->cap_q.w;
815 s->r.height = ctx->cap_q.h;
816 break;
817 default:
818 return -EINVAL;
819 }
820 s->r.left = 0;
821 s->r.top = 0;
822 return 0;
823}
824
825static int s5p_jpeg_g_jpegcomp(struct file *file, void *priv,
826 struct v4l2_jpegcompression *compr)
827{
828 struct s5p_jpeg_ctx *ctx = priv;
829
830 if (ctx->mode == S5P_JPEG_DECODE)
831 return -ENOTTY;
832
833 memset(compr, 0, sizeof(*compr));
834 compr->quality = ctx->compr_quality;
835
836 return 0;
837}
838
839static int s5p_jpeg_s_jpegcomp(struct file *file, void *priv,
840 struct v4l2_jpegcompression *compr)
841{
842 struct s5p_jpeg_ctx *ctx = priv;
843
844 if (ctx->mode == S5P_JPEG_DECODE)
845 return -ENOTTY;
846
847 compr->quality = clamp(compr->quality, S5P_JPEG_COMPR_QUAL_BEST,
848 S5P_JPEG_COMPR_QUAL_WORST);
849
850 ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - compr->quality;
851
852 return 0;
853}
854
855static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
856 .vidioc_querycap = s5p_jpeg_querycap,
857
858 .vidioc_enum_fmt_vid_cap = s5p_jpeg_enum_fmt_vid_cap,
859 .vidioc_enum_fmt_vid_out = s5p_jpeg_enum_fmt_vid_out,
860
861 .vidioc_g_fmt_vid_cap = s5p_jpeg_g_fmt,
862 .vidioc_g_fmt_vid_out = s5p_jpeg_g_fmt,
863
864 .vidioc_try_fmt_vid_cap = s5p_jpeg_try_fmt_vid_cap,
865 .vidioc_try_fmt_vid_out = s5p_jpeg_try_fmt_vid_out,
866
867 .vidioc_s_fmt_vid_cap = s5p_jpeg_s_fmt_vid_cap,
868 .vidioc_s_fmt_vid_out = s5p_jpeg_s_fmt_vid_out,
869
870 .vidioc_reqbufs = s5p_jpeg_reqbufs,
871 .vidioc_querybuf = s5p_jpeg_querybuf,
872
873 .vidioc_qbuf = s5p_jpeg_qbuf,
874 .vidioc_dqbuf = s5p_jpeg_dqbuf,
875
876 .vidioc_streamon = s5p_jpeg_streamon,
877 .vidioc_streamoff = s5p_jpeg_streamoff,
878
879 .vidioc_g_selection = s5p_jpeg_g_selection,
880
881 .vidioc_g_jpegcomp = s5p_jpeg_g_jpegcomp,
882 .vidioc_s_jpegcomp = s5p_jpeg_s_jpegcomp,
883};
884
885/*
886 * ============================================================================
887 * mem2mem callbacks
888 * ============================================================================
889 */
890
891static void s5p_jpeg_device_run(void *priv)
892{
893 struct s5p_jpeg_ctx *ctx = priv;
894 struct s5p_jpeg *jpeg = ctx->jpeg;
895 struct vb2_buffer *src_buf, *dst_buf;
896 unsigned long src_addr, dst_addr;
897
898 src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
899 dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
900 src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
901 dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
902
903 jpeg_reset(jpeg->regs);
904 jpeg_poweron(jpeg->regs);
905 jpeg_proc_mode(jpeg->regs, ctx->mode);
906 if (ctx->mode == S5P_JPEG_ENCODE) {
907 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565)
908 jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_565);
909 else
910 jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_422);
911 if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
912 jpeg_subsampling_mode(jpeg->regs,
913 S5P_JPEG_SUBSAMPLING_422);
914 else
915 jpeg_subsampling_mode(jpeg->regs,
916 S5P_JPEG_SUBSAMPLING_420);
917 jpeg_dri(jpeg->regs, 0);
918 jpeg_x(jpeg->regs, ctx->out_q.w);
919 jpeg_y(jpeg->regs, ctx->out_q.h);
920 jpeg_imgadr(jpeg->regs, src_addr);
921 jpeg_jpgadr(jpeg->regs, dst_addr);
922
923 /* ultimately comes from sizeimage from userspace */
924 jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size);
925
926 /* JPEG RGB to YCbCr conversion matrix */
927 jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11);
928 jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12);
929 jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13);
930 jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21);
931 jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22);
932 jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23);
933 jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31);
934 jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32);
935 jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33);
936
937 /*
938 * JPEG IP allows storing 4 quantization tables
939 * We fill table 0 for luma and table 1 for chroma
940 */
941 jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
942 jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
943 /* use table 0 for Y */
944 jpeg_qtbl(jpeg->regs, 1, 0);
945 /* use table 1 for Cb and Cr*/
946 jpeg_qtbl(jpeg->regs, 2, 1);
947 jpeg_qtbl(jpeg->regs, 3, 1);
948
949 /* Y, Cb, Cr use Huffman table 0 */
950 jpeg_htbl_ac(jpeg->regs, 1);
951 jpeg_htbl_dc(jpeg->regs, 1);
952 jpeg_htbl_ac(jpeg->regs, 2);
953 jpeg_htbl_dc(jpeg->regs, 2);
954 jpeg_htbl_ac(jpeg->regs, 3);
955 jpeg_htbl_dc(jpeg->regs, 3);
956 } else {
957 jpeg_rst_int_enable(jpeg->regs, true);
958 jpeg_data_num_int_enable(jpeg->regs, true);
959 jpeg_final_mcu_num_int_enable(jpeg->regs, true);
960 jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
961 jpeg_jpgadr(jpeg->regs, src_addr);
962 jpeg_imgadr(jpeg->regs, dst_addr);
963 }
964 jpeg_start(jpeg->regs);
965}
966
967static int s5p_jpeg_job_ready(void *priv)
968{
969 struct s5p_jpeg_ctx *ctx = priv;
970
971 if (ctx->mode == S5P_JPEG_DECODE)
972 return ctx->hdr_parsed;
973 return 1;
974}
975
976static void s5p_jpeg_job_abort(void *priv)
977{
978}
979
980static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = {
981 .device_run = s5p_jpeg_device_run,
982 .job_ready = s5p_jpeg_job_ready,
983 .job_abort = s5p_jpeg_job_abort,
984};
985
986/*
987 * ============================================================================
988 * Queue operations
989 * ============================================================================
990 */
991
992static int s5p_jpeg_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
993 unsigned int *nplanes, unsigned int sizes[],
994 void *alloc_ctxs[])
995{
996 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
997 struct s5p_jpeg_q_data *q_data = NULL;
998 unsigned int size, count = *nbuffers;
999
1000 q_data = get_q_data(ctx, vq->type);
1001 BUG_ON(q_data == NULL);
1002
1003 size = q_data->size;
1004
1005 /*
1006 * header is parsed during decoding and parsed information stored
1007 * in the context so we do not allow another buffer to overwrite it
1008 */
1009 if (ctx->mode == S5P_JPEG_DECODE)
1010 count = 1;
1011
1012 *nbuffers = count;
1013 *nplanes = 1;
1014 sizes[0] = size;
1015 alloc_ctxs[0] = ctx->jpeg->alloc_ctx;
1016
1017 return 0;
1018}
1019
1020static int s5p_jpeg_buf_prepare(struct vb2_buffer *vb)
1021{
1022 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1023 struct s5p_jpeg_q_data *q_data = NULL;
1024
1025 q_data = get_q_data(ctx, vb->vb2_queue->type);
1026 BUG_ON(q_data == NULL);
1027
1028 if (vb2_plane_size(vb, 0) < q_data->size) {
1029 pr_err("%s data will not fit into plane (%lu < %lu)\n",
1030 __func__, vb2_plane_size(vb, 0),
1031 (long)q_data->size);
1032 return -EINVAL;
1033 }
1034
1035 vb2_set_plane_payload(vb, 0, q_data->size);
1036
1037 return 0;
1038}
1039
1040static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
1041{
1042 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1043
1044 if (ctx->mode == S5P_JPEG_DECODE &&
1045 vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
1046 struct s5p_jpeg_q_data tmp, *q_data;
1047 ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp,
1048 (unsigned long)vb2_plane_vaddr(vb, 0),
1049 min((unsigned long)ctx->out_q.size,
1050 vb2_get_plane_payload(vb, 0)));
1051 if (!ctx->hdr_parsed) {
1052 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
1053 return;
1054 }
1055
1056 q_data = &ctx->out_q;
1057 q_data->w = tmp.w;
1058 q_data->h = tmp.h;
1059
1060 q_data = &ctx->cap_q;
1061 q_data->w = tmp.w;
1062 q_data->h = tmp.h;
1063
1064 jpeg_bound_align_image(&q_data->w, S5P_JPEG_MIN_WIDTH,
1065 S5P_JPEG_MAX_WIDTH, q_data->fmt->h_align,
1066 &q_data->h, S5P_JPEG_MIN_HEIGHT,
1067 S5P_JPEG_MAX_HEIGHT, q_data->fmt->v_align
1068 );
1069 q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3;
1070 }
1071 if (ctx->m2m_ctx)
1072 v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
1073}
1074
1075static void s5p_jpeg_wait_prepare(struct vb2_queue *vq)
1076{
1077 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
1078
1079 mutex_unlock(&ctx->jpeg->lock);
1080}
1081
1082static void s5p_jpeg_wait_finish(struct vb2_queue *vq)
1083{
1084 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
1085
1086 mutex_lock(&ctx->jpeg->lock);
1087}
1088
1089static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
1090{
1091 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
1092 int ret;
1093
1094 ret = pm_runtime_get_sync(ctx->jpeg->dev);
1095
1096 return ret > 0 ? 0 : ret;
1097}
1098
1099static int s5p_jpeg_stop_streaming(struct vb2_queue *q)
1100{
1101 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
1102
1103 pm_runtime_put(ctx->jpeg->dev);
1104
1105 return 0;
1106}
1107
1108static struct vb2_ops s5p_jpeg_qops = {
1109 .queue_setup = s5p_jpeg_queue_setup,
1110 .buf_prepare = s5p_jpeg_buf_prepare,
1111 .buf_queue = s5p_jpeg_buf_queue,
1112 .wait_prepare = s5p_jpeg_wait_prepare,
1113 .wait_finish = s5p_jpeg_wait_finish,
1114 .start_streaming = s5p_jpeg_start_streaming,
1115 .stop_streaming = s5p_jpeg_stop_streaming,
1116};
1117
1118static int queue_init(void *priv, struct vb2_queue *src_vq,
1119 struct vb2_queue *dst_vq)
1120{
1121 struct s5p_jpeg_ctx *ctx = priv;
1122 int ret;
1123
1124 memset(src_vq, 0, sizeof(*src_vq));
1125 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1126 src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
1127 src_vq->drv_priv = ctx;
1128 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1129 src_vq->ops = &s5p_jpeg_qops;
1130 src_vq->mem_ops = &vb2_dma_contig_memops;
1131
1132 ret = vb2_queue_init(src_vq);
1133 if (ret)
1134 return ret;
1135
1136 memset(dst_vq, 0, sizeof(*dst_vq));
1137 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1138 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
1139 dst_vq->drv_priv = ctx;
1140 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1141 dst_vq->ops = &s5p_jpeg_qops;
1142 dst_vq->mem_ops = &vb2_dma_contig_memops;
1143
1144 return vb2_queue_init(dst_vq);
1145}
1146
1147/*
1148 * ============================================================================
1149 * ISR
1150 * ============================================================================
1151 */
1152
1153static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
1154{
1155 struct s5p_jpeg *jpeg = dev_id;
1156 struct s5p_jpeg_ctx *curr_ctx;
1157 struct vb2_buffer *src_buf, *dst_buf;
1158 unsigned long payload_size = 0;
1159 enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
1160 bool enc_jpeg_too_large = false;
1161 bool timer_elapsed = false;
1162 bool op_completed = false;
1163
1164 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
1165
1166 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
1167 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
1168
1169 if (curr_ctx->mode == S5P_JPEG_ENCODE)
1170 enc_jpeg_too_large = jpeg_enc_stream_stat(jpeg->regs);
1171 timer_elapsed = jpeg_timer_stat(jpeg->regs);
1172 op_completed = jpeg_result_stat_ok(jpeg->regs);
1173 if (curr_ctx->mode == S5P_JPEG_DECODE)
1174 op_completed = op_completed && jpeg_stream_stat_ok(jpeg->regs);
1175
1176 if (enc_jpeg_too_large) {
1177 state = VB2_BUF_STATE_ERROR;
1178 jpeg_clear_enc_stream_stat(jpeg->regs);
1179 } else if (timer_elapsed) {
1180 state = VB2_BUF_STATE_ERROR;
1181 jpeg_clear_timer_stat(jpeg->regs);
1182 } else if (!op_completed) {
1183 state = VB2_BUF_STATE_ERROR;
1184 } else {
1185 payload_size = jpeg_compressed_size(jpeg->regs);
1186 }
1187
1188 v4l2_m2m_buf_done(src_buf, state);
1189 if (curr_ctx->mode == S5P_JPEG_ENCODE)
1190 vb2_set_plane_payload(dst_buf, 0, payload_size);
1191 v4l2_m2m_buf_done(dst_buf, state);
1192 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->m2m_ctx);
1193
1194 jpeg_clear_int(jpeg->regs);
1195
1196 return IRQ_HANDLED;
1197}
1198
1199/*
1200 * ============================================================================
1201 * Driver basic infrastructure
1202 * ============================================================================
1203 */
1204
1205static int s5p_jpeg_probe(struct platform_device *pdev)
1206{
1207 struct s5p_jpeg *jpeg;
1208 struct resource *res;
1209 int ret;
1210
1211 /* JPEG IP abstraction struct */
1212 jpeg = kzalloc(sizeof(struct s5p_jpeg), GFP_KERNEL);
1213 if (!jpeg)
1214 return -ENOMEM;
1215
1216 mutex_init(&jpeg->lock);
1217 jpeg->dev = &pdev->dev;
1218
1219 /* memory-mapped registers */
1220 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1221 if (!res) {
1222 dev_err(&pdev->dev, "cannot find IO resource\n");
1223 ret = -ENOENT;
1224 goto jpeg_alloc_rollback;
1225 }
1226
1227 jpeg->ioarea = request_mem_region(res->start, resource_size(res),
1228 pdev->name);
1229 if (!jpeg->ioarea) {
1230 dev_err(&pdev->dev, "cannot request IO\n");
1231 ret = -ENXIO;
1232 goto jpeg_alloc_rollback;
1233 }
1234
1235 jpeg->regs = ioremap(res->start, resource_size(res));
1236 if (!jpeg->regs) {
1237 dev_err(&pdev->dev, "cannot map IO\n");
1238 ret = -ENXIO;
1239 goto mem_region_rollback;
1240 }
1241
1242 dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",
1243 jpeg->regs, jpeg->ioarea, res);
1244
1245 /* interrupt service routine registration */
1246 jpeg->irq = ret = platform_get_irq(pdev, 0);
1247 if (ret < 0) {
1248 dev_err(&pdev->dev, "cannot find IRQ\n");
1249 goto ioremap_rollback;
1250 }
1251
1252 ret = request_irq(jpeg->irq, s5p_jpeg_irq, 0,
1253 dev_name(&pdev->dev), jpeg);
1254
1255 if (ret) {
1256 dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
1257 goto ioremap_rollback;
1258 }
1259
1260 /* clocks */
1261 jpeg->clk = clk_get(&pdev->dev, "jpeg");
1262 if (IS_ERR(jpeg->clk)) {
1263 dev_err(&pdev->dev, "cannot get clock\n");
1264 ret = PTR_ERR(jpeg->clk);
1265 goto request_irq_rollback;
1266 }
1267 dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk);
1268 clk_enable(jpeg->clk);
1269
1270 /* v4l2 device */
1271 ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
1272 if (ret) {
1273 dev_err(&pdev->dev, "Failed to register v4l2 device\n");
1274 goto clk_get_rollback;
1275 }
1276
1277 /* mem2mem device */
1278 jpeg->m2m_dev = v4l2_m2m_init(&s5p_jpeg_m2m_ops);
1279 if (IS_ERR(jpeg->m2m_dev)) {
1280 v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
1281 ret = PTR_ERR(jpeg->m2m_dev);
1282 goto device_register_rollback;
1283 }
1284
1285 jpeg->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
1286 if (IS_ERR(jpeg->alloc_ctx)) {
1287 v4l2_err(&jpeg->v4l2_dev, "Failed to init memory allocator\n");
1288 ret = PTR_ERR(jpeg->alloc_ctx);
1289 goto m2m_init_rollback;
1290 }
1291
1292 /* JPEG encoder /dev/videoX node */
1293 jpeg->vfd_encoder = video_device_alloc();
1294 if (!jpeg->vfd_encoder) {
1295 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
1296 ret = -ENOMEM;
1297 goto vb2_allocator_rollback;
1298 }
1299 strlcpy(jpeg->vfd_encoder->name, S5P_JPEG_M2M_NAME,
1300 sizeof(jpeg->vfd_encoder->name));
1301 jpeg->vfd_encoder->fops = &s5p_jpeg_fops;
1302 jpeg->vfd_encoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
1303 jpeg->vfd_encoder->minor = -1;
1304 jpeg->vfd_encoder->release = video_device_release;
1305 jpeg->vfd_encoder->lock = &jpeg->lock;
1306 jpeg->vfd_encoder->v4l2_dev = &jpeg->v4l2_dev;
1307
1308 ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
1309 if (ret) {
1310 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
1311 goto enc_vdev_alloc_rollback;
1312 }
1313
1314 video_set_drvdata(jpeg->vfd_encoder, jpeg);
1315 v4l2_info(&jpeg->v4l2_dev,
1316 "encoder device registered as /dev/video%d\n",
1317 jpeg->vfd_encoder->num);
1318
1319 /* JPEG decoder /dev/videoX node */
1320 jpeg->vfd_decoder = video_device_alloc();
1321 if (!jpeg->vfd_decoder) {
1322 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
1323 ret = -ENOMEM;
1324 goto enc_vdev_register_rollback;
1325 }
1326 strlcpy(jpeg->vfd_decoder->name, S5P_JPEG_M2M_NAME,
1327 sizeof(jpeg->vfd_decoder->name));
1328 jpeg->vfd_decoder->fops = &s5p_jpeg_fops;
1329 jpeg->vfd_decoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
1330 jpeg->vfd_decoder->minor = -1;
1331 jpeg->vfd_decoder->release = video_device_release;
1332 jpeg->vfd_decoder->lock = &jpeg->lock;
1333 jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev;
1334
1335 ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
1336 if (ret) {
1337 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
1338 goto dec_vdev_alloc_rollback;
1339 }
1340
1341 video_set_drvdata(jpeg->vfd_decoder, jpeg);
1342 v4l2_info(&jpeg->v4l2_dev,
1343 "decoder device registered as /dev/video%d\n",
1344 jpeg->vfd_decoder->num);
1345
1346 /* final statements & power management */
1347 platform_set_drvdata(pdev, jpeg);
1348
1349 pm_runtime_enable(&pdev->dev);
1350
1351 v4l2_info(&jpeg->v4l2_dev, "Samsung S5P JPEG codec\n");
1352
1353 return 0;
1354
1355dec_vdev_alloc_rollback:
1356 video_device_release(jpeg->vfd_decoder);
1357
1358enc_vdev_register_rollback:
1359 video_unregister_device(jpeg->vfd_encoder);
1360
1361enc_vdev_alloc_rollback:
1362 video_device_release(jpeg->vfd_encoder);
1363
1364vb2_allocator_rollback:
1365 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
1366
1367m2m_init_rollback:
1368 v4l2_m2m_release(jpeg->m2m_dev);
1369
1370device_register_rollback:
1371 v4l2_device_unregister(&jpeg->v4l2_dev);
1372
1373clk_get_rollback:
1374 clk_disable(jpeg->clk);
1375 clk_put(jpeg->clk);
1376
1377request_irq_rollback:
1378 free_irq(jpeg->irq, jpeg);
1379
1380ioremap_rollback:
1381 iounmap(jpeg->regs);
1382
1383mem_region_rollback:
1384 release_resource(jpeg->ioarea);
1385 release_mem_region(jpeg->ioarea->start, resource_size(jpeg->ioarea));
1386
1387jpeg_alloc_rollback:
1388 kfree(jpeg);
1389 return ret;
1390}
1391
1392static int s5p_jpeg_remove(struct platform_device *pdev)
1393{
1394 struct s5p_jpeg *jpeg = platform_get_drvdata(pdev);
1395
1396 pm_runtime_disable(jpeg->dev);
1397
1398 video_unregister_device(jpeg->vfd_decoder);
1399 video_device_release(jpeg->vfd_decoder);
1400 video_unregister_device(jpeg->vfd_encoder);
1401 video_device_release(jpeg->vfd_encoder);
1402 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
1403 v4l2_m2m_release(jpeg->m2m_dev);
1404 v4l2_device_unregister(&jpeg->v4l2_dev);
1405
1406 clk_disable(jpeg->clk);
1407 clk_put(jpeg->clk);
1408
1409 free_irq(jpeg->irq, jpeg);
1410
1411 iounmap(jpeg->regs);
1412
1413 release_resource(jpeg->ioarea);
1414 release_mem_region(jpeg->ioarea->start, resource_size(jpeg->ioarea));
1415 kfree(jpeg);
1416
1417 return 0;
1418}
1419
1420static int s5p_jpeg_runtime_suspend(struct device *dev)
1421{
1422 return 0;
1423}
1424
1425static int s5p_jpeg_runtime_resume(struct device *dev)
1426{
1427 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
1428 /*
1429 * JPEG IP allows storing two Huffman tables for each component
1430 * We fill table 0 for each component
1431 */
1432 jpeg_set_hdctbl(jpeg->regs);
1433 jpeg_set_hdctblg(jpeg->regs);
1434 jpeg_set_hactbl(jpeg->regs);
1435 jpeg_set_hactblg(jpeg->regs);
1436 return 0;
1437}
1438
1439static const struct dev_pm_ops s5p_jpeg_pm_ops = {
1440 .runtime_suspend = s5p_jpeg_runtime_suspend,
1441 .runtime_resume = s5p_jpeg_runtime_resume,
1442};
1443
1444static struct platform_driver s5p_jpeg_driver = {
1445 .probe = s5p_jpeg_probe,
1446 .remove = s5p_jpeg_remove,
1447 .driver = {
1448 .owner = THIS_MODULE,
1449 .name = S5P_JPEG_M2M_NAME,
1450 .pm = &s5p_jpeg_pm_ops,
1451 },
1452};
1453
1454static int __init
1455s5p_jpeg_register(void)
1456{
1457 int ret;
1458
1459 pr_info("S5P JPEG V4L2 Driver, (c) 2011 Samsung Electronics\n");
1460
1461 ret = platform_driver_register(&s5p_jpeg_driver);
1462
1463 if (ret)
1464 pr_err("%s: failed to register jpeg driver\n", __func__);
1465
1466 return ret;
1467}
1468
1469static void __exit
1470s5p_jpeg_unregister(void)
1471{
1472 platform_driver_unregister(&s5p_jpeg_driver);
1473}
1474
1475module_init(s5p_jpeg_register);
1476module_exit(s5p_jpeg_unregister);
1477
1478MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
1479MODULE_DESCRIPTION("Samsung JPEG codec driver");
1480MODULE_LICENSE("GPL");
1481
diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.h b/drivers/media/video/s5p-jpeg/jpeg-core.h
new file mode 100644
index 000000000000..facad6114f5e
--- /dev/null
+++ b/drivers/media/video/s5p-jpeg/jpeg-core.h
@@ -0,0 +1,143 @@
1/* linux/drivers/media/video/s5p-jpeg/jpeg-core.h
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#ifndef JPEG_CORE_H_
14#define JPEG_CORE_H_
15
16#include <media/v4l2-device.h>
17
18#define S5P_JPEG_M2M_NAME "s5p-jpeg"
19
20/* JPEG compression quality setting */
21#define S5P_JPEG_COMPR_QUAL_BEST 0
22#define S5P_JPEG_COMPR_QUAL_WORST 3
23
24/* JPEG RGB to YCbCr conversion matrix coefficients */
25#define S5P_JPEG_COEF11 0x4d
26#define S5P_JPEG_COEF12 0x97
27#define S5P_JPEG_COEF13 0x1e
28#define S5P_JPEG_COEF21 0x2c
29#define S5P_JPEG_COEF22 0x57
30#define S5P_JPEG_COEF23 0x83
31#define S5P_JPEG_COEF31 0x83
32#define S5P_JPEG_COEF32 0x6e
33#define S5P_JPEG_COEF33 0x13
34
35/* a selection of JPEG markers */
36#define TEM 0x01
37#define SOF0 0xc0
38#define RST 0xd0
39#define SOI 0xd8
40#define EOI 0xd9
41#define DHP 0xde
42
43/* Flags that indicate a format can be used for capture/output */
44#define MEM2MEM_CAPTURE (1 << 0)
45#define MEM2MEM_OUTPUT (1 << 1)
46
47/**
48 * struct s5p_jpeg - JPEG IP abstraction
49 * @lock: the mutex protecting this structure
50 * @v4l2_dev: v4l2 device for mem2mem mode
51 * @vfd_encoder: video device node for encoder mem2mem mode
52 * @vfd_decoder: video device node for decoder mem2mem mode
53 * @m2m_dev: v4l2 mem2mem device data
54 * @ioarea: JPEG IP memory region
55 * @regs: JPEG IP registers mapping
56 * @irq: JPEG IP irq
57 * @clk: JPEG IP clock
58 * @dev: JPEG IP struct device
59 * @alloc_ctx: videobuf2 memory allocator's context
60 */
61struct s5p_jpeg {
62 struct mutex lock;
63
64 struct v4l2_device v4l2_dev;
65 struct video_device *vfd_encoder;
66 struct video_device *vfd_decoder;
67 struct v4l2_m2m_dev *m2m_dev;
68
69 struct resource *ioarea;
70 void __iomem *regs;
71 unsigned int irq;
72 struct clk *clk;
73 struct device *dev;
74 void *alloc_ctx;
75};
76
77/**
78 * struct jpeg_fmt - driver's internal color format data
79 * @name: format descritpion
80 * @fourcc: the fourcc code, 0 if not applicable
81 * @depth: number of bits per pixel
82 * @colplanes: number of color planes (1 for packed formats)
83 * @h_align: horizontal alignment order (align to 2^h_align)
84 * @v_align: vertical alignment order (align to 2^v_align)
85 * @types: types of queue this format is applicable to
86 */
87struct s5p_jpeg_fmt {
88 char *name;
89 u32 fourcc;
90 int depth;
91 int colplanes;
92 int h_align;
93 int v_align;
94 u32 types;
95};
96
97/**
98 * s5p_jpeg_q_data - parameters of one queue
99 * @fmt: driver-specific format of this queue
100 * @w: image width
101 * @h: image height
102 * @size: image buffer size in bytes
103 */
104struct s5p_jpeg_q_data {
105 struct s5p_jpeg_fmt *fmt;
106 u32 w;
107 u32 h;
108 u32 size;
109};
110
111/**
112 * s5p_jpeg_ctx - the device context data
113 * @jpeg: JPEG IP device for this context
114 * @mode: compression (encode) operation or decompression (decode)
115 * @compr_quality: destination image quality in compression (encode) mode
116 * @m2m_ctx: mem2mem device context
117 * @out_q: source (output) queue information
118 * @cap_fmt: destination (capture) queue queue information
119 * @hdr_parsed: set if header has been parsed during decompression
120 */
121struct s5p_jpeg_ctx {
122 struct s5p_jpeg *jpeg;
123 unsigned int mode;
124 unsigned int compr_quality;
125 struct v4l2_m2m_ctx *m2m_ctx;
126 struct s5p_jpeg_q_data out_q;
127 struct s5p_jpeg_q_data cap_q;
128 bool hdr_parsed;
129};
130
131/**
132 * s5p_jpeg_buffer - description of memory containing input JPEG data
133 * @size: buffer size
134 * @curr: current position in the buffer
135 * @data: pointer to the data
136 */
137struct s5p_jpeg_buffer {
138 unsigned long size;
139 unsigned long curr;
140 unsigned long data;
141};
142
143#endif /* JPEG_CORE_H */
diff --git a/drivers/media/video/s5p-jpeg/jpeg-hw.h b/drivers/media/video/s5p-jpeg/jpeg-hw.h
new file mode 100644
index 000000000000..e10c744e9f23
--- /dev/null
+++ b/drivers/media/video/s5p-jpeg/jpeg-hw.h
@@ -0,0 +1,353 @@
1/* linux/drivers/media/video/s5p-jpeg/jpeg-hw.h
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef JPEG_HW_H_
13#define JPEG_HW_H_
14
15#include <linux/io.h>
16
17#include "jpeg-hw.h"
18#include "jpeg-regs.h"
19
20#define S5P_JPEG_MIN_WIDTH 32
21#define S5P_JPEG_MIN_HEIGHT 32
22#define S5P_JPEG_MAX_WIDTH 8192
23#define S5P_JPEG_MAX_HEIGHT 8192
24#define S5P_JPEG_ENCODE 0
25#define S5P_JPEG_DECODE 1
26#define S5P_JPEG_RAW_IN_565 0
27#define S5P_JPEG_RAW_IN_422 1
28#define S5P_JPEG_SUBSAMPLING_422 0
29#define S5P_JPEG_SUBSAMPLING_420 1
30#define S5P_JPEG_RAW_OUT_422 0
31#define S5P_JPEG_RAW_OUT_420 1
32
33static inline void jpeg_reset(void __iomem *regs)
34{
35 unsigned long reg;
36
37 writel(1, regs + S5P_JPG_SW_RESET);
38 reg = readl(regs + S5P_JPG_SW_RESET);
39 /* no other way but polling for when JPEG IP becomes operational */
40 while (reg != 0) {
41 cpu_relax();
42 reg = readl(regs + S5P_JPG_SW_RESET);
43 }
44}
45
46static inline void jpeg_poweron(void __iomem *regs)
47{
48 writel(S5P_POWER_ON, regs + S5P_JPGCLKCON);
49}
50
51static inline void jpeg_input_raw_mode(void __iomem *regs, unsigned long mode)
52{
53 unsigned long reg, m;
54
55 m = S5P_MOD_SEL_565;
56 if (mode == S5P_JPEG_RAW_IN_565)
57 m = S5P_MOD_SEL_565;
58 else if (mode == S5P_JPEG_RAW_IN_422)
59 m = S5P_MOD_SEL_422;
60
61 reg = readl(regs + S5P_JPGCMOD);
62 reg &= ~S5P_MOD_SEL_MASK;
63 reg |= m;
64 writel(reg, regs + S5P_JPGCMOD);
65}
66
67static inline void jpeg_input_raw_y16(void __iomem *regs, bool y16)
68{
69 unsigned long reg;
70
71 reg = readl(regs + S5P_JPGCMOD);
72 if (y16)
73 reg |= S5P_MODE_Y16;
74 else
75 reg &= ~S5P_MODE_Y16_MASK;
76 writel(reg, regs + S5P_JPGCMOD);
77}
78
79static inline void jpeg_proc_mode(void __iomem *regs, unsigned long mode)
80{
81 unsigned long reg, m;
82
83 m = S5P_PROC_MODE_DECOMPR;
84 if (mode == S5P_JPEG_ENCODE)
85 m = S5P_PROC_MODE_COMPR;
86 else
87 m = S5P_PROC_MODE_DECOMPR;
88 reg = readl(regs + S5P_JPGMOD);
89 reg &= ~S5P_PROC_MODE_MASK;
90 reg |= m;
91 writel(reg, regs + S5P_JPGMOD);
92}
93
94static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned long mode)
95{
96 unsigned long reg, m;
97
98 m = S5P_SUBSAMPLING_MODE_422;
99 if (mode == S5P_JPEG_SUBSAMPLING_422)
100 m = S5P_SUBSAMPLING_MODE_422;
101 else if (mode == S5P_JPEG_SUBSAMPLING_420)
102 m = S5P_SUBSAMPLING_MODE_420;
103 reg = readl(regs + S5P_JPGMOD);
104 reg &= ~S5P_SUBSAMPLING_MODE_MASK;
105 reg |= m;
106 writel(reg, regs + S5P_JPGMOD);
107}
108
109static inline void jpeg_dri(void __iomem *regs, unsigned int dri)
110{
111 unsigned long reg;
112
113 reg = readl(regs + S5P_JPGDRI_U);
114 reg &= ~0xff;
115 reg |= (dri >> 8) & 0xff;
116 writel(reg, regs + S5P_JPGDRI_U);
117
118 reg = readl(regs + S5P_JPGDRI_L);
119 reg &= ~0xff;
120 reg |= dri & 0xff;
121 writel(reg, regs + S5P_JPGDRI_L);
122}
123
124static inline void jpeg_qtbl(void __iomem *regs, unsigned int t, unsigned int n)
125{
126 unsigned long reg;
127
128 reg = readl(regs + S5P_JPG_QTBL);
129 reg &= ~S5P_QT_NUMt_MASK(t);
130 reg |= (n << S5P_QT_NUMt_SHIFT(t)) & S5P_QT_NUMt_MASK(t);
131 writel(reg, regs + S5P_JPG_QTBL);
132}
133
134static inline void jpeg_htbl_ac(void __iomem *regs, unsigned int t)
135{
136 unsigned long reg;
137
138 reg = readl(regs + S5P_JPG_HTBL);
139 reg &= ~S5P_HT_NUMt_AC_MASK(t);
140 /* this driver uses table 0 for all color components */
141 reg |= (0 << S5P_HT_NUMt_AC_SHIFT(t)) & S5P_HT_NUMt_AC_MASK(t);
142 writel(reg, regs + S5P_JPG_HTBL);
143}
144
145static inline void jpeg_htbl_dc(void __iomem *regs, unsigned int t)
146{
147 unsigned long reg;
148
149 reg = readl(regs + S5P_JPG_HTBL);
150 reg &= ~S5P_HT_NUMt_DC_MASK(t);
151 /* this driver uses table 0 for all color components */
152 reg |= (0 << S5P_HT_NUMt_DC_SHIFT(t)) & S5P_HT_NUMt_DC_MASK(t);
153 writel(reg, regs + S5P_JPG_HTBL);
154}
155
156static inline void jpeg_y(void __iomem *regs, unsigned int y)
157{
158 unsigned long reg;
159
160 reg = readl(regs + S5P_JPGY_U);
161 reg &= ~0xff;
162 reg |= (y >> 8) & 0xff;
163 writel(reg, regs + S5P_JPGY_U);
164
165 reg = readl(regs + S5P_JPGY_L);
166 reg &= ~0xff;
167 reg |= y & 0xff;
168 writel(reg, regs + S5P_JPGY_L);
169}
170
171static inline void jpeg_x(void __iomem *regs, unsigned int x)
172{
173 unsigned long reg;
174
175 reg = readl(regs + S5P_JPGX_U);
176 reg &= ~0xff;
177 reg |= (x >> 8) & 0xff;
178 writel(reg, regs + S5P_JPGX_U);
179
180 reg = readl(regs + S5P_JPGX_L);
181 reg &= ~0xff;
182 reg |= x & 0xff;
183 writel(reg, regs + S5P_JPGX_L);
184}
185
186static inline void jpeg_rst_int_enable(void __iomem *regs, bool enable)
187{
188 unsigned long reg;
189
190 reg = readl(regs + S5P_JPGINTSE);
191 reg &= ~S5P_RSTm_INT_EN_MASK;
192 if (enable)
193 reg |= S5P_RSTm_INT_EN;
194 writel(reg, regs + S5P_JPGINTSE);
195}
196
197static inline void jpeg_data_num_int_enable(void __iomem *regs, bool enable)
198{
199 unsigned long reg;
200
201 reg = readl(regs + S5P_JPGINTSE);
202 reg &= ~S5P_DATA_NUM_INT_EN_MASK;
203 if (enable)
204 reg |= S5P_DATA_NUM_INT_EN;
205 writel(reg, regs + S5P_JPGINTSE);
206}
207
208static inline void jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl)
209{
210 unsigned long reg;
211
212 reg = readl(regs + S5P_JPGINTSE);
213 reg &= ~S5P_FINAL_MCU_NUM_INT_EN_MASK;
214 if (enbl)
215 reg |= S5P_FINAL_MCU_NUM_INT_EN;
216 writel(reg, regs + S5P_JPGINTSE);
217}
218
219static inline void jpeg_timer_enable(void __iomem *regs, unsigned long val)
220{
221 unsigned long reg;
222
223 reg = readl(regs + S5P_JPG_TIMER_SE);
224 reg |= S5P_TIMER_INT_EN;
225 reg &= ~S5P_TIMER_INIT_MASK;
226 reg |= val & S5P_TIMER_INIT_MASK;
227 writel(reg, regs + S5P_JPG_TIMER_SE);
228}
229
230static inline void jpeg_timer_disable(void __iomem *regs)
231{
232 unsigned long reg;
233
234 reg = readl(regs + S5P_JPG_TIMER_SE);
235 reg &= ~S5P_TIMER_INT_EN_MASK;
236 writel(reg, regs + S5P_JPG_TIMER_SE);
237}
238
239static inline int jpeg_timer_stat(void __iomem *regs)
240{
241 return (int)((readl(regs + S5P_JPG_TIMER_ST) & S5P_TIMER_INT_STAT_MASK)
242 >> S5P_TIMER_INT_STAT_SHIFT);
243}
244
245static inline void jpeg_clear_timer_stat(void __iomem *regs)
246{
247 unsigned long reg;
248
249 reg = readl(regs + S5P_JPG_TIMER_SE);
250 reg &= ~S5P_TIMER_INT_STAT_MASK;
251 writel(reg, regs + S5P_JPG_TIMER_SE);
252}
253
254static inline void jpeg_enc_stream_int(void __iomem *regs, unsigned long size)
255{
256 unsigned long reg;
257
258 reg = readl(regs + S5P_JPG_ENC_STREAM_INTSE);
259 reg &= ~S5P_ENC_STREAM_BOUND_MASK;
260 reg |= S5P_ENC_STREAM_INT_EN;
261 reg |= size & S5P_ENC_STREAM_BOUND_MASK;
262 writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE);
263}
264
265static inline int jpeg_enc_stream_stat(void __iomem *regs)
266{
267 return (int)(readl(regs + S5P_JPG_ENC_STREAM_INTST) &
268 S5P_ENC_STREAM_INT_STAT_MASK);
269}
270
271static inline void jpeg_clear_enc_stream_stat(void __iomem *regs)
272{
273 unsigned long reg;
274
275 reg = readl(regs + S5P_JPG_ENC_STREAM_INTSE);
276 reg &= ~S5P_ENC_STREAM_INT_MASK;
277 writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE);
278}
279
280static inline void jpeg_outform_raw(void __iomem *regs, unsigned long format)
281{
282 unsigned long reg, f;
283
284 f = S5P_DEC_OUT_FORMAT_422;
285 if (format == S5P_JPEG_RAW_OUT_422)
286 f = S5P_DEC_OUT_FORMAT_422;
287 else if (format == S5P_JPEG_RAW_OUT_420)
288 f = S5P_DEC_OUT_FORMAT_420;
289 reg = readl(regs + S5P_JPG_OUTFORM);
290 reg &= ~S5P_DEC_OUT_FORMAT_MASK;
291 reg |= f;
292 writel(reg, regs + S5P_JPG_OUTFORM);
293}
294
295static inline void jpeg_jpgadr(void __iomem *regs, unsigned long addr)
296{
297 writel(addr, regs + S5P_JPG_JPGADR);
298}
299
300static inline void jpeg_imgadr(void __iomem *regs, unsigned long addr)
301{
302 writel(addr, regs + S5P_JPG_IMGADR);
303}
304
305static inline void jpeg_coef(void __iomem *regs, unsigned int i,
306 unsigned int j, unsigned int coef)
307{
308 unsigned long reg;
309
310 reg = readl(regs + S5P_JPG_COEF(i));
311 reg &= ~S5P_COEFn_MASK(j);
312 reg |= (coef << S5P_COEFn_SHIFT(j)) & S5P_COEFn_MASK(j);
313 writel(reg, regs + S5P_JPG_COEF(i));
314}
315
316static inline void jpeg_start(void __iomem *regs)
317{
318 writel(1, regs + S5P_JSTART);
319}
320
321static inline int jpeg_result_stat_ok(void __iomem *regs)
322{
323 return (int)((readl(regs + S5P_JPGINTST) & S5P_RESULT_STAT_MASK)
324 >> S5P_RESULT_STAT_SHIFT);
325}
326
327static inline int jpeg_stream_stat_ok(void __iomem *regs)
328{
329 return !(int)((readl(regs + S5P_JPGINTST) & S5P_STREAM_STAT_MASK)
330 >> S5P_STREAM_STAT_SHIFT);
331}
332
333static inline void jpeg_clear_int(void __iomem *regs)
334{
335 unsigned long reg;
336
337 reg = readl(regs + S5P_JPGINTST);
338 writel(S5P_INT_RELEASE, regs + S5P_JPGCOM);
339 reg = readl(regs + S5P_JPGOPR);
340}
341
342static inline unsigned int jpeg_compressed_size(void __iomem *regs)
343{
344 unsigned long jpeg_size = 0;
345
346 jpeg_size |= (readl(regs + S5P_JPGCNT_U) & 0xff) << 16;
347 jpeg_size |= (readl(regs + S5P_JPGCNT_M) & 0xff) << 8;
348 jpeg_size |= (readl(regs + S5P_JPGCNT_L) & 0xff);
349
350 return (unsigned int)jpeg_size;
351}
352
353#endif /* JPEG_HW_H_ */
diff --git a/drivers/media/video/s5p-jpeg/jpeg-regs.h b/drivers/media/video/s5p-jpeg/jpeg-regs.h
new file mode 100644
index 000000000000..91f4dd5f86dd
--- /dev/null
+++ b/drivers/media/video/s5p-jpeg/jpeg-regs.h
@@ -0,0 +1,170 @@
1/* linux/drivers/media/video/s5p-jpeg/jpeg-regs.h
2 *
3 * Register definition file for Samsung JPEG codec driver
4 *
5 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
6 * http://www.samsung.com
7 *
8 * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#ifndef JPEG_REGS_H_
16#define JPEG_REGS_H_
17
18/* JPEG mode register */
19#define S5P_JPGMOD 0x00
20#define S5P_PROC_MODE_MASK (0x1 << 3)
21#define S5P_PROC_MODE_DECOMPR (0x1 << 3)
22#define S5P_PROC_MODE_COMPR (0x0 << 3)
23#define S5P_SUBSAMPLING_MODE_MASK 0x7
24#define S5P_SUBSAMPLING_MODE_444 (0x0 << 0)
25#define S5P_SUBSAMPLING_MODE_422 (0x1 << 0)
26#define S5P_SUBSAMPLING_MODE_420 (0x2 << 0)
27#define S5P_SUBSAMPLING_MODE_GRAY (0x3 << 0)
28
29/* JPEG operation status register */
30#define S5P_JPGOPR 0x04
31
32/* Quantization tables*/
33#define S5P_JPG_QTBL 0x08
34#define S5P_QT_NUMt_SHIFT(t) (((t) - 1) << 1)
35#define S5P_QT_NUMt_MASK(t) (0x3 << S5P_QT_NUMt_SHIFT(t))
36
37/* Huffman tables */
38#define S5P_JPG_HTBL 0x0c
39#define S5P_HT_NUMt_AC_SHIFT(t) (((t) << 1) - 1)
40#define S5P_HT_NUMt_AC_MASK(t) (0x1 << S5P_HT_NUMt_AC_SHIFT(t))
41
42#define S5P_HT_NUMt_DC_SHIFT(t) (((t) - 1) << 1)
43#define S5P_HT_NUMt_DC_MASK(t) (0x1 << S5P_HT_NUMt_DC_SHIFT(t))
44
45/* JPEG restart interval register upper byte */
46#define S5P_JPGDRI_U 0x10
47
48/* JPEG restart interval register lower byte */
49#define S5P_JPGDRI_L 0x14
50
51/* JPEG vertical resolution register upper byte */
52#define S5P_JPGY_U 0x18
53
54/* JPEG vertical resolution register lower byte */
55#define S5P_JPGY_L 0x1c
56
57/* JPEG horizontal resolution register upper byte */
58#define S5P_JPGX_U 0x20
59
60/* JPEG horizontal resolution register lower byte */
61#define S5P_JPGX_L 0x24
62
63/* JPEG byte count register upper byte */
64#define S5P_JPGCNT_U 0x28
65
66/* JPEG byte count register middle byte */
67#define S5P_JPGCNT_M 0x2c
68
69/* JPEG byte count register lower byte */
70#define S5P_JPGCNT_L 0x30
71
72/* JPEG interrupt setting register */
73#define S5P_JPGINTSE 0x34
74#define S5P_RSTm_INT_EN_MASK (0x1 << 7)
75#define S5P_RSTm_INT_EN (0x1 << 7)
76#define S5P_DATA_NUM_INT_EN_MASK (0x1 << 6)
77#define S5P_DATA_NUM_INT_EN (0x1 << 6)
78#define S5P_FINAL_MCU_NUM_INT_EN_MASK (0x1 << 5)
79#define S5P_FINAL_MCU_NUM_INT_EN (0x1 << 5)
80
81/* JPEG interrupt status register */
82#define S5P_JPGINTST 0x38
83#define S5P_RESULT_STAT_SHIFT 6
84#define S5P_RESULT_STAT_MASK (0x1 << S5P_RESULT_STAT_SHIFT)
85#define S5P_STREAM_STAT_SHIFT 5
86#define S5P_STREAM_STAT_MASK (0x1 << S5P_STREAM_STAT_SHIFT)
87
88/* JPEG command register */
89#define S5P_JPGCOM 0x4c
90#define S5P_INT_RELEASE (0x1 << 2)
91
92/* Raw image data r/w address register */
93#define S5P_JPG_IMGADR 0x50
94
95/* JPEG file r/w address register */
96#define S5P_JPG_JPGADR 0x58
97
98/* Coefficient for RGB-to-YCbCr converter register */
99#define S5P_JPG_COEF(n) (0x5c + (((n) - 1) << 2))
100#define S5P_COEFn_SHIFT(j) ((3 - (j)) << 3)
101#define S5P_COEFn_MASK(j) (0xff << S5P_COEFn_SHIFT(j))
102
103/* JPEG color mode register */
104#define S5P_JPGCMOD 0x68
105#define S5P_MOD_SEL_MASK (0x7 << 5)
106#define S5P_MOD_SEL_422 (0x1 << 5)
107#define S5P_MOD_SEL_565 (0x2 << 5)
108#define S5P_MODE_Y16_MASK (0x1 << 1)
109#define S5P_MODE_Y16 (0x1 << 1)
110
111/* JPEG clock control register */
112#define S5P_JPGCLKCON 0x6c
113#define S5P_CLK_DOWN_READY (0x1 << 1)
114#define S5P_POWER_ON (0x1 << 0)
115
116/* JPEG start register */
117#define S5P_JSTART 0x70
118
119/* JPEG SW reset register */
120#define S5P_JPG_SW_RESET 0x78
121
122/* JPEG timer setting register */
123#define S5P_JPG_TIMER_SE 0x7c
124#define S5P_TIMER_INT_EN_MASK (0x1 << 31)
125#define S5P_TIMER_INT_EN (0x1 << 31)
126#define S5P_TIMER_INIT_MASK 0x7fffffff
127
128/* JPEG timer status register */
129#define S5P_JPG_TIMER_ST 0x80
130#define S5P_TIMER_INT_STAT_SHIFT 31
131#define S5P_TIMER_INT_STAT_MASK (0x1 << S5P_TIMER_INT_STAT_SHIFT)
132#define S5P_TIMER_CNT_SHIFT 0
133#define S5P_TIMER_CNT_MASK 0x7fffffff
134
135/* JPEG decompression output format register */
136#define S5P_JPG_OUTFORM 0x88
137#define S5P_DEC_OUT_FORMAT_MASK (0x1 << 0)
138#define S5P_DEC_OUT_FORMAT_422 (0x0 << 0)
139#define S5P_DEC_OUT_FORMAT_420 (0x1 << 0)
140
141/* JPEG version register */
142#define S5P_JPG_VERSION 0x8c
143
144/* JPEG compressed stream size interrupt setting register */
145#define S5P_JPG_ENC_STREAM_INTSE 0x98
146#define S5P_ENC_STREAM_INT_MASK (0x1 << 24)
147#define S5P_ENC_STREAM_INT_EN (0x1 << 24)
148#define S5P_ENC_STREAM_BOUND_MASK 0xffffff
149
150/* JPEG compressed stream size interrupt status register */
151#define S5P_JPG_ENC_STREAM_INTST 0x9c
152#define S5P_ENC_STREAM_INT_STAT_MASK 0x1
153
154/* JPEG quantizer table register */
155#define S5P_JPG_QTBL_CONTENT(n) (0x400 + (n) * 0x100)
156
157/* JPEG DC Huffman table register */
158#define S5P_JPG_HDCTBL(n) (0x800 + (n) * 0x400)
159
160/* JPEG DC Huffman table register */
161#define S5P_JPG_HDCTBLG(n) (0x840 + (n) * 0x400)
162
163/* JPEG AC Huffman table register */
164#define S5P_JPG_HACTBL(n) (0x880 + (n) * 0x400)
165
166/* JPEG AC Huffman table register */
167#define S5P_JPG_HACTBLG(n) (0x8c0 + (n) * 0x400)
168
169#endif /* JPEG_REGS_H_ */
170