blob: fe2727413f3a53809072d4f1696d5c805dc7e741 [file] [log] [blame]
Mauro Carvalho Chehab2c3fb082012-08-14 17:31:16 -03001/* linux/drivers/media/platform/s5p-jpeg/jpeg-core.c
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002 *
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003 * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd.
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03004 * http://www.samsung.com
5 *
6 * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03007 * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03008 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/clk.h>
15#include <linux/err.h>
16#include <linux/gfp.h>
17#include <linux/interrupt.h>
18#include <linux/io.h>
19#include <linux/kernel.h>
20#include <linux/module.h>
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -030021#include <linux/of.h>
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030022#include <linux/platform_device.h>
23#include <linux/pm_runtime.h>
24#include <linux/slab.h>
25#include <linux/spinlock.h>
26#include <linux/string.h>
27#include <media/v4l2-mem2mem.h>
28#include <media/v4l2-ioctl.h>
29#include <media/videobuf2-core.h>
30#include <media/videobuf2-dma-contig.h>
31
32#include "jpeg-core.h"
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -030033#include "jpeg-hw-s5p.h"
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030034#include "jpeg-hw-exynos4.h"
Jacek Anaszewski3246fda2014-07-11 12:19:42 -030035#include "jpeg-hw-exynos3250.h"
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030036#include "jpeg-regs.h"
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030037
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030038static struct s5p_jpeg_fmt sjpeg_formats[] = {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030039 {
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -030040 .name = "JPEG JFIF",
41 .fourcc = V4L2_PIX_FMT_JPEG,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030042 .flags = SJPEG_FMT_FLAG_ENC_CAPTURE |
43 SJPEG_FMT_FLAG_DEC_OUTPUT |
44 SJPEG_FMT_FLAG_S5P |
Jacek Anaszewski3246fda2014-07-11 12:19:42 -030045 SJPEG_FMT_FLAG_EXYNOS3250 |
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030046 SJPEG_FMT_FLAG_EXYNOS4,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030047 },
48 {
49 .name = "YUV 4:2:2 packed, YCbYCr",
50 .fourcc = V4L2_PIX_FMT_YUYV,
51 .depth = 16,
52 .colplanes = 1,
53 .h_align = 4,
54 .v_align = 3,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030055 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
56 SJPEG_FMT_FLAG_DEC_CAPTURE |
57 SJPEG_FMT_FLAG_S5P |
58 SJPEG_FMT_NON_RGB,
59 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030060 },
61 {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030062 .name = "YUV 4:2:2 packed, YCbYCr",
63 .fourcc = V4L2_PIX_FMT_YUYV,
64 .depth = 16,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030065 .colplanes = 1,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030066 .h_align = 1,
67 .v_align = 0,
68 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
69 SJPEG_FMT_FLAG_DEC_CAPTURE |
70 SJPEG_FMT_FLAG_EXYNOS4 |
71 SJPEG_FMT_NON_RGB,
72 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
73 },
74 {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -030075 .name = "YUV 4:2:2 packed, YCbYCr",
76 .fourcc = V4L2_PIX_FMT_YUYV,
77 .depth = 16,
78 .colplanes = 1,
79 .h_align = 2,
80 .v_align = 0,
81 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
82 SJPEG_FMT_FLAG_DEC_CAPTURE |
83 SJPEG_FMT_FLAG_EXYNOS3250 |
84 SJPEG_FMT_NON_RGB,
85 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
86 },
87 {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030088 .name = "YUV 4:2:2 packed, YCrYCb",
89 .fourcc = V4L2_PIX_FMT_YVYU,
90 .depth = 16,
91 .colplanes = 1,
92 .h_align = 1,
93 .v_align = 0,
94 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
95 SJPEG_FMT_FLAG_DEC_CAPTURE |
96 SJPEG_FMT_FLAG_EXYNOS4 |
97 SJPEG_FMT_NON_RGB,
98 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
99 },
100 {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300101 .name = "YUV 4:2:2 packed, YCrYCb",
102 .fourcc = V4L2_PIX_FMT_YVYU,
103 .depth = 16,
104 .colplanes = 1,
105 .h_align = 2,
106 .v_align = 0,
107 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
108 SJPEG_FMT_FLAG_DEC_CAPTURE |
109 SJPEG_FMT_FLAG_EXYNOS3250 |
110 SJPEG_FMT_NON_RGB,
111 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
112 },
113 {
114 .name = "YUV 4:2:2 packed, YCrYCb",
115 .fourcc = V4L2_PIX_FMT_UYVY,
116 .depth = 16,
117 .colplanes = 1,
118 .h_align = 2,
119 .v_align = 0,
120 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
121 SJPEG_FMT_FLAG_DEC_CAPTURE |
122 SJPEG_FMT_FLAG_EXYNOS3250 |
123 SJPEG_FMT_NON_RGB,
124 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
125 },
126 {
127 .name = "YUV 4:2:2 packed, YCrYCb",
128 .fourcc = V4L2_PIX_FMT_VYUY,
129 .depth = 16,
130 .colplanes = 1,
131 .h_align = 2,
132 .v_align = 0,
133 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
134 SJPEG_FMT_FLAG_DEC_CAPTURE |
135 SJPEG_FMT_FLAG_EXYNOS3250 |
136 SJPEG_FMT_NON_RGB,
137 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
138 },
139 {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300140 .name = "RGB565",
141 .fourcc = V4L2_PIX_FMT_RGB565,
142 .depth = 16,
143 .colplanes = 1,
144 .h_align = 0,
145 .v_align = 0,
146 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
147 SJPEG_FMT_FLAG_DEC_CAPTURE |
148 SJPEG_FMT_FLAG_EXYNOS4 |
149 SJPEG_FMT_RGB,
150 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
151 },
152 {
153 .name = "RGB565",
154 .fourcc = V4L2_PIX_FMT_RGB565,
155 .depth = 16,
156 .colplanes = 1,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300157 .h_align = 2,
158 .v_align = 0,
159 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
160 SJPEG_FMT_FLAG_DEC_CAPTURE |
161 SJPEG_FMT_FLAG_EXYNOS3250 |
162 SJPEG_FMT_RGB,
163 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
164 },
165 {
166 .name = "RGB565X",
167 .fourcc = V4L2_PIX_FMT_RGB565X,
168 .depth = 16,
169 .colplanes = 1,
170 .h_align = 2,
171 .v_align = 0,
172 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
173 SJPEG_FMT_FLAG_DEC_CAPTURE |
174 SJPEG_FMT_FLAG_EXYNOS3250 |
175 SJPEG_FMT_RGB,
176 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
177 },
178 {
179 .name = "RGB565",
180 .fourcc = V4L2_PIX_FMT_RGB565,
181 .depth = 16,
182 .colplanes = 1,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300183 .h_align = 0,
184 .v_align = 0,
185 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
186 SJPEG_FMT_FLAG_S5P |
187 SJPEG_FMT_RGB,
188 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
189 },
190 {
191 .name = "ARGB8888, 32 bpp",
192 .fourcc = V4L2_PIX_FMT_RGB32,
193 .depth = 32,
194 .colplanes = 1,
195 .h_align = 0,
196 .v_align = 0,
197 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
198 SJPEG_FMT_FLAG_DEC_CAPTURE |
199 SJPEG_FMT_FLAG_EXYNOS4 |
200 SJPEG_FMT_RGB,
201 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
202 },
203 {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300204 .name = "ARGB8888, 32 bpp",
205 .fourcc = V4L2_PIX_FMT_RGB32,
206 .depth = 32,
207 .colplanes = 1,
208 .h_align = 2,
209 .v_align = 0,
210 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
211 SJPEG_FMT_FLAG_DEC_CAPTURE |
212 SJPEG_FMT_FLAG_EXYNOS3250 |
213 SJPEG_FMT_RGB,
214 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
215 },
216 {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300217 .name = "YUV 4:4:4 planar, Y/CbCr",
218 .fourcc = V4L2_PIX_FMT_NV24,
219 .depth = 24,
220 .colplanes = 2,
221 .h_align = 0,
222 .v_align = 0,
223 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
224 SJPEG_FMT_FLAG_DEC_CAPTURE |
225 SJPEG_FMT_FLAG_EXYNOS4 |
226 SJPEG_FMT_NON_RGB,
227 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
228 },
229 {
230 .name = "YUV 4:4:4 planar, Y/CrCb",
231 .fourcc = V4L2_PIX_FMT_NV42,
232 .depth = 24,
233 .colplanes = 2,
234 .h_align = 0,
235 .v_align = 0,
236 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
237 SJPEG_FMT_FLAG_DEC_CAPTURE |
238 SJPEG_FMT_FLAG_EXYNOS4 |
239 SJPEG_FMT_NON_RGB,
240 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
241 },
242 {
243 .name = "YUV 4:2:2 planar, Y/CrCb",
244 .fourcc = V4L2_PIX_FMT_NV61,
245 .depth = 16,
246 .colplanes = 2,
247 .h_align = 1,
248 .v_align = 0,
249 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
250 SJPEG_FMT_FLAG_DEC_CAPTURE |
251 SJPEG_FMT_FLAG_EXYNOS4 |
252 SJPEG_FMT_NON_RGB,
253 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
254 },
255 {
256 .name = "YUV 4:2:2 planar, Y/CbCr",
257 .fourcc = V4L2_PIX_FMT_NV16,
258 .depth = 16,
259 .colplanes = 2,
260 .h_align = 1,
261 .v_align = 0,
262 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
263 SJPEG_FMT_FLAG_DEC_CAPTURE |
264 SJPEG_FMT_FLAG_EXYNOS4 |
265 SJPEG_FMT_NON_RGB,
266 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
267 },
268 {
269 .name = "YUV 4:2:0 planar, Y/CbCr",
270 .fourcc = V4L2_PIX_FMT_NV12,
Jacek Anaszewskia62cffe2014-01-16 08:26:33 -0300271 .depth = 12,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300272 .colplanes = 2,
273 .h_align = 1,
274 .v_align = 1,
275 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
276 SJPEG_FMT_FLAG_DEC_CAPTURE |
277 SJPEG_FMT_FLAG_EXYNOS4 |
278 SJPEG_FMT_NON_RGB,
279 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
280 },
281 {
282 .name = "YUV 4:2:0 planar, Y/CbCr",
283 .fourcc = V4L2_PIX_FMT_NV12,
Jacek Anaszewskia62cffe2014-01-16 08:26:33 -0300284 .depth = 12,
285 .colplanes = 2,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300286 .h_align = 3,
287 .v_align = 3,
288 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
289 SJPEG_FMT_FLAG_DEC_CAPTURE |
290 SJPEG_FMT_FLAG_EXYNOS3250 |
291 SJPEG_FMT_NON_RGB,
292 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
293 },
294 {
295 .name = "YUV 4:2:0 planar, Y/CbCr",
296 .fourcc = V4L2_PIX_FMT_NV12,
297 .depth = 12,
298 .colplanes = 2,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300299 .h_align = 4,
Jacek Anaszewskia62cffe2014-01-16 08:26:33 -0300300 .v_align = 4,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300301 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
302 SJPEG_FMT_FLAG_DEC_CAPTURE |
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300303 SJPEG_FMT_FLAG_S5P |
304 SJPEG_FMT_NON_RGB,
305 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
306 },
307 {
308 .name = "YUV 4:2:0 planar, Y/CrCb",
309 .fourcc = V4L2_PIX_FMT_NV21,
310 .depth = 12,
311 .colplanes = 2,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300312 .h_align = 3,
313 .v_align = 3,
314 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
315 SJPEG_FMT_FLAG_DEC_CAPTURE |
316 SJPEG_FMT_FLAG_EXYNOS3250 |
317 SJPEG_FMT_NON_RGB,
318 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
319 },
320 {
321 .name = "YUV 4:2:0 planar, Y/CrCb",
322 .fourcc = V4L2_PIX_FMT_NV21,
323 .depth = 12,
324 .colplanes = 2,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300325 .h_align = 1,
326 .v_align = 1,
327 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
328 SJPEG_FMT_FLAG_DEC_CAPTURE |
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300329 SJPEG_FMT_FLAG_EXYNOS3250 |
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300330 SJPEG_FMT_FLAG_EXYNOS4 |
331 SJPEG_FMT_NON_RGB,
332 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
333 },
334 {
335 .name = "YUV 4:2:0 contiguous 3-planar, Y/Cb/Cr",
336 .fourcc = V4L2_PIX_FMT_YUV420,
337 .depth = 12,
338 .colplanes = 3,
339 .h_align = 1,
340 .v_align = 1,
341 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
342 SJPEG_FMT_FLAG_DEC_CAPTURE |
343 SJPEG_FMT_FLAG_EXYNOS4 |
344 SJPEG_FMT_NON_RGB,
345 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
346 },
347 {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300348 .name = "YUV 4:2:0 contiguous 3-planar, Y/Cb/Cr",
349 .fourcc = V4L2_PIX_FMT_YUV420,
350 .depth = 12,
351 .colplanes = 3,
352 .h_align = 4,
353 .v_align = 4,
354 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
355 SJPEG_FMT_FLAG_DEC_CAPTURE |
356 SJPEG_FMT_FLAG_EXYNOS3250 |
357 SJPEG_FMT_NON_RGB,
358 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
359 },
360 {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300361 .name = "Gray",
362 .fourcc = V4L2_PIX_FMT_GREY,
363 .depth = 8,
364 .colplanes = 1,
365 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
366 SJPEG_FMT_FLAG_DEC_CAPTURE |
367 SJPEG_FMT_FLAG_EXYNOS4 |
368 SJPEG_FMT_NON_RGB,
369 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300370 },
371};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300372#define SJPEG_NUM_FORMATS ARRAY_SIZE(sjpeg_formats)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300373
374static const unsigned char qtbl_luminance[4][64] = {
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300375 {/*level 0 - high compression quality */
376 20, 16, 25, 39, 50, 46, 62, 68,
377 16, 18, 23, 38, 38, 53, 65, 68,
378 25, 23, 31, 38, 53, 65, 68, 68,
379 39, 38, 38, 53, 65, 68, 68, 68,
380 50, 38, 53, 65, 68, 68, 68, 68,
381 46, 53, 65, 68, 68, 68, 68, 68,
382 62, 65, 68, 68, 68, 68, 68, 68,
383 68, 68, 68, 68, 68, 68, 68, 68
384 },
385 {/* level 1 */
386 16, 11, 11, 16, 23, 27, 31, 30,
387 11, 12, 12, 15, 20, 23, 23, 30,
388 11, 12, 13, 16, 23, 26, 35, 47,
389 16, 15, 16, 23, 26, 37, 47, 64,
390 23, 20, 23, 26, 39, 51, 64, 64,
391 27, 23, 26, 37, 51, 64, 64, 64,
392 31, 23, 35, 47, 64, 64, 64, 64,
393 30, 30, 47, 64, 64, 64, 64, 64
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300394 },
395 {/* level 2 */
396 12, 8, 8, 12, 17, 21, 24, 23,
397 8, 9, 9, 11, 15, 19, 18, 23,
398 8, 9, 10, 12, 19, 20, 27, 36,
399 12, 11, 12, 21, 20, 28, 36, 53,
400 17, 15, 19, 20, 30, 39, 51, 59,
401 21, 19, 20, 28, 39, 51, 59, 59,
402 24, 18, 27, 36, 51, 59, 59, 59,
403 23, 23, 36, 53, 59, 59, 59, 59
404 },
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300405 {/* level 3 - low compression quality */
406 8, 6, 6, 8, 12, 14, 16, 17,
407 6, 6, 6, 8, 10, 13, 12, 15,
408 6, 6, 7, 8, 13, 14, 18, 24,
409 8, 8, 8, 14, 13, 19, 24, 35,
410 12, 10, 13, 13, 20, 26, 34, 39,
411 14, 13, 14, 19, 26, 34, 39, 39,
412 16, 12, 18, 24, 34, 39, 39, 39,
413 17, 15, 24, 35, 39, 39, 39, 39
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300414 }
415};
416
417static const unsigned char qtbl_chrominance[4][64] = {
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300418 {/*level 0 - high compression quality */
419 21, 25, 32, 38, 54, 68, 68, 68,
420 25, 28, 24, 38, 54, 68, 68, 68,
421 32, 24, 32, 43, 66, 68, 68, 68,
422 38, 38, 43, 53, 68, 68, 68, 68,
423 54, 54, 66, 68, 68, 68, 68, 68,
424 68, 68, 68, 68, 68, 68, 68, 68,
425 68, 68, 68, 68, 68, 68, 68, 68,
426 68, 68, 68, 68, 68, 68, 68, 68
427 },
428 {/* level 1 */
429 17, 15, 17, 21, 20, 26, 38, 48,
430 15, 19, 18, 17, 20, 26, 35, 43,
431 17, 18, 20, 22, 26, 30, 46, 53,
432 21, 17, 22, 28, 30, 39, 53, 64,
433 20, 20, 26, 30, 39, 48, 64, 64,
434 26, 26, 30, 39, 48, 63, 64, 64,
435 38, 35, 46, 53, 64, 64, 64, 64,
436 48, 43, 53, 64, 64, 64, 64, 64
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300437 },
438 {/* level 2 */
439 13, 11, 13, 16, 20, 20, 29, 37,
440 11, 14, 14, 14, 16, 20, 26, 32,
441 13, 14, 15, 17, 20, 23, 35, 40,
442 16, 14, 17, 21, 23, 30, 40, 50,
443 20, 16, 20, 23, 30, 37, 50, 59,
444 20, 20, 23, 30, 37, 48, 59, 59,
445 29, 26, 35, 40, 50, 59, 59, 59,
446 37, 32, 40, 50, 59, 59, 59, 59
447 },
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300448 {/* level 3 - low compression quality */
449 9, 8, 9, 11, 14, 17, 19, 24,
450 8, 10, 9, 11, 14, 13, 17, 22,
451 9, 9, 13, 14, 13, 15, 23, 26,
452 11, 11, 14, 14, 15, 20, 26, 33,
453 14, 14, 13, 15, 20, 24, 33, 39,
454 17, 13, 15, 20, 24, 32, 39, 39,
455 19, 17, 23, 26, 33, 39, 39, 39,
456 24, 22, 26, 33, 39, 39, 39, 39
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300457 }
458};
459
460static const unsigned char hdctbl0[16] = {
461 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
462};
463
464static const unsigned char hdctblg0[12] = {
465 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb
466};
467static const unsigned char hactbl0[16] = {
468 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
469};
470static const unsigned char hactblg0[162] = {
471 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
472 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
473 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
474 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
475 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
476 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
477 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
478 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
479 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
480 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
481 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
482 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
483 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
484 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
485 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
486 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
487 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
488 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
489 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
490 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
491 0xf9, 0xfa
492};
493
Jacek Anaszewski337777a2013-11-22 06:13:34 -0300494/*
495 * Fourcc downgrade schema lookup tables for 422 and 420
496 * chroma subsampling - fourcc on each position maps on the
497 * fourcc from the table fourcc_to_dwngrd_schema_id which allows
498 * to get the most suitable fourcc counterpart for the given
499 * downgraded subsampling property.
500 */
501static const u32 subs422_fourcc_dwngrd_schema[] = {
502 V4L2_PIX_FMT_NV16,
503 V4L2_PIX_FMT_NV61,
504};
505
506static const u32 subs420_fourcc_dwngrd_schema[] = {
507 V4L2_PIX_FMT_NV12,
508 V4L2_PIX_FMT_NV21,
509 V4L2_PIX_FMT_NV12,
510 V4L2_PIX_FMT_NV21,
511 V4L2_PIX_FMT_NV12,
512 V4L2_PIX_FMT_NV21,
513 V4L2_PIX_FMT_GREY,
514 V4L2_PIX_FMT_GREY,
515 V4L2_PIX_FMT_GREY,
516 V4L2_PIX_FMT_GREY,
517};
518
519/*
520 * Lookup table for translation of a fourcc to the position
521 * of its downgraded counterpart in the *fourcc_dwngrd_schema
522 * tables.
523 */
524static const u32 fourcc_to_dwngrd_schema_id[] = {
525 V4L2_PIX_FMT_NV24,
526 V4L2_PIX_FMT_NV42,
527 V4L2_PIX_FMT_NV16,
528 V4L2_PIX_FMT_NV61,
529 V4L2_PIX_FMT_YUYV,
530 V4L2_PIX_FMT_YVYU,
531 V4L2_PIX_FMT_NV12,
532 V4L2_PIX_FMT_NV21,
533 V4L2_PIX_FMT_YUV420,
534 V4L2_PIX_FMT_GREY,
535};
536
537static int s5p_jpeg_get_dwngrd_sch_id_by_fourcc(u32 fourcc)
538{
539 int i;
540 for (i = 0; i < ARRAY_SIZE(fourcc_to_dwngrd_schema_id); ++i) {
541 if (fourcc_to_dwngrd_schema_id[i] == fourcc)
542 return i;
543 }
544
545 return -EINVAL;
546}
547
548static int s5p_jpeg_adjust_fourcc_to_subsampling(
549 enum v4l2_jpeg_chroma_subsampling subs,
550 u32 in_fourcc,
551 u32 *out_fourcc,
552 struct s5p_jpeg_ctx *ctx)
553{
554 int dwngrd_sch_id;
555
556 if (ctx->subsampling != V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY) {
557 dwngrd_sch_id =
558 s5p_jpeg_get_dwngrd_sch_id_by_fourcc(in_fourcc);
559 if (dwngrd_sch_id < 0)
560 return -EINVAL;
561 }
562
563 switch (ctx->subsampling) {
564 case V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY:
565 *out_fourcc = V4L2_PIX_FMT_GREY;
566 break;
567 case V4L2_JPEG_CHROMA_SUBSAMPLING_420:
568 if (dwngrd_sch_id >
569 ARRAY_SIZE(subs420_fourcc_dwngrd_schema) - 1)
570 return -EINVAL;
571 *out_fourcc = subs420_fourcc_dwngrd_schema[dwngrd_sch_id];
572 break;
573 case V4L2_JPEG_CHROMA_SUBSAMPLING_422:
574 if (dwngrd_sch_id >
575 ARRAY_SIZE(subs422_fourcc_dwngrd_schema) - 1)
576 return -EINVAL;
577 *out_fourcc = subs422_fourcc_dwngrd_schema[dwngrd_sch_id];
578 break;
579 default:
580 *out_fourcc = V4L2_PIX_FMT_GREY;
581 break;
582 }
583
584 return 0;
585}
586
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300587static int exynos4x12_decoded_subsampling[] = {
588 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
589 V4L2_JPEG_CHROMA_SUBSAMPLING_444,
590 V4L2_JPEG_CHROMA_SUBSAMPLING_422,
591 V4L2_JPEG_CHROMA_SUBSAMPLING_420,
592};
593
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300594static int exynos3250_decoded_subsampling[] = {
595 V4L2_JPEG_CHROMA_SUBSAMPLING_444,
596 V4L2_JPEG_CHROMA_SUBSAMPLING_422,
597 V4L2_JPEG_CHROMA_SUBSAMPLING_420,
598 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
599 -1,
600 -1,
601 V4L2_JPEG_CHROMA_SUBSAMPLING_411,
602};
603
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300604static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c)
605{
606 return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler);
607}
608
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300609static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh)
610{
611 return container_of(fh, struct s5p_jpeg_ctx, fh);
612}
613
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300614static int s5p_jpeg_to_user_subsampling(struct s5p_jpeg_ctx *ctx)
615{
616 WARN_ON(ctx->subsampling > 3);
617
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300618 switch (ctx->jpeg->variant->version) {
619 case SJPEG_S5P:
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300620 if (ctx->subsampling > 2)
621 return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
622 return ctx->subsampling;
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300623 case SJPEG_EXYNOS3250:
624 if (ctx->subsampling > 3)
625 return V4L2_JPEG_CHROMA_SUBSAMPLING_411;
626 return exynos3250_decoded_subsampling[ctx->subsampling];
627 case SJPEG_EXYNOS4:
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300628 if (ctx->subsampling > 2)
629 return V4L2_JPEG_CHROMA_SUBSAMPLING_420;
630 return exynos4x12_decoded_subsampling[ctx->subsampling];
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300631 default:
632 return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300633 }
634}
635
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300636static inline void s5p_jpeg_set_qtbl(void __iomem *regs,
637 const unsigned char *qtbl,
638 unsigned long tab, int len)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300639{
640 int i;
641
642 for (i = 0; i < len; i++)
643 writel((unsigned int)qtbl[i], regs + tab + (i * 0x04));
644}
645
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300646static inline void s5p_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300647{
648 /* this driver fills quantisation table 0 with data for luma */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300649 s5p_jpeg_set_qtbl(regs, qtbl_luminance[quality],
650 S5P_JPG_QTBL_CONTENT(0),
651 ARRAY_SIZE(qtbl_luminance[quality]));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300652}
653
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300654static inline void s5p_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300655{
656 /* this driver fills quantisation table 1 with data for chroma */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300657 s5p_jpeg_set_qtbl(regs, qtbl_chrominance[quality],
658 S5P_JPG_QTBL_CONTENT(1),
659 ARRAY_SIZE(qtbl_chrominance[quality]));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300660}
661
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300662static inline void s5p_jpeg_set_htbl(void __iomem *regs,
663 const unsigned char *htbl,
664 unsigned long tab, int len)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300665{
666 int i;
667
668 for (i = 0; i < len; i++)
669 writel((unsigned int)htbl[i], regs + tab + (i * 0x04));
670}
671
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300672static inline void s5p_jpeg_set_hdctbl(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300673{
674 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300675 s5p_jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0),
676 ARRAY_SIZE(hdctbl0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300677}
678
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300679static inline void s5p_jpeg_set_hdctblg(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300680{
681 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300682 s5p_jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0),
683 ARRAY_SIZE(hdctblg0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300684}
685
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300686static inline void s5p_jpeg_set_hactbl(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300687{
688 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300689 s5p_jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0),
690 ARRAY_SIZE(hactbl0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300691}
692
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300693static inline void s5p_jpeg_set_hactblg(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300694{
695 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300696 s5p_jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0),
697 ARRAY_SIZE(hactblg0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300698}
699
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300700static inline void exynos4_jpeg_set_tbl(void __iomem *regs,
701 const unsigned char *tbl,
702 unsigned long tab, int len)
703{
704 int i;
705 unsigned int dword;
706
707 for (i = 0; i < len; i += 4) {
708 dword = tbl[i] |
709 (tbl[i + 1] << 8) |
710 (tbl[i + 2] << 16) |
711 (tbl[i + 3] << 24);
712 writel(dword, regs + tab + i);
713 }
714}
715
716static inline void exynos4_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
717{
718 /* this driver fills quantisation table 0 with data for luma */
719 exynos4_jpeg_set_tbl(regs, qtbl_luminance[quality],
720 EXYNOS4_QTBL_CONTENT(0),
721 ARRAY_SIZE(qtbl_luminance[quality]));
722}
723
724static inline void exynos4_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
725{
726 /* this driver fills quantisation table 1 with data for chroma */
727 exynos4_jpeg_set_tbl(regs, qtbl_chrominance[quality],
728 EXYNOS4_QTBL_CONTENT(1),
729 ARRAY_SIZE(qtbl_chrominance[quality]));
730}
731
Mauro Carvalho Chehabaf425be2014-08-26 10:50:23 -0300732static void exynos4_jpeg_set_huff_tbl(void __iomem *base)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300733{
734 exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCLL,
735 ARRAY_SIZE(hdctbl0));
736 exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCCL,
737 ARRAY_SIZE(hdctbl0));
738 exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCLV,
739 ARRAY_SIZE(hdctblg0));
740 exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCCV,
741 ARRAY_SIZE(hdctblg0));
742 exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACLL,
743 ARRAY_SIZE(hactbl0));
744 exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACCL,
745 ARRAY_SIZE(hactbl0));
746 exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACLV,
747 ARRAY_SIZE(hactblg0));
748 exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACCV,
749 ARRAY_SIZE(hactblg0));
750}
751
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300752/*
753 * ============================================================================
754 * Device file operations
755 * ============================================================================
756 */
757
758static int queue_init(void *priv, struct vb2_queue *src_vq,
759 struct vb2_queue *dst_vq);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300760static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
761 __u32 pixelformat, unsigned int fmt_type);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300762static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300763
764static int s5p_jpeg_open(struct file *file)
765{
766 struct s5p_jpeg *jpeg = video_drvdata(file);
767 struct video_device *vfd = video_devdata(file);
768 struct s5p_jpeg_ctx *ctx;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300769 struct s5p_jpeg_fmt *out_fmt, *cap_fmt;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300770 int ret = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300771
Sachin Kamatb5146c92012-08-16 08:52:58 -0300772 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300773 if (!ctx)
774 return -ENOMEM;
775
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300776 if (mutex_lock_interruptible(&jpeg->lock)) {
777 ret = -ERESTARTSYS;
778 goto free;
779 }
780
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300781 v4l2_fh_init(&ctx->fh, vfd);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300782 /* Use separate control handler per file handle */
783 ctx->fh.ctrl_handler = &ctx->ctrl_handler;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300784 file->private_data = &ctx->fh;
785 v4l2_fh_add(&ctx->fh);
786
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300787 ctx->jpeg = jpeg;
788 if (vfd == jpeg->vfd_encoder) {
789 ctx->mode = S5P_JPEG_ENCODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300790 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB565,
791 FMT_TYPE_OUTPUT);
792 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
793 FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300794 } else {
795 ctx->mode = S5P_JPEG_DECODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300796 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
797 FMT_TYPE_OUTPUT);
798 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_YUYV,
799 FMT_TYPE_CAPTURE);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300800 ctx->scale_factor = EXYNOS3250_DEC_SCALE_FACTOR_8_8;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300801 }
802
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300803 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
804 if (IS_ERR(ctx->fh.m2m_ctx)) {
805 ret = PTR_ERR(ctx->fh.m2m_ctx);
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300806 goto error;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300807 }
808
809 ctx->out_q.fmt = out_fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300810 ctx->cap_q.fmt = cap_fmt;
811
812 ret = s5p_jpeg_controls_create(ctx);
813 if (ret < 0)
814 goto error;
815
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300816 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300817 return 0;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300818
819error:
820 v4l2_fh_del(&ctx->fh);
821 v4l2_fh_exit(&ctx->fh);
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300822 mutex_unlock(&jpeg->lock);
823free:
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300824 kfree(ctx);
825 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300826}
827
828static int s5p_jpeg_release(struct file *file)
829{
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300830 struct s5p_jpeg *jpeg = video_drvdata(file);
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300831 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300832
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300833 mutex_lock(&jpeg->lock);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300834 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300835 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300836 v4l2_fh_del(&ctx->fh);
837 v4l2_fh_exit(&ctx->fh);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300838 kfree(ctx);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300839 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300840
841 return 0;
842}
843
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300844static const struct v4l2_file_operations s5p_jpeg_fops = {
845 .owner = THIS_MODULE,
846 .open = s5p_jpeg_open,
847 .release = s5p_jpeg_release,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300848 .poll = v4l2_m2m_fop_poll,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300849 .unlocked_ioctl = video_ioctl2,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300850 .mmap = v4l2_m2m_fop_mmap,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300851};
852
853/*
854 * ============================================================================
855 * video ioctl operations
856 * ============================================================================
857 */
858
859static int get_byte(struct s5p_jpeg_buffer *buf)
860{
861 if (buf->curr >= buf->size)
862 return -1;
863
864 return ((unsigned char *)buf->data)[buf->curr++];
865}
866
867static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word)
868{
869 unsigned int temp;
870 int byte;
871
872 byte = get_byte(buf);
873 if (byte == -1)
874 return -1;
875 temp = byte << 8;
876 byte = get_byte(buf);
877 if (byte == -1)
878 return -1;
879 *word = (unsigned int)byte | temp;
880 return 0;
881}
882
883static void skip(struct s5p_jpeg_buffer *buf, long len)
884{
885 if (len <= 0)
886 return;
887
888 while (len--)
889 get_byte(buf);
890}
891
892static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300893 unsigned long buffer, unsigned long size,
894 struct s5p_jpeg_ctx *ctx)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300895{
Jacek Anaszewskif3d83a12014-10-10 05:46:49 -0300896 int c, components = 0, notfound;
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300897 unsigned int height, width, word, subsampling = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300898 long length;
899 struct s5p_jpeg_buffer jpeg_buffer;
900
901 jpeg_buffer.size = size;
902 jpeg_buffer.data = buffer;
903 jpeg_buffer.curr = 0;
904
905 notfound = 1;
906 while (notfound) {
907 c = get_byte(&jpeg_buffer);
908 if (c == -1)
Jacek Anaszewskia35f6002014-07-11 12:19:43 -0300909 return false;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300910 if (c != 0xff)
911 continue;
912 do
913 c = get_byte(&jpeg_buffer);
914 while (c == 0xff);
915 if (c == -1)
Jacek Anaszewskia35f6002014-07-11 12:19:43 -0300916 return false;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300917 if (c == 0)
918 continue;
919 length = 0;
920 switch (c) {
921 /* SOF0: baseline JPEG */
922 case SOF0:
923 if (get_word_be(&jpeg_buffer, &word))
924 break;
925 if (get_byte(&jpeg_buffer) == -1)
926 break;
927 if (get_word_be(&jpeg_buffer, &height))
928 break;
929 if (get_word_be(&jpeg_buffer, &width))
930 break;
931 components = get_byte(&jpeg_buffer);
932 if (components == -1)
933 break;
934 notfound = 0;
935
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300936 if (components == 1) {
937 subsampling = 0x33;
938 } else {
939 skip(&jpeg_buffer, 1);
940 subsampling = get_byte(&jpeg_buffer);
941 skip(&jpeg_buffer, 1);
942 }
943
944 skip(&jpeg_buffer, components * 2);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300945 break;
946
947 /* skip payload-less markers */
948 case RST ... RST + 7:
949 case SOI:
950 case EOI:
951 case TEM:
952 break;
953
954 /* skip uninteresting payload markers */
955 default:
956 if (get_word_be(&jpeg_buffer, &word))
957 break;
958 length = (long)word - 2;
959 skip(&jpeg_buffer, length);
960 break;
961 }
962 }
963 result->w = width;
964 result->h = height;
965 result->size = components;
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300966
967 switch (subsampling) {
968 case 0x11:
969 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444;
970 break;
971 case 0x21:
972 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422;
973 break;
974 case 0x22:
975 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420;
976 break;
977 case 0x33:
978 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
979 break;
980 default:
981 return false;
982 }
983
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300984 return !notfound;
985}
986
987static int s5p_jpeg_querycap(struct file *file, void *priv,
988 struct v4l2_capability *cap)
989{
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300990 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300991
992 if (ctx->mode == S5P_JPEG_ENCODE) {
993 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder",
994 sizeof(cap->driver));
995 strlcpy(cap->card, S5P_JPEG_M2M_NAME " encoder",
996 sizeof(cap->card));
997 } else {
998 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " decoder",
999 sizeof(cap->driver));
1000 strlcpy(cap->card, S5P_JPEG_M2M_NAME " decoder",
1001 sizeof(cap->card));
1002 }
1003 cap->bus_info[0] = 0;
Sylwester Nawrockif0476a82012-07-26 09:30:00 -03001004 /*
1005 * This is only a mem-to-mem video device. The capture and output
1006 * device capability flags are left only for backward compatibility
1007 * and are scheduled for removal.
1008 */
1009 cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M |
1010 V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001011 return 0;
1012}
1013
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001014static int enum_fmt(struct s5p_jpeg_fmt *sjpeg_formats, int n,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001015 struct v4l2_fmtdesc *f, u32 type)
1016{
1017 int i, num = 0;
1018
1019 for (i = 0; i < n; ++i) {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001020 if (sjpeg_formats[i].flags & type) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001021 /* index-th format of type type found ? */
1022 if (num == f->index)
1023 break;
1024 /* Correct type but haven't reached our index yet,
1025 * just increment per-type index */
1026 ++num;
1027 }
1028 }
1029
1030 /* Format not found */
1031 if (i >= n)
1032 return -EINVAL;
1033
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001034 strlcpy(f->description, sjpeg_formats[i].name, sizeof(f->description));
1035 f->pixelformat = sjpeg_formats[i].fourcc;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001036
1037 return 0;
1038}
1039
1040static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
1041 struct v4l2_fmtdesc *f)
1042{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001043 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001044
1045 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001046 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1047 SJPEG_FMT_FLAG_ENC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001048
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001049 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1050 SJPEG_FMT_FLAG_DEC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001051}
1052
1053static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
1054 struct v4l2_fmtdesc *f)
1055{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001056 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001057
1058 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001059 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1060 SJPEG_FMT_FLAG_ENC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001061
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001062 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1063 SJPEG_FMT_FLAG_DEC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001064}
1065
1066static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx,
1067 enum v4l2_buf_type type)
1068{
1069 if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1070 return &ctx->out_q;
1071 if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1072 return &ctx->cap_q;
1073
1074 return NULL;
1075}
1076
1077static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
1078{
1079 struct vb2_queue *vq;
1080 struct s5p_jpeg_q_data *q_data = NULL;
1081 struct v4l2_pix_format *pix = &f->fmt.pix;
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001082 struct s5p_jpeg_ctx *ct = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001083
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001084 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001085 if (!vq)
1086 return -EINVAL;
1087
1088 if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
1089 ct->mode == S5P_JPEG_DECODE && !ct->hdr_parsed)
1090 return -EINVAL;
1091 q_data = get_q_data(ct, f->type);
1092 BUG_ON(q_data == NULL);
1093
1094 pix->width = q_data->w;
1095 pix->height = q_data->h;
1096 pix->field = V4L2_FIELD_NONE;
1097 pix->pixelformat = q_data->fmt->fourcc;
1098 pix->bytesperline = 0;
1099 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
1100 u32 bpl = q_data->w;
1101 if (q_data->fmt->colplanes == 1)
1102 bpl = (bpl * q_data->fmt->depth) >> 3;
1103 pix->bytesperline = bpl;
1104 }
1105 pix->sizeimage = q_data->size;
1106
1107 return 0;
1108}
1109
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001110static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
1111 u32 pixelformat, unsigned int fmt_type)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001112{
Jacek Anaszewskib2451682014-04-10 04:32:11 -03001113 unsigned int k, fmt_flag;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001114
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001115 if (ctx->mode == S5P_JPEG_ENCODE)
1116 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
1117 SJPEG_FMT_FLAG_ENC_OUTPUT :
1118 SJPEG_FMT_FLAG_ENC_CAPTURE;
1119 else
1120 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
1121 SJPEG_FMT_FLAG_DEC_OUTPUT :
1122 SJPEG_FMT_FLAG_DEC_CAPTURE;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001123
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001124 for (k = 0; k < ARRAY_SIZE(sjpeg_formats); k++) {
1125 struct s5p_jpeg_fmt *fmt = &sjpeg_formats[k];
1126 if (fmt->fourcc == pixelformat &&
1127 fmt->flags & fmt_flag &&
Jacek Anaszewskib2451682014-04-10 04:32:11 -03001128 fmt->flags & ctx->jpeg->variant->fmt_ver_flag) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001129 return fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001130 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001131 }
1132
1133 return NULL;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001134}
1135
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001136static void jpeg_bound_align_image(struct s5p_jpeg_ctx *ctx,
1137 u32 *w, unsigned int wmin, unsigned int wmax,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001138 unsigned int walign,
1139 u32 *h, unsigned int hmin, unsigned int hmax,
1140 unsigned int halign)
1141{
1142 int width, height, w_step, h_step;
1143
1144 width = *w;
1145 height = *h;
1146
1147 w_step = 1 << walign;
1148 h_step = 1 << halign;
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001149
1150 if (ctx->jpeg->variant->version == SJPEG_EXYNOS3250) {
1151 /*
1152 * Rightmost and bottommost pixels are cropped by the
1153 * Exynos3250 JPEG IP for RGB formats, for the specific
1154 * width and height values respectively. This assignment
1155 * will result in v4l_bound_align_image returning dimensions
1156 * reduced by 1 for the aforementioned cases.
1157 */
1158 if (w_step == 4 && ((width & 3) == 1)) {
1159 wmax = width;
1160 hmax = height;
1161 }
1162 }
1163
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001164 v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
1165
1166 if (*w < width && (*w + w_step) < wmax)
1167 *w += w_step;
1168 if (*h < height && (*h + h_step) < hmax)
1169 *h += h_step;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001170}
1171
1172static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
1173 struct s5p_jpeg_ctx *ctx, int q_type)
1174{
1175 struct v4l2_pix_format *pix = &f->fmt.pix;
1176
1177 if (pix->field == V4L2_FIELD_ANY)
1178 pix->field = V4L2_FIELD_NONE;
1179 else if (pix->field != V4L2_FIELD_NONE)
1180 return -EINVAL;
1181
1182 /* V4L2 specification suggests the driver corrects the format struct
1183 * if any of the dimensions is unsupported */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001184 if (q_type == FMT_TYPE_OUTPUT)
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001185 jpeg_bound_align_image(ctx, &pix->width, S5P_JPEG_MIN_WIDTH,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001186 S5P_JPEG_MAX_WIDTH, 0,
1187 &pix->height, S5P_JPEG_MIN_HEIGHT,
1188 S5P_JPEG_MAX_HEIGHT, 0);
1189 else
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001190 jpeg_bound_align_image(ctx, &pix->width, S5P_JPEG_MIN_WIDTH,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001191 S5P_JPEG_MAX_WIDTH, fmt->h_align,
1192 &pix->height, S5P_JPEG_MIN_HEIGHT,
1193 S5P_JPEG_MAX_HEIGHT, fmt->v_align);
1194
1195 if (fmt->fourcc == V4L2_PIX_FMT_JPEG) {
1196 if (pix->sizeimage <= 0)
1197 pix->sizeimage = PAGE_SIZE;
1198 pix->bytesperline = 0;
1199 } else {
1200 u32 bpl = pix->bytesperline;
1201
1202 if (fmt->colplanes > 1 && bpl < pix->width)
1203 bpl = pix->width; /* planar */
1204
1205 if (fmt->colplanes == 1 && /* packed */
Jacek Anaszewskicc690902013-11-25 06:58:10 -03001206 (bpl << 3) / fmt->depth < pix->width)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001207 bpl = (pix->width * fmt->depth) >> 3;
1208
1209 pix->bytesperline = bpl;
1210 pix->sizeimage = (pix->width * pix->height * fmt->depth) >> 3;
1211 }
1212
1213 return 0;
1214}
1215
1216static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
1217 struct v4l2_format *f)
1218{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001219 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001220 struct v4l2_pix_format *pix = &f->fmt.pix;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001221 struct s5p_jpeg_fmt *fmt;
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001222 int ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001223
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001224 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
1225 FMT_TYPE_CAPTURE);
1226 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001227 v4l2_err(&ctx->jpeg->v4l2_dev,
1228 "Fourcc format (0x%08x) invalid.\n",
1229 f->fmt.pix.pixelformat);
1230 return -EINVAL;
1231 }
1232
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001233 if ((ctx->jpeg->variant->version != SJPEG_EXYNOS4) ||
1234 (ctx->mode != S5P_JPEG_DECODE))
1235 goto exit;
1236
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001237 /*
1238 * The exynos4x12 device requires resulting YUV image
1239 * subsampling not to be lower than the input jpeg subsampling.
1240 * If this requirement is not met then downgrade the requested
1241 * capture format to the one with subsampling equal to the input jpeg.
1242 */
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001243 if ((fmt->flags & SJPEG_FMT_NON_RGB) &&
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001244 (fmt->subsampling < ctx->subsampling)) {
1245 ret = s5p_jpeg_adjust_fourcc_to_subsampling(ctx->subsampling,
1246 fmt->fourcc,
1247 &pix->pixelformat,
1248 ctx);
1249 if (ret < 0)
1250 pix->pixelformat = V4L2_PIX_FMT_GREY;
1251
1252 fmt = s5p_jpeg_find_format(ctx, pix->pixelformat,
1253 FMT_TYPE_CAPTURE);
1254 }
1255
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001256 /*
1257 * Decompression of a JPEG file with 4:2:0 subsampling and odd
1258 * width to the YUV 4:2:0 compliant formats produces a raw image
1259 * with broken luma component. Adjust capture format to RGB565
1260 * in such a case.
1261 */
1262 if (ctx->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_420 &&
1263 (ctx->out_q.w & 1) &&
1264 (pix->pixelformat == V4L2_PIX_FMT_NV12 ||
1265 pix->pixelformat == V4L2_PIX_FMT_NV21 ||
1266 pix->pixelformat == V4L2_PIX_FMT_YUV420)) {
1267 pix->pixelformat = V4L2_PIX_FMT_RGB565;
1268 fmt = s5p_jpeg_find_format(ctx, pix->pixelformat,
1269 FMT_TYPE_CAPTURE);
1270 }
1271
1272exit:
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001273 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001274}
1275
1276static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
1277 struct v4l2_format *f)
1278{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001279 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001280 struct s5p_jpeg_fmt *fmt;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001281
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001282 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
1283 FMT_TYPE_OUTPUT);
1284 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001285 v4l2_err(&ctx->jpeg->v4l2_dev,
1286 "Fourcc format (0x%08x) invalid.\n",
1287 f->fmt.pix.pixelformat);
1288 return -EINVAL;
1289 }
1290
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001291 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001292}
1293
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001294static int exynos4_jpeg_get_output_buffer_size(struct s5p_jpeg_ctx *ctx,
1295 struct v4l2_format *f,
1296 int fmt_depth)
1297{
1298 struct v4l2_pix_format *pix = &f->fmt.pix;
1299 u32 pix_fmt = f->fmt.pix.pixelformat;
1300 int w = pix->width, h = pix->height, wh_align;
1301
1302 if (pix_fmt == V4L2_PIX_FMT_RGB32 ||
1303 pix_fmt == V4L2_PIX_FMT_NV24 ||
1304 pix_fmt == V4L2_PIX_FMT_NV42 ||
1305 pix_fmt == V4L2_PIX_FMT_NV12 ||
1306 pix_fmt == V4L2_PIX_FMT_NV21 ||
1307 pix_fmt == V4L2_PIX_FMT_YUV420)
1308 wh_align = 4;
1309 else
1310 wh_align = 1;
1311
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001312 jpeg_bound_align_image(ctx, &w, S5P_JPEG_MIN_WIDTH,
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001313 S5P_JPEG_MAX_WIDTH, wh_align,
1314 &h, S5P_JPEG_MIN_HEIGHT,
1315 S5P_JPEG_MAX_HEIGHT, wh_align);
1316
1317 return w * h * fmt_depth >> 3;
1318}
1319
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001320static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx,
1321 struct v4l2_rect *r);
1322
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001323static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
1324{
1325 struct vb2_queue *vq;
1326 struct s5p_jpeg_q_data *q_data = NULL;
1327 struct v4l2_pix_format *pix = &f->fmt.pix;
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001328 struct v4l2_ctrl *ctrl_subs;
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001329 struct v4l2_rect scale_rect;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001330 unsigned int f_type;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001331
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001332 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001333 if (!vq)
1334 return -EINVAL;
1335
1336 q_data = get_q_data(ct, f->type);
1337 BUG_ON(q_data == NULL);
1338
1339 if (vb2_is_busy(vq)) {
1340 v4l2_err(&ct->jpeg->v4l2_dev, "%s queue busy\n", __func__);
1341 return -EBUSY;
1342 }
1343
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001344 f_type = V4L2_TYPE_IS_OUTPUT(f->type) ?
1345 FMT_TYPE_OUTPUT : FMT_TYPE_CAPTURE;
1346
1347 q_data->fmt = s5p_jpeg_find_format(ct, pix->pixelformat, f_type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001348 q_data->w = pix->width;
1349 q_data->h = pix->height;
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001350 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
1351 /*
1352 * During encoding Exynos4x12 SoCs access wider memory area
1353 * than it results from Image_x and Image_y values written to
1354 * the JPEG_IMAGE_SIZE register. In order to avoid sysmmu
1355 * page fault calculate proper buffer size in such a case.
1356 */
1357 if (ct->jpeg->variant->version == SJPEG_EXYNOS4 &&
1358 f_type == FMT_TYPE_OUTPUT && ct->mode == S5P_JPEG_ENCODE)
1359 q_data->size = exynos4_jpeg_get_output_buffer_size(ct,
1360 f,
1361 q_data->fmt->depth);
1362 else
1363 q_data->size = q_data->w * q_data->h *
1364 q_data->fmt->depth >> 3;
1365 } else {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001366 q_data->size = pix->sizeimage;
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001367 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001368
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001369 if (f_type == FMT_TYPE_OUTPUT) {
1370 ctrl_subs = v4l2_ctrl_find(&ct->ctrl_handler,
1371 V4L2_CID_JPEG_CHROMA_SUBSAMPLING);
1372 if (ctrl_subs)
1373 v4l2_ctrl_s_ctrl(ctrl_subs, q_data->fmt->subsampling);
Jacek Anaszewskidfd96902014-07-11 12:19:46 -03001374 ct->crop_altered = false;
1375 }
1376
1377 /*
1378 * For decoding init crop_rect with capture buffer dimmensions which
1379 * contain aligned dimensions of the input JPEG image and do it only
1380 * if crop rectangle hasn't been altered by the user space e.g. with
1381 * S_SELECTION ioctl. For encoding assign output buffer dimensions.
1382 */
1383 if (!ct->crop_altered &&
1384 ((ct->mode == S5P_JPEG_DECODE && f_type == FMT_TYPE_CAPTURE) ||
1385 (ct->mode == S5P_JPEG_ENCODE && f_type == FMT_TYPE_OUTPUT))) {
1386 ct->crop_rect.width = pix->width;
1387 ct->crop_rect.height = pix->height;
1388 }
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001389
1390 /*
1391 * Prevent downscaling to YUV420 format by more than 2
1392 * for Exynos3250 SoC as it produces broken raw image
1393 * in such cases.
1394 */
1395 if (ct->mode == S5P_JPEG_DECODE &&
1396 f_type == FMT_TYPE_CAPTURE &&
1397 ct->jpeg->variant->version == SJPEG_EXYNOS3250 &&
1398 pix->pixelformat == V4L2_PIX_FMT_YUV420 &&
1399 ct->scale_factor > 2) {
1400 scale_rect.width = ct->out_q.w / 2;
1401 scale_rect.height = ct->out_q.h / 2;
1402 exynos3250_jpeg_try_downscale(ct, &scale_rect);
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001403 }
1404
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001405 return 0;
1406}
1407
1408static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
1409 struct v4l2_format *f)
1410{
1411 int ret;
1412
1413 ret = s5p_jpeg_try_fmt_vid_cap(file, priv, f);
1414 if (ret)
1415 return ret;
1416
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001417 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001418}
1419
1420static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
1421 struct v4l2_format *f)
1422{
1423 int ret;
1424
1425 ret = s5p_jpeg_try_fmt_vid_out(file, priv, f);
1426 if (ret)
1427 return ret;
1428
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001429 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001430}
1431
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001432static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx,
1433 struct v4l2_rect *r)
1434{
1435 int w_ratio, h_ratio, scale_factor, cur_ratio, i;
1436
1437 w_ratio = ctx->out_q.w / r->width;
1438 h_ratio = ctx->out_q.h / r->height;
1439
1440 scale_factor = w_ratio > h_ratio ? w_ratio : h_ratio;
1441 scale_factor = clamp_val(scale_factor, 1, 8);
1442
1443 /* Align scale ratio to the nearest power of 2 */
1444 for (i = 0; i <= 3; ++i) {
1445 cur_ratio = 1 << i;
1446 if (scale_factor <= cur_ratio) {
1447 ctx->scale_factor = cur_ratio;
1448 break;
1449 }
1450 }
1451
1452 r->width = round_down(ctx->out_q.w / ctx->scale_factor, 2);
1453 r->height = round_down(ctx->out_q.h / ctx->scale_factor, 2);
1454
1455 ctx->crop_rect.width = r->width;
1456 ctx->crop_rect.height = r->height;
1457 ctx->crop_rect.left = 0;
1458 ctx->crop_rect.top = 0;
1459
1460 ctx->crop_altered = true;
1461
1462 return 0;
1463}
1464
1465/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */
1466static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
1467{
1468 if (a->left < b->left || a->top < b->top)
1469 return 0;
1470 if (a->left + a->width > b->left + b->width)
1471 return 0;
1472 if (a->top + a->height > b->top + b->height)
1473 return 0;
1474
1475 return 1;
1476}
1477
1478static int exynos3250_jpeg_try_crop(struct s5p_jpeg_ctx *ctx,
1479 struct v4l2_rect *r)
1480{
1481 struct v4l2_rect base_rect;
1482 int w_step, h_step;
1483
1484 switch (ctx->cap_q.fmt->fourcc) {
1485 case V4L2_PIX_FMT_NV12:
1486 case V4L2_PIX_FMT_NV21:
1487 w_step = 1;
1488 h_step = 2;
1489 break;
1490 case V4L2_PIX_FMT_YUV420:
1491 w_step = 2;
1492 h_step = 2;
1493 break;
1494 default:
1495 w_step = 1;
1496 h_step = 1;
1497 break;
1498 }
1499
1500 base_rect.top = 0;
1501 base_rect.left = 0;
1502 base_rect.width = ctx->out_q.w;
1503 base_rect.height = ctx->out_q.h;
1504
1505 r->width = round_down(r->width, w_step);
1506 r->height = round_down(r->height, h_step);
1507 r->left = round_down(r->left, 2);
1508 r->top = round_down(r->top, 2);
1509
1510 if (!enclosed_rectangle(r, &base_rect))
1511 return -EINVAL;
1512
1513 ctx->crop_rect.left = r->left;
1514 ctx->crop_rect.top = r->top;
1515 ctx->crop_rect.width = r->width;
1516 ctx->crop_rect.height = r->height;
1517
1518 ctx->crop_altered = true;
1519
1520 return 0;
1521}
1522
1523/*
1524 * V4L2 controls
1525 */
1526
Sachin Kamat9f3bd322012-05-10 03:38:40 -03001527static int s5p_jpeg_g_selection(struct file *file, void *priv,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001528 struct v4l2_selection *s)
1529{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001530 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001531
1532 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
Jacek Anaszewski38a6ef32014-04-10 04:32:15 -03001533 s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001534 return -EINVAL;
1535
1536 /* For JPEG blob active == default == bounds */
1537 switch (s->target) {
Sylwester Nawrockic1334822012-05-20 11:17:12 -03001538 case V4L2_SEL_TGT_CROP:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001539 case V4L2_SEL_TGT_CROP_BOUNDS:
1540 case V4L2_SEL_TGT_CROP_DEFAULT:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001541 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
1542 s->r.width = ctx->out_q.w;
1543 s->r.height = ctx->out_q.h;
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001544 s->r.left = 0;
1545 s->r.top = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001546 break;
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001547 case V4L2_SEL_TGT_COMPOSE:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001548 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
1549 case V4L2_SEL_TGT_COMPOSE_PADDED:
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001550 s->r.width = ctx->crop_rect.width;
1551 s->r.height = ctx->crop_rect.height;
1552 s->r.left = ctx->crop_rect.left;
1553 s->r.top = ctx->crop_rect.top;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001554 break;
1555 default:
1556 return -EINVAL;
1557 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001558 return 0;
1559}
1560
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001561/*
1562 * V4L2 controls
1563 */
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001564static int s5p_jpeg_s_selection(struct file *file, void *fh,
1565 struct v4l2_selection *s)
1566{
1567 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
1568 struct v4l2_rect *rect = &s->r;
1569 int ret = -EINVAL;
1570
1571 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1572 return -EINVAL;
1573
1574 if (s->target == V4L2_SEL_TGT_COMPOSE) {
1575 if (ctx->mode != S5P_JPEG_DECODE)
1576 return -EINVAL;
1577 if (ctx->jpeg->variant->version == SJPEG_EXYNOS3250)
1578 ret = exynos3250_jpeg_try_downscale(ctx, rect);
1579 } else if (s->target == V4L2_SEL_TGT_CROP) {
1580 if (ctx->mode != S5P_JPEG_ENCODE)
1581 return -EINVAL;
1582 if (ctx->jpeg->variant->version == SJPEG_EXYNOS3250)
1583 ret = exynos3250_jpeg_try_crop(ctx, rect);
1584 }
1585
1586 return ret;
1587}
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001588
1589static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001590{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001591 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1592 struct s5p_jpeg *jpeg = ctx->jpeg;
1593 unsigned long flags;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001594
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001595 switch (ctrl->id) {
1596 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1597 spin_lock_irqsave(&jpeg->slock, flags);
Jacek Anaszewski303b0a92013-12-18 11:14:00 -03001598 ctrl->val = s5p_jpeg_to_user_subsampling(ctx);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001599 spin_unlock_irqrestore(&jpeg->slock, flags);
1600 break;
1601 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001602
1603 return 0;
1604}
1605
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001606static int s5p_jpeg_adjust_subs_ctrl(struct s5p_jpeg_ctx *ctx, int *ctrl_val)
1607{
1608 switch (ctx->jpeg->variant->version) {
1609 case SJPEG_S5P:
1610 return 0;
1611 case SJPEG_EXYNOS3250:
1612 /*
1613 * The exynos3250 device can produce JPEG image only
1614 * of 4:4:4 subsampling when given RGB32 source image.
1615 */
1616 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB32)
1617 *ctrl_val = 0;
1618 break;
1619 case SJPEG_EXYNOS4:
1620 /*
1621 * The exynos4x12 device requires input raw image fourcc
1622 * to be V4L2_PIX_FMT_GREY if gray jpeg format
1623 * is to be set.
1624 */
1625 if (ctx->out_q.fmt->fourcc != V4L2_PIX_FMT_GREY &&
1626 *ctrl_val == V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY)
1627 return -EINVAL;
1628 break;
1629 }
1630
1631 /*
1632 * The exynos4x12 and exynos3250 devices require resulting
1633 * jpeg subsampling not to be lower than the input raw image
1634 * subsampling.
1635 */
1636 if (ctx->out_q.fmt->subsampling > *ctrl_val)
1637 *ctrl_val = ctx->out_q.fmt->subsampling;
1638
1639 return 0;
1640}
1641
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001642static int s5p_jpeg_try_ctrl(struct v4l2_ctrl *ctrl)
1643{
1644 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1645 unsigned long flags;
1646 int ret = 0;
1647
1648 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1649
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001650 if (ctrl->id == V4L2_CID_JPEG_CHROMA_SUBSAMPLING)
1651 ret = s5p_jpeg_adjust_subs_ctrl(ctx, &ctrl->val);
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001652
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001653 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1654 return ret;
1655}
1656
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001657static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001658{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001659 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1660 unsigned long flags;
1661
1662 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1663
1664 switch (ctrl->id) {
1665 case V4L2_CID_JPEG_COMPRESSION_QUALITY:
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001666 ctx->compr_quality = ctrl->val;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001667 break;
1668 case V4L2_CID_JPEG_RESTART_INTERVAL:
1669 ctx->restart_interval = ctrl->val;
1670 break;
1671 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1672 ctx->subsampling = ctrl->val;
1673 break;
1674 }
1675
1676 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1677 return 0;
1678}
1679
1680static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
1681 .g_volatile_ctrl = s5p_jpeg_g_volatile_ctrl,
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001682 .try_ctrl = s5p_jpeg_try_ctrl,
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001683 .s_ctrl = s5p_jpeg_s_ctrl,
1684};
1685
1686static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
1687{
1688 unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */
1689 struct v4l2_ctrl *ctrl;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001690 int ret;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001691
1692 v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
1693
1694 if (ctx->mode == S5P_JPEG_ENCODE) {
1695 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1696 V4L2_CID_JPEG_COMPRESSION_QUALITY,
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001697 0, 3, 1, S5P_JPEG_COMPR_QUAL_WORST);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001698
1699 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1700 V4L2_CID_JPEG_RESTART_INTERVAL,
1701 0, 3, 0xffff, 0);
Jacek Anaszewskifdf9e2b2013-11-21 13:33:41 -03001702 if (ctx->jpeg->variant->version == SJPEG_S5P)
1703 mask = ~0x06; /* 422, 420 */
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001704 }
1705
1706 ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1707 V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
1708 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask,
1709 V4L2_JPEG_CHROMA_SUBSAMPLING_422);
1710
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001711 if (ctx->ctrl_handler.error) {
1712 ret = ctx->ctrl_handler.error;
1713 goto error_free;
1714 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001715
1716 if (ctx->mode == S5P_JPEG_DECODE)
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001717 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
1718 V4L2_CTRL_FLAG_READ_ONLY;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001719
1720 ret = v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
1721 if (ret < 0)
1722 goto error_free;
1723
1724 return ret;
1725
1726error_free:
1727 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
1728 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001729}
1730
1731static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
1732 .vidioc_querycap = s5p_jpeg_querycap,
1733
1734 .vidioc_enum_fmt_vid_cap = s5p_jpeg_enum_fmt_vid_cap,
1735 .vidioc_enum_fmt_vid_out = s5p_jpeg_enum_fmt_vid_out,
1736
1737 .vidioc_g_fmt_vid_cap = s5p_jpeg_g_fmt,
1738 .vidioc_g_fmt_vid_out = s5p_jpeg_g_fmt,
1739
1740 .vidioc_try_fmt_vid_cap = s5p_jpeg_try_fmt_vid_cap,
1741 .vidioc_try_fmt_vid_out = s5p_jpeg_try_fmt_vid_out,
1742
1743 .vidioc_s_fmt_vid_cap = s5p_jpeg_s_fmt_vid_cap,
1744 .vidioc_s_fmt_vid_out = s5p_jpeg_s_fmt_vid_out,
1745
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001746 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
1747 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
1748 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
1749 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001750
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001751 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
1752 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001753
1754 .vidioc_g_selection = s5p_jpeg_g_selection,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001755 .vidioc_s_selection = s5p_jpeg_s_selection,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001756};
1757
1758/*
1759 * ============================================================================
1760 * mem2mem callbacks
1761 * ============================================================================
1762 */
1763
1764static void s5p_jpeg_device_run(void *priv)
1765{
1766 struct s5p_jpeg_ctx *ctx = priv;
1767 struct s5p_jpeg *jpeg = ctx->jpeg;
1768 struct vb2_buffer *src_buf, *dst_buf;
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001769 unsigned long src_addr, dst_addr, flags;
1770
1771 spin_lock_irqsave(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001772
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001773 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1774 dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001775 src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
1776 dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
1777
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001778 s5p_jpeg_reset(jpeg->regs);
1779 s5p_jpeg_poweron(jpeg->regs);
1780 s5p_jpeg_proc_mode(jpeg->regs, ctx->mode);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001781 if (ctx->mode == S5P_JPEG_ENCODE) {
1782 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001783 s5p_jpeg_input_raw_mode(jpeg->regs,
1784 S5P_JPEG_RAW_IN_565);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001785 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001786 s5p_jpeg_input_raw_mode(jpeg->regs,
1787 S5P_JPEG_RAW_IN_422);
1788 s5p_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
1789 s5p_jpeg_dri(jpeg->regs, ctx->restart_interval);
1790 s5p_jpeg_x(jpeg->regs, ctx->out_q.w);
1791 s5p_jpeg_y(jpeg->regs, ctx->out_q.h);
1792 s5p_jpeg_imgadr(jpeg->regs, src_addr);
1793 s5p_jpeg_jpgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001794
1795 /* ultimately comes from sizeimage from userspace */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001796 s5p_jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001797
1798 /* JPEG RGB to YCbCr conversion matrix */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001799 s5p_jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11);
1800 s5p_jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12);
1801 s5p_jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13);
1802 s5p_jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21);
1803 s5p_jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22);
1804 s5p_jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23);
1805 s5p_jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31);
1806 s5p_jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32);
1807 s5p_jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001808
1809 /*
1810 * JPEG IP allows storing 4 quantization tables
1811 * We fill table 0 for luma and table 1 for chroma
1812 */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03001813 s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
1814 s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001815 /* use table 0 for Y */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001816 s5p_jpeg_qtbl(jpeg->regs, 1, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001817 /* use table 1 for Cb and Cr*/
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001818 s5p_jpeg_qtbl(jpeg->regs, 2, 1);
1819 s5p_jpeg_qtbl(jpeg->regs, 3, 1);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001820
1821 /* Y, Cb, Cr use Huffman table 0 */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001822 s5p_jpeg_htbl_ac(jpeg->regs, 1);
1823 s5p_jpeg_htbl_dc(jpeg->regs, 1);
1824 s5p_jpeg_htbl_ac(jpeg->regs, 2);
1825 s5p_jpeg_htbl_dc(jpeg->regs, 2);
1826 s5p_jpeg_htbl_ac(jpeg->regs, 3);
1827 s5p_jpeg_htbl_dc(jpeg->regs, 3);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001828 } else { /* S5P_JPEG_DECODE */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001829 s5p_jpeg_rst_int_enable(jpeg->regs, true);
1830 s5p_jpeg_data_num_int_enable(jpeg->regs, true);
1831 s5p_jpeg_final_mcu_num_int_enable(jpeg->regs, true);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001832 if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001833 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001834 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001835 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420);
1836 s5p_jpeg_jpgadr(jpeg->regs, src_addr);
1837 s5p_jpeg_imgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001838 }
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001839
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001840 s5p_jpeg_start(jpeg->regs);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001841
1842 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001843}
1844
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001845static void exynos4_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
1846{
1847 struct s5p_jpeg *jpeg = ctx->jpeg;
1848 struct s5p_jpeg_fmt *fmt;
1849 struct vb2_buffer *vb;
1850 struct s5p_jpeg_addr jpeg_addr;
1851 u32 pix_size, padding_bytes = 0;
1852
1853 pix_size = ctx->cap_q.w * ctx->cap_q.h;
1854
1855 if (ctx->mode == S5P_JPEG_ENCODE) {
1856 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1857 fmt = ctx->out_q.fmt;
1858 if (ctx->out_q.w % 2 && fmt->h_align > 0)
1859 padding_bytes = ctx->out_q.h;
1860 } else {
1861 fmt = ctx->cap_q.fmt;
1862 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1863 }
1864
1865 jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
1866
1867 if (fmt->colplanes == 2) {
1868 jpeg_addr.cb = jpeg_addr.y + pix_size - padding_bytes;
1869 } else if (fmt->colplanes == 3) {
1870 jpeg_addr.cb = jpeg_addr.y + pix_size;
1871 if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
1872 jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
1873 else
1874 jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
1875 }
1876
1877 exynos4_jpeg_set_frame_buf_address(jpeg->regs, &jpeg_addr);
1878}
1879
1880static void exynos4_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
1881{
1882 struct s5p_jpeg *jpeg = ctx->jpeg;
1883 struct vb2_buffer *vb;
1884 unsigned int jpeg_addr = 0;
1885
1886 if (ctx->mode == S5P_JPEG_ENCODE)
1887 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1888 else
1889 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1890
1891 jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
1892 exynos4_jpeg_set_stream_buf_address(jpeg->regs, jpeg_addr);
1893}
1894
1895static void exynos4_jpeg_device_run(void *priv)
1896{
1897 struct s5p_jpeg_ctx *ctx = priv;
1898 struct s5p_jpeg *jpeg = ctx->jpeg;
1899 unsigned int bitstream_size;
1900 unsigned long flags;
1901
1902 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1903
1904 if (ctx->mode == S5P_JPEG_ENCODE) {
1905 exynos4_jpeg_sw_reset(jpeg->regs);
1906 exynos4_jpeg_set_interrupt(jpeg->regs);
1907 exynos4_jpeg_set_huf_table_enable(jpeg->regs, 1);
1908
1909 exynos4_jpeg_set_huff_tbl(jpeg->regs);
1910
1911 /*
1912 * JPEG IP allows storing 4 quantization tables
1913 * We fill table 0 for luma and table 1 for chroma
1914 */
1915 exynos4_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
1916 exynos4_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
1917
1918 exynos4_jpeg_set_encode_tbl_select(jpeg->regs,
1919 ctx->compr_quality);
1920 exynos4_jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w,
1921 ctx->cap_q.h);
1922
1923 exynos4_jpeg_set_enc_out_fmt(jpeg->regs, ctx->subsampling);
1924 exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->out_q.fmt->fourcc);
1925 exynos4_jpeg_set_img_addr(ctx);
1926 exynos4_jpeg_set_jpeg_addr(ctx);
1927 exynos4_jpeg_set_encode_hoff_cnt(jpeg->regs,
1928 ctx->out_q.fmt->fourcc);
1929 } else {
1930 exynos4_jpeg_sw_reset(jpeg->regs);
1931 exynos4_jpeg_set_interrupt(jpeg->regs);
1932 exynos4_jpeg_set_img_addr(ctx);
1933 exynos4_jpeg_set_jpeg_addr(ctx);
1934 exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->cap_q.fmt->fourcc);
1935
1936 bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 32);
1937
1938 exynos4_jpeg_set_dec_bitstream_size(jpeg->regs, bitstream_size);
1939 }
1940
1941 exynos4_jpeg_set_enc_dec_mode(jpeg->regs, ctx->mode);
1942
1943 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1944}
1945
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001946static void exynos3250_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
1947{
1948 struct s5p_jpeg *jpeg = ctx->jpeg;
1949 struct s5p_jpeg_fmt *fmt;
1950 struct vb2_buffer *vb;
1951 struct s5p_jpeg_addr jpeg_addr;
1952 u32 pix_size;
1953
1954 pix_size = ctx->cap_q.w * ctx->cap_q.h;
1955
1956 if (ctx->mode == S5P_JPEG_ENCODE) {
1957 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1958 fmt = ctx->out_q.fmt;
1959 } else {
1960 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1961 fmt = ctx->cap_q.fmt;
1962 }
1963
1964 jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
1965
1966 if (fmt->colplanes == 2) {
1967 jpeg_addr.cb = jpeg_addr.y + pix_size;
1968 } else if (fmt->colplanes == 3) {
1969 jpeg_addr.cb = jpeg_addr.y + pix_size;
1970 if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
1971 jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
1972 else
1973 jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
1974 }
1975
1976 exynos3250_jpeg_imgadr(jpeg->regs, &jpeg_addr);
1977}
1978
1979static void exynos3250_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
1980{
1981 struct s5p_jpeg *jpeg = ctx->jpeg;
1982 struct vb2_buffer *vb;
1983 unsigned int jpeg_addr = 0;
1984
1985 if (ctx->mode == S5P_JPEG_ENCODE)
1986 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1987 else
1988 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1989
1990 jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
1991 exynos3250_jpeg_jpgadr(jpeg->regs, jpeg_addr);
1992}
1993
1994static void exynos3250_jpeg_device_run(void *priv)
1995{
1996 struct s5p_jpeg_ctx *ctx = priv;
1997 struct s5p_jpeg *jpeg = ctx->jpeg;
1998 unsigned long flags;
1999
2000 spin_lock_irqsave(&ctx->jpeg->slock, flags);
2001
2002 exynos3250_jpeg_reset(jpeg->regs);
2003 exynos3250_jpeg_set_dma_num(jpeg->regs);
2004 exynos3250_jpeg_poweron(jpeg->regs);
2005 exynos3250_jpeg_clk_set(jpeg->regs);
2006 exynos3250_jpeg_proc_mode(jpeg->regs, ctx->mode);
2007
2008 if (ctx->mode == S5P_JPEG_ENCODE) {
2009 exynos3250_jpeg_input_raw_fmt(jpeg->regs,
2010 ctx->out_q.fmt->fourcc);
2011 exynos3250_jpeg_dri(jpeg->regs, ctx->restart_interval);
2012
2013 /*
2014 * JPEG IP allows storing 4 quantization tables
2015 * We fill table 0 for luma and table 1 for chroma
2016 */
2017 s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
2018 s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
2019 /* use table 0 for Y */
2020 exynos3250_jpeg_qtbl(jpeg->regs, 1, 0);
2021 /* use table 1 for Cb and Cr*/
2022 exynos3250_jpeg_qtbl(jpeg->regs, 2, 1);
2023 exynos3250_jpeg_qtbl(jpeg->regs, 3, 1);
2024
2025 /* Y, Cb, Cr use Huffman table 0 */
2026 exynos3250_jpeg_htbl_ac(jpeg->regs, 1);
2027 exynos3250_jpeg_htbl_dc(jpeg->regs, 1);
2028 exynos3250_jpeg_htbl_ac(jpeg->regs, 2);
2029 exynos3250_jpeg_htbl_dc(jpeg->regs, 2);
2030 exynos3250_jpeg_htbl_ac(jpeg->regs, 3);
2031 exynos3250_jpeg_htbl_dc(jpeg->regs, 3);
2032
2033 exynos3250_jpeg_set_x(jpeg->regs, ctx->crop_rect.width);
2034 exynos3250_jpeg_set_y(jpeg->regs, ctx->crop_rect.height);
2035 exynos3250_jpeg_stride(jpeg->regs, ctx->out_q.fmt->fourcc,
2036 ctx->out_q.w);
2037 exynos3250_jpeg_offset(jpeg->regs, ctx->crop_rect.left,
2038 ctx->crop_rect.top);
2039 exynos3250_jpeg_set_img_addr(ctx);
2040 exynos3250_jpeg_set_jpeg_addr(ctx);
2041 exynos3250_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
2042
2043 /* ultimately comes from sizeimage from userspace */
2044 exynos3250_jpeg_enc_stream_bound(jpeg->regs, ctx->cap_q.size);
2045
2046 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565 ||
2047 ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565X ||
2048 ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB32)
2049 exynos3250_jpeg_set_y16(jpeg->regs, true);
2050 } else {
2051 exynos3250_jpeg_set_img_addr(ctx);
2052 exynos3250_jpeg_set_jpeg_addr(ctx);
2053 exynos3250_jpeg_stride(jpeg->regs, ctx->cap_q.fmt->fourcc,
2054 ctx->cap_q.w);
2055 exynos3250_jpeg_offset(jpeg->regs, 0, 0);
2056 exynos3250_jpeg_dec_scaling_ratio(jpeg->regs,
2057 ctx->scale_factor);
2058 exynos3250_jpeg_dec_stream_size(jpeg->regs, ctx->out_q.size);
2059 exynos3250_jpeg_output_raw_fmt(jpeg->regs,
2060 ctx->cap_q.fmt->fourcc);
2061 }
2062
2063 exynos3250_jpeg_interrupts_enable(jpeg->regs);
2064
2065 /* JPEG RGB to YCbCr conversion matrix */
2066 exynos3250_jpeg_coef(jpeg->regs, ctx->mode);
2067
2068 exynos3250_jpeg_set_timer(jpeg->regs, EXYNOS3250_IRQ_TIMEOUT);
2069 jpeg->irq_status = 0;
2070 exynos3250_jpeg_start(jpeg->regs);
2071
2072 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
2073}
2074
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002075static int s5p_jpeg_job_ready(void *priv)
2076{
2077 struct s5p_jpeg_ctx *ctx = priv;
2078
2079 if (ctx->mode == S5P_JPEG_DECODE)
2080 return ctx->hdr_parsed;
2081 return 1;
2082}
2083
2084static void s5p_jpeg_job_abort(void *priv)
2085{
2086}
2087
2088static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = {
2089 .device_run = s5p_jpeg_device_run,
2090 .job_ready = s5p_jpeg_job_ready,
2091 .job_abort = s5p_jpeg_job_abort,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002092};
2093
2094static struct v4l2_m2m_ops exynos3250_jpeg_m2m_ops = {
2095 .device_run = exynos3250_jpeg_device_run,
2096 .job_ready = s5p_jpeg_job_ready,
2097 .job_abort = s5p_jpeg_job_abort,
2098};
2099
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03002100static struct v4l2_m2m_ops exynos4_jpeg_m2m_ops = {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002101 .device_run = exynos4_jpeg_device_run,
2102 .job_ready = s5p_jpeg_job_ready,
2103 .job_abort = s5p_jpeg_job_abort,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002104};
2105
2106/*
2107 * ============================================================================
2108 * Queue operations
2109 * ============================================================================
2110 */
2111
Marek Szyprowski719c1742012-01-13 05:12:38 -03002112static int s5p_jpeg_queue_setup(struct vb2_queue *vq,
2113 const struct v4l2_format *fmt,
2114 unsigned int *nbuffers, unsigned int *nplanes,
2115 unsigned int sizes[], void *alloc_ctxs[])
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002116{
2117 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
2118 struct s5p_jpeg_q_data *q_data = NULL;
2119 unsigned int size, count = *nbuffers;
2120
2121 q_data = get_q_data(ctx, vq->type);
2122 BUG_ON(q_data == NULL);
2123
2124 size = q_data->size;
2125
2126 /*
2127 * header is parsed during decoding and parsed information stored
2128 * in the context so we do not allow another buffer to overwrite it
2129 */
2130 if (ctx->mode == S5P_JPEG_DECODE)
2131 count = 1;
2132
2133 *nbuffers = count;
2134 *nplanes = 1;
2135 sizes[0] = size;
2136 alloc_ctxs[0] = ctx->jpeg->alloc_ctx;
2137
2138 return 0;
2139}
2140
2141static int s5p_jpeg_buf_prepare(struct vb2_buffer *vb)
2142{
2143 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
2144 struct s5p_jpeg_q_data *q_data = NULL;
2145
2146 q_data = get_q_data(ctx, vb->vb2_queue->type);
2147 BUG_ON(q_data == NULL);
2148
2149 if (vb2_plane_size(vb, 0) < q_data->size) {
2150 pr_err("%s data will not fit into plane (%lu < %lu)\n",
2151 __func__, vb2_plane_size(vb, 0),
2152 (long)q_data->size);
2153 return -EINVAL;
2154 }
2155
2156 vb2_set_plane_payload(vb, 0, q_data->size);
2157
2158 return 0;
2159}
2160
2161static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
2162{
2163 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
2164
2165 if (ctx->mode == S5P_JPEG_DECODE &&
2166 vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
2167 struct s5p_jpeg_q_data tmp, *q_data;
2168 ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp,
2169 (unsigned long)vb2_plane_vaddr(vb, 0),
2170 min((unsigned long)ctx->out_q.size,
Jacek Anaszewskif8433962013-11-21 13:33:09 -03002171 vb2_get_plane_payload(vb, 0)), ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002172 if (!ctx->hdr_parsed) {
2173 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
2174 return;
2175 }
2176
2177 q_data = &ctx->out_q;
2178 q_data->w = tmp.w;
2179 q_data->h = tmp.h;
2180
2181 q_data = &ctx->cap_q;
2182 q_data->w = tmp.w;
2183 q_data->h = tmp.h;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002184 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002185
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002186 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002187}
2188
2189static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
2190{
2191 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
2192 int ret;
2193
2194 ret = pm_runtime_get_sync(ctx->jpeg->dev);
2195
2196 return ret > 0 ? 0 : ret;
2197}
2198
Hans Verkuile37559b2014-04-17 02:47:21 -03002199static void s5p_jpeg_stop_streaming(struct vb2_queue *q)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002200{
2201 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
2202
2203 pm_runtime_put(ctx->jpeg->dev);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002204}
2205
2206static struct vb2_ops s5p_jpeg_qops = {
2207 .queue_setup = s5p_jpeg_queue_setup,
2208 .buf_prepare = s5p_jpeg_buf_prepare,
2209 .buf_queue = s5p_jpeg_buf_queue,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002210 .wait_prepare = vb2_ops_wait_prepare,
2211 .wait_finish = vb2_ops_wait_finish,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002212 .start_streaming = s5p_jpeg_start_streaming,
2213 .stop_streaming = s5p_jpeg_stop_streaming,
2214};
2215
2216static int queue_init(void *priv, struct vb2_queue *src_vq,
2217 struct vb2_queue *dst_vq)
2218{
2219 struct s5p_jpeg_ctx *ctx = priv;
2220 int ret;
2221
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002222 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
2223 src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
2224 src_vq->drv_priv = ctx;
2225 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
2226 src_vq->ops = &s5p_jpeg_qops;
2227 src_vq->mem_ops = &vb2_dma_contig_memops;
Sakari Ailusade48682014-02-25 19:12:19 -03002228 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002229 src_vq->lock = &ctx->jpeg->lock;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002230
2231 ret = vb2_queue_init(src_vq);
2232 if (ret)
2233 return ret;
2234
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002235 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2236 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
2237 dst_vq->drv_priv = ctx;
2238 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
2239 dst_vq->ops = &s5p_jpeg_qops;
2240 dst_vq->mem_ops = &vb2_dma_contig_memops;
Sakari Ailusade48682014-02-25 19:12:19 -03002241 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002242 dst_vq->lock = &ctx->jpeg->lock;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002243
2244 return vb2_queue_init(dst_vq);
2245}
2246
2247/*
2248 * ============================================================================
2249 * ISR
2250 * ============================================================================
2251 */
2252
2253static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
2254{
2255 struct s5p_jpeg *jpeg = dev_id;
2256 struct s5p_jpeg_ctx *curr_ctx;
2257 struct vb2_buffer *src_buf, *dst_buf;
2258 unsigned long payload_size = 0;
2259 enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
2260 bool enc_jpeg_too_large = false;
2261 bool timer_elapsed = false;
2262 bool op_completed = false;
2263
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002264 spin_lock(&jpeg->slock);
2265
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002266 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2267
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002268 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2269 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002270
2271 if (curr_ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002272 enc_jpeg_too_large = s5p_jpeg_enc_stream_stat(jpeg->regs);
2273 timer_elapsed = s5p_jpeg_timer_stat(jpeg->regs);
2274 op_completed = s5p_jpeg_result_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002275 if (curr_ctx->mode == S5P_JPEG_DECODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002276 op_completed = op_completed &&
2277 s5p_jpeg_stream_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002278
2279 if (enc_jpeg_too_large) {
2280 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002281 s5p_jpeg_clear_enc_stream_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002282 } else if (timer_elapsed) {
2283 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002284 s5p_jpeg_clear_timer_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002285 } else if (!op_completed) {
2286 state = VB2_BUF_STATE_ERROR;
2287 } else {
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002288 payload_size = s5p_jpeg_compressed_size(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002289 }
2290
Kamil Debskiaca326a2013-04-24 10:08:02 -03002291 dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
2292 dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
Sakari Ailus309f4d62014-02-08 14:21:35 -03002293 dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
2294 dst_buf->v4l2_buf.flags |=
2295 src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
Kamil Debskiaca326a2013-04-24 10:08:02 -03002296
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002297 v4l2_m2m_buf_done(src_buf, state);
2298 if (curr_ctx->mode == S5P_JPEG_ENCODE)
2299 vb2_set_plane_payload(dst_buf, 0, payload_size);
2300 v4l2_m2m_buf_done(dst_buf, state);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002301 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002302
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002303 curr_ctx->subsampling = s5p_jpeg_get_subsampling_mode(jpeg->regs);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002304 spin_unlock(&jpeg->slock);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03002305
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002306 s5p_jpeg_clear_int(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002307
2308 return IRQ_HANDLED;
2309}
2310
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002311static irqreturn_t exynos4_jpeg_irq(int irq, void *priv)
2312{
2313 unsigned int int_status;
2314 struct vb2_buffer *src_vb, *dst_vb;
2315 struct s5p_jpeg *jpeg = priv;
2316 struct s5p_jpeg_ctx *curr_ctx;
2317 unsigned long payload_size = 0;
2318
2319 spin_lock(&jpeg->slock);
2320
2321 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2322
2323 src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2324 dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
2325
2326 int_status = exynos4_jpeg_get_int_status(jpeg->regs);
2327
2328 if (int_status) {
2329 switch (int_status & 0x1f) {
2330 case 0x1:
2331 jpeg->irq_ret = ERR_PROT;
2332 break;
2333 case 0x2:
2334 jpeg->irq_ret = OK_ENC_OR_DEC;
2335 break;
2336 case 0x4:
2337 jpeg->irq_ret = ERR_DEC_INVALID_FORMAT;
2338 break;
2339 case 0x8:
2340 jpeg->irq_ret = ERR_MULTI_SCAN;
2341 break;
2342 case 0x10:
2343 jpeg->irq_ret = ERR_FRAME;
2344 break;
2345 default:
2346 jpeg->irq_ret = ERR_UNKNOWN;
2347 break;
2348 }
2349 } else {
2350 jpeg->irq_ret = ERR_UNKNOWN;
2351 }
2352
2353 if (jpeg->irq_ret == OK_ENC_OR_DEC) {
2354 if (curr_ctx->mode == S5P_JPEG_ENCODE) {
2355 payload_size = exynos4_jpeg_get_stream_size(jpeg->regs);
2356 vb2_set_plane_payload(dst_vb, 0, payload_size);
2357 }
2358 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
2359 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
2360 } else {
2361 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
2362 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
2363 }
2364
2365 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
2366 curr_ctx->subsampling = exynos4_jpeg_get_frame_fmt(jpeg->regs);
2367
2368 spin_unlock(&jpeg->slock);
2369 return IRQ_HANDLED;
2370}
2371
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002372static irqreturn_t exynos3250_jpeg_irq(int irq, void *dev_id)
2373{
2374 struct s5p_jpeg *jpeg = dev_id;
2375 struct s5p_jpeg_ctx *curr_ctx;
2376 struct vb2_buffer *src_buf, *dst_buf;
2377 unsigned long payload_size = 0;
2378 enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
2379 bool interrupt_timeout = false;
2380 u32 irq_status;
2381
2382 spin_lock(&jpeg->slock);
2383
2384 irq_status = exynos3250_jpeg_get_timer_status(jpeg->regs);
2385 if (irq_status & EXYNOS3250_TIMER_INT_STAT) {
2386 exynos3250_jpeg_clear_timer_status(jpeg->regs);
2387 interrupt_timeout = true;
2388 dev_err(jpeg->dev, "Interrupt timeout occurred.\n");
2389 }
2390
2391 irq_status = exynos3250_jpeg_get_int_status(jpeg->regs);
2392 exynos3250_jpeg_clear_int_status(jpeg->regs, irq_status);
2393
2394 jpeg->irq_status |= irq_status;
2395
2396 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2397
2398 if (!curr_ctx)
2399 goto exit_unlock;
2400
2401 if ((irq_status & EXYNOS3250_HEADER_STAT) &&
2402 (curr_ctx->mode == S5P_JPEG_DECODE)) {
2403 exynos3250_jpeg_rstart(jpeg->regs);
2404 goto exit_unlock;
2405 }
2406
2407 if (jpeg->irq_status & (EXYNOS3250_JPEG_DONE |
2408 EXYNOS3250_WDMA_DONE |
2409 EXYNOS3250_RDMA_DONE |
2410 EXYNOS3250_RESULT_STAT))
2411 payload_size = exynos3250_jpeg_compressed_size(jpeg->regs);
2412 else if (interrupt_timeout)
2413 state = VB2_BUF_STATE_ERROR;
2414 else
2415 goto exit_unlock;
2416
2417 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2418 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
2419
2420 dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
2421 dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
2422
2423 v4l2_m2m_buf_done(src_buf, state);
2424 if (curr_ctx->mode == S5P_JPEG_ENCODE)
2425 vb2_set_plane_payload(dst_buf, 0, payload_size);
2426 v4l2_m2m_buf_done(dst_buf, state);
2427 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
2428
2429 curr_ctx->subsampling =
2430 exynos3250_jpeg_get_subsampling_mode(jpeg->regs);
2431exit_unlock:
2432 spin_unlock(&jpeg->slock);
2433 return IRQ_HANDLED;
2434}
2435
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03002436static void *jpeg_get_drv_data(struct device *dev);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002437
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002438/*
2439 * ============================================================================
2440 * Driver basic infrastructure
2441 * ============================================================================
2442 */
2443
2444static int s5p_jpeg_probe(struct platform_device *pdev)
2445{
2446 struct s5p_jpeg *jpeg;
2447 struct resource *res;
2448 int ret;
2449
2450 /* JPEG IP abstraction struct */
Sachin Kamat5b58b952012-05-14 06:33:34 -03002451 jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002452 if (!jpeg)
2453 return -ENOMEM;
2454
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03002455 jpeg->variant = jpeg_get_drv_data(&pdev->dev);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002456
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002457 mutex_init(&jpeg->lock);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002458 spin_lock_init(&jpeg->slock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002459 jpeg->dev = &pdev->dev;
2460
2461 /* memory-mapped registers */
2462 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002463
Thierry Redingf23999e2013-01-21 06:09:07 -03002464 jpeg->regs = devm_ioremap_resource(&pdev->dev, res);
2465 if (IS_ERR(jpeg->regs))
2466 return PTR_ERR(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002467
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002468 /* interrupt service routine registration */
2469 jpeg->irq = ret = platform_get_irq(pdev, 0);
2470 if (ret < 0) {
2471 dev_err(&pdev->dev, "cannot find IRQ\n");
Sachin Kamat5b58b952012-05-14 06:33:34 -03002472 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002473 }
2474
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002475 ret = devm_request_irq(&pdev->dev, jpeg->irq, jpeg->variant->jpeg_irq,
2476 0, dev_name(&pdev->dev), jpeg);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002477 if (ret) {
2478 dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
Sachin Kamat5b58b952012-05-14 06:33:34 -03002479 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002480 }
2481
2482 /* clocks */
2483 jpeg->clk = clk_get(&pdev->dev, "jpeg");
2484 if (IS_ERR(jpeg->clk)) {
2485 dev_err(&pdev->dev, "cannot get clock\n");
2486 ret = PTR_ERR(jpeg->clk);
Sachin Kamat5b58b952012-05-14 06:33:34 -03002487 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002488 }
2489 dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002490
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002491 jpeg->sclk = clk_get(&pdev->dev, "sclk");
2492 if (IS_ERR(jpeg->sclk))
2493 dev_info(&pdev->dev, "sclk clock not available\n");
2494
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002495 /* v4l2 device */
2496 ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
2497 if (ret) {
2498 dev_err(&pdev->dev, "Failed to register v4l2 device\n");
2499 goto clk_get_rollback;
2500 }
2501
2502 /* mem2mem device */
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03002503 jpeg->m2m_dev = v4l2_m2m_init(jpeg->variant->m2m_ops);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002504 if (IS_ERR(jpeg->m2m_dev)) {
2505 v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
2506 ret = PTR_ERR(jpeg->m2m_dev);
2507 goto device_register_rollback;
2508 }
2509
2510 jpeg->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
2511 if (IS_ERR(jpeg->alloc_ctx)) {
2512 v4l2_err(&jpeg->v4l2_dev, "Failed to init memory allocator\n");
2513 ret = PTR_ERR(jpeg->alloc_ctx);
2514 goto m2m_init_rollback;
2515 }
2516
2517 /* JPEG encoder /dev/videoX node */
2518 jpeg->vfd_encoder = video_device_alloc();
2519 if (!jpeg->vfd_encoder) {
2520 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
2521 ret = -ENOMEM;
2522 goto vb2_allocator_rollback;
2523 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03002524 snprintf(jpeg->vfd_encoder->name, sizeof(jpeg->vfd_encoder->name),
2525 "%s-enc", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002526 jpeg->vfd_encoder->fops = &s5p_jpeg_fops;
2527 jpeg->vfd_encoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
2528 jpeg->vfd_encoder->minor = -1;
2529 jpeg->vfd_encoder->release = video_device_release;
2530 jpeg->vfd_encoder->lock = &jpeg->lock;
2531 jpeg->vfd_encoder->v4l2_dev = &jpeg->v4l2_dev;
Hans Verkuil954f3402012-09-05 06:05:50 -03002532 jpeg->vfd_encoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002533
2534 ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
2535 if (ret) {
2536 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
2537 goto enc_vdev_alloc_rollback;
2538 }
2539
2540 video_set_drvdata(jpeg->vfd_encoder, jpeg);
2541 v4l2_info(&jpeg->v4l2_dev,
2542 "encoder device registered as /dev/video%d\n",
2543 jpeg->vfd_encoder->num);
2544
2545 /* JPEG decoder /dev/videoX node */
2546 jpeg->vfd_decoder = video_device_alloc();
2547 if (!jpeg->vfd_decoder) {
2548 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
2549 ret = -ENOMEM;
2550 goto enc_vdev_register_rollback;
2551 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03002552 snprintf(jpeg->vfd_decoder->name, sizeof(jpeg->vfd_decoder->name),
2553 "%s-dec", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002554 jpeg->vfd_decoder->fops = &s5p_jpeg_fops;
2555 jpeg->vfd_decoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
2556 jpeg->vfd_decoder->minor = -1;
2557 jpeg->vfd_decoder->release = video_device_release;
2558 jpeg->vfd_decoder->lock = &jpeg->lock;
2559 jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev;
Jacek Anaszewski7f7d8fe2013-09-11 06:17:45 -03002560 jpeg->vfd_decoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002561
2562 ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
2563 if (ret) {
2564 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
2565 goto dec_vdev_alloc_rollback;
2566 }
2567
2568 video_set_drvdata(jpeg->vfd_decoder, jpeg);
2569 v4l2_info(&jpeg->v4l2_dev,
2570 "decoder device registered as /dev/video%d\n",
2571 jpeg->vfd_decoder->num);
2572
2573 /* final statements & power management */
2574 platform_set_drvdata(pdev, jpeg);
2575
2576 pm_runtime_enable(&pdev->dev);
2577
2578 v4l2_info(&jpeg->v4l2_dev, "Samsung S5P JPEG codec\n");
2579
2580 return 0;
2581
2582dec_vdev_alloc_rollback:
2583 video_device_release(jpeg->vfd_decoder);
2584
2585enc_vdev_register_rollback:
2586 video_unregister_device(jpeg->vfd_encoder);
2587
2588enc_vdev_alloc_rollback:
2589 video_device_release(jpeg->vfd_encoder);
2590
2591vb2_allocator_rollback:
2592 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
2593
2594m2m_init_rollback:
2595 v4l2_m2m_release(jpeg->m2m_dev);
2596
2597device_register_rollback:
2598 v4l2_device_unregister(&jpeg->v4l2_dev);
2599
2600clk_get_rollback:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002601 clk_put(jpeg->clk);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002602 if (!IS_ERR(jpeg->sclk))
2603 clk_put(jpeg->sclk);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002604
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002605 return ret;
2606}
2607
2608static int s5p_jpeg_remove(struct platform_device *pdev)
2609{
2610 struct s5p_jpeg *jpeg = platform_get_drvdata(pdev);
2611
2612 pm_runtime_disable(jpeg->dev);
2613
2614 video_unregister_device(jpeg->vfd_decoder);
2615 video_device_release(jpeg->vfd_decoder);
2616 video_unregister_device(jpeg->vfd_encoder);
2617 video_device_release(jpeg->vfd_encoder);
2618 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
2619 v4l2_m2m_release(jpeg->m2m_dev);
2620 v4l2_device_unregister(&jpeg->v4l2_dev);
2621
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002622 if (!pm_runtime_status_suspended(&pdev->dev)) {
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002623 clk_disable_unprepare(jpeg->clk);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002624 if (!IS_ERR(jpeg->sclk))
2625 clk_disable_unprepare(jpeg->sclk);
2626 }
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002627
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002628 clk_put(jpeg->clk);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002629 if (!IS_ERR(jpeg->sclk))
2630 clk_put(jpeg->sclk);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002631
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002632 return 0;
2633}
2634
Rafael J. Wysockie243c7c2014-12-04 01:10:10 +01002635#ifdef CONFIG_PM
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002636static int s5p_jpeg_runtime_suspend(struct device *dev)
2637{
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002638 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
2639
2640 clk_disable_unprepare(jpeg->clk);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002641 if (!IS_ERR(jpeg->sclk))
2642 clk_disable_unprepare(jpeg->sclk);
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002643
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002644 return 0;
2645}
2646
2647static int s5p_jpeg_runtime_resume(struct device *dev)
2648{
2649 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002650 unsigned long flags;
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002651 int ret;
2652
2653 ret = clk_prepare_enable(jpeg->clk);
2654 if (ret < 0)
2655 return ret;
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03002656
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002657 if (!IS_ERR(jpeg->sclk)) {
2658 ret = clk_prepare_enable(jpeg->sclk);
2659 if (ret < 0)
2660 return ret;
2661 }
2662
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002663 spin_lock_irqsave(&jpeg->slock, flags);
2664
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002665 /*
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002666 * JPEG IP allows storing two Huffman tables for each component.
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002667 * We fill table 0 for each component and do this here only
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002668 * for S5PC210 and Exynos3250 SoCs. Exynos4x12 SoC requires
2669 * programming its Huffman tables each time the encoding process
2670 * is initialized, and thus it is accomplished in the device_run
2671 * callback of m2m_ops.
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002672 */
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002673 if (jpeg->variant->version == SJPEG_S5P ||
2674 jpeg->variant->version == SJPEG_EXYNOS3250) {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002675 s5p_jpeg_set_hdctbl(jpeg->regs);
2676 s5p_jpeg_set_hdctblg(jpeg->regs);
2677 s5p_jpeg_set_hactbl(jpeg->regs);
2678 s5p_jpeg_set_hactblg(jpeg->regs);
2679 }
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03002680
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002681 spin_unlock_irqrestore(&jpeg->slock, flags);
2682
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002683 return 0;
2684}
Rafael J. Wysockie243c7c2014-12-04 01:10:10 +01002685#endif /* CONFIG_PM */
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002686
Thierry Redingde3767a2014-10-14 07:10:40 -03002687#ifdef CONFIG_PM_SLEEP
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002688static int s5p_jpeg_suspend(struct device *dev)
2689{
2690 if (pm_runtime_suspended(dev))
2691 return 0;
2692
2693 return s5p_jpeg_runtime_suspend(dev);
2694}
2695
2696static int s5p_jpeg_resume(struct device *dev)
2697{
2698 if (pm_runtime_suspended(dev))
2699 return 0;
2700
2701 return s5p_jpeg_runtime_resume(dev);
2702}
Thierry Redingde3767a2014-10-14 07:10:40 -03002703#endif
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002704
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002705static const struct dev_pm_ops s5p_jpeg_pm_ops = {
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002706 SET_SYSTEM_SLEEP_PM_OPS(s5p_jpeg_suspend, s5p_jpeg_resume)
2707 SET_RUNTIME_PM_OPS(s5p_jpeg_runtime_suspend, s5p_jpeg_runtime_resume, NULL)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002708};
2709
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002710static struct s5p_jpeg_variant s5p_jpeg_drvdata = {
2711 .version = SJPEG_S5P,
2712 .jpeg_irq = s5p_jpeg_irq,
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03002713 .m2m_ops = &s5p_jpeg_m2m_ops,
Jacek Anaszewskib2451682014-04-10 04:32:11 -03002714 .fmt_ver_flag = SJPEG_FMT_FLAG_S5P,
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03002715};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002716
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002717static struct s5p_jpeg_variant exynos3250_jpeg_drvdata = {
2718 .version = SJPEG_EXYNOS3250,
2719 .jpeg_irq = exynos3250_jpeg_irq,
2720 .m2m_ops = &exynos3250_jpeg_m2m_ops,
2721 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS3250,
2722};
2723
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002724static struct s5p_jpeg_variant exynos4_jpeg_drvdata = {
2725 .version = SJPEG_EXYNOS4,
2726 .jpeg_irq = exynos4_jpeg_irq,
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03002727 .m2m_ops = &exynos4_jpeg_m2m_ops,
Jacek Anaszewskib2451682014-04-10 04:32:11 -03002728 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS4,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002729};
2730
2731static const struct of_device_id samsung_jpeg_match[] = {
2732 {
2733 .compatible = "samsung,s5pv210-jpeg",
2734 .data = &s5p_jpeg_drvdata,
2735 }, {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002736 .compatible = "samsung,exynos3250-jpeg",
2737 .data = &exynos3250_jpeg_drvdata,
2738 }, {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002739 .compatible = "samsung,exynos4210-jpeg",
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002740 .data = &exynos4_jpeg_drvdata,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002741 }, {
2742 .compatible = "samsung,exynos4212-jpeg",
2743 .data = &exynos4_jpeg_drvdata,
2744 },
2745 {},
2746};
2747
2748MODULE_DEVICE_TABLE(of, samsung_jpeg_match);
2749
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03002750static void *jpeg_get_drv_data(struct device *dev)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002751{
2752 struct s5p_jpeg_variant *driver_data = NULL;
2753 const struct of_device_id *match;
2754
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03002755 if (!IS_ENABLED(CONFIG_OF) || !dev->of_node)
2756 return &s5p_jpeg_drvdata;
2757
2758 match = of_match_node(samsung_jpeg_match, dev->of_node);
2759
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002760 if (match)
2761 driver_data = (struct s5p_jpeg_variant *)match->data;
2762
2763 return driver_data;
2764}
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03002765
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002766static struct platform_driver s5p_jpeg_driver = {
2767 .probe = s5p_jpeg_probe,
2768 .remove = s5p_jpeg_remove,
2769 .driver = {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002770 .of_match_table = of_match_ptr(samsung_jpeg_match),
2771 .owner = THIS_MODULE,
2772 .name = S5P_JPEG_M2M_NAME,
2773 .pm = &s5p_jpeg_pm_ops,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002774 },
2775};
2776
Sachin Kamat87e94292012-07-03 05:54:33 -03002777module_platform_driver(s5p_jpeg_driver);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002778
2779MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002780MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002781MODULE_DESCRIPTION("Samsung JPEG codec driver");
2782MODULE_LICENSE("GPL");