blob: 697dc0e1945db170f5a4482dececaf18bb3e0629 [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:
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -0300624 case SJPEG_EXYNOS5420:
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300625 if (ctx->subsampling > 3)
626 return V4L2_JPEG_CHROMA_SUBSAMPLING_411;
627 return exynos3250_decoded_subsampling[ctx->subsampling];
628 case SJPEG_EXYNOS4:
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300629 if (ctx->subsampling > 2)
630 return V4L2_JPEG_CHROMA_SUBSAMPLING_420;
631 return exynos4x12_decoded_subsampling[ctx->subsampling];
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300632 default:
633 return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300634 }
635}
636
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300637static inline void s5p_jpeg_set_qtbl(void __iomem *regs,
638 const unsigned char *qtbl,
639 unsigned long tab, int len)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300640{
641 int i;
642
643 for (i = 0; i < len; i++)
644 writel((unsigned int)qtbl[i], regs + tab + (i * 0x04));
645}
646
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300647static inline void s5p_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300648{
649 /* this driver fills quantisation table 0 with data for luma */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300650 s5p_jpeg_set_qtbl(regs, qtbl_luminance[quality],
651 S5P_JPG_QTBL_CONTENT(0),
652 ARRAY_SIZE(qtbl_luminance[quality]));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300653}
654
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300655static inline void s5p_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300656{
657 /* this driver fills quantisation table 1 with data for chroma */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300658 s5p_jpeg_set_qtbl(regs, qtbl_chrominance[quality],
659 S5P_JPG_QTBL_CONTENT(1),
660 ARRAY_SIZE(qtbl_chrominance[quality]));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300661}
662
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300663static inline void s5p_jpeg_set_htbl(void __iomem *regs,
664 const unsigned char *htbl,
665 unsigned long tab, int len)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300666{
667 int i;
668
669 for (i = 0; i < len; i++)
670 writel((unsigned int)htbl[i], regs + tab + (i * 0x04));
671}
672
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300673static inline void s5p_jpeg_set_hdctbl(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300674{
675 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300676 s5p_jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0),
677 ARRAY_SIZE(hdctbl0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300678}
679
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300680static inline void s5p_jpeg_set_hdctblg(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300681{
682 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300683 s5p_jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0),
684 ARRAY_SIZE(hdctblg0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300685}
686
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300687static inline void s5p_jpeg_set_hactbl(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300688{
689 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300690 s5p_jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0),
691 ARRAY_SIZE(hactbl0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300692}
693
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300694static inline void s5p_jpeg_set_hactblg(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300695{
696 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300697 s5p_jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0),
698 ARRAY_SIZE(hactblg0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300699}
700
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300701static inline void exynos4_jpeg_set_tbl(void __iomem *regs,
702 const unsigned char *tbl,
703 unsigned long tab, int len)
704{
705 int i;
706 unsigned int dword;
707
708 for (i = 0; i < len; i += 4) {
709 dword = tbl[i] |
710 (tbl[i + 1] << 8) |
711 (tbl[i + 2] << 16) |
712 (tbl[i + 3] << 24);
713 writel(dword, regs + tab + i);
714 }
715}
716
717static inline void exynos4_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
718{
719 /* this driver fills quantisation table 0 with data for luma */
720 exynos4_jpeg_set_tbl(regs, qtbl_luminance[quality],
721 EXYNOS4_QTBL_CONTENT(0),
722 ARRAY_SIZE(qtbl_luminance[quality]));
723}
724
725static inline void exynos4_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
726{
727 /* this driver fills quantisation table 1 with data for chroma */
728 exynos4_jpeg_set_tbl(regs, qtbl_chrominance[quality],
729 EXYNOS4_QTBL_CONTENT(1),
730 ARRAY_SIZE(qtbl_chrominance[quality]));
731}
732
Mauro Carvalho Chehabaf425be2014-08-26 10:50:23 -0300733static void exynos4_jpeg_set_huff_tbl(void __iomem *base)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300734{
735 exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCLL,
736 ARRAY_SIZE(hdctbl0));
737 exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCCL,
738 ARRAY_SIZE(hdctbl0));
739 exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCLV,
740 ARRAY_SIZE(hdctblg0));
741 exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCCV,
742 ARRAY_SIZE(hdctblg0));
743 exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACLL,
744 ARRAY_SIZE(hactbl0));
745 exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACCL,
746 ARRAY_SIZE(hactbl0));
747 exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACLV,
748 ARRAY_SIZE(hactblg0));
749 exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACCV,
750 ARRAY_SIZE(hactblg0));
751}
752
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300753/*
754 * ============================================================================
755 * Device file operations
756 * ============================================================================
757 */
758
759static int queue_init(void *priv, struct vb2_queue *src_vq,
760 struct vb2_queue *dst_vq);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300761static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
762 __u32 pixelformat, unsigned int fmt_type);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300763static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300764
765static int s5p_jpeg_open(struct file *file)
766{
767 struct s5p_jpeg *jpeg = video_drvdata(file);
768 struct video_device *vfd = video_devdata(file);
769 struct s5p_jpeg_ctx *ctx;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300770 struct s5p_jpeg_fmt *out_fmt, *cap_fmt;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300771 int ret = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300772
Sachin Kamatb5146c92012-08-16 08:52:58 -0300773 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300774 if (!ctx)
775 return -ENOMEM;
776
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300777 if (mutex_lock_interruptible(&jpeg->lock)) {
778 ret = -ERESTARTSYS;
779 goto free;
780 }
781
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300782 v4l2_fh_init(&ctx->fh, vfd);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300783 /* Use separate control handler per file handle */
784 ctx->fh.ctrl_handler = &ctx->ctrl_handler;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300785 file->private_data = &ctx->fh;
786 v4l2_fh_add(&ctx->fh);
787
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300788 ctx->jpeg = jpeg;
789 if (vfd == jpeg->vfd_encoder) {
790 ctx->mode = S5P_JPEG_ENCODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300791 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB565,
792 FMT_TYPE_OUTPUT);
793 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
794 FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300795 } else {
796 ctx->mode = S5P_JPEG_DECODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300797 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
798 FMT_TYPE_OUTPUT);
799 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_YUYV,
800 FMT_TYPE_CAPTURE);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300801 ctx->scale_factor = EXYNOS3250_DEC_SCALE_FACTOR_8_8;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300802 }
803
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300804 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
805 if (IS_ERR(ctx->fh.m2m_ctx)) {
806 ret = PTR_ERR(ctx->fh.m2m_ctx);
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300807 goto error;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300808 }
809
810 ctx->out_q.fmt = out_fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300811 ctx->cap_q.fmt = cap_fmt;
812
813 ret = s5p_jpeg_controls_create(ctx);
814 if (ret < 0)
815 goto error;
816
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300817 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300818 return 0;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300819
820error:
821 v4l2_fh_del(&ctx->fh);
822 v4l2_fh_exit(&ctx->fh);
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300823 mutex_unlock(&jpeg->lock);
824free:
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300825 kfree(ctx);
826 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300827}
828
829static int s5p_jpeg_release(struct file *file)
830{
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300831 struct s5p_jpeg *jpeg = video_drvdata(file);
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300832 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300833
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300834 mutex_lock(&jpeg->lock);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300835 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300836 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300837 v4l2_fh_del(&ctx->fh);
838 v4l2_fh_exit(&ctx->fh);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300839 kfree(ctx);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300840 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300841
842 return 0;
843}
844
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300845static const struct v4l2_file_operations s5p_jpeg_fops = {
846 .owner = THIS_MODULE,
847 .open = s5p_jpeg_open,
848 .release = s5p_jpeg_release,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300849 .poll = v4l2_m2m_fop_poll,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300850 .unlocked_ioctl = video_ioctl2,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300851 .mmap = v4l2_m2m_fop_mmap,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300852};
853
854/*
855 * ============================================================================
856 * video ioctl operations
857 * ============================================================================
858 */
859
860static int get_byte(struct s5p_jpeg_buffer *buf)
861{
862 if (buf->curr >= buf->size)
863 return -1;
864
865 return ((unsigned char *)buf->data)[buf->curr++];
866}
867
868static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word)
869{
870 unsigned int temp;
871 int byte;
872
873 byte = get_byte(buf);
874 if (byte == -1)
875 return -1;
876 temp = byte << 8;
877 byte = get_byte(buf);
878 if (byte == -1)
879 return -1;
880 *word = (unsigned int)byte | temp;
881 return 0;
882}
883
884static void skip(struct s5p_jpeg_buffer *buf, long len)
885{
886 if (len <= 0)
887 return;
888
889 while (len--)
890 get_byte(buf);
891}
892
893static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300894 unsigned long buffer, unsigned long size,
895 struct s5p_jpeg_ctx *ctx)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300896{
Jacek Anaszewskif3d83a12014-10-10 05:46:49 -0300897 int c, components = 0, notfound;
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300898 unsigned int height, width, word, subsampling = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300899 long length;
900 struct s5p_jpeg_buffer jpeg_buffer;
901
902 jpeg_buffer.size = size;
903 jpeg_buffer.data = buffer;
904 jpeg_buffer.curr = 0;
905
906 notfound = 1;
907 while (notfound) {
908 c = get_byte(&jpeg_buffer);
909 if (c == -1)
Jacek Anaszewskia35f6002014-07-11 12:19:43 -0300910 return false;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300911 if (c != 0xff)
912 continue;
913 do
914 c = get_byte(&jpeg_buffer);
915 while (c == 0xff);
916 if (c == -1)
Jacek Anaszewskia35f6002014-07-11 12:19:43 -0300917 return false;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300918 if (c == 0)
919 continue;
920 length = 0;
921 switch (c) {
922 /* SOF0: baseline JPEG */
923 case SOF0:
924 if (get_word_be(&jpeg_buffer, &word))
925 break;
926 if (get_byte(&jpeg_buffer) == -1)
927 break;
928 if (get_word_be(&jpeg_buffer, &height))
929 break;
930 if (get_word_be(&jpeg_buffer, &width))
931 break;
932 components = get_byte(&jpeg_buffer);
933 if (components == -1)
934 break;
935 notfound = 0;
936
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300937 if (components == 1) {
938 subsampling = 0x33;
939 } else {
940 skip(&jpeg_buffer, 1);
941 subsampling = get_byte(&jpeg_buffer);
942 skip(&jpeg_buffer, 1);
943 }
944
945 skip(&jpeg_buffer, components * 2);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300946 break;
947
948 /* skip payload-less markers */
949 case RST ... RST + 7:
950 case SOI:
951 case EOI:
952 case TEM:
953 break;
954
955 /* skip uninteresting payload markers */
956 default:
957 if (get_word_be(&jpeg_buffer, &word))
958 break;
959 length = (long)word - 2;
960 skip(&jpeg_buffer, length);
961 break;
962 }
963 }
964 result->w = width;
965 result->h = height;
966 result->size = components;
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300967
968 switch (subsampling) {
969 case 0x11:
970 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444;
971 break;
972 case 0x21:
973 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422;
974 break;
975 case 0x22:
976 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420;
977 break;
978 case 0x33:
979 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
980 break;
981 default:
982 return false;
983 }
984
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300985 return !notfound;
986}
987
988static int s5p_jpeg_querycap(struct file *file, void *priv,
989 struct v4l2_capability *cap)
990{
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300991 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300992
993 if (ctx->mode == S5P_JPEG_ENCODE) {
994 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder",
995 sizeof(cap->driver));
996 strlcpy(cap->card, S5P_JPEG_M2M_NAME " encoder",
997 sizeof(cap->card));
998 } else {
999 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " decoder",
1000 sizeof(cap->driver));
1001 strlcpy(cap->card, S5P_JPEG_M2M_NAME " decoder",
1002 sizeof(cap->card));
1003 }
1004 cap->bus_info[0] = 0;
Hans Verkuil8c17e5e2014-11-24 06:37:26 -03001005 cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M;
1006 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001007 return 0;
1008}
1009
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001010static int enum_fmt(struct s5p_jpeg_fmt *sjpeg_formats, int n,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001011 struct v4l2_fmtdesc *f, u32 type)
1012{
1013 int i, num = 0;
1014
1015 for (i = 0; i < n; ++i) {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001016 if (sjpeg_formats[i].flags & type) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001017 /* index-th format of type type found ? */
1018 if (num == f->index)
1019 break;
1020 /* Correct type but haven't reached our index yet,
1021 * just increment per-type index */
1022 ++num;
1023 }
1024 }
1025
1026 /* Format not found */
1027 if (i >= n)
1028 return -EINVAL;
1029
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001030 strlcpy(f->description, sjpeg_formats[i].name, sizeof(f->description));
1031 f->pixelformat = sjpeg_formats[i].fourcc;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001032
1033 return 0;
1034}
1035
1036static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
1037 struct v4l2_fmtdesc *f)
1038{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001039 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001040
1041 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001042 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1043 SJPEG_FMT_FLAG_ENC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001044
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001045 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1046 SJPEG_FMT_FLAG_DEC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001047}
1048
1049static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
1050 struct v4l2_fmtdesc *f)
1051{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001052 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001053
1054 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001055 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1056 SJPEG_FMT_FLAG_ENC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001057
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001058 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1059 SJPEG_FMT_FLAG_DEC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001060}
1061
1062static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx,
1063 enum v4l2_buf_type type)
1064{
1065 if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1066 return &ctx->out_q;
1067 if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1068 return &ctx->cap_q;
1069
1070 return NULL;
1071}
1072
1073static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
1074{
1075 struct vb2_queue *vq;
1076 struct s5p_jpeg_q_data *q_data = NULL;
1077 struct v4l2_pix_format *pix = &f->fmt.pix;
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001078 struct s5p_jpeg_ctx *ct = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001079
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001080 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001081 if (!vq)
1082 return -EINVAL;
1083
1084 if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
1085 ct->mode == S5P_JPEG_DECODE && !ct->hdr_parsed)
1086 return -EINVAL;
1087 q_data = get_q_data(ct, f->type);
1088 BUG_ON(q_data == NULL);
1089
1090 pix->width = q_data->w;
1091 pix->height = q_data->h;
1092 pix->field = V4L2_FIELD_NONE;
1093 pix->pixelformat = q_data->fmt->fourcc;
1094 pix->bytesperline = 0;
1095 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
1096 u32 bpl = q_data->w;
1097 if (q_data->fmt->colplanes == 1)
1098 bpl = (bpl * q_data->fmt->depth) >> 3;
1099 pix->bytesperline = bpl;
1100 }
1101 pix->sizeimage = q_data->size;
1102
1103 return 0;
1104}
1105
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001106static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
1107 u32 pixelformat, unsigned int fmt_type)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001108{
Jacek Anaszewskib2451682014-04-10 04:32:11 -03001109 unsigned int k, fmt_flag;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001110
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001111 if (ctx->mode == S5P_JPEG_ENCODE)
1112 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
1113 SJPEG_FMT_FLAG_ENC_OUTPUT :
1114 SJPEG_FMT_FLAG_ENC_CAPTURE;
1115 else
1116 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
1117 SJPEG_FMT_FLAG_DEC_OUTPUT :
1118 SJPEG_FMT_FLAG_DEC_CAPTURE;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001119
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001120 for (k = 0; k < ARRAY_SIZE(sjpeg_formats); k++) {
1121 struct s5p_jpeg_fmt *fmt = &sjpeg_formats[k];
1122 if (fmt->fourcc == pixelformat &&
1123 fmt->flags & fmt_flag &&
Jacek Anaszewskib2451682014-04-10 04:32:11 -03001124 fmt->flags & ctx->jpeg->variant->fmt_ver_flag) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001125 return fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001126 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001127 }
1128
1129 return NULL;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001130}
1131
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001132static void jpeg_bound_align_image(struct s5p_jpeg_ctx *ctx,
1133 u32 *w, unsigned int wmin, unsigned int wmax,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001134 unsigned int walign,
1135 u32 *h, unsigned int hmin, unsigned int hmax,
1136 unsigned int halign)
1137{
1138 int width, height, w_step, h_step;
1139
1140 width = *w;
1141 height = *h;
1142
1143 w_step = 1 << walign;
1144 h_step = 1 << halign;
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001145
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001146 if (ctx->jpeg->variant->hw3250_compat) {
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001147 /*
1148 * Rightmost and bottommost pixels are cropped by the
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001149 * Exynos3250/compatible JPEG IP for RGB formats, for the
1150 * specific width and height values respectively. This
1151 * assignment will result in v4l_bound_align_image returning
1152 * dimensions reduced by 1 for the aforementioned cases.
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001153 */
1154 if (w_step == 4 && ((width & 3) == 1)) {
1155 wmax = width;
1156 hmax = height;
1157 }
1158 }
1159
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001160 v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
1161
1162 if (*w < width && (*w + w_step) < wmax)
1163 *w += w_step;
1164 if (*h < height && (*h + h_step) < hmax)
1165 *h += h_step;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001166}
1167
1168static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
1169 struct s5p_jpeg_ctx *ctx, int q_type)
1170{
1171 struct v4l2_pix_format *pix = &f->fmt.pix;
1172
1173 if (pix->field == V4L2_FIELD_ANY)
1174 pix->field = V4L2_FIELD_NONE;
1175 else if (pix->field != V4L2_FIELD_NONE)
1176 return -EINVAL;
1177
1178 /* V4L2 specification suggests the driver corrects the format struct
1179 * if any of the dimensions is unsupported */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001180 if (q_type == FMT_TYPE_OUTPUT)
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001181 jpeg_bound_align_image(ctx, &pix->width, S5P_JPEG_MIN_WIDTH,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001182 S5P_JPEG_MAX_WIDTH, 0,
1183 &pix->height, S5P_JPEG_MIN_HEIGHT,
1184 S5P_JPEG_MAX_HEIGHT, 0);
1185 else
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001186 jpeg_bound_align_image(ctx, &pix->width, S5P_JPEG_MIN_WIDTH,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001187 S5P_JPEG_MAX_WIDTH, fmt->h_align,
1188 &pix->height, S5P_JPEG_MIN_HEIGHT,
1189 S5P_JPEG_MAX_HEIGHT, fmt->v_align);
1190
1191 if (fmt->fourcc == V4L2_PIX_FMT_JPEG) {
1192 if (pix->sizeimage <= 0)
1193 pix->sizeimage = PAGE_SIZE;
1194 pix->bytesperline = 0;
1195 } else {
1196 u32 bpl = pix->bytesperline;
1197
1198 if (fmt->colplanes > 1 && bpl < pix->width)
1199 bpl = pix->width; /* planar */
1200
1201 if (fmt->colplanes == 1 && /* packed */
Jacek Anaszewskicc690902013-11-25 06:58:10 -03001202 (bpl << 3) / fmt->depth < pix->width)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001203 bpl = (pix->width * fmt->depth) >> 3;
1204
1205 pix->bytesperline = bpl;
1206 pix->sizeimage = (pix->width * pix->height * fmt->depth) >> 3;
1207 }
1208
1209 return 0;
1210}
1211
1212static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
1213 struct v4l2_format *f)
1214{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001215 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001216 struct v4l2_pix_format *pix = &f->fmt.pix;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001217 struct s5p_jpeg_fmt *fmt;
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001218 int ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001219
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001220 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
1221 FMT_TYPE_CAPTURE);
1222 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001223 v4l2_err(&ctx->jpeg->v4l2_dev,
1224 "Fourcc format (0x%08x) invalid.\n",
1225 f->fmt.pix.pixelformat);
1226 return -EINVAL;
1227 }
1228
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001229 if ((ctx->jpeg->variant->version != SJPEG_EXYNOS4) ||
1230 (ctx->mode != S5P_JPEG_DECODE))
1231 goto exit;
1232
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001233 /*
1234 * The exynos4x12 device requires resulting YUV image
1235 * subsampling not to be lower than the input jpeg subsampling.
1236 * If this requirement is not met then downgrade the requested
1237 * capture format to the one with subsampling equal to the input jpeg.
1238 */
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001239 if ((fmt->flags & SJPEG_FMT_NON_RGB) &&
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001240 (fmt->subsampling < ctx->subsampling)) {
1241 ret = s5p_jpeg_adjust_fourcc_to_subsampling(ctx->subsampling,
1242 fmt->fourcc,
1243 &pix->pixelformat,
1244 ctx);
1245 if (ret < 0)
1246 pix->pixelformat = V4L2_PIX_FMT_GREY;
1247
1248 fmt = s5p_jpeg_find_format(ctx, pix->pixelformat,
1249 FMT_TYPE_CAPTURE);
1250 }
1251
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001252 /*
1253 * Decompression of a JPEG file with 4:2:0 subsampling and odd
1254 * width to the YUV 4:2:0 compliant formats produces a raw image
1255 * with broken luma component. Adjust capture format to RGB565
1256 * in such a case.
1257 */
1258 if (ctx->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_420 &&
1259 (ctx->out_q.w & 1) &&
1260 (pix->pixelformat == V4L2_PIX_FMT_NV12 ||
1261 pix->pixelformat == V4L2_PIX_FMT_NV21 ||
1262 pix->pixelformat == V4L2_PIX_FMT_YUV420)) {
1263 pix->pixelformat = V4L2_PIX_FMT_RGB565;
1264 fmt = s5p_jpeg_find_format(ctx, pix->pixelformat,
1265 FMT_TYPE_CAPTURE);
1266 }
1267
1268exit:
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001269 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001270}
1271
1272static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
1273 struct v4l2_format *f)
1274{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001275 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001276 struct s5p_jpeg_fmt *fmt;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001277
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001278 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
1279 FMT_TYPE_OUTPUT);
1280 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001281 v4l2_err(&ctx->jpeg->v4l2_dev,
1282 "Fourcc format (0x%08x) invalid.\n",
1283 f->fmt.pix.pixelformat);
1284 return -EINVAL;
1285 }
1286
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001287 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001288}
1289
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001290static int exynos4_jpeg_get_output_buffer_size(struct s5p_jpeg_ctx *ctx,
1291 struct v4l2_format *f,
1292 int fmt_depth)
1293{
1294 struct v4l2_pix_format *pix = &f->fmt.pix;
1295 u32 pix_fmt = f->fmt.pix.pixelformat;
1296 int w = pix->width, h = pix->height, wh_align;
1297
1298 if (pix_fmt == V4L2_PIX_FMT_RGB32 ||
1299 pix_fmt == V4L2_PIX_FMT_NV24 ||
1300 pix_fmt == V4L2_PIX_FMT_NV42 ||
1301 pix_fmt == V4L2_PIX_FMT_NV12 ||
1302 pix_fmt == V4L2_PIX_FMT_NV21 ||
1303 pix_fmt == V4L2_PIX_FMT_YUV420)
1304 wh_align = 4;
1305 else
1306 wh_align = 1;
1307
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001308 jpeg_bound_align_image(ctx, &w, S5P_JPEG_MIN_WIDTH,
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001309 S5P_JPEG_MAX_WIDTH, wh_align,
1310 &h, S5P_JPEG_MIN_HEIGHT,
1311 S5P_JPEG_MAX_HEIGHT, wh_align);
1312
1313 return w * h * fmt_depth >> 3;
1314}
1315
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001316static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx,
1317 struct v4l2_rect *r);
1318
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001319static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
1320{
1321 struct vb2_queue *vq;
1322 struct s5p_jpeg_q_data *q_data = NULL;
1323 struct v4l2_pix_format *pix = &f->fmt.pix;
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001324 struct v4l2_ctrl *ctrl_subs;
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001325 struct v4l2_rect scale_rect;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001326 unsigned int f_type;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001327
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001328 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001329 if (!vq)
1330 return -EINVAL;
1331
1332 q_data = get_q_data(ct, f->type);
1333 BUG_ON(q_data == NULL);
1334
1335 if (vb2_is_busy(vq)) {
1336 v4l2_err(&ct->jpeg->v4l2_dev, "%s queue busy\n", __func__);
1337 return -EBUSY;
1338 }
1339
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001340 f_type = V4L2_TYPE_IS_OUTPUT(f->type) ?
1341 FMT_TYPE_OUTPUT : FMT_TYPE_CAPTURE;
1342
1343 q_data->fmt = s5p_jpeg_find_format(ct, pix->pixelformat, f_type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001344 q_data->w = pix->width;
1345 q_data->h = pix->height;
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001346 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
1347 /*
1348 * During encoding Exynos4x12 SoCs access wider memory area
1349 * than it results from Image_x and Image_y values written to
1350 * the JPEG_IMAGE_SIZE register. In order to avoid sysmmu
1351 * page fault calculate proper buffer size in such a case.
1352 */
1353 if (ct->jpeg->variant->version == SJPEG_EXYNOS4 &&
1354 f_type == FMT_TYPE_OUTPUT && ct->mode == S5P_JPEG_ENCODE)
1355 q_data->size = exynos4_jpeg_get_output_buffer_size(ct,
1356 f,
1357 q_data->fmt->depth);
1358 else
1359 q_data->size = q_data->w * q_data->h *
1360 q_data->fmt->depth >> 3;
1361 } else {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001362 q_data->size = pix->sizeimage;
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001363 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001364
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001365 if (f_type == FMT_TYPE_OUTPUT) {
1366 ctrl_subs = v4l2_ctrl_find(&ct->ctrl_handler,
1367 V4L2_CID_JPEG_CHROMA_SUBSAMPLING);
1368 if (ctrl_subs)
1369 v4l2_ctrl_s_ctrl(ctrl_subs, q_data->fmt->subsampling);
Jacek Anaszewskidfd96902014-07-11 12:19:46 -03001370 ct->crop_altered = false;
1371 }
1372
1373 /*
1374 * For decoding init crop_rect with capture buffer dimmensions which
1375 * contain aligned dimensions of the input JPEG image and do it only
1376 * if crop rectangle hasn't been altered by the user space e.g. with
1377 * S_SELECTION ioctl. For encoding assign output buffer dimensions.
1378 */
1379 if (!ct->crop_altered &&
1380 ((ct->mode == S5P_JPEG_DECODE && f_type == FMT_TYPE_CAPTURE) ||
1381 (ct->mode == S5P_JPEG_ENCODE && f_type == FMT_TYPE_OUTPUT))) {
1382 ct->crop_rect.width = pix->width;
1383 ct->crop_rect.height = pix->height;
1384 }
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001385
1386 /*
1387 * Prevent downscaling to YUV420 format by more than 2
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001388 * for Exynos3250/compatible SoC as it produces broken raw image
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001389 * in such cases.
1390 */
1391 if (ct->mode == S5P_JPEG_DECODE &&
1392 f_type == FMT_TYPE_CAPTURE &&
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001393 ct->jpeg->variant->hw3250_compat &&
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001394 pix->pixelformat == V4L2_PIX_FMT_YUV420 &&
1395 ct->scale_factor > 2) {
1396 scale_rect.width = ct->out_q.w / 2;
1397 scale_rect.height = ct->out_q.h / 2;
1398 exynos3250_jpeg_try_downscale(ct, &scale_rect);
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001399 }
1400
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001401 return 0;
1402}
1403
1404static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
1405 struct v4l2_format *f)
1406{
1407 int ret;
1408
1409 ret = s5p_jpeg_try_fmt_vid_cap(file, priv, f);
1410 if (ret)
1411 return ret;
1412
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001413 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001414}
1415
1416static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
1417 struct v4l2_format *f)
1418{
1419 int ret;
1420
1421 ret = s5p_jpeg_try_fmt_vid_out(file, priv, f);
1422 if (ret)
1423 return ret;
1424
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001425 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001426}
1427
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001428static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx,
1429 struct v4l2_rect *r)
1430{
1431 int w_ratio, h_ratio, scale_factor, cur_ratio, i;
1432
1433 w_ratio = ctx->out_q.w / r->width;
1434 h_ratio = ctx->out_q.h / r->height;
1435
1436 scale_factor = w_ratio > h_ratio ? w_ratio : h_ratio;
1437 scale_factor = clamp_val(scale_factor, 1, 8);
1438
1439 /* Align scale ratio to the nearest power of 2 */
1440 for (i = 0; i <= 3; ++i) {
1441 cur_ratio = 1 << i;
1442 if (scale_factor <= cur_ratio) {
1443 ctx->scale_factor = cur_ratio;
1444 break;
1445 }
1446 }
1447
1448 r->width = round_down(ctx->out_q.w / ctx->scale_factor, 2);
1449 r->height = round_down(ctx->out_q.h / ctx->scale_factor, 2);
1450
1451 ctx->crop_rect.width = r->width;
1452 ctx->crop_rect.height = r->height;
1453 ctx->crop_rect.left = 0;
1454 ctx->crop_rect.top = 0;
1455
1456 ctx->crop_altered = true;
1457
1458 return 0;
1459}
1460
1461/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */
1462static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
1463{
1464 if (a->left < b->left || a->top < b->top)
1465 return 0;
1466 if (a->left + a->width > b->left + b->width)
1467 return 0;
1468 if (a->top + a->height > b->top + b->height)
1469 return 0;
1470
1471 return 1;
1472}
1473
1474static int exynos3250_jpeg_try_crop(struct s5p_jpeg_ctx *ctx,
1475 struct v4l2_rect *r)
1476{
1477 struct v4l2_rect base_rect;
1478 int w_step, h_step;
1479
1480 switch (ctx->cap_q.fmt->fourcc) {
1481 case V4L2_PIX_FMT_NV12:
1482 case V4L2_PIX_FMT_NV21:
1483 w_step = 1;
1484 h_step = 2;
1485 break;
1486 case V4L2_PIX_FMT_YUV420:
1487 w_step = 2;
1488 h_step = 2;
1489 break;
1490 default:
1491 w_step = 1;
1492 h_step = 1;
1493 break;
1494 }
1495
1496 base_rect.top = 0;
1497 base_rect.left = 0;
1498 base_rect.width = ctx->out_q.w;
1499 base_rect.height = ctx->out_q.h;
1500
1501 r->width = round_down(r->width, w_step);
1502 r->height = round_down(r->height, h_step);
1503 r->left = round_down(r->left, 2);
1504 r->top = round_down(r->top, 2);
1505
1506 if (!enclosed_rectangle(r, &base_rect))
1507 return -EINVAL;
1508
1509 ctx->crop_rect.left = r->left;
1510 ctx->crop_rect.top = r->top;
1511 ctx->crop_rect.width = r->width;
1512 ctx->crop_rect.height = r->height;
1513
1514 ctx->crop_altered = true;
1515
1516 return 0;
1517}
1518
1519/*
1520 * V4L2 controls
1521 */
1522
Sachin Kamat9f3bd322012-05-10 03:38:40 -03001523static int s5p_jpeg_g_selection(struct file *file, void *priv,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001524 struct v4l2_selection *s)
1525{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001526 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001527
1528 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
Jacek Anaszewski38a6ef32014-04-10 04:32:15 -03001529 s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001530 return -EINVAL;
1531
1532 /* For JPEG blob active == default == bounds */
1533 switch (s->target) {
Sylwester Nawrockic1334822012-05-20 11:17:12 -03001534 case V4L2_SEL_TGT_CROP:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001535 case V4L2_SEL_TGT_CROP_BOUNDS:
1536 case V4L2_SEL_TGT_CROP_DEFAULT:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001537 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
1538 s->r.width = ctx->out_q.w;
1539 s->r.height = ctx->out_q.h;
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001540 s->r.left = 0;
1541 s->r.top = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001542 break;
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001543 case V4L2_SEL_TGT_COMPOSE:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001544 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
1545 case V4L2_SEL_TGT_COMPOSE_PADDED:
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001546 s->r.width = ctx->crop_rect.width;
1547 s->r.height = ctx->crop_rect.height;
1548 s->r.left = ctx->crop_rect.left;
1549 s->r.top = ctx->crop_rect.top;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001550 break;
1551 default:
1552 return -EINVAL;
1553 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001554 return 0;
1555}
1556
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001557/*
1558 * V4L2 controls
1559 */
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001560static int s5p_jpeg_s_selection(struct file *file, void *fh,
1561 struct v4l2_selection *s)
1562{
1563 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
1564 struct v4l2_rect *rect = &s->r;
1565 int ret = -EINVAL;
1566
1567 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1568 return -EINVAL;
1569
1570 if (s->target == V4L2_SEL_TGT_COMPOSE) {
1571 if (ctx->mode != S5P_JPEG_DECODE)
1572 return -EINVAL;
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001573 if (ctx->jpeg->variant->hw3250_compat)
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001574 ret = exynos3250_jpeg_try_downscale(ctx, rect);
1575 } else if (s->target == V4L2_SEL_TGT_CROP) {
1576 if (ctx->mode != S5P_JPEG_ENCODE)
1577 return -EINVAL;
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001578 if (ctx->jpeg->variant->hw3250_compat)
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001579 ret = exynos3250_jpeg_try_crop(ctx, rect);
1580 }
1581
1582 return ret;
1583}
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001584
1585static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001586{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001587 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1588 struct s5p_jpeg *jpeg = ctx->jpeg;
1589 unsigned long flags;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001590
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001591 switch (ctrl->id) {
1592 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1593 spin_lock_irqsave(&jpeg->slock, flags);
Jacek Anaszewski303b0a92013-12-18 11:14:00 -03001594 ctrl->val = s5p_jpeg_to_user_subsampling(ctx);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001595 spin_unlock_irqrestore(&jpeg->slock, flags);
1596 break;
1597 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001598
1599 return 0;
1600}
1601
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001602static int s5p_jpeg_adjust_subs_ctrl(struct s5p_jpeg_ctx *ctx, int *ctrl_val)
1603{
1604 switch (ctx->jpeg->variant->version) {
1605 case SJPEG_S5P:
1606 return 0;
1607 case SJPEG_EXYNOS3250:
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001608 case SJPEG_EXYNOS5420:
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001609 /*
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001610 * The exynos3250/compatible device can produce JPEG image only
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001611 * of 4:4:4 subsampling when given RGB32 source image.
1612 */
1613 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB32)
1614 *ctrl_val = 0;
1615 break;
1616 case SJPEG_EXYNOS4:
1617 /*
1618 * The exynos4x12 device requires input raw image fourcc
1619 * to be V4L2_PIX_FMT_GREY if gray jpeg format
1620 * is to be set.
1621 */
1622 if (ctx->out_q.fmt->fourcc != V4L2_PIX_FMT_GREY &&
1623 *ctrl_val == V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY)
1624 return -EINVAL;
1625 break;
1626 }
1627
1628 /*
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001629 * The exynos4x12 and exynos3250/compatible devices require resulting
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001630 * jpeg subsampling not to be lower than the input raw image
1631 * subsampling.
1632 */
1633 if (ctx->out_q.fmt->subsampling > *ctrl_val)
1634 *ctrl_val = ctx->out_q.fmt->subsampling;
1635
1636 return 0;
1637}
1638
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001639static int s5p_jpeg_try_ctrl(struct v4l2_ctrl *ctrl)
1640{
1641 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1642 unsigned long flags;
1643 int ret = 0;
1644
1645 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1646
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001647 if (ctrl->id == V4L2_CID_JPEG_CHROMA_SUBSAMPLING)
1648 ret = s5p_jpeg_adjust_subs_ctrl(ctx, &ctrl->val);
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001649
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001650 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1651 return ret;
1652}
1653
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001654static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001655{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001656 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1657 unsigned long flags;
1658
1659 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1660
1661 switch (ctrl->id) {
1662 case V4L2_CID_JPEG_COMPRESSION_QUALITY:
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001663 ctx->compr_quality = ctrl->val;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001664 break;
1665 case V4L2_CID_JPEG_RESTART_INTERVAL:
1666 ctx->restart_interval = ctrl->val;
1667 break;
1668 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1669 ctx->subsampling = ctrl->val;
1670 break;
1671 }
1672
1673 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1674 return 0;
1675}
1676
1677static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
1678 .g_volatile_ctrl = s5p_jpeg_g_volatile_ctrl,
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001679 .try_ctrl = s5p_jpeg_try_ctrl,
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001680 .s_ctrl = s5p_jpeg_s_ctrl,
1681};
1682
1683static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
1684{
1685 unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */
1686 struct v4l2_ctrl *ctrl;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001687 int ret;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001688
1689 v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
1690
1691 if (ctx->mode == S5P_JPEG_ENCODE) {
1692 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1693 V4L2_CID_JPEG_COMPRESSION_QUALITY,
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001694 0, 3, 1, S5P_JPEG_COMPR_QUAL_WORST);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001695
1696 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1697 V4L2_CID_JPEG_RESTART_INTERVAL,
1698 0, 3, 0xffff, 0);
Jacek Anaszewskifdf9e2b2013-11-21 13:33:41 -03001699 if (ctx->jpeg->variant->version == SJPEG_S5P)
1700 mask = ~0x06; /* 422, 420 */
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001701 }
1702
1703 ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1704 V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
1705 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask,
1706 V4L2_JPEG_CHROMA_SUBSAMPLING_422);
1707
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001708 if (ctx->ctrl_handler.error) {
1709 ret = ctx->ctrl_handler.error;
1710 goto error_free;
1711 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001712
1713 if (ctx->mode == S5P_JPEG_DECODE)
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001714 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
1715 V4L2_CTRL_FLAG_READ_ONLY;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001716
1717 ret = v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
1718 if (ret < 0)
1719 goto error_free;
1720
1721 return ret;
1722
1723error_free:
1724 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
1725 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001726}
1727
1728static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
1729 .vidioc_querycap = s5p_jpeg_querycap,
1730
1731 .vidioc_enum_fmt_vid_cap = s5p_jpeg_enum_fmt_vid_cap,
1732 .vidioc_enum_fmt_vid_out = s5p_jpeg_enum_fmt_vid_out,
1733
1734 .vidioc_g_fmt_vid_cap = s5p_jpeg_g_fmt,
1735 .vidioc_g_fmt_vid_out = s5p_jpeg_g_fmt,
1736
1737 .vidioc_try_fmt_vid_cap = s5p_jpeg_try_fmt_vid_cap,
1738 .vidioc_try_fmt_vid_out = s5p_jpeg_try_fmt_vid_out,
1739
1740 .vidioc_s_fmt_vid_cap = s5p_jpeg_s_fmt_vid_cap,
1741 .vidioc_s_fmt_vid_out = s5p_jpeg_s_fmt_vid_out,
1742
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001743 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
1744 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
1745 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
1746 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001747
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001748 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
1749 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001750
1751 .vidioc_g_selection = s5p_jpeg_g_selection,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001752 .vidioc_s_selection = s5p_jpeg_s_selection,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001753};
1754
1755/*
1756 * ============================================================================
1757 * mem2mem callbacks
1758 * ============================================================================
1759 */
1760
1761static void s5p_jpeg_device_run(void *priv)
1762{
1763 struct s5p_jpeg_ctx *ctx = priv;
1764 struct s5p_jpeg *jpeg = ctx->jpeg;
1765 struct vb2_buffer *src_buf, *dst_buf;
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001766 unsigned long src_addr, dst_addr, flags;
1767
1768 spin_lock_irqsave(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001769
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001770 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1771 dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001772 src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
1773 dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
1774
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001775 s5p_jpeg_reset(jpeg->regs);
1776 s5p_jpeg_poweron(jpeg->regs);
1777 s5p_jpeg_proc_mode(jpeg->regs, ctx->mode);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001778 if (ctx->mode == S5P_JPEG_ENCODE) {
1779 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001780 s5p_jpeg_input_raw_mode(jpeg->regs,
1781 S5P_JPEG_RAW_IN_565);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001782 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001783 s5p_jpeg_input_raw_mode(jpeg->regs,
1784 S5P_JPEG_RAW_IN_422);
1785 s5p_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
1786 s5p_jpeg_dri(jpeg->regs, ctx->restart_interval);
1787 s5p_jpeg_x(jpeg->regs, ctx->out_q.w);
1788 s5p_jpeg_y(jpeg->regs, ctx->out_q.h);
1789 s5p_jpeg_imgadr(jpeg->regs, src_addr);
1790 s5p_jpeg_jpgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001791
1792 /* ultimately comes from sizeimage from userspace */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001793 s5p_jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001794
1795 /* JPEG RGB to YCbCr conversion matrix */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001796 s5p_jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11);
1797 s5p_jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12);
1798 s5p_jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13);
1799 s5p_jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21);
1800 s5p_jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22);
1801 s5p_jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23);
1802 s5p_jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31);
1803 s5p_jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32);
1804 s5p_jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001805
1806 /*
1807 * JPEG IP allows storing 4 quantization tables
1808 * We fill table 0 for luma and table 1 for chroma
1809 */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03001810 s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
1811 s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001812 /* use table 0 for Y */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001813 s5p_jpeg_qtbl(jpeg->regs, 1, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001814 /* use table 1 for Cb and Cr*/
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001815 s5p_jpeg_qtbl(jpeg->regs, 2, 1);
1816 s5p_jpeg_qtbl(jpeg->regs, 3, 1);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001817
1818 /* Y, Cb, Cr use Huffman table 0 */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001819 s5p_jpeg_htbl_ac(jpeg->regs, 1);
1820 s5p_jpeg_htbl_dc(jpeg->regs, 1);
1821 s5p_jpeg_htbl_ac(jpeg->regs, 2);
1822 s5p_jpeg_htbl_dc(jpeg->regs, 2);
1823 s5p_jpeg_htbl_ac(jpeg->regs, 3);
1824 s5p_jpeg_htbl_dc(jpeg->regs, 3);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001825 } else { /* S5P_JPEG_DECODE */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001826 s5p_jpeg_rst_int_enable(jpeg->regs, true);
1827 s5p_jpeg_data_num_int_enable(jpeg->regs, true);
1828 s5p_jpeg_final_mcu_num_int_enable(jpeg->regs, true);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001829 if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001830 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001831 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001832 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420);
1833 s5p_jpeg_jpgadr(jpeg->regs, src_addr);
1834 s5p_jpeg_imgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001835 }
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001836
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001837 s5p_jpeg_start(jpeg->regs);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001838
1839 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001840}
1841
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001842static void exynos4_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
1843{
1844 struct s5p_jpeg *jpeg = ctx->jpeg;
1845 struct s5p_jpeg_fmt *fmt;
1846 struct vb2_buffer *vb;
Jacek Anaszewski12b05562015-03-05 10:56:25 -03001847 struct s5p_jpeg_addr jpeg_addr = {};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001848 u32 pix_size, padding_bytes = 0;
1849
1850 pix_size = ctx->cap_q.w * ctx->cap_q.h;
1851
1852 if (ctx->mode == S5P_JPEG_ENCODE) {
1853 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1854 fmt = ctx->out_q.fmt;
1855 if (ctx->out_q.w % 2 && fmt->h_align > 0)
1856 padding_bytes = ctx->out_q.h;
1857 } else {
1858 fmt = ctx->cap_q.fmt;
1859 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1860 }
1861
1862 jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
1863
1864 if (fmt->colplanes == 2) {
1865 jpeg_addr.cb = jpeg_addr.y + pix_size - padding_bytes;
1866 } else if (fmt->colplanes == 3) {
1867 jpeg_addr.cb = jpeg_addr.y + pix_size;
1868 if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
1869 jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
1870 else
1871 jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
1872 }
1873
1874 exynos4_jpeg_set_frame_buf_address(jpeg->regs, &jpeg_addr);
1875}
1876
1877static void exynos4_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
1878{
1879 struct s5p_jpeg *jpeg = ctx->jpeg;
1880 struct vb2_buffer *vb;
1881 unsigned int jpeg_addr = 0;
1882
1883 if (ctx->mode == S5P_JPEG_ENCODE)
1884 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1885 else
1886 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1887
1888 jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
1889 exynos4_jpeg_set_stream_buf_address(jpeg->regs, jpeg_addr);
1890}
1891
1892static void exynos4_jpeg_device_run(void *priv)
1893{
1894 struct s5p_jpeg_ctx *ctx = priv;
1895 struct s5p_jpeg *jpeg = ctx->jpeg;
1896 unsigned int bitstream_size;
1897 unsigned long flags;
1898
1899 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1900
1901 if (ctx->mode == S5P_JPEG_ENCODE) {
1902 exynos4_jpeg_sw_reset(jpeg->regs);
1903 exynos4_jpeg_set_interrupt(jpeg->regs);
1904 exynos4_jpeg_set_huf_table_enable(jpeg->regs, 1);
1905
1906 exynos4_jpeg_set_huff_tbl(jpeg->regs);
1907
1908 /*
1909 * JPEG IP allows storing 4 quantization tables
1910 * We fill table 0 for luma and table 1 for chroma
1911 */
1912 exynos4_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
1913 exynos4_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
1914
1915 exynos4_jpeg_set_encode_tbl_select(jpeg->regs,
1916 ctx->compr_quality);
1917 exynos4_jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w,
1918 ctx->cap_q.h);
1919
1920 exynos4_jpeg_set_enc_out_fmt(jpeg->regs, ctx->subsampling);
1921 exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->out_q.fmt->fourcc);
1922 exynos4_jpeg_set_img_addr(ctx);
1923 exynos4_jpeg_set_jpeg_addr(ctx);
1924 exynos4_jpeg_set_encode_hoff_cnt(jpeg->regs,
1925 ctx->out_q.fmt->fourcc);
1926 } else {
1927 exynos4_jpeg_sw_reset(jpeg->regs);
1928 exynos4_jpeg_set_interrupt(jpeg->regs);
1929 exynos4_jpeg_set_img_addr(ctx);
1930 exynos4_jpeg_set_jpeg_addr(ctx);
1931 exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->cap_q.fmt->fourcc);
1932
1933 bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 32);
1934
1935 exynos4_jpeg_set_dec_bitstream_size(jpeg->regs, bitstream_size);
1936 }
1937
1938 exynos4_jpeg_set_enc_dec_mode(jpeg->regs, ctx->mode);
1939
1940 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1941}
1942
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001943static void exynos3250_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
1944{
1945 struct s5p_jpeg *jpeg = ctx->jpeg;
1946 struct s5p_jpeg_fmt *fmt;
1947 struct vb2_buffer *vb;
Jacek Anaszewski12b05562015-03-05 10:56:25 -03001948 struct s5p_jpeg_addr jpeg_addr = {};
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001949 u32 pix_size;
1950
1951 pix_size = ctx->cap_q.w * ctx->cap_q.h;
1952
1953 if (ctx->mode == S5P_JPEG_ENCODE) {
1954 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1955 fmt = ctx->out_q.fmt;
1956 } else {
1957 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1958 fmt = ctx->cap_q.fmt;
1959 }
1960
1961 jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
1962
1963 if (fmt->colplanes == 2) {
1964 jpeg_addr.cb = jpeg_addr.y + pix_size;
1965 } else if (fmt->colplanes == 3) {
1966 jpeg_addr.cb = jpeg_addr.y + pix_size;
1967 if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
1968 jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
1969 else
1970 jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
1971 }
1972
1973 exynos3250_jpeg_imgadr(jpeg->regs, &jpeg_addr);
1974}
1975
1976static void exynos3250_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
1977{
1978 struct s5p_jpeg *jpeg = ctx->jpeg;
1979 struct vb2_buffer *vb;
1980 unsigned int jpeg_addr = 0;
1981
1982 if (ctx->mode == S5P_JPEG_ENCODE)
1983 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1984 else
1985 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1986
1987 jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
1988 exynos3250_jpeg_jpgadr(jpeg->regs, jpeg_addr);
1989}
1990
1991static void exynos3250_jpeg_device_run(void *priv)
1992{
1993 struct s5p_jpeg_ctx *ctx = priv;
1994 struct s5p_jpeg *jpeg = ctx->jpeg;
1995 unsigned long flags;
1996
1997 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1998
1999 exynos3250_jpeg_reset(jpeg->regs);
2000 exynos3250_jpeg_set_dma_num(jpeg->regs);
2001 exynos3250_jpeg_poweron(jpeg->regs);
2002 exynos3250_jpeg_clk_set(jpeg->regs);
2003 exynos3250_jpeg_proc_mode(jpeg->regs, ctx->mode);
2004
2005 if (ctx->mode == S5P_JPEG_ENCODE) {
2006 exynos3250_jpeg_input_raw_fmt(jpeg->regs,
2007 ctx->out_q.fmt->fourcc);
2008 exynos3250_jpeg_dri(jpeg->regs, ctx->restart_interval);
2009
2010 /*
2011 * JPEG IP allows storing 4 quantization tables
2012 * We fill table 0 for luma and table 1 for chroma
2013 */
2014 s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
2015 s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
2016 /* use table 0 for Y */
2017 exynos3250_jpeg_qtbl(jpeg->regs, 1, 0);
2018 /* use table 1 for Cb and Cr*/
2019 exynos3250_jpeg_qtbl(jpeg->regs, 2, 1);
2020 exynos3250_jpeg_qtbl(jpeg->regs, 3, 1);
2021
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03002022 /*
2023 * Some SoCs require setting Huffman tables before each run
2024 */
2025 if (jpeg->variant->htbl_reinit) {
2026 s5p_jpeg_set_hdctbl(jpeg->regs);
2027 s5p_jpeg_set_hdctblg(jpeg->regs);
2028 s5p_jpeg_set_hactbl(jpeg->regs);
2029 s5p_jpeg_set_hactblg(jpeg->regs);
2030 }
2031
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002032 /* Y, Cb, Cr use Huffman table 0 */
2033 exynos3250_jpeg_htbl_ac(jpeg->regs, 1);
2034 exynos3250_jpeg_htbl_dc(jpeg->regs, 1);
2035 exynos3250_jpeg_htbl_ac(jpeg->regs, 2);
2036 exynos3250_jpeg_htbl_dc(jpeg->regs, 2);
2037 exynos3250_jpeg_htbl_ac(jpeg->regs, 3);
2038 exynos3250_jpeg_htbl_dc(jpeg->regs, 3);
2039
2040 exynos3250_jpeg_set_x(jpeg->regs, ctx->crop_rect.width);
2041 exynos3250_jpeg_set_y(jpeg->regs, ctx->crop_rect.height);
2042 exynos3250_jpeg_stride(jpeg->regs, ctx->out_q.fmt->fourcc,
2043 ctx->out_q.w);
2044 exynos3250_jpeg_offset(jpeg->regs, ctx->crop_rect.left,
2045 ctx->crop_rect.top);
2046 exynos3250_jpeg_set_img_addr(ctx);
2047 exynos3250_jpeg_set_jpeg_addr(ctx);
2048 exynos3250_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
2049
2050 /* ultimately comes from sizeimage from userspace */
2051 exynos3250_jpeg_enc_stream_bound(jpeg->regs, ctx->cap_q.size);
2052
2053 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565 ||
2054 ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565X ||
2055 ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB32)
2056 exynos3250_jpeg_set_y16(jpeg->regs, true);
2057 } else {
2058 exynos3250_jpeg_set_img_addr(ctx);
2059 exynos3250_jpeg_set_jpeg_addr(ctx);
2060 exynos3250_jpeg_stride(jpeg->regs, ctx->cap_q.fmt->fourcc,
2061 ctx->cap_q.w);
2062 exynos3250_jpeg_offset(jpeg->regs, 0, 0);
2063 exynos3250_jpeg_dec_scaling_ratio(jpeg->regs,
2064 ctx->scale_factor);
2065 exynos3250_jpeg_dec_stream_size(jpeg->regs, ctx->out_q.size);
2066 exynos3250_jpeg_output_raw_fmt(jpeg->regs,
2067 ctx->cap_q.fmt->fourcc);
2068 }
2069
2070 exynos3250_jpeg_interrupts_enable(jpeg->regs);
2071
2072 /* JPEG RGB to YCbCr conversion matrix */
2073 exynos3250_jpeg_coef(jpeg->regs, ctx->mode);
2074
2075 exynos3250_jpeg_set_timer(jpeg->regs, EXYNOS3250_IRQ_TIMEOUT);
2076 jpeg->irq_status = 0;
2077 exynos3250_jpeg_start(jpeg->regs);
2078
2079 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
2080}
2081
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002082static int s5p_jpeg_job_ready(void *priv)
2083{
2084 struct s5p_jpeg_ctx *ctx = priv;
2085
2086 if (ctx->mode == S5P_JPEG_DECODE)
2087 return ctx->hdr_parsed;
2088 return 1;
2089}
2090
2091static void s5p_jpeg_job_abort(void *priv)
2092{
2093}
2094
2095static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = {
2096 .device_run = s5p_jpeg_device_run,
2097 .job_ready = s5p_jpeg_job_ready,
2098 .job_abort = s5p_jpeg_job_abort,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002099};
2100
2101static struct v4l2_m2m_ops exynos3250_jpeg_m2m_ops = {
2102 .device_run = exynos3250_jpeg_device_run,
2103 .job_ready = s5p_jpeg_job_ready,
2104 .job_abort = s5p_jpeg_job_abort,
2105};
2106
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03002107static struct v4l2_m2m_ops exynos4_jpeg_m2m_ops = {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002108 .device_run = exynos4_jpeg_device_run,
2109 .job_ready = s5p_jpeg_job_ready,
2110 .job_abort = s5p_jpeg_job_abort,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002111};
2112
2113/*
2114 * ============================================================================
2115 * Queue operations
2116 * ============================================================================
2117 */
2118
Marek Szyprowski719c1742012-01-13 05:12:38 -03002119static int s5p_jpeg_queue_setup(struct vb2_queue *vq,
2120 const struct v4l2_format *fmt,
2121 unsigned int *nbuffers, unsigned int *nplanes,
2122 unsigned int sizes[], void *alloc_ctxs[])
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002123{
2124 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
2125 struct s5p_jpeg_q_data *q_data = NULL;
2126 unsigned int size, count = *nbuffers;
2127
2128 q_data = get_q_data(ctx, vq->type);
2129 BUG_ON(q_data == NULL);
2130
2131 size = q_data->size;
2132
2133 /*
2134 * header is parsed during decoding and parsed information stored
2135 * in the context so we do not allow another buffer to overwrite it
2136 */
2137 if (ctx->mode == S5P_JPEG_DECODE)
2138 count = 1;
2139
2140 *nbuffers = count;
2141 *nplanes = 1;
2142 sizes[0] = size;
2143 alloc_ctxs[0] = ctx->jpeg->alloc_ctx;
2144
2145 return 0;
2146}
2147
2148static int s5p_jpeg_buf_prepare(struct vb2_buffer *vb)
2149{
2150 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
2151 struct s5p_jpeg_q_data *q_data = NULL;
2152
2153 q_data = get_q_data(ctx, vb->vb2_queue->type);
2154 BUG_ON(q_data == NULL);
2155
2156 if (vb2_plane_size(vb, 0) < q_data->size) {
2157 pr_err("%s data will not fit into plane (%lu < %lu)\n",
2158 __func__, vb2_plane_size(vb, 0),
2159 (long)q_data->size);
2160 return -EINVAL;
2161 }
2162
2163 vb2_set_plane_payload(vb, 0, q_data->size);
2164
2165 return 0;
2166}
2167
2168static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
2169{
2170 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
2171
2172 if (ctx->mode == S5P_JPEG_DECODE &&
2173 vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
2174 struct s5p_jpeg_q_data tmp, *q_data;
2175 ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp,
2176 (unsigned long)vb2_plane_vaddr(vb, 0),
2177 min((unsigned long)ctx->out_q.size,
Jacek Anaszewskif8433962013-11-21 13:33:09 -03002178 vb2_get_plane_payload(vb, 0)), ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002179 if (!ctx->hdr_parsed) {
2180 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
2181 return;
2182 }
2183
2184 q_data = &ctx->out_q;
2185 q_data->w = tmp.w;
2186 q_data->h = tmp.h;
2187
2188 q_data = &ctx->cap_q;
2189 q_data->w = tmp.w;
2190 q_data->h = tmp.h;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002191 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002192
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002193 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002194}
2195
2196static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
2197{
2198 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
2199 int ret;
2200
2201 ret = pm_runtime_get_sync(ctx->jpeg->dev);
2202
2203 return ret > 0 ? 0 : ret;
2204}
2205
Hans Verkuile37559b2014-04-17 02:47:21 -03002206static void s5p_jpeg_stop_streaming(struct vb2_queue *q)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002207{
2208 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
2209
2210 pm_runtime_put(ctx->jpeg->dev);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002211}
2212
2213static struct vb2_ops s5p_jpeg_qops = {
2214 .queue_setup = s5p_jpeg_queue_setup,
2215 .buf_prepare = s5p_jpeg_buf_prepare,
2216 .buf_queue = s5p_jpeg_buf_queue,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002217 .wait_prepare = vb2_ops_wait_prepare,
2218 .wait_finish = vb2_ops_wait_finish,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002219 .start_streaming = s5p_jpeg_start_streaming,
2220 .stop_streaming = s5p_jpeg_stop_streaming,
2221};
2222
2223static int queue_init(void *priv, struct vb2_queue *src_vq,
2224 struct vb2_queue *dst_vq)
2225{
2226 struct s5p_jpeg_ctx *ctx = priv;
2227 int ret;
2228
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002229 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
2230 src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
2231 src_vq->drv_priv = ctx;
2232 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
2233 src_vq->ops = &s5p_jpeg_qops;
2234 src_vq->mem_ops = &vb2_dma_contig_memops;
Sakari Ailusade48682014-02-25 19:12:19 -03002235 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002236 src_vq->lock = &ctx->jpeg->lock;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002237
2238 ret = vb2_queue_init(src_vq);
2239 if (ret)
2240 return ret;
2241
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002242 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2243 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
2244 dst_vq->drv_priv = ctx;
2245 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
2246 dst_vq->ops = &s5p_jpeg_qops;
2247 dst_vq->mem_ops = &vb2_dma_contig_memops;
Sakari Ailusade48682014-02-25 19:12:19 -03002248 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002249 dst_vq->lock = &ctx->jpeg->lock;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002250
2251 return vb2_queue_init(dst_vq);
2252}
2253
2254/*
2255 * ============================================================================
2256 * ISR
2257 * ============================================================================
2258 */
2259
2260static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
2261{
2262 struct s5p_jpeg *jpeg = dev_id;
2263 struct s5p_jpeg_ctx *curr_ctx;
2264 struct vb2_buffer *src_buf, *dst_buf;
2265 unsigned long payload_size = 0;
2266 enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
2267 bool enc_jpeg_too_large = false;
2268 bool timer_elapsed = false;
2269 bool op_completed = false;
2270
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002271 spin_lock(&jpeg->slock);
2272
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002273 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2274
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002275 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2276 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002277
2278 if (curr_ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002279 enc_jpeg_too_large = s5p_jpeg_enc_stream_stat(jpeg->regs);
2280 timer_elapsed = s5p_jpeg_timer_stat(jpeg->regs);
2281 op_completed = s5p_jpeg_result_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002282 if (curr_ctx->mode == S5P_JPEG_DECODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002283 op_completed = op_completed &&
2284 s5p_jpeg_stream_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002285
2286 if (enc_jpeg_too_large) {
2287 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002288 s5p_jpeg_clear_enc_stream_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002289 } else if (timer_elapsed) {
2290 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002291 s5p_jpeg_clear_timer_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002292 } else if (!op_completed) {
2293 state = VB2_BUF_STATE_ERROR;
2294 } else {
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002295 payload_size = s5p_jpeg_compressed_size(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002296 }
2297
Kamil Debskiaca326a2013-04-24 10:08:02 -03002298 dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
2299 dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
Sakari Ailus309f4d62014-02-08 14:21:35 -03002300 dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
2301 dst_buf->v4l2_buf.flags |=
2302 src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
Kamil Debskiaca326a2013-04-24 10:08:02 -03002303
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002304 v4l2_m2m_buf_done(src_buf, state);
2305 if (curr_ctx->mode == S5P_JPEG_ENCODE)
2306 vb2_set_plane_payload(dst_buf, 0, payload_size);
2307 v4l2_m2m_buf_done(dst_buf, state);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002308 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002309
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002310 curr_ctx->subsampling = s5p_jpeg_get_subsampling_mode(jpeg->regs);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002311 spin_unlock(&jpeg->slock);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03002312
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002313 s5p_jpeg_clear_int(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002314
2315 return IRQ_HANDLED;
2316}
2317
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002318static irqreturn_t exynos4_jpeg_irq(int irq, void *priv)
2319{
2320 unsigned int int_status;
2321 struct vb2_buffer *src_vb, *dst_vb;
2322 struct s5p_jpeg *jpeg = priv;
2323 struct s5p_jpeg_ctx *curr_ctx;
2324 unsigned long payload_size = 0;
2325
2326 spin_lock(&jpeg->slock);
2327
2328 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2329
2330 src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2331 dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
2332
2333 int_status = exynos4_jpeg_get_int_status(jpeg->regs);
2334
2335 if (int_status) {
2336 switch (int_status & 0x1f) {
2337 case 0x1:
2338 jpeg->irq_ret = ERR_PROT;
2339 break;
2340 case 0x2:
2341 jpeg->irq_ret = OK_ENC_OR_DEC;
2342 break;
2343 case 0x4:
2344 jpeg->irq_ret = ERR_DEC_INVALID_FORMAT;
2345 break;
2346 case 0x8:
2347 jpeg->irq_ret = ERR_MULTI_SCAN;
2348 break;
2349 case 0x10:
2350 jpeg->irq_ret = ERR_FRAME;
2351 break;
2352 default:
2353 jpeg->irq_ret = ERR_UNKNOWN;
2354 break;
2355 }
2356 } else {
2357 jpeg->irq_ret = ERR_UNKNOWN;
2358 }
2359
2360 if (jpeg->irq_ret == OK_ENC_OR_DEC) {
2361 if (curr_ctx->mode == S5P_JPEG_ENCODE) {
2362 payload_size = exynos4_jpeg_get_stream_size(jpeg->regs);
2363 vb2_set_plane_payload(dst_vb, 0, payload_size);
2364 }
2365 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
2366 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
2367 } else {
2368 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
2369 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
2370 }
2371
2372 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
2373 curr_ctx->subsampling = exynos4_jpeg_get_frame_fmt(jpeg->regs);
2374
2375 spin_unlock(&jpeg->slock);
2376 return IRQ_HANDLED;
2377}
2378
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002379static irqreturn_t exynos3250_jpeg_irq(int irq, void *dev_id)
2380{
2381 struct s5p_jpeg *jpeg = dev_id;
2382 struct s5p_jpeg_ctx *curr_ctx;
2383 struct vb2_buffer *src_buf, *dst_buf;
2384 unsigned long payload_size = 0;
2385 enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
2386 bool interrupt_timeout = false;
2387 u32 irq_status;
2388
2389 spin_lock(&jpeg->slock);
2390
2391 irq_status = exynos3250_jpeg_get_timer_status(jpeg->regs);
2392 if (irq_status & EXYNOS3250_TIMER_INT_STAT) {
2393 exynos3250_jpeg_clear_timer_status(jpeg->regs);
2394 interrupt_timeout = true;
2395 dev_err(jpeg->dev, "Interrupt timeout occurred.\n");
2396 }
2397
2398 irq_status = exynos3250_jpeg_get_int_status(jpeg->regs);
2399 exynos3250_jpeg_clear_int_status(jpeg->regs, irq_status);
2400
2401 jpeg->irq_status |= irq_status;
2402
2403 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2404
2405 if (!curr_ctx)
2406 goto exit_unlock;
2407
2408 if ((irq_status & EXYNOS3250_HEADER_STAT) &&
2409 (curr_ctx->mode == S5P_JPEG_DECODE)) {
2410 exynos3250_jpeg_rstart(jpeg->regs);
2411 goto exit_unlock;
2412 }
2413
2414 if (jpeg->irq_status & (EXYNOS3250_JPEG_DONE |
2415 EXYNOS3250_WDMA_DONE |
2416 EXYNOS3250_RDMA_DONE |
2417 EXYNOS3250_RESULT_STAT))
2418 payload_size = exynos3250_jpeg_compressed_size(jpeg->regs);
2419 else if (interrupt_timeout)
2420 state = VB2_BUF_STATE_ERROR;
2421 else
2422 goto exit_unlock;
2423
2424 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2425 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
2426
2427 dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
2428 dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
2429
2430 v4l2_m2m_buf_done(src_buf, state);
2431 if (curr_ctx->mode == S5P_JPEG_ENCODE)
2432 vb2_set_plane_payload(dst_buf, 0, payload_size);
2433 v4l2_m2m_buf_done(dst_buf, state);
2434 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
2435
2436 curr_ctx->subsampling =
2437 exynos3250_jpeg_get_subsampling_mode(jpeg->regs);
2438exit_unlock:
2439 spin_unlock(&jpeg->slock);
2440 return IRQ_HANDLED;
2441}
2442
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03002443static void *jpeg_get_drv_data(struct device *dev);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002444
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002445/*
2446 * ============================================================================
2447 * Driver basic infrastructure
2448 * ============================================================================
2449 */
2450
2451static int s5p_jpeg_probe(struct platform_device *pdev)
2452{
2453 struct s5p_jpeg *jpeg;
2454 struct resource *res;
2455 int ret;
2456
2457 /* JPEG IP abstraction struct */
Sachin Kamat5b58b952012-05-14 06:33:34 -03002458 jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002459 if (!jpeg)
2460 return -ENOMEM;
2461
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03002462 jpeg->variant = jpeg_get_drv_data(&pdev->dev);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002463
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002464 mutex_init(&jpeg->lock);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002465 spin_lock_init(&jpeg->slock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002466 jpeg->dev = &pdev->dev;
2467
2468 /* memory-mapped registers */
2469 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002470
Thierry Redingf23999e2013-01-21 06:09:07 -03002471 jpeg->regs = devm_ioremap_resource(&pdev->dev, res);
2472 if (IS_ERR(jpeg->regs))
2473 return PTR_ERR(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002474
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002475 /* interrupt service routine registration */
2476 jpeg->irq = ret = platform_get_irq(pdev, 0);
2477 if (ret < 0) {
2478 dev_err(&pdev->dev, "cannot find IRQ\n");
Sachin Kamat5b58b952012-05-14 06:33:34 -03002479 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002480 }
2481
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002482 ret = devm_request_irq(&pdev->dev, jpeg->irq, jpeg->variant->jpeg_irq,
2483 0, dev_name(&pdev->dev), jpeg);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002484 if (ret) {
2485 dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
Sachin Kamat5b58b952012-05-14 06:33:34 -03002486 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002487 }
2488
2489 /* clocks */
2490 jpeg->clk = clk_get(&pdev->dev, "jpeg");
2491 if (IS_ERR(jpeg->clk)) {
2492 dev_err(&pdev->dev, "cannot get clock\n");
2493 ret = PTR_ERR(jpeg->clk);
Sachin Kamat5b58b952012-05-14 06:33:34 -03002494 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002495 }
2496 dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002497
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002498 jpeg->sclk = clk_get(&pdev->dev, "sclk");
2499 if (IS_ERR(jpeg->sclk))
2500 dev_info(&pdev->dev, "sclk clock not available\n");
2501
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002502 /* v4l2 device */
2503 ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
2504 if (ret) {
2505 dev_err(&pdev->dev, "Failed to register v4l2 device\n");
2506 goto clk_get_rollback;
2507 }
2508
2509 /* mem2mem device */
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03002510 jpeg->m2m_dev = v4l2_m2m_init(jpeg->variant->m2m_ops);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002511 if (IS_ERR(jpeg->m2m_dev)) {
2512 v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
2513 ret = PTR_ERR(jpeg->m2m_dev);
2514 goto device_register_rollback;
2515 }
2516
2517 jpeg->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
2518 if (IS_ERR(jpeg->alloc_ctx)) {
2519 v4l2_err(&jpeg->v4l2_dev, "Failed to init memory allocator\n");
2520 ret = PTR_ERR(jpeg->alloc_ctx);
2521 goto m2m_init_rollback;
2522 }
2523
2524 /* JPEG encoder /dev/videoX node */
2525 jpeg->vfd_encoder = video_device_alloc();
2526 if (!jpeg->vfd_encoder) {
2527 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
2528 ret = -ENOMEM;
2529 goto vb2_allocator_rollback;
2530 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03002531 snprintf(jpeg->vfd_encoder->name, sizeof(jpeg->vfd_encoder->name),
2532 "%s-enc", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002533 jpeg->vfd_encoder->fops = &s5p_jpeg_fops;
2534 jpeg->vfd_encoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
2535 jpeg->vfd_encoder->minor = -1;
2536 jpeg->vfd_encoder->release = video_device_release;
2537 jpeg->vfd_encoder->lock = &jpeg->lock;
2538 jpeg->vfd_encoder->v4l2_dev = &jpeg->v4l2_dev;
Hans Verkuil954f3402012-09-05 06:05:50 -03002539 jpeg->vfd_encoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002540
2541 ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
2542 if (ret) {
2543 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
2544 goto enc_vdev_alloc_rollback;
2545 }
2546
2547 video_set_drvdata(jpeg->vfd_encoder, jpeg);
2548 v4l2_info(&jpeg->v4l2_dev,
2549 "encoder device registered as /dev/video%d\n",
2550 jpeg->vfd_encoder->num);
2551
2552 /* JPEG decoder /dev/videoX node */
2553 jpeg->vfd_decoder = video_device_alloc();
2554 if (!jpeg->vfd_decoder) {
2555 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
2556 ret = -ENOMEM;
2557 goto enc_vdev_register_rollback;
2558 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03002559 snprintf(jpeg->vfd_decoder->name, sizeof(jpeg->vfd_decoder->name),
2560 "%s-dec", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002561 jpeg->vfd_decoder->fops = &s5p_jpeg_fops;
2562 jpeg->vfd_decoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
2563 jpeg->vfd_decoder->minor = -1;
2564 jpeg->vfd_decoder->release = video_device_release;
2565 jpeg->vfd_decoder->lock = &jpeg->lock;
2566 jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev;
Jacek Anaszewski7f7d8fe2013-09-11 06:17:45 -03002567 jpeg->vfd_decoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002568
2569 ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
2570 if (ret) {
2571 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
2572 goto dec_vdev_alloc_rollback;
2573 }
2574
2575 video_set_drvdata(jpeg->vfd_decoder, jpeg);
2576 v4l2_info(&jpeg->v4l2_dev,
2577 "decoder device registered as /dev/video%d\n",
2578 jpeg->vfd_decoder->num);
2579
2580 /* final statements & power management */
2581 platform_set_drvdata(pdev, jpeg);
2582
2583 pm_runtime_enable(&pdev->dev);
2584
2585 v4l2_info(&jpeg->v4l2_dev, "Samsung S5P JPEG codec\n");
2586
2587 return 0;
2588
2589dec_vdev_alloc_rollback:
2590 video_device_release(jpeg->vfd_decoder);
2591
2592enc_vdev_register_rollback:
2593 video_unregister_device(jpeg->vfd_encoder);
2594
2595enc_vdev_alloc_rollback:
2596 video_device_release(jpeg->vfd_encoder);
2597
2598vb2_allocator_rollback:
2599 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
2600
2601m2m_init_rollback:
2602 v4l2_m2m_release(jpeg->m2m_dev);
2603
2604device_register_rollback:
2605 v4l2_device_unregister(&jpeg->v4l2_dev);
2606
2607clk_get_rollback:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002608 clk_put(jpeg->clk);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002609 if (!IS_ERR(jpeg->sclk))
2610 clk_put(jpeg->sclk);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002611
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002612 return ret;
2613}
2614
2615static int s5p_jpeg_remove(struct platform_device *pdev)
2616{
2617 struct s5p_jpeg *jpeg = platform_get_drvdata(pdev);
2618
2619 pm_runtime_disable(jpeg->dev);
2620
2621 video_unregister_device(jpeg->vfd_decoder);
2622 video_device_release(jpeg->vfd_decoder);
2623 video_unregister_device(jpeg->vfd_encoder);
2624 video_device_release(jpeg->vfd_encoder);
2625 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
2626 v4l2_m2m_release(jpeg->m2m_dev);
2627 v4l2_device_unregister(&jpeg->v4l2_dev);
2628
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002629 if (!pm_runtime_status_suspended(&pdev->dev)) {
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002630 clk_disable_unprepare(jpeg->clk);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002631 if (!IS_ERR(jpeg->sclk))
2632 clk_disable_unprepare(jpeg->sclk);
2633 }
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002634
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002635 clk_put(jpeg->clk);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002636 if (!IS_ERR(jpeg->sclk))
2637 clk_put(jpeg->sclk);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002638
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002639 return 0;
2640}
2641
Rafael J. Wysockie243c7c2014-12-04 01:10:10 +01002642#ifdef CONFIG_PM
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002643static int s5p_jpeg_runtime_suspend(struct device *dev)
2644{
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002645 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
2646
2647 clk_disable_unprepare(jpeg->clk);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002648 if (!IS_ERR(jpeg->sclk))
2649 clk_disable_unprepare(jpeg->sclk);
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002650
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002651 return 0;
2652}
2653
2654static int s5p_jpeg_runtime_resume(struct device *dev)
2655{
2656 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002657 unsigned long flags;
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002658 int ret;
2659
2660 ret = clk_prepare_enable(jpeg->clk);
2661 if (ret < 0)
2662 return ret;
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03002663
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002664 if (!IS_ERR(jpeg->sclk)) {
2665 ret = clk_prepare_enable(jpeg->sclk);
2666 if (ret < 0)
2667 return ret;
2668 }
2669
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002670 spin_lock_irqsave(&jpeg->slock, flags);
2671
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002672 /*
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002673 * JPEG IP allows storing two Huffman tables for each component.
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002674 * We fill table 0 for each component and do this here only
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03002675 * for S5PC210 and Exynos3250 SoCs. Exynos4x12 and Exynos542x SoC
2676 * require programming their Huffman tables each time the encoding
2677 * process is initialized, and thus it is accomplished in the
2678 * device_run callback of m2m_ops.
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002679 */
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03002680 if (!jpeg->variant->htbl_reinit) {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002681 s5p_jpeg_set_hdctbl(jpeg->regs);
2682 s5p_jpeg_set_hdctblg(jpeg->regs);
2683 s5p_jpeg_set_hactbl(jpeg->regs);
2684 s5p_jpeg_set_hactblg(jpeg->regs);
2685 }
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03002686
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002687 spin_unlock_irqrestore(&jpeg->slock, flags);
2688
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002689 return 0;
2690}
Rafael J. Wysockie243c7c2014-12-04 01:10:10 +01002691#endif /* CONFIG_PM */
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002692
Thierry Redingde3767a2014-10-14 07:10:40 -03002693#ifdef CONFIG_PM_SLEEP
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002694static int s5p_jpeg_suspend(struct device *dev)
2695{
2696 if (pm_runtime_suspended(dev))
2697 return 0;
2698
2699 return s5p_jpeg_runtime_suspend(dev);
2700}
2701
2702static int s5p_jpeg_resume(struct device *dev)
2703{
2704 if (pm_runtime_suspended(dev))
2705 return 0;
2706
2707 return s5p_jpeg_runtime_resume(dev);
2708}
Thierry Redingde3767a2014-10-14 07:10:40 -03002709#endif
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002710
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002711static const struct dev_pm_ops s5p_jpeg_pm_ops = {
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002712 SET_SYSTEM_SLEEP_PM_OPS(s5p_jpeg_suspend, s5p_jpeg_resume)
2713 SET_RUNTIME_PM_OPS(s5p_jpeg_runtime_suspend, s5p_jpeg_runtime_resume, NULL)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002714};
2715
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002716static struct s5p_jpeg_variant s5p_jpeg_drvdata = {
2717 .version = SJPEG_S5P,
2718 .jpeg_irq = s5p_jpeg_irq,
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03002719 .m2m_ops = &s5p_jpeg_m2m_ops,
Jacek Anaszewskib2451682014-04-10 04:32:11 -03002720 .fmt_ver_flag = SJPEG_FMT_FLAG_S5P,
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03002721};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002722
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002723static struct s5p_jpeg_variant exynos3250_jpeg_drvdata = {
2724 .version = SJPEG_EXYNOS3250,
2725 .jpeg_irq = exynos3250_jpeg_irq,
2726 .m2m_ops = &exynos3250_jpeg_m2m_ops,
2727 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS3250,
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03002728 .hw3250_compat = 1,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002729};
2730
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002731static struct s5p_jpeg_variant exynos4_jpeg_drvdata = {
2732 .version = SJPEG_EXYNOS4,
2733 .jpeg_irq = exynos4_jpeg_irq,
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03002734 .m2m_ops = &exynos4_jpeg_m2m_ops,
Jacek Anaszewskib2451682014-04-10 04:32:11 -03002735 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS4,
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03002736 .htbl_reinit = 1,
2737};
2738
2739static struct s5p_jpeg_variant exynos5420_jpeg_drvdata = {
2740 .version = SJPEG_EXYNOS5420,
2741 .jpeg_irq = exynos3250_jpeg_irq, /* intentionally 3250 */
2742 .m2m_ops = &exynos3250_jpeg_m2m_ops, /* intentionally 3250 */
2743 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS3250, /* intentionally 3250 */
2744 .hw3250_compat = 1,
2745 .htbl_reinit = 1,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002746};
2747
2748static const struct of_device_id samsung_jpeg_match[] = {
2749 {
2750 .compatible = "samsung,s5pv210-jpeg",
2751 .data = &s5p_jpeg_drvdata,
2752 }, {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002753 .compatible = "samsung,exynos3250-jpeg",
2754 .data = &exynos3250_jpeg_drvdata,
2755 }, {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002756 .compatible = "samsung,exynos4210-jpeg",
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002757 .data = &exynos4_jpeg_drvdata,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002758 }, {
2759 .compatible = "samsung,exynos4212-jpeg",
2760 .data = &exynos4_jpeg_drvdata,
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03002761 }, {
2762 .compatible = "samsung,exynos5420-jpeg",
2763 .data = &exynos5420_jpeg_drvdata,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002764 },
2765 {},
2766};
2767
2768MODULE_DEVICE_TABLE(of, samsung_jpeg_match);
2769
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03002770static void *jpeg_get_drv_data(struct device *dev)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002771{
2772 struct s5p_jpeg_variant *driver_data = NULL;
2773 const struct of_device_id *match;
2774
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03002775 if (!IS_ENABLED(CONFIG_OF) || !dev->of_node)
2776 return &s5p_jpeg_drvdata;
2777
2778 match = of_match_node(samsung_jpeg_match, dev->of_node);
2779
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002780 if (match)
2781 driver_data = (struct s5p_jpeg_variant *)match->data;
2782
2783 return driver_data;
2784}
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03002785
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002786static struct platform_driver s5p_jpeg_driver = {
2787 .probe = s5p_jpeg_probe,
2788 .remove = s5p_jpeg_remove,
2789 .driver = {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002790 .of_match_table = of_match_ptr(samsung_jpeg_match),
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002791 .name = S5P_JPEG_M2M_NAME,
2792 .pm = &s5p_jpeg_pm_ops,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002793 },
2794};
2795
Sachin Kamat87e94292012-07-03 05:54:33 -03002796module_platform_driver(s5p_jpeg_driver);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002797
2798MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002799MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002800MODULE_DESCRIPTION("Samsung JPEG codec driver");
2801MODULE_LICENSE("GPL");