blob: a92ff4249d100d33e84acaf50b372eb5e2a190b0 [file] [log] [blame]
Mauro Carvalho Chehab2c3fb082012-08-14 17:31:16 -03001/* linux/drivers/media/platform/s5p-jpeg/jpeg-core.c
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002 *
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003 * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd.
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03004 * http://www.samsung.com
5 *
6 * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03007 * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03008 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/clk.h>
15#include <linux/err.h>
16#include <linux/gfp.h>
17#include <linux/interrupt.h>
18#include <linux/io.h>
19#include <linux/kernel.h>
20#include <linux/module.h>
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -030021#include <linux/of.h>
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030022#include <linux/platform_device.h>
23#include <linux/pm_runtime.h>
24#include <linux/slab.h>
25#include <linux/spinlock.h>
26#include <linux/string.h>
27#include <media/v4l2-mem2mem.h>
28#include <media/v4l2-ioctl.h>
29#include <media/videobuf2-core.h>
30#include <media/videobuf2-dma-contig.h>
31
32#include "jpeg-core.h"
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -030033#include "jpeg-hw-s5p.h"
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030034#include "jpeg-hw-exynos4.h"
Jacek Anaszewski3246fda2014-07-11 12:19:42 -030035#include "jpeg-hw-exynos3250.h"
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030036#include "jpeg-regs.h"
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030037
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030038static struct s5p_jpeg_fmt sjpeg_formats[] = {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030039 {
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -030040 .name = "JPEG JFIF",
41 .fourcc = V4L2_PIX_FMT_JPEG,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030042 .flags = SJPEG_FMT_FLAG_ENC_CAPTURE |
43 SJPEG_FMT_FLAG_DEC_OUTPUT |
44 SJPEG_FMT_FLAG_S5P |
Jacek Anaszewski3246fda2014-07-11 12:19:42 -030045 SJPEG_FMT_FLAG_EXYNOS3250 |
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030046 SJPEG_FMT_FLAG_EXYNOS4,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030047 },
48 {
49 .name = "YUV 4:2:2 packed, YCbYCr",
50 .fourcc = V4L2_PIX_FMT_YUYV,
51 .depth = 16,
52 .colplanes = 1,
53 .h_align = 4,
54 .v_align = 3,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030055 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
56 SJPEG_FMT_FLAG_DEC_CAPTURE |
57 SJPEG_FMT_FLAG_S5P |
58 SJPEG_FMT_NON_RGB,
59 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030060 },
61 {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030062 .name = "YUV 4:2:2 packed, YCbYCr",
63 .fourcc = V4L2_PIX_FMT_YUYV,
64 .depth = 16,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030065 .colplanes = 1,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030066 .h_align = 1,
67 .v_align = 0,
68 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
69 SJPEG_FMT_FLAG_DEC_CAPTURE |
70 SJPEG_FMT_FLAG_EXYNOS4 |
71 SJPEG_FMT_NON_RGB,
72 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
73 },
74 {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -030075 .name = "YUV 4:2:2 packed, YCbYCr",
76 .fourcc = V4L2_PIX_FMT_YUYV,
77 .depth = 16,
78 .colplanes = 1,
79 .h_align = 2,
80 .v_align = 0,
81 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
82 SJPEG_FMT_FLAG_DEC_CAPTURE |
83 SJPEG_FMT_FLAG_EXYNOS3250 |
84 SJPEG_FMT_NON_RGB,
85 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
86 },
87 {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030088 .name = "YUV 4:2:2 packed, YCrYCb",
89 .fourcc = V4L2_PIX_FMT_YVYU,
90 .depth = 16,
91 .colplanes = 1,
92 .h_align = 1,
93 .v_align = 0,
94 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
95 SJPEG_FMT_FLAG_DEC_CAPTURE |
96 SJPEG_FMT_FLAG_EXYNOS4 |
97 SJPEG_FMT_NON_RGB,
98 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
99 },
100 {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300101 .name = "YUV 4:2:2 packed, YCrYCb",
102 .fourcc = V4L2_PIX_FMT_YVYU,
103 .depth = 16,
104 .colplanes = 1,
105 .h_align = 2,
106 .v_align = 0,
107 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
108 SJPEG_FMT_FLAG_DEC_CAPTURE |
109 SJPEG_FMT_FLAG_EXYNOS3250 |
110 SJPEG_FMT_NON_RGB,
111 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
112 },
113 {
114 .name = "YUV 4:2:2 packed, YCrYCb",
115 .fourcc = V4L2_PIX_FMT_UYVY,
116 .depth = 16,
117 .colplanes = 1,
118 .h_align = 2,
119 .v_align = 0,
120 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
121 SJPEG_FMT_FLAG_DEC_CAPTURE |
122 SJPEG_FMT_FLAG_EXYNOS3250 |
123 SJPEG_FMT_NON_RGB,
124 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
125 },
126 {
127 .name = "YUV 4:2:2 packed, YCrYCb",
128 .fourcc = V4L2_PIX_FMT_VYUY,
129 .depth = 16,
130 .colplanes = 1,
131 .h_align = 2,
132 .v_align = 0,
133 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
134 SJPEG_FMT_FLAG_DEC_CAPTURE |
135 SJPEG_FMT_FLAG_EXYNOS3250 |
136 SJPEG_FMT_NON_RGB,
137 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
138 },
139 {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300140 .name = "RGB565",
141 .fourcc = V4L2_PIX_FMT_RGB565,
142 .depth = 16,
143 .colplanes = 1,
144 .h_align = 0,
145 .v_align = 0,
146 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
147 SJPEG_FMT_FLAG_DEC_CAPTURE |
148 SJPEG_FMT_FLAG_EXYNOS4 |
149 SJPEG_FMT_RGB,
150 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
151 },
152 {
153 .name = "RGB565",
154 .fourcc = V4L2_PIX_FMT_RGB565,
155 .depth = 16,
156 .colplanes = 1,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300157 .h_align = 2,
158 .v_align = 0,
159 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
160 SJPEG_FMT_FLAG_DEC_CAPTURE |
161 SJPEG_FMT_FLAG_EXYNOS3250 |
162 SJPEG_FMT_RGB,
163 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
164 },
165 {
166 .name = "RGB565X",
167 .fourcc = V4L2_PIX_FMT_RGB565X,
168 .depth = 16,
169 .colplanes = 1,
170 .h_align = 2,
171 .v_align = 0,
172 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
173 SJPEG_FMT_FLAG_DEC_CAPTURE |
174 SJPEG_FMT_FLAG_EXYNOS3250 |
175 SJPEG_FMT_RGB,
176 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
177 },
178 {
179 .name = "RGB565",
180 .fourcc = V4L2_PIX_FMT_RGB565,
181 .depth = 16,
182 .colplanes = 1,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300183 .h_align = 0,
184 .v_align = 0,
185 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
186 SJPEG_FMT_FLAG_S5P |
187 SJPEG_FMT_RGB,
188 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
189 },
190 {
191 .name = "ARGB8888, 32 bpp",
192 .fourcc = V4L2_PIX_FMT_RGB32,
193 .depth = 32,
194 .colplanes = 1,
195 .h_align = 0,
196 .v_align = 0,
197 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
198 SJPEG_FMT_FLAG_DEC_CAPTURE |
199 SJPEG_FMT_FLAG_EXYNOS4 |
200 SJPEG_FMT_RGB,
201 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
202 },
203 {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300204 .name = "ARGB8888, 32 bpp",
205 .fourcc = V4L2_PIX_FMT_RGB32,
206 .depth = 32,
207 .colplanes = 1,
208 .h_align = 2,
209 .v_align = 0,
210 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
211 SJPEG_FMT_FLAG_DEC_CAPTURE |
212 SJPEG_FMT_FLAG_EXYNOS3250 |
213 SJPEG_FMT_RGB,
214 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
215 },
216 {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300217 .name = "YUV 4:4:4 planar, Y/CbCr",
218 .fourcc = V4L2_PIX_FMT_NV24,
219 .depth = 24,
220 .colplanes = 2,
221 .h_align = 0,
222 .v_align = 0,
223 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
224 SJPEG_FMT_FLAG_DEC_CAPTURE |
225 SJPEG_FMT_FLAG_EXYNOS4 |
226 SJPEG_FMT_NON_RGB,
227 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
228 },
229 {
230 .name = "YUV 4:4:4 planar, Y/CrCb",
231 .fourcc = V4L2_PIX_FMT_NV42,
232 .depth = 24,
233 .colplanes = 2,
234 .h_align = 0,
235 .v_align = 0,
236 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
237 SJPEG_FMT_FLAG_DEC_CAPTURE |
238 SJPEG_FMT_FLAG_EXYNOS4 |
239 SJPEG_FMT_NON_RGB,
240 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
241 },
242 {
243 .name = "YUV 4:2:2 planar, Y/CrCb",
244 .fourcc = V4L2_PIX_FMT_NV61,
245 .depth = 16,
246 .colplanes = 2,
247 .h_align = 1,
248 .v_align = 0,
249 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
250 SJPEG_FMT_FLAG_DEC_CAPTURE |
251 SJPEG_FMT_FLAG_EXYNOS4 |
252 SJPEG_FMT_NON_RGB,
253 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
254 },
255 {
256 .name = "YUV 4:2:2 planar, Y/CbCr",
257 .fourcc = V4L2_PIX_FMT_NV16,
258 .depth = 16,
259 .colplanes = 2,
260 .h_align = 1,
261 .v_align = 0,
262 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
263 SJPEG_FMT_FLAG_DEC_CAPTURE |
264 SJPEG_FMT_FLAG_EXYNOS4 |
265 SJPEG_FMT_NON_RGB,
266 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
267 },
268 {
269 .name = "YUV 4:2:0 planar, Y/CbCr",
270 .fourcc = V4L2_PIX_FMT_NV12,
Jacek Anaszewskia62cffe2014-01-16 08:26:33 -0300271 .depth = 12,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300272 .colplanes = 2,
273 .h_align = 1,
274 .v_align = 1,
275 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
276 SJPEG_FMT_FLAG_DEC_CAPTURE |
277 SJPEG_FMT_FLAG_EXYNOS4 |
278 SJPEG_FMT_NON_RGB,
279 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
280 },
281 {
282 .name = "YUV 4:2:0 planar, Y/CbCr",
283 .fourcc = V4L2_PIX_FMT_NV12,
Jacek Anaszewskia62cffe2014-01-16 08:26:33 -0300284 .depth = 12,
285 .colplanes = 2,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300286 .h_align = 3,
287 .v_align = 3,
288 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
289 SJPEG_FMT_FLAG_DEC_CAPTURE |
290 SJPEG_FMT_FLAG_EXYNOS3250 |
291 SJPEG_FMT_NON_RGB,
292 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
293 },
294 {
295 .name = "YUV 4:2:0 planar, Y/CbCr",
296 .fourcc = V4L2_PIX_FMT_NV12,
297 .depth = 12,
298 .colplanes = 2,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300299 .h_align = 4,
Jacek Anaszewskia62cffe2014-01-16 08:26:33 -0300300 .v_align = 4,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300301 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
302 SJPEG_FMT_FLAG_DEC_CAPTURE |
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300303 SJPEG_FMT_FLAG_S5P |
304 SJPEG_FMT_NON_RGB,
305 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
306 },
307 {
308 .name = "YUV 4:2:0 planar, Y/CrCb",
309 .fourcc = V4L2_PIX_FMT_NV21,
310 .depth = 12,
311 .colplanes = 2,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300312 .h_align = 3,
313 .v_align = 3,
314 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
315 SJPEG_FMT_FLAG_DEC_CAPTURE |
316 SJPEG_FMT_FLAG_EXYNOS3250 |
317 SJPEG_FMT_NON_RGB,
318 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
319 },
320 {
321 .name = "YUV 4:2:0 planar, Y/CrCb",
322 .fourcc = V4L2_PIX_FMT_NV21,
323 .depth = 12,
324 .colplanes = 2,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300325 .h_align = 1,
326 .v_align = 1,
327 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
328 SJPEG_FMT_FLAG_DEC_CAPTURE |
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300329 SJPEG_FMT_FLAG_EXYNOS3250 |
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300330 SJPEG_FMT_FLAG_EXYNOS4 |
331 SJPEG_FMT_NON_RGB,
332 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
333 },
334 {
335 .name = "YUV 4:2:0 contiguous 3-planar, Y/Cb/Cr",
336 .fourcc = V4L2_PIX_FMT_YUV420,
337 .depth = 12,
338 .colplanes = 3,
339 .h_align = 1,
340 .v_align = 1,
341 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
342 SJPEG_FMT_FLAG_DEC_CAPTURE |
343 SJPEG_FMT_FLAG_EXYNOS4 |
344 SJPEG_FMT_NON_RGB,
345 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
346 },
347 {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300348 .name = "YUV 4:2:0 contiguous 3-planar, Y/Cb/Cr",
349 .fourcc = V4L2_PIX_FMT_YUV420,
350 .depth = 12,
351 .colplanes = 3,
352 .h_align = 4,
353 .v_align = 4,
354 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
355 SJPEG_FMT_FLAG_DEC_CAPTURE |
356 SJPEG_FMT_FLAG_EXYNOS3250 |
357 SJPEG_FMT_NON_RGB,
358 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
359 },
360 {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300361 .name = "Gray",
362 .fourcc = V4L2_PIX_FMT_GREY,
363 .depth = 8,
364 .colplanes = 1,
365 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
366 SJPEG_FMT_FLAG_DEC_CAPTURE |
367 SJPEG_FMT_FLAG_EXYNOS4 |
368 SJPEG_FMT_NON_RGB,
369 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300370 },
371};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300372#define SJPEG_NUM_FORMATS ARRAY_SIZE(sjpeg_formats)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300373
374static const unsigned char qtbl_luminance[4][64] = {
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300375 {/*level 0 - high compression quality */
376 20, 16, 25, 39, 50, 46, 62, 68,
377 16, 18, 23, 38, 38, 53, 65, 68,
378 25, 23, 31, 38, 53, 65, 68, 68,
379 39, 38, 38, 53, 65, 68, 68, 68,
380 50, 38, 53, 65, 68, 68, 68, 68,
381 46, 53, 65, 68, 68, 68, 68, 68,
382 62, 65, 68, 68, 68, 68, 68, 68,
383 68, 68, 68, 68, 68, 68, 68, 68
384 },
385 {/* level 1 */
386 16, 11, 11, 16, 23, 27, 31, 30,
387 11, 12, 12, 15, 20, 23, 23, 30,
388 11, 12, 13, 16, 23, 26, 35, 47,
389 16, 15, 16, 23, 26, 37, 47, 64,
390 23, 20, 23, 26, 39, 51, 64, 64,
391 27, 23, 26, 37, 51, 64, 64, 64,
392 31, 23, 35, 47, 64, 64, 64, 64,
393 30, 30, 47, 64, 64, 64, 64, 64
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300394 },
395 {/* level 2 */
396 12, 8, 8, 12, 17, 21, 24, 23,
397 8, 9, 9, 11, 15, 19, 18, 23,
398 8, 9, 10, 12, 19, 20, 27, 36,
399 12, 11, 12, 21, 20, 28, 36, 53,
400 17, 15, 19, 20, 30, 39, 51, 59,
401 21, 19, 20, 28, 39, 51, 59, 59,
402 24, 18, 27, 36, 51, 59, 59, 59,
403 23, 23, 36, 53, 59, 59, 59, 59
404 },
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300405 {/* level 3 - low compression quality */
406 8, 6, 6, 8, 12, 14, 16, 17,
407 6, 6, 6, 8, 10, 13, 12, 15,
408 6, 6, 7, 8, 13, 14, 18, 24,
409 8, 8, 8, 14, 13, 19, 24, 35,
410 12, 10, 13, 13, 20, 26, 34, 39,
411 14, 13, 14, 19, 26, 34, 39, 39,
412 16, 12, 18, 24, 34, 39, 39, 39,
413 17, 15, 24, 35, 39, 39, 39, 39
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300414 }
415};
416
417static const unsigned char qtbl_chrominance[4][64] = {
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300418 {/*level 0 - high compression quality */
419 21, 25, 32, 38, 54, 68, 68, 68,
420 25, 28, 24, 38, 54, 68, 68, 68,
421 32, 24, 32, 43, 66, 68, 68, 68,
422 38, 38, 43, 53, 68, 68, 68, 68,
423 54, 54, 66, 68, 68, 68, 68, 68,
424 68, 68, 68, 68, 68, 68, 68, 68,
425 68, 68, 68, 68, 68, 68, 68, 68,
426 68, 68, 68, 68, 68, 68, 68, 68
427 },
428 {/* level 1 */
429 17, 15, 17, 21, 20, 26, 38, 48,
430 15, 19, 18, 17, 20, 26, 35, 43,
431 17, 18, 20, 22, 26, 30, 46, 53,
432 21, 17, 22, 28, 30, 39, 53, 64,
433 20, 20, 26, 30, 39, 48, 64, 64,
434 26, 26, 30, 39, 48, 63, 64, 64,
435 38, 35, 46, 53, 64, 64, 64, 64,
436 48, 43, 53, 64, 64, 64, 64, 64
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300437 },
438 {/* level 2 */
439 13, 11, 13, 16, 20, 20, 29, 37,
440 11, 14, 14, 14, 16, 20, 26, 32,
441 13, 14, 15, 17, 20, 23, 35, 40,
442 16, 14, 17, 21, 23, 30, 40, 50,
443 20, 16, 20, 23, 30, 37, 50, 59,
444 20, 20, 23, 30, 37, 48, 59, 59,
445 29, 26, 35, 40, 50, 59, 59, 59,
446 37, 32, 40, 50, 59, 59, 59, 59
447 },
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300448 {/* level 3 - low compression quality */
449 9, 8, 9, 11, 14, 17, 19, 24,
450 8, 10, 9, 11, 14, 13, 17, 22,
451 9, 9, 13, 14, 13, 15, 23, 26,
452 11, 11, 14, 14, 15, 20, 26, 33,
453 14, 14, 13, 15, 20, 24, 33, 39,
454 17, 13, 15, 20, 24, 32, 39, 39,
455 19, 17, 23, 26, 33, 39, 39, 39,
456 24, 22, 26, 33, 39, 39, 39, 39
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300457 }
458};
459
460static const unsigned char hdctbl0[16] = {
461 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
462};
463
464static const unsigned char hdctblg0[12] = {
465 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb
466};
467static const unsigned char hactbl0[16] = {
468 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
469};
470static const unsigned char hactblg0[162] = {
471 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
472 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
473 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
474 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
475 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
476 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
477 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
478 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
479 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
480 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
481 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
482 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
483 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
484 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
485 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
486 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
487 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
488 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
489 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
490 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
491 0xf9, 0xfa
492};
493
Jacek Anaszewski337777a2013-11-22 06:13:34 -0300494/*
495 * Fourcc downgrade schema lookup tables for 422 and 420
496 * chroma subsampling - fourcc on each position maps on the
497 * fourcc from the table fourcc_to_dwngrd_schema_id which allows
498 * to get the most suitable fourcc counterpart for the given
499 * downgraded subsampling property.
500 */
501static const u32 subs422_fourcc_dwngrd_schema[] = {
502 V4L2_PIX_FMT_NV16,
503 V4L2_PIX_FMT_NV61,
504};
505
506static const u32 subs420_fourcc_dwngrd_schema[] = {
507 V4L2_PIX_FMT_NV12,
508 V4L2_PIX_FMT_NV21,
509 V4L2_PIX_FMT_NV12,
510 V4L2_PIX_FMT_NV21,
511 V4L2_PIX_FMT_NV12,
512 V4L2_PIX_FMT_NV21,
513 V4L2_PIX_FMT_GREY,
514 V4L2_PIX_FMT_GREY,
515 V4L2_PIX_FMT_GREY,
516 V4L2_PIX_FMT_GREY,
517};
518
519/*
520 * Lookup table for translation of a fourcc to the position
521 * of its downgraded counterpart in the *fourcc_dwngrd_schema
522 * tables.
523 */
524static const u32 fourcc_to_dwngrd_schema_id[] = {
525 V4L2_PIX_FMT_NV24,
526 V4L2_PIX_FMT_NV42,
527 V4L2_PIX_FMT_NV16,
528 V4L2_PIX_FMT_NV61,
529 V4L2_PIX_FMT_YUYV,
530 V4L2_PIX_FMT_YVYU,
531 V4L2_PIX_FMT_NV12,
532 V4L2_PIX_FMT_NV21,
533 V4L2_PIX_FMT_YUV420,
534 V4L2_PIX_FMT_GREY,
535};
536
537static int s5p_jpeg_get_dwngrd_sch_id_by_fourcc(u32 fourcc)
538{
539 int i;
540 for (i = 0; i < ARRAY_SIZE(fourcc_to_dwngrd_schema_id); ++i) {
541 if (fourcc_to_dwngrd_schema_id[i] == fourcc)
542 return i;
543 }
544
545 return -EINVAL;
546}
547
548static int s5p_jpeg_adjust_fourcc_to_subsampling(
549 enum v4l2_jpeg_chroma_subsampling subs,
550 u32 in_fourcc,
551 u32 *out_fourcc,
552 struct s5p_jpeg_ctx *ctx)
553{
554 int dwngrd_sch_id;
555
556 if (ctx->subsampling != V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY) {
557 dwngrd_sch_id =
558 s5p_jpeg_get_dwngrd_sch_id_by_fourcc(in_fourcc);
559 if (dwngrd_sch_id < 0)
560 return -EINVAL;
561 }
562
563 switch (ctx->subsampling) {
564 case V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY:
565 *out_fourcc = V4L2_PIX_FMT_GREY;
566 break;
567 case V4L2_JPEG_CHROMA_SUBSAMPLING_420:
568 if (dwngrd_sch_id >
569 ARRAY_SIZE(subs420_fourcc_dwngrd_schema) - 1)
570 return -EINVAL;
571 *out_fourcc = subs420_fourcc_dwngrd_schema[dwngrd_sch_id];
572 break;
573 case V4L2_JPEG_CHROMA_SUBSAMPLING_422:
574 if (dwngrd_sch_id >
575 ARRAY_SIZE(subs422_fourcc_dwngrd_schema) - 1)
576 return -EINVAL;
577 *out_fourcc = subs422_fourcc_dwngrd_schema[dwngrd_sch_id];
578 break;
579 default:
580 *out_fourcc = V4L2_PIX_FMT_GREY;
581 break;
582 }
583
584 return 0;
585}
586
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300587static int exynos4x12_decoded_subsampling[] = {
588 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
589 V4L2_JPEG_CHROMA_SUBSAMPLING_444,
590 V4L2_JPEG_CHROMA_SUBSAMPLING_422,
591 V4L2_JPEG_CHROMA_SUBSAMPLING_420,
592};
593
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300594static int exynos3250_decoded_subsampling[] = {
595 V4L2_JPEG_CHROMA_SUBSAMPLING_444,
596 V4L2_JPEG_CHROMA_SUBSAMPLING_422,
597 V4L2_JPEG_CHROMA_SUBSAMPLING_420,
598 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
599 -1,
600 -1,
601 V4L2_JPEG_CHROMA_SUBSAMPLING_411,
602};
603
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300604static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c)
605{
606 return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler);
607}
608
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300609static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh)
610{
611 return container_of(fh, struct s5p_jpeg_ctx, fh);
612}
613
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300614static int s5p_jpeg_to_user_subsampling(struct s5p_jpeg_ctx *ctx)
615{
616 WARN_ON(ctx->subsampling > 3);
617
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300618 switch (ctx->jpeg->variant->version) {
619 case SJPEG_S5P:
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300620 if (ctx->subsampling > 2)
621 return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
622 return ctx->subsampling;
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300623 case SJPEG_EXYNOS3250:
624 if (ctx->subsampling > 3)
625 return V4L2_JPEG_CHROMA_SUBSAMPLING_411;
626 return exynos3250_decoded_subsampling[ctx->subsampling];
627 case SJPEG_EXYNOS4:
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300628 if (ctx->subsampling > 2)
629 return V4L2_JPEG_CHROMA_SUBSAMPLING_420;
630 return exynos4x12_decoded_subsampling[ctx->subsampling];
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300631 default:
632 return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300633 }
634}
635
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300636static inline void s5p_jpeg_set_qtbl(void __iomem *regs,
637 const unsigned char *qtbl,
638 unsigned long tab, int len)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300639{
640 int i;
641
642 for (i = 0; i < len; i++)
643 writel((unsigned int)qtbl[i], regs + tab + (i * 0x04));
644}
645
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300646static inline void s5p_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300647{
648 /* this driver fills quantisation table 0 with data for luma */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300649 s5p_jpeg_set_qtbl(regs, qtbl_luminance[quality],
650 S5P_JPG_QTBL_CONTENT(0),
651 ARRAY_SIZE(qtbl_luminance[quality]));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300652}
653
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300654static inline void s5p_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300655{
656 /* this driver fills quantisation table 1 with data for chroma */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300657 s5p_jpeg_set_qtbl(regs, qtbl_chrominance[quality],
658 S5P_JPG_QTBL_CONTENT(1),
659 ARRAY_SIZE(qtbl_chrominance[quality]));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300660}
661
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300662static inline void s5p_jpeg_set_htbl(void __iomem *regs,
663 const unsigned char *htbl,
664 unsigned long tab, int len)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300665{
666 int i;
667
668 for (i = 0; i < len; i++)
669 writel((unsigned int)htbl[i], regs + tab + (i * 0x04));
670}
671
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300672static inline void s5p_jpeg_set_hdctbl(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300673{
674 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300675 s5p_jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0),
676 ARRAY_SIZE(hdctbl0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300677}
678
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300679static inline void s5p_jpeg_set_hdctblg(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300680{
681 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300682 s5p_jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0),
683 ARRAY_SIZE(hdctblg0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300684}
685
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300686static inline void s5p_jpeg_set_hactbl(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300687{
688 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300689 s5p_jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0),
690 ARRAY_SIZE(hactbl0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300691}
692
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300693static inline void s5p_jpeg_set_hactblg(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300694{
695 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300696 s5p_jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0),
697 ARRAY_SIZE(hactblg0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300698}
699
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300700static inline void exynos4_jpeg_set_tbl(void __iomem *regs,
701 const unsigned char *tbl,
702 unsigned long tab, int len)
703{
704 int i;
705 unsigned int dword;
706
707 for (i = 0; i < len; i += 4) {
708 dword = tbl[i] |
709 (tbl[i + 1] << 8) |
710 (tbl[i + 2] << 16) |
711 (tbl[i + 3] << 24);
712 writel(dword, regs + tab + i);
713 }
714}
715
716static inline void exynos4_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
717{
718 /* this driver fills quantisation table 0 with data for luma */
719 exynos4_jpeg_set_tbl(regs, qtbl_luminance[quality],
720 EXYNOS4_QTBL_CONTENT(0),
721 ARRAY_SIZE(qtbl_luminance[quality]));
722}
723
724static inline void exynos4_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
725{
726 /* this driver fills quantisation table 1 with data for chroma */
727 exynos4_jpeg_set_tbl(regs, qtbl_chrominance[quality],
728 EXYNOS4_QTBL_CONTENT(1),
729 ARRAY_SIZE(qtbl_chrominance[quality]));
730}
731
Mauro Carvalho Chehabaf425be2014-08-26 10:50:23 -0300732static void exynos4_jpeg_set_huff_tbl(void __iomem *base)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300733{
734 exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCLL,
735 ARRAY_SIZE(hdctbl0));
736 exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCCL,
737 ARRAY_SIZE(hdctbl0));
738 exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCLV,
739 ARRAY_SIZE(hdctblg0));
740 exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCCV,
741 ARRAY_SIZE(hdctblg0));
742 exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACLL,
743 ARRAY_SIZE(hactbl0));
744 exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACCL,
745 ARRAY_SIZE(hactbl0));
746 exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACLV,
747 ARRAY_SIZE(hactblg0));
748 exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACCV,
749 ARRAY_SIZE(hactblg0));
750}
751
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300752/*
753 * ============================================================================
754 * Device file operations
755 * ============================================================================
756 */
757
758static int queue_init(void *priv, struct vb2_queue *src_vq,
759 struct vb2_queue *dst_vq);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300760static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
761 __u32 pixelformat, unsigned int fmt_type);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300762static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300763
764static int s5p_jpeg_open(struct file *file)
765{
766 struct s5p_jpeg *jpeg = video_drvdata(file);
767 struct video_device *vfd = video_devdata(file);
768 struct s5p_jpeg_ctx *ctx;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300769 struct s5p_jpeg_fmt *out_fmt, *cap_fmt;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300770 int ret = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300771
Sachin Kamatb5146c92012-08-16 08:52:58 -0300772 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300773 if (!ctx)
774 return -ENOMEM;
775
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300776 if (mutex_lock_interruptible(&jpeg->lock)) {
777 ret = -ERESTARTSYS;
778 goto free;
779 }
780
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300781 v4l2_fh_init(&ctx->fh, vfd);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300782 /* Use separate control handler per file handle */
783 ctx->fh.ctrl_handler = &ctx->ctrl_handler;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300784 file->private_data = &ctx->fh;
785 v4l2_fh_add(&ctx->fh);
786
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300787 ctx->jpeg = jpeg;
788 if (vfd == jpeg->vfd_encoder) {
789 ctx->mode = S5P_JPEG_ENCODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300790 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB565,
791 FMT_TYPE_OUTPUT);
792 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
793 FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300794 } else {
795 ctx->mode = S5P_JPEG_DECODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300796 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
797 FMT_TYPE_OUTPUT);
798 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_YUYV,
799 FMT_TYPE_CAPTURE);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300800 ctx->scale_factor = EXYNOS3250_DEC_SCALE_FACTOR_8_8;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300801 }
802
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300803 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
804 if (IS_ERR(ctx->fh.m2m_ctx)) {
805 ret = PTR_ERR(ctx->fh.m2m_ctx);
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300806 goto error;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300807 }
808
809 ctx->out_q.fmt = out_fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300810 ctx->cap_q.fmt = cap_fmt;
811
812 ret = s5p_jpeg_controls_create(ctx);
813 if (ret < 0)
814 goto error;
815
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300816 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300817 return 0;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300818
819error:
820 v4l2_fh_del(&ctx->fh);
821 v4l2_fh_exit(&ctx->fh);
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300822 mutex_unlock(&jpeg->lock);
823free:
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300824 kfree(ctx);
825 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300826}
827
828static int s5p_jpeg_release(struct file *file)
829{
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300830 struct s5p_jpeg *jpeg = video_drvdata(file);
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300831 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300832
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300833 mutex_lock(&jpeg->lock);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300834 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300835 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300836 v4l2_fh_del(&ctx->fh);
837 v4l2_fh_exit(&ctx->fh);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300838 kfree(ctx);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300839 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300840
841 return 0;
842}
843
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300844static const struct v4l2_file_operations s5p_jpeg_fops = {
845 .owner = THIS_MODULE,
846 .open = s5p_jpeg_open,
847 .release = s5p_jpeg_release,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300848 .poll = v4l2_m2m_fop_poll,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300849 .unlocked_ioctl = video_ioctl2,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300850 .mmap = v4l2_m2m_fop_mmap,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300851};
852
853/*
854 * ============================================================================
855 * video ioctl operations
856 * ============================================================================
857 */
858
859static int get_byte(struct s5p_jpeg_buffer *buf)
860{
861 if (buf->curr >= buf->size)
862 return -1;
863
864 return ((unsigned char *)buf->data)[buf->curr++];
865}
866
867static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word)
868{
869 unsigned int temp;
870 int byte;
871
872 byte = get_byte(buf);
873 if (byte == -1)
874 return -1;
875 temp = byte << 8;
876 byte = get_byte(buf);
877 if (byte == -1)
878 return -1;
879 *word = (unsigned int)byte | temp;
880 return 0;
881}
882
883static void skip(struct s5p_jpeg_buffer *buf, long len)
884{
885 if (len <= 0)
886 return;
887
888 while (len--)
889 get_byte(buf);
890}
891
892static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300893 unsigned long buffer, unsigned long size,
894 struct s5p_jpeg_ctx *ctx)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300895{
Jacek Anaszewskif3d83a12014-10-10 05:46:49 -0300896 int c, components = 0, notfound;
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300897 unsigned int height, width, word, subsampling = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300898 long length;
899 struct s5p_jpeg_buffer jpeg_buffer;
900
901 jpeg_buffer.size = size;
902 jpeg_buffer.data = buffer;
903 jpeg_buffer.curr = 0;
904
905 notfound = 1;
906 while (notfound) {
907 c = get_byte(&jpeg_buffer);
908 if (c == -1)
Jacek Anaszewskia35f6002014-07-11 12:19:43 -0300909 return false;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300910 if (c != 0xff)
911 continue;
912 do
913 c = get_byte(&jpeg_buffer);
914 while (c == 0xff);
915 if (c == -1)
Jacek Anaszewskia35f6002014-07-11 12:19:43 -0300916 return false;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300917 if (c == 0)
918 continue;
919 length = 0;
920 switch (c) {
921 /* SOF0: baseline JPEG */
922 case SOF0:
923 if (get_word_be(&jpeg_buffer, &word))
924 break;
925 if (get_byte(&jpeg_buffer) == -1)
926 break;
927 if (get_word_be(&jpeg_buffer, &height))
928 break;
929 if (get_word_be(&jpeg_buffer, &width))
930 break;
931 components = get_byte(&jpeg_buffer);
932 if (components == -1)
933 break;
934 notfound = 0;
935
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300936 if (components == 1) {
937 subsampling = 0x33;
938 } else {
939 skip(&jpeg_buffer, 1);
940 subsampling = get_byte(&jpeg_buffer);
941 skip(&jpeg_buffer, 1);
942 }
943
944 skip(&jpeg_buffer, components * 2);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300945 break;
946
947 /* skip payload-less markers */
948 case RST ... RST + 7:
949 case SOI:
950 case EOI:
951 case TEM:
952 break;
953
954 /* skip uninteresting payload markers */
955 default:
956 if (get_word_be(&jpeg_buffer, &word))
957 break;
958 length = (long)word - 2;
959 skip(&jpeg_buffer, length);
960 break;
961 }
962 }
963 result->w = width;
964 result->h = height;
965 result->size = components;
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300966
967 switch (subsampling) {
968 case 0x11:
969 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444;
970 break;
971 case 0x21:
972 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422;
973 break;
974 case 0x22:
975 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420;
976 break;
977 case 0x33:
978 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
979 break;
980 default:
981 return false;
982 }
983
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300984 return !notfound;
985}
986
987static int s5p_jpeg_querycap(struct file *file, void *priv,
988 struct v4l2_capability *cap)
989{
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300990 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300991
992 if (ctx->mode == S5P_JPEG_ENCODE) {
993 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder",
994 sizeof(cap->driver));
995 strlcpy(cap->card, S5P_JPEG_M2M_NAME " encoder",
996 sizeof(cap->card));
997 } else {
998 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " decoder",
999 sizeof(cap->driver));
1000 strlcpy(cap->card, S5P_JPEG_M2M_NAME " decoder",
1001 sizeof(cap->card));
1002 }
1003 cap->bus_info[0] = 0;
Hans Verkuil8c17e5e2014-11-24 06:37:26 -03001004 cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M;
1005 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001006 return 0;
1007}
1008
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001009static int enum_fmt(struct s5p_jpeg_fmt *sjpeg_formats, int n,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001010 struct v4l2_fmtdesc *f, u32 type)
1011{
1012 int i, num = 0;
1013
1014 for (i = 0; i < n; ++i) {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001015 if (sjpeg_formats[i].flags & type) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001016 /* index-th format of type type found ? */
1017 if (num == f->index)
1018 break;
1019 /* Correct type but haven't reached our index yet,
1020 * just increment per-type index */
1021 ++num;
1022 }
1023 }
1024
1025 /* Format not found */
1026 if (i >= n)
1027 return -EINVAL;
1028
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001029 strlcpy(f->description, sjpeg_formats[i].name, sizeof(f->description));
1030 f->pixelformat = sjpeg_formats[i].fourcc;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001031
1032 return 0;
1033}
1034
1035static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
1036 struct v4l2_fmtdesc *f)
1037{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001038 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001039
1040 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001041 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1042 SJPEG_FMT_FLAG_ENC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001043
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001044 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1045 SJPEG_FMT_FLAG_DEC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001046}
1047
1048static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
1049 struct v4l2_fmtdesc *f)
1050{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001051 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001052
1053 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001054 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1055 SJPEG_FMT_FLAG_ENC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001056
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001057 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1058 SJPEG_FMT_FLAG_DEC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001059}
1060
1061static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx,
1062 enum v4l2_buf_type type)
1063{
1064 if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1065 return &ctx->out_q;
1066 if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1067 return &ctx->cap_q;
1068
1069 return NULL;
1070}
1071
1072static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
1073{
1074 struct vb2_queue *vq;
1075 struct s5p_jpeg_q_data *q_data = NULL;
1076 struct v4l2_pix_format *pix = &f->fmt.pix;
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001077 struct s5p_jpeg_ctx *ct = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001078
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001079 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001080 if (!vq)
1081 return -EINVAL;
1082
1083 if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
1084 ct->mode == S5P_JPEG_DECODE && !ct->hdr_parsed)
1085 return -EINVAL;
1086 q_data = get_q_data(ct, f->type);
1087 BUG_ON(q_data == NULL);
1088
1089 pix->width = q_data->w;
1090 pix->height = q_data->h;
1091 pix->field = V4L2_FIELD_NONE;
1092 pix->pixelformat = q_data->fmt->fourcc;
1093 pix->bytesperline = 0;
1094 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
1095 u32 bpl = q_data->w;
1096 if (q_data->fmt->colplanes == 1)
1097 bpl = (bpl * q_data->fmt->depth) >> 3;
1098 pix->bytesperline = bpl;
1099 }
1100 pix->sizeimage = q_data->size;
1101
1102 return 0;
1103}
1104
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001105static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
1106 u32 pixelformat, unsigned int fmt_type)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001107{
Jacek Anaszewskib2451682014-04-10 04:32:11 -03001108 unsigned int k, fmt_flag;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001109
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001110 if (ctx->mode == S5P_JPEG_ENCODE)
1111 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
1112 SJPEG_FMT_FLAG_ENC_OUTPUT :
1113 SJPEG_FMT_FLAG_ENC_CAPTURE;
1114 else
1115 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
1116 SJPEG_FMT_FLAG_DEC_OUTPUT :
1117 SJPEG_FMT_FLAG_DEC_CAPTURE;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001118
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001119 for (k = 0; k < ARRAY_SIZE(sjpeg_formats); k++) {
1120 struct s5p_jpeg_fmt *fmt = &sjpeg_formats[k];
1121 if (fmt->fourcc == pixelformat &&
1122 fmt->flags & fmt_flag &&
Jacek Anaszewskib2451682014-04-10 04:32:11 -03001123 fmt->flags & ctx->jpeg->variant->fmt_ver_flag) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001124 return fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001125 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001126 }
1127
1128 return NULL;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001129}
1130
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001131static void jpeg_bound_align_image(struct s5p_jpeg_ctx *ctx,
1132 u32 *w, unsigned int wmin, unsigned int wmax,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001133 unsigned int walign,
1134 u32 *h, unsigned int hmin, unsigned int hmax,
1135 unsigned int halign)
1136{
1137 int width, height, w_step, h_step;
1138
1139 width = *w;
1140 height = *h;
1141
1142 w_step = 1 << walign;
1143 h_step = 1 << halign;
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001144
1145 if (ctx->jpeg->variant->version == SJPEG_EXYNOS3250) {
1146 /*
1147 * Rightmost and bottommost pixels are cropped by the
1148 * Exynos3250 JPEG IP for RGB formats, for the specific
1149 * width and height values respectively. This assignment
1150 * will result in v4l_bound_align_image returning dimensions
1151 * reduced by 1 for the aforementioned cases.
1152 */
1153 if (w_step == 4 && ((width & 3) == 1)) {
1154 wmax = width;
1155 hmax = height;
1156 }
1157 }
1158
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001159 v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
1160
1161 if (*w < width && (*w + w_step) < wmax)
1162 *w += w_step;
1163 if (*h < height && (*h + h_step) < hmax)
1164 *h += h_step;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001165}
1166
1167static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
1168 struct s5p_jpeg_ctx *ctx, int q_type)
1169{
1170 struct v4l2_pix_format *pix = &f->fmt.pix;
1171
1172 if (pix->field == V4L2_FIELD_ANY)
1173 pix->field = V4L2_FIELD_NONE;
1174 else if (pix->field != V4L2_FIELD_NONE)
1175 return -EINVAL;
1176
1177 /* V4L2 specification suggests the driver corrects the format struct
1178 * if any of the dimensions is unsupported */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001179 if (q_type == FMT_TYPE_OUTPUT)
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001180 jpeg_bound_align_image(ctx, &pix->width, S5P_JPEG_MIN_WIDTH,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001181 S5P_JPEG_MAX_WIDTH, 0,
1182 &pix->height, S5P_JPEG_MIN_HEIGHT,
1183 S5P_JPEG_MAX_HEIGHT, 0);
1184 else
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001185 jpeg_bound_align_image(ctx, &pix->width, S5P_JPEG_MIN_WIDTH,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001186 S5P_JPEG_MAX_WIDTH, fmt->h_align,
1187 &pix->height, S5P_JPEG_MIN_HEIGHT,
1188 S5P_JPEG_MAX_HEIGHT, fmt->v_align);
1189
1190 if (fmt->fourcc == V4L2_PIX_FMT_JPEG) {
1191 if (pix->sizeimage <= 0)
1192 pix->sizeimage = PAGE_SIZE;
1193 pix->bytesperline = 0;
1194 } else {
1195 u32 bpl = pix->bytesperline;
1196
1197 if (fmt->colplanes > 1 && bpl < pix->width)
1198 bpl = pix->width; /* planar */
1199
1200 if (fmt->colplanes == 1 && /* packed */
Jacek Anaszewskicc690902013-11-25 06:58:10 -03001201 (bpl << 3) / fmt->depth < pix->width)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001202 bpl = (pix->width * fmt->depth) >> 3;
1203
1204 pix->bytesperline = bpl;
1205 pix->sizeimage = (pix->width * pix->height * fmt->depth) >> 3;
1206 }
1207
1208 return 0;
1209}
1210
1211static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
1212 struct v4l2_format *f)
1213{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001214 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001215 struct v4l2_pix_format *pix = &f->fmt.pix;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001216 struct s5p_jpeg_fmt *fmt;
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001217 int ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001218
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001219 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
1220 FMT_TYPE_CAPTURE);
1221 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001222 v4l2_err(&ctx->jpeg->v4l2_dev,
1223 "Fourcc format (0x%08x) invalid.\n",
1224 f->fmt.pix.pixelformat);
1225 return -EINVAL;
1226 }
1227
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001228 if ((ctx->jpeg->variant->version != SJPEG_EXYNOS4) ||
1229 (ctx->mode != S5P_JPEG_DECODE))
1230 goto exit;
1231
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001232 /*
1233 * The exynos4x12 device requires resulting YUV image
1234 * subsampling not to be lower than the input jpeg subsampling.
1235 * If this requirement is not met then downgrade the requested
1236 * capture format to the one with subsampling equal to the input jpeg.
1237 */
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001238 if ((fmt->flags & SJPEG_FMT_NON_RGB) &&
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001239 (fmt->subsampling < ctx->subsampling)) {
1240 ret = s5p_jpeg_adjust_fourcc_to_subsampling(ctx->subsampling,
1241 fmt->fourcc,
1242 &pix->pixelformat,
1243 ctx);
1244 if (ret < 0)
1245 pix->pixelformat = V4L2_PIX_FMT_GREY;
1246
1247 fmt = s5p_jpeg_find_format(ctx, pix->pixelformat,
1248 FMT_TYPE_CAPTURE);
1249 }
1250
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001251 /*
1252 * Decompression of a JPEG file with 4:2:0 subsampling and odd
1253 * width to the YUV 4:2:0 compliant formats produces a raw image
1254 * with broken luma component. Adjust capture format to RGB565
1255 * in such a case.
1256 */
1257 if (ctx->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_420 &&
1258 (ctx->out_q.w & 1) &&
1259 (pix->pixelformat == V4L2_PIX_FMT_NV12 ||
1260 pix->pixelformat == V4L2_PIX_FMT_NV21 ||
1261 pix->pixelformat == V4L2_PIX_FMT_YUV420)) {
1262 pix->pixelformat = V4L2_PIX_FMT_RGB565;
1263 fmt = s5p_jpeg_find_format(ctx, pix->pixelformat,
1264 FMT_TYPE_CAPTURE);
1265 }
1266
1267exit:
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001268 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001269}
1270
1271static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
1272 struct v4l2_format *f)
1273{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001274 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001275 struct s5p_jpeg_fmt *fmt;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001276
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001277 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
1278 FMT_TYPE_OUTPUT);
1279 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001280 v4l2_err(&ctx->jpeg->v4l2_dev,
1281 "Fourcc format (0x%08x) invalid.\n",
1282 f->fmt.pix.pixelformat);
1283 return -EINVAL;
1284 }
1285
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001286 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001287}
1288
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001289static int exynos4_jpeg_get_output_buffer_size(struct s5p_jpeg_ctx *ctx,
1290 struct v4l2_format *f,
1291 int fmt_depth)
1292{
1293 struct v4l2_pix_format *pix = &f->fmt.pix;
1294 u32 pix_fmt = f->fmt.pix.pixelformat;
1295 int w = pix->width, h = pix->height, wh_align;
1296
1297 if (pix_fmt == V4L2_PIX_FMT_RGB32 ||
1298 pix_fmt == V4L2_PIX_FMT_NV24 ||
1299 pix_fmt == V4L2_PIX_FMT_NV42 ||
1300 pix_fmt == V4L2_PIX_FMT_NV12 ||
1301 pix_fmt == V4L2_PIX_FMT_NV21 ||
1302 pix_fmt == V4L2_PIX_FMT_YUV420)
1303 wh_align = 4;
1304 else
1305 wh_align = 1;
1306
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001307 jpeg_bound_align_image(ctx, &w, S5P_JPEG_MIN_WIDTH,
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001308 S5P_JPEG_MAX_WIDTH, wh_align,
1309 &h, S5P_JPEG_MIN_HEIGHT,
1310 S5P_JPEG_MAX_HEIGHT, wh_align);
1311
1312 return w * h * fmt_depth >> 3;
1313}
1314
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001315static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx,
1316 struct v4l2_rect *r);
1317
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001318static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
1319{
1320 struct vb2_queue *vq;
1321 struct s5p_jpeg_q_data *q_data = NULL;
1322 struct v4l2_pix_format *pix = &f->fmt.pix;
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001323 struct v4l2_ctrl *ctrl_subs;
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001324 struct v4l2_rect scale_rect;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001325 unsigned int f_type;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001326
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001327 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001328 if (!vq)
1329 return -EINVAL;
1330
1331 q_data = get_q_data(ct, f->type);
1332 BUG_ON(q_data == NULL);
1333
1334 if (vb2_is_busy(vq)) {
1335 v4l2_err(&ct->jpeg->v4l2_dev, "%s queue busy\n", __func__);
1336 return -EBUSY;
1337 }
1338
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001339 f_type = V4L2_TYPE_IS_OUTPUT(f->type) ?
1340 FMT_TYPE_OUTPUT : FMT_TYPE_CAPTURE;
1341
1342 q_data->fmt = s5p_jpeg_find_format(ct, pix->pixelformat, f_type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001343 q_data->w = pix->width;
1344 q_data->h = pix->height;
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001345 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
1346 /*
1347 * During encoding Exynos4x12 SoCs access wider memory area
1348 * than it results from Image_x and Image_y values written to
1349 * the JPEG_IMAGE_SIZE register. In order to avoid sysmmu
1350 * page fault calculate proper buffer size in such a case.
1351 */
1352 if (ct->jpeg->variant->version == SJPEG_EXYNOS4 &&
1353 f_type == FMT_TYPE_OUTPUT && ct->mode == S5P_JPEG_ENCODE)
1354 q_data->size = exynos4_jpeg_get_output_buffer_size(ct,
1355 f,
1356 q_data->fmt->depth);
1357 else
1358 q_data->size = q_data->w * q_data->h *
1359 q_data->fmt->depth >> 3;
1360 } else {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001361 q_data->size = pix->sizeimage;
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001362 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001363
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001364 if (f_type == FMT_TYPE_OUTPUT) {
1365 ctrl_subs = v4l2_ctrl_find(&ct->ctrl_handler,
1366 V4L2_CID_JPEG_CHROMA_SUBSAMPLING);
1367 if (ctrl_subs)
1368 v4l2_ctrl_s_ctrl(ctrl_subs, q_data->fmt->subsampling);
Jacek Anaszewskidfd96902014-07-11 12:19:46 -03001369 ct->crop_altered = false;
1370 }
1371
1372 /*
1373 * For decoding init crop_rect with capture buffer dimmensions which
1374 * contain aligned dimensions of the input JPEG image and do it only
1375 * if crop rectangle hasn't been altered by the user space e.g. with
1376 * S_SELECTION ioctl. For encoding assign output buffer dimensions.
1377 */
1378 if (!ct->crop_altered &&
1379 ((ct->mode == S5P_JPEG_DECODE && f_type == FMT_TYPE_CAPTURE) ||
1380 (ct->mode == S5P_JPEG_ENCODE && f_type == FMT_TYPE_OUTPUT))) {
1381 ct->crop_rect.width = pix->width;
1382 ct->crop_rect.height = pix->height;
1383 }
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001384
1385 /*
1386 * Prevent downscaling to YUV420 format by more than 2
1387 * for Exynos3250 SoC as it produces broken raw image
1388 * in such cases.
1389 */
1390 if (ct->mode == S5P_JPEG_DECODE &&
1391 f_type == FMT_TYPE_CAPTURE &&
1392 ct->jpeg->variant->version == SJPEG_EXYNOS3250 &&
1393 pix->pixelformat == V4L2_PIX_FMT_YUV420 &&
1394 ct->scale_factor > 2) {
1395 scale_rect.width = ct->out_q.w / 2;
1396 scale_rect.height = ct->out_q.h / 2;
1397 exynos3250_jpeg_try_downscale(ct, &scale_rect);
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001398 }
1399
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001400 return 0;
1401}
1402
1403static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
1404 struct v4l2_format *f)
1405{
1406 int ret;
1407
1408 ret = s5p_jpeg_try_fmt_vid_cap(file, priv, f);
1409 if (ret)
1410 return ret;
1411
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001412 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001413}
1414
1415static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
1416 struct v4l2_format *f)
1417{
1418 int ret;
1419
1420 ret = s5p_jpeg_try_fmt_vid_out(file, priv, f);
1421 if (ret)
1422 return ret;
1423
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001424 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001425}
1426
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001427static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx,
1428 struct v4l2_rect *r)
1429{
1430 int w_ratio, h_ratio, scale_factor, cur_ratio, i;
1431
1432 w_ratio = ctx->out_q.w / r->width;
1433 h_ratio = ctx->out_q.h / r->height;
1434
1435 scale_factor = w_ratio > h_ratio ? w_ratio : h_ratio;
1436 scale_factor = clamp_val(scale_factor, 1, 8);
1437
1438 /* Align scale ratio to the nearest power of 2 */
1439 for (i = 0; i <= 3; ++i) {
1440 cur_ratio = 1 << i;
1441 if (scale_factor <= cur_ratio) {
1442 ctx->scale_factor = cur_ratio;
1443 break;
1444 }
1445 }
1446
1447 r->width = round_down(ctx->out_q.w / ctx->scale_factor, 2);
1448 r->height = round_down(ctx->out_q.h / ctx->scale_factor, 2);
1449
1450 ctx->crop_rect.width = r->width;
1451 ctx->crop_rect.height = r->height;
1452 ctx->crop_rect.left = 0;
1453 ctx->crop_rect.top = 0;
1454
1455 ctx->crop_altered = true;
1456
1457 return 0;
1458}
1459
1460/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */
1461static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
1462{
1463 if (a->left < b->left || a->top < b->top)
1464 return 0;
1465 if (a->left + a->width > b->left + b->width)
1466 return 0;
1467 if (a->top + a->height > b->top + b->height)
1468 return 0;
1469
1470 return 1;
1471}
1472
1473static int exynos3250_jpeg_try_crop(struct s5p_jpeg_ctx *ctx,
1474 struct v4l2_rect *r)
1475{
1476 struct v4l2_rect base_rect;
1477 int w_step, h_step;
1478
1479 switch (ctx->cap_q.fmt->fourcc) {
1480 case V4L2_PIX_FMT_NV12:
1481 case V4L2_PIX_FMT_NV21:
1482 w_step = 1;
1483 h_step = 2;
1484 break;
1485 case V4L2_PIX_FMT_YUV420:
1486 w_step = 2;
1487 h_step = 2;
1488 break;
1489 default:
1490 w_step = 1;
1491 h_step = 1;
1492 break;
1493 }
1494
1495 base_rect.top = 0;
1496 base_rect.left = 0;
1497 base_rect.width = ctx->out_q.w;
1498 base_rect.height = ctx->out_q.h;
1499
1500 r->width = round_down(r->width, w_step);
1501 r->height = round_down(r->height, h_step);
1502 r->left = round_down(r->left, 2);
1503 r->top = round_down(r->top, 2);
1504
1505 if (!enclosed_rectangle(r, &base_rect))
1506 return -EINVAL;
1507
1508 ctx->crop_rect.left = r->left;
1509 ctx->crop_rect.top = r->top;
1510 ctx->crop_rect.width = r->width;
1511 ctx->crop_rect.height = r->height;
1512
1513 ctx->crop_altered = true;
1514
1515 return 0;
1516}
1517
1518/*
1519 * V4L2 controls
1520 */
1521
Sachin Kamat9f3bd322012-05-10 03:38:40 -03001522static int s5p_jpeg_g_selection(struct file *file, void *priv,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001523 struct v4l2_selection *s)
1524{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001525 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001526
1527 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
Jacek Anaszewski38a6ef32014-04-10 04:32:15 -03001528 s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001529 return -EINVAL;
1530
1531 /* For JPEG blob active == default == bounds */
1532 switch (s->target) {
Sylwester Nawrockic1334822012-05-20 11:17:12 -03001533 case V4L2_SEL_TGT_CROP:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001534 case V4L2_SEL_TGT_CROP_BOUNDS:
1535 case V4L2_SEL_TGT_CROP_DEFAULT:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001536 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
1537 s->r.width = ctx->out_q.w;
1538 s->r.height = ctx->out_q.h;
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001539 s->r.left = 0;
1540 s->r.top = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001541 break;
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001542 case V4L2_SEL_TGT_COMPOSE:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001543 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
1544 case V4L2_SEL_TGT_COMPOSE_PADDED:
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001545 s->r.width = ctx->crop_rect.width;
1546 s->r.height = ctx->crop_rect.height;
1547 s->r.left = ctx->crop_rect.left;
1548 s->r.top = ctx->crop_rect.top;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001549 break;
1550 default:
1551 return -EINVAL;
1552 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001553 return 0;
1554}
1555
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001556/*
1557 * V4L2 controls
1558 */
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001559static int s5p_jpeg_s_selection(struct file *file, void *fh,
1560 struct v4l2_selection *s)
1561{
1562 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
1563 struct v4l2_rect *rect = &s->r;
1564 int ret = -EINVAL;
1565
1566 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1567 return -EINVAL;
1568
1569 if (s->target == V4L2_SEL_TGT_COMPOSE) {
1570 if (ctx->mode != S5P_JPEG_DECODE)
1571 return -EINVAL;
1572 if (ctx->jpeg->variant->version == SJPEG_EXYNOS3250)
1573 ret = exynos3250_jpeg_try_downscale(ctx, rect);
1574 } else if (s->target == V4L2_SEL_TGT_CROP) {
1575 if (ctx->mode != S5P_JPEG_ENCODE)
1576 return -EINVAL;
1577 if (ctx->jpeg->variant->version == SJPEG_EXYNOS3250)
1578 ret = exynos3250_jpeg_try_crop(ctx, rect);
1579 }
1580
1581 return ret;
1582}
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001583
1584static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001585{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001586 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1587 struct s5p_jpeg *jpeg = ctx->jpeg;
1588 unsigned long flags;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001589
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001590 switch (ctrl->id) {
1591 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1592 spin_lock_irqsave(&jpeg->slock, flags);
Jacek Anaszewski303b0a92013-12-18 11:14:00 -03001593 ctrl->val = s5p_jpeg_to_user_subsampling(ctx);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001594 spin_unlock_irqrestore(&jpeg->slock, flags);
1595 break;
1596 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001597
1598 return 0;
1599}
1600
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001601static int s5p_jpeg_adjust_subs_ctrl(struct s5p_jpeg_ctx *ctx, int *ctrl_val)
1602{
1603 switch (ctx->jpeg->variant->version) {
1604 case SJPEG_S5P:
1605 return 0;
1606 case SJPEG_EXYNOS3250:
1607 /*
1608 * The exynos3250 device can produce JPEG image only
1609 * of 4:4:4 subsampling when given RGB32 source image.
1610 */
1611 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB32)
1612 *ctrl_val = 0;
1613 break;
1614 case SJPEG_EXYNOS4:
1615 /*
1616 * The exynos4x12 device requires input raw image fourcc
1617 * to be V4L2_PIX_FMT_GREY if gray jpeg format
1618 * is to be set.
1619 */
1620 if (ctx->out_q.fmt->fourcc != V4L2_PIX_FMT_GREY &&
1621 *ctrl_val == V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY)
1622 return -EINVAL;
1623 break;
1624 }
1625
1626 /*
1627 * The exynos4x12 and exynos3250 devices require resulting
1628 * jpeg subsampling not to be lower than the input raw image
1629 * subsampling.
1630 */
1631 if (ctx->out_q.fmt->subsampling > *ctrl_val)
1632 *ctrl_val = ctx->out_q.fmt->subsampling;
1633
1634 return 0;
1635}
1636
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001637static int s5p_jpeg_try_ctrl(struct v4l2_ctrl *ctrl)
1638{
1639 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1640 unsigned long flags;
1641 int ret = 0;
1642
1643 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1644
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001645 if (ctrl->id == V4L2_CID_JPEG_CHROMA_SUBSAMPLING)
1646 ret = s5p_jpeg_adjust_subs_ctrl(ctx, &ctrl->val);
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001647
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001648 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1649 return ret;
1650}
1651
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001652static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001653{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001654 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1655 unsigned long flags;
1656
1657 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1658
1659 switch (ctrl->id) {
1660 case V4L2_CID_JPEG_COMPRESSION_QUALITY:
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001661 ctx->compr_quality = ctrl->val;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001662 break;
1663 case V4L2_CID_JPEG_RESTART_INTERVAL:
1664 ctx->restart_interval = ctrl->val;
1665 break;
1666 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1667 ctx->subsampling = ctrl->val;
1668 break;
1669 }
1670
1671 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1672 return 0;
1673}
1674
1675static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
1676 .g_volatile_ctrl = s5p_jpeg_g_volatile_ctrl,
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001677 .try_ctrl = s5p_jpeg_try_ctrl,
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001678 .s_ctrl = s5p_jpeg_s_ctrl,
1679};
1680
1681static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
1682{
1683 unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */
1684 struct v4l2_ctrl *ctrl;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001685 int ret;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001686
1687 v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
1688
1689 if (ctx->mode == S5P_JPEG_ENCODE) {
1690 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1691 V4L2_CID_JPEG_COMPRESSION_QUALITY,
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001692 0, 3, 1, S5P_JPEG_COMPR_QUAL_WORST);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001693
1694 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1695 V4L2_CID_JPEG_RESTART_INTERVAL,
1696 0, 3, 0xffff, 0);
Jacek Anaszewskifdf9e2b2013-11-21 13:33:41 -03001697 if (ctx->jpeg->variant->version == SJPEG_S5P)
1698 mask = ~0x06; /* 422, 420 */
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001699 }
1700
1701 ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1702 V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
1703 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask,
1704 V4L2_JPEG_CHROMA_SUBSAMPLING_422);
1705
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001706 if (ctx->ctrl_handler.error) {
1707 ret = ctx->ctrl_handler.error;
1708 goto error_free;
1709 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001710
1711 if (ctx->mode == S5P_JPEG_DECODE)
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001712 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
1713 V4L2_CTRL_FLAG_READ_ONLY;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001714
1715 ret = v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
1716 if (ret < 0)
1717 goto error_free;
1718
1719 return ret;
1720
1721error_free:
1722 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
1723 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001724}
1725
1726static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
1727 .vidioc_querycap = s5p_jpeg_querycap,
1728
1729 .vidioc_enum_fmt_vid_cap = s5p_jpeg_enum_fmt_vid_cap,
1730 .vidioc_enum_fmt_vid_out = s5p_jpeg_enum_fmt_vid_out,
1731
1732 .vidioc_g_fmt_vid_cap = s5p_jpeg_g_fmt,
1733 .vidioc_g_fmt_vid_out = s5p_jpeg_g_fmt,
1734
1735 .vidioc_try_fmt_vid_cap = s5p_jpeg_try_fmt_vid_cap,
1736 .vidioc_try_fmt_vid_out = s5p_jpeg_try_fmt_vid_out,
1737
1738 .vidioc_s_fmt_vid_cap = s5p_jpeg_s_fmt_vid_cap,
1739 .vidioc_s_fmt_vid_out = s5p_jpeg_s_fmt_vid_out,
1740
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001741 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
1742 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
1743 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
1744 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001745
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001746 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
1747 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001748
1749 .vidioc_g_selection = s5p_jpeg_g_selection,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001750 .vidioc_s_selection = s5p_jpeg_s_selection,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001751};
1752
1753/*
1754 * ============================================================================
1755 * mem2mem callbacks
1756 * ============================================================================
1757 */
1758
1759static void s5p_jpeg_device_run(void *priv)
1760{
1761 struct s5p_jpeg_ctx *ctx = priv;
1762 struct s5p_jpeg *jpeg = ctx->jpeg;
1763 struct vb2_buffer *src_buf, *dst_buf;
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001764 unsigned long src_addr, dst_addr, flags;
1765
1766 spin_lock_irqsave(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001767
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001768 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1769 dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001770 src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
1771 dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
1772
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001773 s5p_jpeg_reset(jpeg->regs);
1774 s5p_jpeg_poweron(jpeg->regs);
1775 s5p_jpeg_proc_mode(jpeg->regs, ctx->mode);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001776 if (ctx->mode == S5P_JPEG_ENCODE) {
1777 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001778 s5p_jpeg_input_raw_mode(jpeg->regs,
1779 S5P_JPEG_RAW_IN_565);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001780 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001781 s5p_jpeg_input_raw_mode(jpeg->regs,
1782 S5P_JPEG_RAW_IN_422);
1783 s5p_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
1784 s5p_jpeg_dri(jpeg->regs, ctx->restart_interval);
1785 s5p_jpeg_x(jpeg->regs, ctx->out_q.w);
1786 s5p_jpeg_y(jpeg->regs, ctx->out_q.h);
1787 s5p_jpeg_imgadr(jpeg->regs, src_addr);
1788 s5p_jpeg_jpgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001789
1790 /* ultimately comes from sizeimage from userspace */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001791 s5p_jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001792
1793 /* JPEG RGB to YCbCr conversion matrix */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001794 s5p_jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11);
1795 s5p_jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12);
1796 s5p_jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13);
1797 s5p_jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21);
1798 s5p_jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22);
1799 s5p_jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23);
1800 s5p_jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31);
1801 s5p_jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32);
1802 s5p_jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001803
1804 /*
1805 * JPEG IP allows storing 4 quantization tables
1806 * We fill table 0 for luma and table 1 for chroma
1807 */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03001808 s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
1809 s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001810 /* use table 0 for Y */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001811 s5p_jpeg_qtbl(jpeg->regs, 1, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001812 /* use table 1 for Cb and Cr*/
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001813 s5p_jpeg_qtbl(jpeg->regs, 2, 1);
1814 s5p_jpeg_qtbl(jpeg->regs, 3, 1);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001815
1816 /* Y, Cb, Cr use Huffman table 0 */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001817 s5p_jpeg_htbl_ac(jpeg->regs, 1);
1818 s5p_jpeg_htbl_dc(jpeg->regs, 1);
1819 s5p_jpeg_htbl_ac(jpeg->regs, 2);
1820 s5p_jpeg_htbl_dc(jpeg->regs, 2);
1821 s5p_jpeg_htbl_ac(jpeg->regs, 3);
1822 s5p_jpeg_htbl_dc(jpeg->regs, 3);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001823 } else { /* S5P_JPEG_DECODE */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001824 s5p_jpeg_rst_int_enable(jpeg->regs, true);
1825 s5p_jpeg_data_num_int_enable(jpeg->regs, true);
1826 s5p_jpeg_final_mcu_num_int_enable(jpeg->regs, true);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001827 if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001828 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001829 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001830 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420);
1831 s5p_jpeg_jpgadr(jpeg->regs, src_addr);
1832 s5p_jpeg_imgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001833 }
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001834
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001835 s5p_jpeg_start(jpeg->regs);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001836
1837 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001838}
1839
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001840static void exynos4_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
1841{
1842 struct s5p_jpeg *jpeg = ctx->jpeg;
1843 struct s5p_jpeg_fmt *fmt;
1844 struct vb2_buffer *vb;
1845 struct s5p_jpeg_addr jpeg_addr;
1846 u32 pix_size, padding_bytes = 0;
1847
Tony K Nadackalcb0c3f52014-12-17 04:21:21 -03001848 jpeg_addr.cb = 0;
1849 jpeg_addr.cr = 0;
1850
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001851 pix_size = ctx->cap_q.w * ctx->cap_q.h;
1852
1853 if (ctx->mode == S5P_JPEG_ENCODE) {
1854 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1855 fmt = ctx->out_q.fmt;
1856 if (ctx->out_q.w % 2 && fmt->h_align > 0)
1857 padding_bytes = ctx->out_q.h;
1858 } else {
1859 fmt = ctx->cap_q.fmt;
1860 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1861 }
1862
1863 jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
1864
1865 if (fmt->colplanes == 2) {
1866 jpeg_addr.cb = jpeg_addr.y + pix_size - padding_bytes;
1867 } else if (fmt->colplanes == 3) {
1868 jpeg_addr.cb = jpeg_addr.y + pix_size;
1869 if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
1870 jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
1871 else
1872 jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
1873 }
1874
1875 exynos4_jpeg_set_frame_buf_address(jpeg->regs, &jpeg_addr);
1876}
1877
1878static void exynos4_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
1879{
1880 struct s5p_jpeg *jpeg = ctx->jpeg;
1881 struct vb2_buffer *vb;
1882 unsigned int jpeg_addr = 0;
1883
1884 if (ctx->mode == S5P_JPEG_ENCODE)
1885 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1886 else
1887 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1888
1889 jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
1890 exynos4_jpeg_set_stream_buf_address(jpeg->regs, jpeg_addr);
1891}
1892
1893static void exynos4_jpeg_device_run(void *priv)
1894{
1895 struct s5p_jpeg_ctx *ctx = priv;
1896 struct s5p_jpeg *jpeg = ctx->jpeg;
1897 unsigned int bitstream_size;
1898 unsigned long flags;
1899
1900 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1901
1902 if (ctx->mode == S5P_JPEG_ENCODE) {
1903 exynos4_jpeg_sw_reset(jpeg->regs);
1904 exynos4_jpeg_set_interrupt(jpeg->regs);
1905 exynos4_jpeg_set_huf_table_enable(jpeg->regs, 1);
1906
1907 exynos4_jpeg_set_huff_tbl(jpeg->regs);
1908
1909 /*
1910 * JPEG IP allows storing 4 quantization tables
1911 * We fill table 0 for luma and table 1 for chroma
1912 */
1913 exynos4_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
1914 exynos4_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
1915
1916 exynos4_jpeg_set_encode_tbl_select(jpeg->regs,
1917 ctx->compr_quality);
1918 exynos4_jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w,
1919 ctx->cap_q.h);
1920
1921 exynos4_jpeg_set_enc_out_fmt(jpeg->regs, ctx->subsampling);
1922 exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->out_q.fmt->fourcc);
1923 exynos4_jpeg_set_img_addr(ctx);
1924 exynos4_jpeg_set_jpeg_addr(ctx);
1925 exynos4_jpeg_set_encode_hoff_cnt(jpeg->regs,
1926 ctx->out_q.fmt->fourcc);
1927 } else {
1928 exynos4_jpeg_sw_reset(jpeg->regs);
1929 exynos4_jpeg_set_interrupt(jpeg->regs);
1930 exynos4_jpeg_set_img_addr(ctx);
1931 exynos4_jpeg_set_jpeg_addr(ctx);
1932 exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->cap_q.fmt->fourcc);
1933
1934 bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 32);
1935
1936 exynos4_jpeg_set_dec_bitstream_size(jpeg->regs, bitstream_size);
1937 }
1938
1939 exynos4_jpeg_set_enc_dec_mode(jpeg->regs, ctx->mode);
1940
1941 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1942}
1943
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001944static void exynos3250_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
1945{
1946 struct s5p_jpeg *jpeg = ctx->jpeg;
1947 struct s5p_jpeg_fmt *fmt;
1948 struct vb2_buffer *vb;
1949 struct s5p_jpeg_addr jpeg_addr;
1950 u32 pix_size;
1951
1952 pix_size = ctx->cap_q.w * ctx->cap_q.h;
1953
1954 if (ctx->mode == S5P_JPEG_ENCODE) {
1955 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1956 fmt = ctx->out_q.fmt;
1957 } else {
1958 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1959 fmt = ctx->cap_q.fmt;
1960 }
1961
1962 jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
1963
1964 if (fmt->colplanes == 2) {
1965 jpeg_addr.cb = jpeg_addr.y + pix_size;
1966 } else if (fmt->colplanes == 3) {
1967 jpeg_addr.cb = jpeg_addr.y + pix_size;
1968 if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
1969 jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
1970 else
1971 jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
1972 }
1973
1974 exynos3250_jpeg_imgadr(jpeg->regs, &jpeg_addr);
1975}
1976
1977static void exynos3250_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
1978{
1979 struct s5p_jpeg *jpeg = ctx->jpeg;
1980 struct vb2_buffer *vb;
1981 unsigned int jpeg_addr = 0;
1982
1983 if (ctx->mode == S5P_JPEG_ENCODE)
1984 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1985 else
1986 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1987
1988 jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
1989 exynos3250_jpeg_jpgadr(jpeg->regs, jpeg_addr);
1990}
1991
1992static void exynos3250_jpeg_device_run(void *priv)
1993{
1994 struct s5p_jpeg_ctx *ctx = priv;
1995 struct s5p_jpeg *jpeg = ctx->jpeg;
1996 unsigned long flags;
1997
1998 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1999
2000 exynos3250_jpeg_reset(jpeg->regs);
2001 exynos3250_jpeg_set_dma_num(jpeg->regs);
2002 exynos3250_jpeg_poweron(jpeg->regs);
2003 exynos3250_jpeg_clk_set(jpeg->regs);
2004 exynos3250_jpeg_proc_mode(jpeg->regs, ctx->mode);
2005
2006 if (ctx->mode == S5P_JPEG_ENCODE) {
2007 exynos3250_jpeg_input_raw_fmt(jpeg->regs,
2008 ctx->out_q.fmt->fourcc);
2009 exynos3250_jpeg_dri(jpeg->regs, ctx->restart_interval);
2010
2011 /*
2012 * JPEG IP allows storing 4 quantization tables
2013 * We fill table 0 for luma and table 1 for chroma
2014 */
2015 s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
2016 s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
2017 /* use table 0 for Y */
2018 exynos3250_jpeg_qtbl(jpeg->regs, 1, 0);
2019 /* use table 1 for Cb and Cr*/
2020 exynos3250_jpeg_qtbl(jpeg->regs, 2, 1);
2021 exynos3250_jpeg_qtbl(jpeg->regs, 3, 1);
2022
2023 /* Y, Cb, Cr use Huffman table 0 */
2024 exynos3250_jpeg_htbl_ac(jpeg->regs, 1);
2025 exynos3250_jpeg_htbl_dc(jpeg->regs, 1);
2026 exynos3250_jpeg_htbl_ac(jpeg->regs, 2);
2027 exynos3250_jpeg_htbl_dc(jpeg->regs, 2);
2028 exynos3250_jpeg_htbl_ac(jpeg->regs, 3);
2029 exynos3250_jpeg_htbl_dc(jpeg->regs, 3);
2030
2031 exynos3250_jpeg_set_x(jpeg->regs, ctx->crop_rect.width);
2032 exynos3250_jpeg_set_y(jpeg->regs, ctx->crop_rect.height);
2033 exynos3250_jpeg_stride(jpeg->regs, ctx->out_q.fmt->fourcc,
2034 ctx->out_q.w);
2035 exynos3250_jpeg_offset(jpeg->regs, ctx->crop_rect.left,
2036 ctx->crop_rect.top);
2037 exynos3250_jpeg_set_img_addr(ctx);
2038 exynos3250_jpeg_set_jpeg_addr(ctx);
2039 exynos3250_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
2040
2041 /* ultimately comes from sizeimage from userspace */
2042 exynos3250_jpeg_enc_stream_bound(jpeg->regs, ctx->cap_q.size);
2043
2044 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565 ||
2045 ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565X ||
2046 ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB32)
2047 exynos3250_jpeg_set_y16(jpeg->regs, true);
2048 } else {
2049 exynos3250_jpeg_set_img_addr(ctx);
2050 exynos3250_jpeg_set_jpeg_addr(ctx);
2051 exynos3250_jpeg_stride(jpeg->regs, ctx->cap_q.fmt->fourcc,
2052 ctx->cap_q.w);
2053 exynos3250_jpeg_offset(jpeg->regs, 0, 0);
2054 exynos3250_jpeg_dec_scaling_ratio(jpeg->regs,
2055 ctx->scale_factor);
2056 exynos3250_jpeg_dec_stream_size(jpeg->regs, ctx->out_q.size);
2057 exynos3250_jpeg_output_raw_fmt(jpeg->regs,
2058 ctx->cap_q.fmt->fourcc);
2059 }
2060
2061 exynos3250_jpeg_interrupts_enable(jpeg->regs);
2062
2063 /* JPEG RGB to YCbCr conversion matrix */
2064 exynos3250_jpeg_coef(jpeg->regs, ctx->mode);
2065
2066 exynos3250_jpeg_set_timer(jpeg->regs, EXYNOS3250_IRQ_TIMEOUT);
2067 jpeg->irq_status = 0;
2068 exynos3250_jpeg_start(jpeg->regs);
2069
2070 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
2071}
2072
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002073static int s5p_jpeg_job_ready(void *priv)
2074{
2075 struct s5p_jpeg_ctx *ctx = priv;
2076
2077 if (ctx->mode == S5P_JPEG_DECODE)
2078 return ctx->hdr_parsed;
2079 return 1;
2080}
2081
2082static void s5p_jpeg_job_abort(void *priv)
2083{
2084}
2085
2086static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = {
2087 .device_run = s5p_jpeg_device_run,
2088 .job_ready = s5p_jpeg_job_ready,
2089 .job_abort = s5p_jpeg_job_abort,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002090};
2091
2092static struct v4l2_m2m_ops exynos3250_jpeg_m2m_ops = {
2093 .device_run = exynos3250_jpeg_device_run,
2094 .job_ready = s5p_jpeg_job_ready,
2095 .job_abort = s5p_jpeg_job_abort,
2096};
2097
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03002098static struct v4l2_m2m_ops exynos4_jpeg_m2m_ops = {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002099 .device_run = exynos4_jpeg_device_run,
2100 .job_ready = s5p_jpeg_job_ready,
2101 .job_abort = s5p_jpeg_job_abort,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002102};
2103
2104/*
2105 * ============================================================================
2106 * Queue operations
2107 * ============================================================================
2108 */
2109
Marek Szyprowski719c1742012-01-13 05:12:38 -03002110static int s5p_jpeg_queue_setup(struct vb2_queue *vq,
2111 const struct v4l2_format *fmt,
2112 unsigned int *nbuffers, unsigned int *nplanes,
2113 unsigned int sizes[], void *alloc_ctxs[])
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002114{
2115 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
2116 struct s5p_jpeg_q_data *q_data = NULL;
2117 unsigned int size, count = *nbuffers;
2118
2119 q_data = get_q_data(ctx, vq->type);
2120 BUG_ON(q_data == NULL);
2121
2122 size = q_data->size;
2123
2124 /*
2125 * header is parsed during decoding and parsed information stored
2126 * in the context so we do not allow another buffer to overwrite it
2127 */
2128 if (ctx->mode == S5P_JPEG_DECODE)
2129 count = 1;
2130
2131 *nbuffers = count;
2132 *nplanes = 1;
2133 sizes[0] = size;
2134 alloc_ctxs[0] = ctx->jpeg->alloc_ctx;
2135
2136 return 0;
2137}
2138
2139static int s5p_jpeg_buf_prepare(struct vb2_buffer *vb)
2140{
2141 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
2142 struct s5p_jpeg_q_data *q_data = NULL;
2143
2144 q_data = get_q_data(ctx, vb->vb2_queue->type);
2145 BUG_ON(q_data == NULL);
2146
2147 if (vb2_plane_size(vb, 0) < q_data->size) {
2148 pr_err("%s data will not fit into plane (%lu < %lu)\n",
2149 __func__, vb2_plane_size(vb, 0),
2150 (long)q_data->size);
2151 return -EINVAL;
2152 }
2153
2154 vb2_set_plane_payload(vb, 0, q_data->size);
2155
2156 return 0;
2157}
2158
2159static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
2160{
2161 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
2162
2163 if (ctx->mode == S5P_JPEG_DECODE &&
2164 vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
2165 struct s5p_jpeg_q_data tmp, *q_data;
2166 ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp,
2167 (unsigned long)vb2_plane_vaddr(vb, 0),
2168 min((unsigned long)ctx->out_q.size,
Jacek Anaszewskif8433962013-11-21 13:33:09 -03002169 vb2_get_plane_payload(vb, 0)), ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002170 if (!ctx->hdr_parsed) {
2171 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
2172 return;
2173 }
2174
2175 q_data = &ctx->out_q;
2176 q_data->w = tmp.w;
2177 q_data->h = tmp.h;
2178
2179 q_data = &ctx->cap_q;
2180 q_data->w = tmp.w;
2181 q_data->h = tmp.h;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002182 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002183
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002184 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002185}
2186
2187static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
2188{
2189 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
2190 int ret;
2191
2192 ret = pm_runtime_get_sync(ctx->jpeg->dev);
2193
2194 return ret > 0 ? 0 : ret;
2195}
2196
Hans Verkuile37559b2014-04-17 02:47:21 -03002197static void s5p_jpeg_stop_streaming(struct vb2_queue *q)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002198{
2199 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
2200
2201 pm_runtime_put(ctx->jpeg->dev);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002202}
2203
2204static struct vb2_ops s5p_jpeg_qops = {
2205 .queue_setup = s5p_jpeg_queue_setup,
2206 .buf_prepare = s5p_jpeg_buf_prepare,
2207 .buf_queue = s5p_jpeg_buf_queue,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002208 .wait_prepare = vb2_ops_wait_prepare,
2209 .wait_finish = vb2_ops_wait_finish,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002210 .start_streaming = s5p_jpeg_start_streaming,
2211 .stop_streaming = s5p_jpeg_stop_streaming,
2212};
2213
2214static int queue_init(void *priv, struct vb2_queue *src_vq,
2215 struct vb2_queue *dst_vq)
2216{
2217 struct s5p_jpeg_ctx *ctx = priv;
2218 int ret;
2219
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002220 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
2221 src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
2222 src_vq->drv_priv = ctx;
2223 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
2224 src_vq->ops = &s5p_jpeg_qops;
2225 src_vq->mem_ops = &vb2_dma_contig_memops;
Sakari Ailusade48682014-02-25 19:12:19 -03002226 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002227 src_vq->lock = &ctx->jpeg->lock;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002228
2229 ret = vb2_queue_init(src_vq);
2230 if (ret)
2231 return ret;
2232
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002233 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2234 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
2235 dst_vq->drv_priv = ctx;
2236 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
2237 dst_vq->ops = &s5p_jpeg_qops;
2238 dst_vq->mem_ops = &vb2_dma_contig_memops;
Sakari Ailusade48682014-02-25 19:12:19 -03002239 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002240 dst_vq->lock = &ctx->jpeg->lock;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002241
2242 return vb2_queue_init(dst_vq);
2243}
2244
2245/*
2246 * ============================================================================
2247 * ISR
2248 * ============================================================================
2249 */
2250
2251static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
2252{
2253 struct s5p_jpeg *jpeg = dev_id;
2254 struct s5p_jpeg_ctx *curr_ctx;
2255 struct vb2_buffer *src_buf, *dst_buf;
2256 unsigned long payload_size = 0;
2257 enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
2258 bool enc_jpeg_too_large = false;
2259 bool timer_elapsed = false;
2260 bool op_completed = false;
2261
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002262 spin_lock(&jpeg->slock);
2263
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002264 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2265
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002266 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2267 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002268
2269 if (curr_ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002270 enc_jpeg_too_large = s5p_jpeg_enc_stream_stat(jpeg->regs);
2271 timer_elapsed = s5p_jpeg_timer_stat(jpeg->regs);
2272 op_completed = s5p_jpeg_result_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002273 if (curr_ctx->mode == S5P_JPEG_DECODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002274 op_completed = op_completed &&
2275 s5p_jpeg_stream_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002276
2277 if (enc_jpeg_too_large) {
2278 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002279 s5p_jpeg_clear_enc_stream_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002280 } else if (timer_elapsed) {
2281 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002282 s5p_jpeg_clear_timer_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002283 } else if (!op_completed) {
2284 state = VB2_BUF_STATE_ERROR;
2285 } else {
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002286 payload_size = s5p_jpeg_compressed_size(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002287 }
2288
Kamil Debskiaca326a2013-04-24 10:08:02 -03002289 dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
2290 dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
Sakari Ailus309f4d62014-02-08 14:21:35 -03002291 dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
2292 dst_buf->v4l2_buf.flags |=
2293 src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
Kamil Debskiaca326a2013-04-24 10:08:02 -03002294
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002295 v4l2_m2m_buf_done(src_buf, state);
2296 if (curr_ctx->mode == S5P_JPEG_ENCODE)
2297 vb2_set_plane_payload(dst_buf, 0, payload_size);
2298 v4l2_m2m_buf_done(dst_buf, state);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002299 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002300
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002301 curr_ctx->subsampling = s5p_jpeg_get_subsampling_mode(jpeg->regs);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002302 spin_unlock(&jpeg->slock);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03002303
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002304 s5p_jpeg_clear_int(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002305
2306 return IRQ_HANDLED;
2307}
2308
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002309static irqreturn_t exynos4_jpeg_irq(int irq, void *priv)
2310{
2311 unsigned int int_status;
2312 struct vb2_buffer *src_vb, *dst_vb;
2313 struct s5p_jpeg *jpeg = priv;
2314 struct s5p_jpeg_ctx *curr_ctx;
2315 unsigned long payload_size = 0;
2316
2317 spin_lock(&jpeg->slock);
2318
2319 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2320
2321 src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2322 dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
2323
2324 int_status = exynos4_jpeg_get_int_status(jpeg->regs);
2325
2326 if (int_status) {
2327 switch (int_status & 0x1f) {
2328 case 0x1:
2329 jpeg->irq_ret = ERR_PROT;
2330 break;
2331 case 0x2:
2332 jpeg->irq_ret = OK_ENC_OR_DEC;
2333 break;
2334 case 0x4:
2335 jpeg->irq_ret = ERR_DEC_INVALID_FORMAT;
2336 break;
2337 case 0x8:
2338 jpeg->irq_ret = ERR_MULTI_SCAN;
2339 break;
2340 case 0x10:
2341 jpeg->irq_ret = ERR_FRAME;
2342 break;
2343 default:
2344 jpeg->irq_ret = ERR_UNKNOWN;
2345 break;
2346 }
2347 } else {
2348 jpeg->irq_ret = ERR_UNKNOWN;
2349 }
2350
2351 if (jpeg->irq_ret == OK_ENC_OR_DEC) {
2352 if (curr_ctx->mode == S5P_JPEG_ENCODE) {
2353 payload_size = exynos4_jpeg_get_stream_size(jpeg->regs);
2354 vb2_set_plane_payload(dst_vb, 0, payload_size);
2355 }
2356 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
2357 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
2358 } else {
2359 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
2360 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
2361 }
2362
2363 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
2364 curr_ctx->subsampling = exynos4_jpeg_get_frame_fmt(jpeg->regs);
2365
2366 spin_unlock(&jpeg->slock);
2367 return IRQ_HANDLED;
2368}
2369
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002370static irqreturn_t exynos3250_jpeg_irq(int irq, void *dev_id)
2371{
2372 struct s5p_jpeg *jpeg = dev_id;
2373 struct s5p_jpeg_ctx *curr_ctx;
2374 struct vb2_buffer *src_buf, *dst_buf;
2375 unsigned long payload_size = 0;
2376 enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
2377 bool interrupt_timeout = false;
2378 u32 irq_status;
2379
2380 spin_lock(&jpeg->slock);
2381
2382 irq_status = exynos3250_jpeg_get_timer_status(jpeg->regs);
2383 if (irq_status & EXYNOS3250_TIMER_INT_STAT) {
2384 exynos3250_jpeg_clear_timer_status(jpeg->regs);
2385 interrupt_timeout = true;
2386 dev_err(jpeg->dev, "Interrupt timeout occurred.\n");
2387 }
2388
2389 irq_status = exynos3250_jpeg_get_int_status(jpeg->regs);
2390 exynos3250_jpeg_clear_int_status(jpeg->regs, irq_status);
2391
2392 jpeg->irq_status |= irq_status;
2393
2394 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2395
2396 if (!curr_ctx)
2397 goto exit_unlock;
2398
2399 if ((irq_status & EXYNOS3250_HEADER_STAT) &&
2400 (curr_ctx->mode == S5P_JPEG_DECODE)) {
2401 exynos3250_jpeg_rstart(jpeg->regs);
2402 goto exit_unlock;
2403 }
2404
2405 if (jpeg->irq_status & (EXYNOS3250_JPEG_DONE |
2406 EXYNOS3250_WDMA_DONE |
2407 EXYNOS3250_RDMA_DONE |
2408 EXYNOS3250_RESULT_STAT))
2409 payload_size = exynos3250_jpeg_compressed_size(jpeg->regs);
2410 else if (interrupt_timeout)
2411 state = VB2_BUF_STATE_ERROR;
2412 else
2413 goto exit_unlock;
2414
2415 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2416 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
2417
2418 dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
2419 dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
2420
2421 v4l2_m2m_buf_done(src_buf, state);
2422 if (curr_ctx->mode == S5P_JPEG_ENCODE)
2423 vb2_set_plane_payload(dst_buf, 0, payload_size);
2424 v4l2_m2m_buf_done(dst_buf, state);
2425 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
2426
2427 curr_ctx->subsampling =
2428 exynos3250_jpeg_get_subsampling_mode(jpeg->regs);
2429exit_unlock:
2430 spin_unlock(&jpeg->slock);
2431 return IRQ_HANDLED;
2432}
2433
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03002434static void *jpeg_get_drv_data(struct device *dev);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002435
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002436/*
2437 * ============================================================================
2438 * Driver basic infrastructure
2439 * ============================================================================
2440 */
2441
2442static int s5p_jpeg_probe(struct platform_device *pdev)
2443{
2444 struct s5p_jpeg *jpeg;
2445 struct resource *res;
2446 int ret;
2447
2448 /* JPEG IP abstraction struct */
Sachin Kamat5b58b952012-05-14 06:33:34 -03002449 jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002450 if (!jpeg)
2451 return -ENOMEM;
2452
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03002453 jpeg->variant = jpeg_get_drv_data(&pdev->dev);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002454
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002455 mutex_init(&jpeg->lock);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002456 spin_lock_init(&jpeg->slock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002457 jpeg->dev = &pdev->dev;
2458
2459 /* memory-mapped registers */
2460 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002461
Thierry Redingf23999e2013-01-21 06:09:07 -03002462 jpeg->regs = devm_ioremap_resource(&pdev->dev, res);
2463 if (IS_ERR(jpeg->regs))
2464 return PTR_ERR(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002465
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002466 /* interrupt service routine registration */
2467 jpeg->irq = ret = platform_get_irq(pdev, 0);
2468 if (ret < 0) {
2469 dev_err(&pdev->dev, "cannot find IRQ\n");
Sachin Kamat5b58b952012-05-14 06:33:34 -03002470 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002471 }
2472
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002473 ret = devm_request_irq(&pdev->dev, jpeg->irq, jpeg->variant->jpeg_irq,
2474 0, dev_name(&pdev->dev), jpeg);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002475 if (ret) {
2476 dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
Sachin Kamat5b58b952012-05-14 06:33:34 -03002477 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002478 }
2479
2480 /* clocks */
2481 jpeg->clk = clk_get(&pdev->dev, "jpeg");
2482 if (IS_ERR(jpeg->clk)) {
2483 dev_err(&pdev->dev, "cannot get clock\n");
2484 ret = PTR_ERR(jpeg->clk);
Sachin Kamat5b58b952012-05-14 06:33:34 -03002485 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002486 }
2487 dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002488
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002489 jpeg->sclk = clk_get(&pdev->dev, "sclk");
2490 if (IS_ERR(jpeg->sclk))
2491 dev_info(&pdev->dev, "sclk clock not available\n");
2492
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002493 /* v4l2 device */
2494 ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
2495 if (ret) {
2496 dev_err(&pdev->dev, "Failed to register v4l2 device\n");
2497 goto clk_get_rollback;
2498 }
2499
2500 /* mem2mem device */
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03002501 jpeg->m2m_dev = v4l2_m2m_init(jpeg->variant->m2m_ops);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002502 if (IS_ERR(jpeg->m2m_dev)) {
2503 v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
2504 ret = PTR_ERR(jpeg->m2m_dev);
2505 goto device_register_rollback;
2506 }
2507
2508 jpeg->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
2509 if (IS_ERR(jpeg->alloc_ctx)) {
2510 v4l2_err(&jpeg->v4l2_dev, "Failed to init memory allocator\n");
2511 ret = PTR_ERR(jpeg->alloc_ctx);
2512 goto m2m_init_rollback;
2513 }
2514
2515 /* JPEG encoder /dev/videoX node */
2516 jpeg->vfd_encoder = video_device_alloc();
2517 if (!jpeg->vfd_encoder) {
2518 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
2519 ret = -ENOMEM;
2520 goto vb2_allocator_rollback;
2521 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03002522 snprintf(jpeg->vfd_encoder->name, sizeof(jpeg->vfd_encoder->name),
2523 "%s-enc", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002524 jpeg->vfd_encoder->fops = &s5p_jpeg_fops;
2525 jpeg->vfd_encoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
2526 jpeg->vfd_encoder->minor = -1;
2527 jpeg->vfd_encoder->release = video_device_release;
2528 jpeg->vfd_encoder->lock = &jpeg->lock;
2529 jpeg->vfd_encoder->v4l2_dev = &jpeg->v4l2_dev;
Hans Verkuil954f3402012-09-05 06:05:50 -03002530 jpeg->vfd_encoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002531
2532 ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
2533 if (ret) {
2534 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
2535 goto enc_vdev_alloc_rollback;
2536 }
2537
2538 video_set_drvdata(jpeg->vfd_encoder, jpeg);
2539 v4l2_info(&jpeg->v4l2_dev,
2540 "encoder device registered as /dev/video%d\n",
2541 jpeg->vfd_encoder->num);
2542
2543 /* JPEG decoder /dev/videoX node */
2544 jpeg->vfd_decoder = video_device_alloc();
2545 if (!jpeg->vfd_decoder) {
2546 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
2547 ret = -ENOMEM;
2548 goto enc_vdev_register_rollback;
2549 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03002550 snprintf(jpeg->vfd_decoder->name, sizeof(jpeg->vfd_decoder->name),
2551 "%s-dec", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002552 jpeg->vfd_decoder->fops = &s5p_jpeg_fops;
2553 jpeg->vfd_decoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
2554 jpeg->vfd_decoder->minor = -1;
2555 jpeg->vfd_decoder->release = video_device_release;
2556 jpeg->vfd_decoder->lock = &jpeg->lock;
2557 jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev;
Jacek Anaszewski7f7d8fe2013-09-11 06:17:45 -03002558 jpeg->vfd_decoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002559
2560 ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
2561 if (ret) {
2562 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
2563 goto dec_vdev_alloc_rollback;
2564 }
2565
2566 video_set_drvdata(jpeg->vfd_decoder, jpeg);
2567 v4l2_info(&jpeg->v4l2_dev,
2568 "decoder device registered as /dev/video%d\n",
2569 jpeg->vfd_decoder->num);
2570
2571 /* final statements & power management */
2572 platform_set_drvdata(pdev, jpeg);
2573
2574 pm_runtime_enable(&pdev->dev);
2575
2576 v4l2_info(&jpeg->v4l2_dev, "Samsung S5P JPEG codec\n");
2577
2578 return 0;
2579
2580dec_vdev_alloc_rollback:
2581 video_device_release(jpeg->vfd_decoder);
2582
2583enc_vdev_register_rollback:
2584 video_unregister_device(jpeg->vfd_encoder);
2585
2586enc_vdev_alloc_rollback:
2587 video_device_release(jpeg->vfd_encoder);
2588
2589vb2_allocator_rollback:
2590 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
2591
2592m2m_init_rollback:
2593 v4l2_m2m_release(jpeg->m2m_dev);
2594
2595device_register_rollback:
2596 v4l2_device_unregister(&jpeg->v4l2_dev);
2597
2598clk_get_rollback:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002599 clk_put(jpeg->clk);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002600 if (!IS_ERR(jpeg->sclk))
2601 clk_put(jpeg->sclk);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002602
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002603 return ret;
2604}
2605
2606static int s5p_jpeg_remove(struct platform_device *pdev)
2607{
2608 struct s5p_jpeg *jpeg = platform_get_drvdata(pdev);
2609
2610 pm_runtime_disable(jpeg->dev);
2611
2612 video_unregister_device(jpeg->vfd_decoder);
2613 video_device_release(jpeg->vfd_decoder);
2614 video_unregister_device(jpeg->vfd_encoder);
2615 video_device_release(jpeg->vfd_encoder);
2616 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
2617 v4l2_m2m_release(jpeg->m2m_dev);
2618 v4l2_device_unregister(&jpeg->v4l2_dev);
2619
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002620 if (!pm_runtime_status_suspended(&pdev->dev)) {
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002621 clk_disable_unprepare(jpeg->clk);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002622 if (!IS_ERR(jpeg->sclk))
2623 clk_disable_unprepare(jpeg->sclk);
2624 }
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002625
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002626 clk_put(jpeg->clk);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002627 if (!IS_ERR(jpeg->sclk))
2628 clk_put(jpeg->sclk);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002629
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002630 return 0;
2631}
2632
Rafael J. Wysockie243c7c2014-12-04 01:10:10 +01002633#ifdef CONFIG_PM
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002634static int s5p_jpeg_runtime_suspend(struct device *dev)
2635{
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002636 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
2637
2638 clk_disable_unprepare(jpeg->clk);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002639 if (!IS_ERR(jpeg->sclk))
2640 clk_disable_unprepare(jpeg->sclk);
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002641
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002642 return 0;
2643}
2644
2645static int s5p_jpeg_runtime_resume(struct device *dev)
2646{
2647 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002648 unsigned long flags;
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002649 int ret;
2650
2651 ret = clk_prepare_enable(jpeg->clk);
2652 if (ret < 0)
2653 return ret;
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03002654
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002655 if (!IS_ERR(jpeg->sclk)) {
2656 ret = clk_prepare_enable(jpeg->sclk);
2657 if (ret < 0)
2658 return ret;
2659 }
2660
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002661 spin_lock_irqsave(&jpeg->slock, flags);
2662
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002663 /*
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002664 * JPEG IP allows storing two Huffman tables for each component.
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002665 * We fill table 0 for each component and do this here only
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002666 * for S5PC210 and Exynos3250 SoCs. Exynos4x12 SoC requires
2667 * programming its Huffman tables each time the encoding process
2668 * is initialized, and thus it is accomplished in the device_run
2669 * callback of m2m_ops.
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002670 */
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002671 if (jpeg->variant->version == SJPEG_S5P ||
2672 jpeg->variant->version == SJPEG_EXYNOS3250) {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002673 s5p_jpeg_set_hdctbl(jpeg->regs);
2674 s5p_jpeg_set_hdctblg(jpeg->regs);
2675 s5p_jpeg_set_hactbl(jpeg->regs);
2676 s5p_jpeg_set_hactblg(jpeg->regs);
2677 }
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03002678
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002679 spin_unlock_irqrestore(&jpeg->slock, flags);
2680
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002681 return 0;
2682}
Rafael J. Wysockie243c7c2014-12-04 01:10:10 +01002683#endif /* CONFIG_PM */
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002684
Thierry Redingde3767a2014-10-14 07:10:40 -03002685#ifdef CONFIG_PM_SLEEP
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002686static int s5p_jpeg_suspend(struct device *dev)
2687{
2688 if (pm_runtime_suspended(dev))
2689 return 0;
2690
2691 return s5p_jpeg_runtime_suspend(dev);
2692}
2693
2694static int s5p_jpeg_resume(struct device *dev)
2695{
2696 if (pm_runtime_suspended(dev))
2697 return 0;
2698
2699 return s5p_jpeg_runtime_resume(dev);
2700}
Thierry Redingde3767a2014-10-14 07:10:40 -03002701#endif
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002702
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002703static const struct dev_pm_ops s5p_jpeg_pm_ops = {
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002704 SET_SYSTEM_SLEEP_PM_OPS(s5p_jpeg_suspend, s5p_jpeg_resume)
2705 SET_RUNTIME_PM_OPS(s5p_jpeg_runtime_suspend, s5p_jpeg_runtime_resume, NULL)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002706};
2707
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002708static struct s5p_jpeg_variant s5p_jpeg_drvdata = {
2709 .version = SJPEG_S5P,
2710 .jpeg_irq = s5p_jpeg_irq,
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03002711 .m2m_ops = &s5p_jpeg_m2m_ops,
Jacek Anaszewskib2451682014-04-10 04:32:11 -03002712 .fmt_ver_flag = SJPEG_FMT_FLAG_S5P,
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03002713};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002714
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002715static struct s5p_jpeg_variant exynos3250_jpeg_drvdata = {
2716 .version = SJPEG_EXYNOS3250,
2717 .jpeg_irq = exynos3250_jpeg_irq,
2718 .m2m_ops = &exynos3250_jpeg_m2m_ops,
2719 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS3250,
2720};
2721
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002722static struct s5p_jpeg_variant exynos4_jpeg_drvdata = {
2723 .version = SJPEG_EXYNOS4,
2724 .jpeg_irq = exynos4_jpeg_irq,
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03002725 .m2m_ops = &exynos4_jpeg_m2m_ops,
Jacek Anaszewskib2451682014-04-10 04:32:11 -03002726 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS4,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002727};
2728
2729static const struct of_device_id samsung_jpeg_match[] = {
2730 {
2731 .compatible = "samsung,s5pv210-jpeg",
2732 .data = &s5p_jpeg_drvdata,
2733 }, {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002734 .compatible = "samsung,exynos3250-jpeg",
2735 .data = &exynos3250_jpeg_drvdata,
2736 }, {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002737 .compatible = "samsung,exynos4210-jpeg",
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002738 .data = &exynos4_jpeg_drvdata,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002739 }, {
2740 .compatible = "samsung,exynos4212-jpeg",
2741 .data = &exynos4_jpeg_drvdata,
2742 },
2743 {},
2744};
2745
2746MODULE_DEVICE_TABLE(of, samsung_jpeg_match);
2747
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03002748static void *jpeg_get_drv_data(struct device *dev)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002749{
2750 struct s5p_jpeg_variant *driver_data = NULL;
2751 const struct of_device_id *match;
2752
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03002753 if (!IS_ENABLED(CONFIG_OF) || !dev->of_node)
2754 return &s5p_jpeg_drvdata;
2755
2756 match = of_match_node(samsung_jpeg_match, dev->of_node);
2757
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002758 if (match)
2759 driver_data = (struct s5p_jpeg_variant *)match->data;
2760
2761 return driver_data;
2762}
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03002763
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002764static struct platform_driver s5p_jpeg_driver = {
2765 .probe = s5p_jpeg_probe,
2766 .remove = s5p_jpeg_remove,
2767 .driver = {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002768 .of_match_table = of_match_ptr(samsung_jpeg_match),
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002769 .name = S5P_JPEG_M2M_NAME,
2770 .pm = &s5p_jpeg_pm_ops,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002771 },
2772};
2773
Sachin Kamat87e94292012-07-03 05:54:33 -03002774module_platform_driver(s5p_jpeg_driver);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002775
2776MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002777MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002778MODULE_DESCRIPTION("Samsung JPEG codec driver");
2779MODULE_LICENSE("GPL");