blob: dde9d3598c48a26a6a38e4ad0180cbc39d7a43a6 [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>
Junghak Sungc1399902015-09-22 10:30:29 -030029#include <media/videobuf2-v4l2.h>
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030030#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;
Shuah Khan605b8922016-07-14 17:01:56 -0300540
Jacek Anaszewski337777a2013-11-22 06:13:34 -0300541 for (i = 0; i < ARRAY_SIZE(fourcc_to_dwngrd_schema_id); ++i) {
542 if (fourcc_to_dwngrd_schema_id[i] == fourcc)
543 return i;
544 }
545
546 return -EINVAL;
547}
548
549static int s5p_jpeg_adjust_fourcc_to_subsampling(
550 enum v4l2_jpeg_chroma_subsampling subs,
551 u32 in_fourcc,
552 u32 *out_fourcc,
553 struct s5p_jpeg_ctx *ctx)
554{
555 int dwngrd_sch_id;
556
557 if (ctx->subsampling != V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY) {
558 dwngrd_sch_id =
559 s5p_jpeg_get_dwngrd_sch_id_by_fourcc(in_fourcc);
560 if (dwngrd_sch_id < 0)
561 return -EINVAL;
562 }
563
564 switch (ctx->subsampling) {
565 case V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY:
566 *out_fourcc = V4L2_PIX_FMT_GREY;
567 break;
568 case V4L2_JPEG_CHROMA_SUBSAMPLING_420:
569 if (dwngrd_sch_id >
570 ARRAY_SIZE(subs420_fourcc_dwngrd_schema) - 1)
571 return -EINVAL;
572 *out_fourcc = subs420_fourcc_dwngrd_schema[dwngrd_sch_id];
573 break;
574 case V4L2_JPEG_CHROMA_SUBSAMPLING_422:
575 if (dwngrd_sch_id >
576 ARRAY_SIZE(subs422_fourcc_dwngrd_schema) - 1)
577 return -EINVAL;
578 *out_fourcc = subs422_fourcc_dwngrd_schema[dwngrd_sch_id];
579 break;
580 default:
581 *out_fourcc = V4L2_PIX_FMT_GREY;
582 break;
583 }
584
585 return 0;
586}
587
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300588static int exynos4x12_decoded_subsampling[] = {
589 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
590 V4L2_JPEG_CHROMA_SUBSAMPLING_444,
591 V4L2_JPEG_CHROMA_SUBSAMPLING_422,
592 V4L2_JPEG_CHROMA_SUBSAMPLING_420,
593};
594
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300595static int exynos3250_decoded_subsampling[] = {
596 V4L2_JPEG_CHROMA_SUBSAMPLING_444,
597 V4L2_JPEG_CHROMA_SUBSAMPLING_422,
598 V4L2_JPEG_CHROMA_SUBSAMPLING_420,
599 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
600 -1,
601 -1,
602 V4L2_JPEG_CHROMA_SUBSAMPLING_411,
603};
604
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300605static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c)
606{
607 return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler);
608}
609
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300610static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh)
611{
612 return container_of(fh, struct s5p_jpeg_ctx, fh);
613}
614
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300615static int s5p_jpeg_to_user_subsampling(struct s5p_jpeg_ctx *ctx)
616{
617 WARN_ON(ctx->subsampling > 3);
618
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300619 switch (ctx->jpeg->variant->version) {
620 case SJPEG_S5P:
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300621 if (ctx->subsampling > 2)
622 return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
623 return ctx->subsampling;
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300624 case SJPEG_EXYNOS3250:
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -0300625 case SJPEG_EXYNOS5420:
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300626 if (ctx->subsampling > 3)
627 return V4L2_JPEG_CHROMA_SUBSAMPLING_411;
628 return exynos3250_decoded_subsampling[ctx->subsampling];
629 case SJPEG_EXYNOS4:
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300630 case SJPEG_EXYNOS5433:
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300631 if (ctx->subsampling > 2)
632 return V4L2_JPEG_CHROMA_SUBSAMPLING_420;
633 return exynos4x12_decoded_subsampling[ctx->subsampling];
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300634 default:
635 return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300636 }
637}
638
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300639static inline void s5p_jpeg_set_qtbl(void __iomem *regs,
640 const unsigned char *qtbl,
641 unsigned long tab, int len)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300642{
643 int i;
644
645 for (i = 0; i < len; i++)
646 writel((unsigned int)qtbl[i], regs + tab + (i * 0x04));
647}
648
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300649static inline void s5p_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300650{
651 /* this driver fills quantisation table 0 with data for luma */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300652 s5p_jpeg_set_qtbl(regs, qtbl_luminance[quality],
653 S5P_JPG_QTBL_CONTENT(0),
654 ARRAY_SIZE(qtbl_luminance[quality]));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300655}
656
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300657static inline void s5p_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300658{
659 /* this driver fills quantisation table 1 with data for chroma */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300660 s5p_jpeg_set_qtbl(regs, qtbl_chrominance[quality],
661 S5P_JPG_QTBL_CONTENT(1),
662 ARRAY_SIZE(qtbl_chrominance[quality]));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300663}
664
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300665static inline void s5p_jpeg_set_htbl(void __iomem *regs,
666 const unsigned char *htbl,
667 unsigned long tab, int len)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300668{
669 int i;
670
671 for (i = 0; i < len; i++)
672 writel((unsigned int)htbl[i], regs + tab + (i * 0x04));
673}
674
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300675static inline void s5p_jpeg_set_hdctbl(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300676{
677 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300678 s5p_jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0),
679 ARRAY_SIZE(hdctbl0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300680}
681
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300682static inline void s5p_jpeg_set_hdctblg(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300683{
684 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300685 s5p_jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0),
686 ARRAY_SIZE(hdctblg0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300687}
688
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300689static inline void s5p_jpeg_set_hactbl(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300690{
691 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300692 s5p_jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0),
693 ARRAY_SIZE(hactbl0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300694}
695
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300696static inline void s5p_jpeg_set_hactblg(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300697{
698 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300699 s5p_jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0),
700 ARRAY_SIZE(hactblg0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300701}
702
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300703static inline void exynos4_jpeg_set_tbl(void __iomem *regs,
704 const unsigned char *tbl,
705 unsigned long tab, int len)
706{
707 int i;
708 unsigned int dword;
709
710 for (i = 0; i < len; i += 4) {
711 dword = tbl[i] |
712 (tbl[i + 1] << 8) |
713 (tbl[i + 2] << 16) |
714 (tbl[i + 3] << 24);
715 writel(dword, regs + tab + i);
716 }
717}
718
719static inline void exynos4_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
720{
721 /* this driver fills quantisation table 0 with data for luma */
722 exynos4_jpeg_set_tbl(regs, qtbl_luminance[quality],
723 EXYNOS4_QTBL_CONTENT(0),
724 ARRAY_SIZE(qtbl_luminance[quality]));
725}
726
727static inline void exynos4_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
728{
729 /* this driver fills quantisation table 1 with data for chroma */
730 exynos4_jpeg_set_tbl(regs, qtbl_chrominance[quality],
731 EXYNOS4_QTBL_CONTENT(1),
732 ARRAY_SIZE(qtbl_chrominance[quality]));
733}
734
Mauro Carvalho Chehabaf425be2014-08-26 10:50:23 -0300735static void exynos4_jpeg_set_huff_tbl(void __iomem *base)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300736{
737 exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCLL,
738 ARRAY_SIZE(hdctbl0));
739 exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCCL,
740 ARRAY_SIZE(hdctbl0));
741 exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCLV,
742 ARRAY_SIZE(hdctblg0));
743 exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCCV,
744 ARRAY_SIZE(hdctblg0));
745 exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACLL,
746 ARRAY_SIZE(hactbl0));
747 exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACCL,
748 ARRAY_SIZE(hactbl0));
749 exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACLV,
750 ARRAY_SIZE(hactblg0));
751 exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACCV,
752 ARRAY_SIZE(hactblg0));
753}
754
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300755static inline int __exynos4_huff_tbl(int class, int id, bool lenval)
756{
757 /*
758 * class: 0 - DC, 1 - AC
759 * id: 0 - Y, 1 - Cb/Cr
760 */
761 if (class) {
762 if (id)
763 return lenval ? EXYNOS4_HUFF_TBL_HACCL :
764 EXYNOS4_HUFF_TBL_HACCV;
765 return lenval ? EXYNOS4_HUFF_TBL_HACLL : EXYNOS4_HUFF_TBL_HACLV;
766
767 }
768 /* class == 0 */
769 if (id)
770 return lenval ? EXYNOS4_HUFF_TBL_HDCCL : EXYNOS4_HUFF_TBL_HDCCV;
771
772 return lenval ? EXYNOS4_HUFF_TBL_HDCLL : EXYNOS4_HUFF_TBL_HDCLV;
773}
774
775static inline int exynos4_huff_tbl_len(int class, int id)
776{
777 return __exynos4_huff_tbl(class, id, true);
778}
779
780static inline int exynos4_huff_tbl_val(int class, int id)
781{
782 return __exynos4_huff_tbl(class, id, false);
783}
784
785static int get_byte(struct s5p_jpeg_buffer *buf);
786static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word);
787static void skip(struct s5p_jpeg_buffer *buf, long len);
788
789static void exynos4_jpeg_parse_decode_h_tbl(struct s5p_jpeg_ctx *ctx)
790{
791 struct s5p_jpeg *jpeg = ctx->jpeg;
792 struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
793 struct s5p_jpeg_buffer jpeg_buffer;
794 unsigned int word;
795 int c, x, components;
796
797 jpeg_buffer.size = 2; /* Ls */
798 jpeg_buffer.data =
799 (unsigned long)vb2_plane_vaddr(vb, 0) + ctx->out_q.sos + 2;
800 jpeg_buffer.curr = 0;
801
802 word = 0;
803
804 if (get_word_be(&jpeg_buffer, &word))
805 return;
806 jpeg_buffer.size = (long)word - 2;
807 jpeg_buffer.data += 2;
808 jpeg_buffer.curr = 0;
809
810 components = get_byte(&jpeg_buffer);
811 if (components == -1)
812 return;
813 while (components--) {
814 c = get_byte(&jpeg_buffer);
815 if (c == -1)
816 return;
817 x = get_byte(&jpeg_buffer);
818 if (x == -1)
819 return;
820 exynos4_jpeg_select_dec_h_tbl(jpeg->regs, c,
821 (((x >> 4) & 0x1) << 1) | (x & 0x1));
822 }
823
824}
825
826static void exynos4_jpeg_parse_huff_tbl(struct s5p_jpeg_ctx *ctx)
827{
828 struct s5p_jpeg *jpeg = ctx->jpeg;
829 struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
830 struct s5p_jpeg_buffer jpeg_buffer;
831 unsigned int word;
832 int c, i, n, j;
833
834 for (j = 0; j < ctx->out_q.dht.n; ++j) {
835 jpeg_buffer.size = ctx->out_q.dht.len[j];
836 jpeg_buffer.data = (unsigned long)vb2_plane_vaddr(vb, 0) +
837 ctx->out_q.dht.marker[j];
838 jpeg_buffer.curr = 0;
839
840 word = 0;
841 while (jpeg_buffer.curr < jpeg_buffer.size) {
842 char id, class;
843
844 c = get_byte(&jpeg_buffer);
845 if (c == -1)
846 return;
847 id = c & 0xf;
848 class = (c >> 4) & 0xf;
849 n = 0;
850 for (i = 0; i < 16; ++i) {
851 c = get_byte(&jpeg_buffer);
852 if (c == -1)
853 return;
854 word |= c << ((i % 4) * 8);
855 if ((i + 1) % 4 == 0) {
856 writel(word, jpeg->regs +
857 exynos4_huff_tbl_len(class, id) +
858 (i / 4) * 4);
859 word = 0;
860 }
861 n += c;
862 }
863 word = 0;
864 for (i = 0; i < n; ++i) {
865 c = get_byte(&jpeg_buffer);
866 if (c == -1)
867 return;
868 word |= c << ((i % 4) * 8);
869 if ((i + 1) % 4 == 0) {
870 writel(word, jpeg->regs +
871 exynos4_huff_tbl_val(class, id) +
872 (i / 4) * 4);
873 word = 0;
874 }
875 }
876 if (i % 4) {
877 writel(word, jpeg->regs +
878 exynos4_huff_tbl_val(class, id) + (i / 4) * 4);
879 }
880 word = 0;
881 }
882 }
883}
884
885static void exynos4_jpeg_parse_decode_q_tbl(struct s5p_jpeg_ctx *ctx)
886{
887 struct s5p_jpeg *jpeg = ctx->jpeg;
888 struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
889 struct s5p_jpeg_buffer jpeg_buffer;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300890 int c, x, components;
891
892 jpeg_buffer.size = ctx->out_q.sof_len;
893 jpeg_buffer.data =
894 (unsigned long)vb2_plane_vaddr(vb, 0) + ctx->out_q.sof;
895 jpeg_buffer.curr = 0;
896
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300897 skip(&jpeg_buffer, 5); /* P, Y, X */
898 components = get_byte(&jpeg_buffer);
899 if (components == -1)
900 return;
901
902 exynos4_jpeg_set_dec_components(jpeg->regs, components);
903
904 while (components--) {
905 c = get_byte(&jpeg_buffer);
906 if (c == -1)
907 return;
908 skip(&jpeg_buffer, 1);
909 x = get_byte(&jpeg_buffer);
910 if (x == -1)
911 return;
912 exynos4_jpeg_select_dec_q_tbl(jpeg->regs, c, x);
913 }
914}
915
916static void exynos4_jpeg_parse_q_tbl(struct s5p_jpeg_ctx *ctx)
917{
918 struct s5p_jpeg *jpeg = ctx->jpeg;
919 struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
920 struct s5p_jpeg_buffer jpeg_buffer;
921 unsigned int word;
922 int c, i, j;
923
924 for (j = 0; j < ctx->out_q.dqt.n; ++j) {
925 jpeg_buffer.size = ctx->out_q.dqt.len[j];
926 jpeg_buffer.data = (unsigned long)vb2_plane_vaddr(vb, 0) +
927 ctx->out_q.dqt.marker[j];
928 jpeg_buffer.curr = 0;
929
930 word = 0;
931 while (jpeg_buffer.size - jpeg_buffer.curr >= 65) {
932 char id;
933
934 c = get_byte(&jpeg_buffer);
935 if (c == -1)
936 return;
937 id = c & 0xf;
938 /* nonzero means extended mode - not supported */
939 if ((c >> 4) & 0xf)
940 return;
941 for (i = 0; i < 64; ++i) {
942 c = get_byte(&jpeg_buffer);
943 if (c == -1)
944 return;
945 word |= c << ((i % 4) * 8);
946 if ((i + 1) % 4 == 0) {
947 writel(word, jpeg->regs +
948 EXYNOS4_QTBL_CONTENT(id) + (i / 4) * 4);
949 word = 0;
950 }
951 }
952 word = 0;
953 }
954 }
955}
956
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300957/*
958 * ============================================================================
959 * Device file operations
960 * ============================================================================
961 */
962
963static int queue_init(void *priv, struct vb2_queue *src_vq,
964 struct vb2_queue *dst_vq);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300965static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
966 __u32 pixelformat, unsigned int fmt_type);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300967static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300968
969static int s5p_jpeg_open(struct file *file)
970{
971 struct s5p_jpeg *jpeg = video_drvdata(file);
972 struct video_device *vfd = video_devdata(file);
973 struct s5p_jpeg_ctx *ctx;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300974 struct s5p_jpeg_fmt *out_fmt, *cap_fmt;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300975 int ret = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300976
Sachin Kamatb5146c92012-08-16 08:52:58 -0300977 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300978 if (!ctx)
979 return -ENOMEM;
980
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300981 if (mutex_lock_interruptible(&jpeg->lock)) {
982 ret = -ERESTARTSYS;
983 goto free;
984 }
985
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300986 v4l2_fh_init(&ctx->fh, vfd);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300987 /* Use separate control handler per file handle */
988 ctx->fh.ctrl_handler = &ctx->ctrl_handler;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300989 file->private_data = &ctx->fh;
990 v4l2_fh_add(&ctx->fh);
991
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300992 ctx->jpeg = jpeg;
993 if (vfd == jpeg->vfd_encoder) {
994 ctx->mode = S5P_JPEG_ENCODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300995 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB565,
996 FMT_TYPE_OUTPUT);
997 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
998 FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300999 } else {
1000 ctx->mode = S5P_JPEG_DECODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001001 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
1002 FMT_TYPE_OUTPUT);
1003 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_YUYV,
1004 FMT_TYPE_CAPTURE);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001005 ctx->scale_factor = EXYNOS3250_DEC_SCALE_FACTOR_8_8;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001006 }
1007
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001008 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
1009 if (IS_ERR(ctx->fh.m2m_ctx)) {
1010 ret = PTR_ERR(ctx->fh.m2m_ctx);
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001011 goto error;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001012 }
1013
1014 ctx->out_q.fmt = out_fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001015 ctx->cap_q.fmt = cap_fmt;
1016
1017 ret = s5p_jpeg_controls_create(ctx);
1018 if (ret < 0)
1019 goto error;
1020
Hans Verkuilb0d5cd62012-06-24 06:54:18 -03001021 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001022 return 0;
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001023
1024error:
1025 v4l2_fh_del(&ctx->fh);
1026 v4l2_fh_exit(&ctx->fh);
Hans Verkuilb0d5cd62012-06-24 06:54:18 -03001027 mutex_unlock(&jpeg->lock);
1028free:
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001029 kfree(ctx);
1030 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001031}
1032
1033static int s5p_jpeg_release(struct file *file)
1034{
Hans Verkuilb0d5cd62012-06-24 06:54:18 -03001035 struct s5p_jpeg *jpeg = video_drvdata(file);
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001036 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001037
Hans Verkuilb0d5cd62012-06-24 06:54:18 -03001038 mutex_lock(&jpeg->lock);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001039 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001040 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001041 v4l2_fh_del(&ctx->fh);
1042 v4l2_fh_exit(&ctx->fh);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001043 kfree(ctx);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001044 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001045
1046 return 0;
1047}
1048
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001049static const struct v4l2_file_operations s5p_jpeg_fops = {
1050 .owner = THIS_MODULE,
1051 .open = s5p_jpeg_open,
1052 .release = s5p_jpeg_release,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001053 .poll = v4l2_m2m_fop_poll,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001054 .unlocked_ioctl = video_ioctl2,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001055 .mmap = v4l2_m2m_fop_mmap,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001056};
1057
1058/*
1059 * ============================================================================
1060 * video ioctl operations
1061 * ============================================================================
1062 */
1063
1064static int get_byte(struct s5p_jpeg_buffer *buf)
1065{
1066 if (buf->curr >= buf->size)
1067 return -1;
1068
1069 return ((unsigned char *)buf->data)[buf->curr++];
1070}
1071
1072static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word)
1073{
1074 unsigned int temp;
1075 int byte;
1076
1077 byte = get_byte(buf);
1078 if (byte == -1)
1079 return -1;
1080 temp = byte << 8;
1081 byte = get_byte(buf);
1082 if (byte == -1)
1083 return -1;
1084 *word = (unsigned int)byte | temp;
1085 return 0;
1086}
1087
1088static void skip(struct s5p_jpeg_buffer *buf, long len)
1089{
1090 if (len <= 0)
1091 return;
1092
1093 while (len--)
1094 get_byte(buf);
1095}
1096
1097static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001098 unsigned long buffer, unsigned long size,
1099 struct s5p_jpeg_ctx *ctx)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001100{
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001101 int c, components = 0, notfound, n_dht = 0, n_dqt = 0;
1102 unsigned int height, width, word, subsampling = 0, sos = 0, sof = 0,
1103 sof_len = 0;
1104 unsigned int dht[S5P_JPEG_MAX_MARKER], dht_len[S5P_JPEG_MAX_MARKER],
1105 dqt[S5P_JPEG_MAX_MARKER], dqt_len[S5P_JPEG_MAX_MARKER];
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001106 long length;
1107 struct s5p_jpeg_buffer jpeg_buffer;
1108
1109 jpeg_buffer.size = size;
1110 jpeg_buffer.data = buffer;
1111 jpeg_buffer.curr = 0;
1112
1113 notfound = 1;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001114 while (notfound || !sos) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001115 c = get_byte(&jpeg_buffer);
1116 if (c == -1)
Jacek Anaszewskia35f6002014-07-11 12:19:43 -03001117 return false;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001118 if (c != 0xff)
1119 continue;
1120 do
1121 c = get_byte(&jpeg_buffer);
1122 while (c == 0xff);
1123 if (c == -1)
Jacek Anaszewskia35f6002014-07-11 12:19:43 -03001124 return false;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001125 if (c == 0)
1126 continue;
1127 length = 0;
1128 switch (c) {
1129 /* SOF0: baseline JPEG */
1130 case SOF0:
1131 if (get_word_be(&jpeg_buffer, &word))
1132 break;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001133 length = (long)word - 2;
1134 if (!length)
1135 return false;
1136 sof = jpeg_buffer.curr; /* after 0xffc0 */
1137 sof_len = length;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001138 if (get_byte(&jpeg_buffer) == -1)
1139 break;
1140 if (get_word_be(&jpeg_buffer, &height))
1141 break;
1142 if (get_word_be(&jpeg_buffer, &width))
1143 break;
1144 components = get_byte(&jpeg_buffer);
1145 if (components == -1)
1146 break;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001147
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001148 if (components == 1) {
1149 subsampling = 0x33;
1150 } else {
1151 skip(&jpeg_buffer, 1);
1152 subsampling = get_byte(&jpeg_buffer);
1153 skip(&jpeg_buffer, 1);
1154 }
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001155 if (components > 3)
1156 return false;
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001157 skip(&jpeg_buffer, components * 2);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001158 notfound = 0;
1159 break;
1160
1161 case DQT:
1162 if (get_word_be(&jpeg_buffer, &word))
1163 break;
1164 length = (long)word - 2;
1165 if (!length)
1166 return false;
1167 if (n_dqt >= S5P_JPEG_MAX_MARKER)
1168 return false;
1169 dqt[n_dqt] = jpeg_buffer.curr; /* after 0xffdb */
1170 dqt_len[n_dqt++] = length;
1171 skip(&jpeg_buffer, length);
1172 break;
1173
1174 case DHT:
1175 if (get_word_be(&jpeg_buffer, &word))
1176 break;
1177 length = (long)word - 2;
1178 if (!length)
1179 return false;
1180 if (n_dht >= S5P_JPEG_MAX_MARKER)
1181 return false;
1182 dht[n_dht] = jpeg_buffer.curr; /* after 0xffc4 */
1183 dht_len[n_dht++] = length;
1184 skip(&jpeg_buffer, length);
1185 break;
1186
1187 case SOS:
1188 sos = jpeg_buffer.curr - 2; /* 0xffda */
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001189 break;
1190
1191 /* skip payload-less markers */
1192 case RST ... RST + 7:
1193 case SOI:
1194 case EOI:
1195 case TEM:
1196 break;
1197
1198 /* skip uninteresting payload markers */
1199 default:
1200 if (get_word_be(&jpeg_buffer, &word))
1201 break;
1202 length = (long)word - 2;
1203 skip(&jpeg_buffer, length);
1204 break;
1205 }
1206 }
1207 result->w = width;
1208 result->h = height;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001209 result->sos = sos;
1210 result->dht.n = n_dht;
1211 while (n_dht--) {
1212 result->dht.marker[n_dht] = dht[n_dht];
1213 result->dht.len[n_dht] = dht_len[n_dht];
1214 }
1215 result->dqt.n = n_dqt;
1216 while (n_dqt--) {
1217 result->dqt.marker[n_dqt] = dqt[n_dqt];
1218 result->dqt.len[n_dqt] = dqt_len[n_dqt];
1219 }
1220 result->sof = sof;
1221 result->sof_len = sof_len;
1222 result->size = result->components = components;
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001223
1224 switch (subsampling) {
1225 case 0x11:
1226 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444;
1227 break;
1228 case 0x21:
1229 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422;
1230 break;
1231 case 0x22:
1232 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420;
1233 break;
1234 case 0x33:
1235 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
1236 break;
1237 default:
1238 return false;
1239 }
1240
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001241 return !notfound && sos;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001242}
1243
1244static int s5p_jpeg_querycap(struct file *file, void *priv,
1245 struct v4l2_capability *cap)
1246{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001247 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001248
1249 if (ctx->mode == S5P_JPEG_ENCODE) {
Javier Martinez Canillasb9f19f02016-06-16 18:40:33 -03001250 strlcpy(cap->driver, S5P_JPEG_M2M_NAME,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001251 sizeof(cap->driver));
1252 strlcpy(cap->card, S5P_JPEG_M2M_NAME " encoder",
1253 sizeof(cap->card));
1254 } else {
Javier Martinez Canillasb9f19f02016-06-16 18:40:33 -03001255 strlcpy(cap->driver, S5P_JPEG_M2M_NAME,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001256 sizeof(cap->driver));
1257 strlcpy(cap->card, S5P_JPEG_M2M_NAME " decoder",
1258 sizeof(cap->card));
1259 }
Javier Martinez Canillas3b2aa382016-06-16 18:40:32 -03001260 snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
1261 dev_name(ctx->jpeg->dev));
Hans Verkuil8c17e5e2014-11-24 06:37:26 -03001262 cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M;
1263 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001264 return 0;
1265}
1266
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001267static int enum_fmt(struct s5p_jpeg_fmt *sjpeg_formats, int n,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001268 struct v4l2_fmtdesc *f, u32 type)
1269{
1270 int i, num = 0;
1271
1272 for (i = 0; i < n; ++i) {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001273 if (sjpeg_formats[i].flags & type) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001274 /* index-th format of type type found ? */
1275 if (num == f->index)
1276 break;
1277 /* Correct type but haven't reached our index yet,
Shuah Khan605b8922016-07-14 17:01:56 -03001278 * just increment per-type index
1279 */
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001280 ++num;
1281 }
1282 }
1283
1284 /* Format not found */
1285 if (i >= n)
1286 return -EINVAL;
1287
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001288 strlcpy(f->description, sjpeg_formats[i].name, sizeof(f->description));
1289 f->pixelformat = sjpeg_formats[i].fourcc;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001290
1291 return 0;
1292}
1293
1294static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
1295 struct v4l2_fmtdesc *f)
1296{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001297 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001298
1299 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001300 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1301 SJPEG_FMT_FLAG_ENC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001302
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001303 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1304 SJPEG_FMT_FLAG_DEC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001305}
1306
1307static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
1308 struct v4l2_fmtdesc *f)
1309{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001310 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001311
1312 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001313 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1314 SJPEG_FMT_FLAG_ENC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001315
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001316 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1317 SJPEG_FMT_FLAG_DEC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001318}
1319
1320static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx,
1321 enum v4l2_buf_type type)
1322{
1323 if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1324 return &ctx->out_q;
1325 if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1326 return &ctx->cap_q;
1327
1328 return NULL;
1329}
1330
1331static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
1332{
1333 struct vb2_queue *vq;
1334 struct s5p_jpeg_q_data *q_data = NULL;
1335 struct v4l2_pix_format *pix = &f->fmt.pix;
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001336 struct s5p_jpeg_ctx *ct = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001337
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001338 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001339 if (!vq)
1340 return -EINVAL;
1341
1342 if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
1343 ct->mode == S5P_JPEG_DECODE && !ct->hdr_parsed)
1344 return -EINVAL;
1345 q_data = get_q_data(ct, f->type);
1346 BUG_ON(q_data == NULL);
1347
1348 pix->width = q_data->w;
1349 pix->height = q_data->h;
1350 pix->field = V4L2_FIELD_NONE;
1351 pix->pixelformat = q_data->fmt->fourcc;
1352 pix->bytesperline = 0;
1353 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
1354 u32 bpl = q_data->w;
Shuah Khan605b8922016-07-14 17:01:56 -03001355
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001356 if (q_data->fmt->colplanes == 1)
1357 bpl = (bpl * q_data->fmt->depth) >> 3;
1358 pix->bytesperline = bpl;
1359 }
1360 pix->sizeimage = q_data->size;
1361
1362 return 0;
1363}
1364
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001365static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
1366 u32 pixelformat, unsigned int fmt_type)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001367{
Jacek Anaszewskib2451682014-04-10 04:32:11 -03001368 unsigned int k, fmt_flag;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001369
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001370 if (ctx->mode == S5P_JPEG_ENCODE)
1371 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
1372 SJPEG_FMT_FLAG_ENC_OUTPUT :
1373 SJPEG_FMT_FLAG_ENC_CAPTURE;
1374 else
1375 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
1376 SJPEG_FMT_FLAG_DEC_OUTPUT :
1377 SJPEG_FMT_FLAG_DEC_CAPTURE;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001378
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001379 for (k = 0; k < ARRAY_SIZE(sjpeg_formats); k++) {
1380 struct s5p_jpeg_fmt *fmt = &sjpeg_formats[k];
Shuah Khan605b8922016-07-14 17:01:56 -03001381
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001382 if (fmt->fourcc == pixelformat &&
1383 fmt->flags & fmt_flag &&
Jacek Anaszewskib2451682014-04-10 04:32:11 -03001384 fmt->flags & ctx->jpeg->variant->fmt_ver_flag) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001385 return fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001386 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001387 }
1388
1389 return NULL;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001390}
1391
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001392static void jpeg_bound_align_image(struct s5p_jpeg_ctx *ctx,
1393 u32 *w, unsigned int wmin, unsigned int wmax,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001394 unsigned int walign,
1395 u32 *h, unsigned int hmin, unsigned int hmax,
1396 unsigned int halign)
1397{
1398 int width, height, w_step, h_step;
1399
1400 width = *w;
1401 height = *h;
1402
1403 w_step = 1 << walign;
1404 h_step = 1 << halign;
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001405
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001406 if (ctx->jpeg->variant->hw3250_compat) {
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001407 /*
1408 * Rightmost and bottommost pixels are cropped by the
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001409 * Exynos3250/compatible JPEG IP for RGB formats, for the
1410 * specific width and height values respectively. This
1411 * assignment will result in v4l_bound_align_image returning
1412 * dimensions reduced by 1 for the aforementioned cases.
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001413 */
1414 if (w_step == 4 && ((width & 3) == 1)) {
1415 wmax = width;
1416 hmax = height;
1417 }
1418 }
1419
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001420 v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
1421
1422 if (*w < width && (*w + w_step) < wmax)
1423 *w += w_step;
1424 if (*h < height && (*h + h_step) < hmax)
1425 *h += h_step;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001426}
1427
1428static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
1429 struct s5p_jpeg_ctx *ctx, int q_type)
1430{
1431 struct v4l2_pix_format *pix = &f->fmt.pix;
1432
1433 if (pix->field == V4L2_FIELD_ANY)
1434 pix->field = V4L2_FIELD_NONE;
1435 else if (pix->field != V4L2_FIELD_NONE)
1436 return -EINVAL;
1437
1438 /* V4L2 specification suggests the driver corrects the format struct
Shuah Khan605b8922016-07-14 17:01:56 -03001439 * if any of the dimensions is unsupported
1440 */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001441 if (q_type == FMT_TYPE_OUTPUT)
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001442 jpeg_bound_align_image(ctx, &pix->width, S5P_JPEG_MIN_WIDTH,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001443 S5P_JPEG_MAX_WIDTH, 0,
1444 &pix->height, S5P_JPEG_MIN_HEIGHT,
1445 S5P_JPEG_MAX_HEIGHT, 0);
1446 else
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001447 jpeg_bound_align_image(ctx, &pix->width, S5P_JPEG_MIN_WIDTH,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001448 S5P_JPEG_MAX_WIDTH, fmt->h_align,
1449 &pix->height, S5P_JPEG_MIN_HEIGHT,
1450 S5P_JPEG_MAX_HEIGHT, fmt->v_align);
1451
1452 if (fmt->fourcc == V4L2_PIX_FMT_JPEG) {
1453 if (pix->sizeimage <= 0)
1454 pix->sizeimage = PAGE_SIZE;
1455 pix->bytesperline = 0;
1456 } else {
1457 u32 bpl = pix->bytesperline;
1458
1459 if (fmt->colplanes > 1 && bpl < pix->width)
1460 bpl = pix->width; /* planar */
1461
1462 if (fmt->colplanes == 1 && /* packed */
Jacek Anaszewskicc690902013-11-25 06:58:10 -03001463 (bpl << 3) / fmt->depth < pix->width)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001464 bpl = (pix->width * fmt->depth) >> 3;
1465
1466 pix->bytesperline = bpl;
1467 pix->sizeimage = (pix->width * pix->height * fmt->depth) >> 3;
1468 }
1469
1470 return 0;
1471}
1472
1473static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
1474 struct v4l2_format *f)
1475{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001476 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001477 struct v4l2_pix_format *pix = &f->fmt.pix;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001478 struct s5p_jpeg_fmt *fmt;
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001479 int ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001480
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001481 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
1482 FMT_TYPE_CAPTURE);
1483 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001484 v4l2_err(&ctx->jpeg->v4l2_dev,
1485 "Fourcc format (0x%08x) invalid.\n",
1486 f->fmt.pix.pixelformat);
1487 return -EINVAL;
1488 }
1489
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001490 if (!ctx->jpeg->variant->hw_ex4_compat || ctx->mode != S5P_JPEG_DECODE)
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001491 goto exit;
1492
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001493 /*
1494 * The exynos4x12 device requires resulting YUV image
1495 * subsampling not to be lower than the input jpeg subsampling.
1496 * If this requirement is not met then downgrade the requested
1497 * capture format to the one with subsampling equal to the input jpeg.
1498 */
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001499 if ((fmt->flags & SJPEG_FMT_NON_RGB) &&
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001500 (fmt->subsampling < ctx->subsampling)) {
1501 ret = s5p_jpeg_adjust_fourcc_to_subsampling(ctx->subsampling,
1502 fmt->fourcc,
1503 &pix->pixelformat,
1504 ctx);
1505 if (ret < 0)
1506 pix->pixelformat = V4L2_PIX_FMT_GREY;
1507
1508 fmt = s5p_jpeg_find_format(ctx, pix->pixelformat,
1509 FMT_TYPE_CAPTURE);
1510 }
1511
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001512 /*
1513 * Decompression of a JPEG file with 4:2:0 subsampling and odd
1514 * width to the YUV 4:2:0 compliant formats produces a raw image
1515 * with broken luma component. Adjust capture format to RGB565
1516 * in such a case.
1517 */
1518 if (ctx->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_420 &&
1519 (ctx->out_q.w & 1) &&
1520 (pix->pixelformat == V4L2_PIX_FMT_NV12 ||
1521 pix->pixelformat == V4L2_PIX_FMT_NV21 ||
1522 pix->pixelformat == V4L2_PIX_FMT_YUV420)) {
1523 pix->pixelformat = V4L2_PIX_FMT_RGB565;
1524 fmt = s5p_jpeg_find_format(ctx, pix->pixelformat,
1525 FMT_TYPE_CAPTURE);
1526 }
1527
1528exit:
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001529 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001530}
1531
1532static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
1533 struct v4l2_format *f)
1534{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001535 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001536 struct s5p_jpeg_fmt *fmt;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001537
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001538 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
1539 FMT_TYPE_OUTPUT);
1540 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001541 v4l2_err(&ctx->jpeg->v4l2_dev,
1542 "Fourcc format (0x%08x) invalid.\n",
1543 f->fmt.pix.pixelformat);
1544 return -EINVAL;
1545 }
1546
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001547 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001548}
1549
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001550static int exynos4_jpeg_get_output_buffer_size(struct s5p_jpeg_ctx *ctx,
1551 struct v4l2_format *f,
1552 int fmt_depth)
1553{
1554 struct v4l2_pix_format *pix = &f->fmt.pix;
1555 u32 pix_fmt = f->fmt.pix.pixelformat;
1556 int w = pix->width, h = pix->height, wh_align;
Andrzej Pietrasiewicz77401dd2015-12-08 12:39:08 -02001557 int padding = 0;
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001558
1559 if (pix_fmt == V4L2_PIX_FMT_RGB32 ||
Andrzej Pietrasiewicz77401dd2015-12-08 12:39:08 -02001560 pix_fmt == V4L2_PIX_FMT_RGB565 ||
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001561 pix_fmt == V4L2_PIX_FMT_NV24 ||
1562 pix_fmt == V4L2_PIX_FMT_NV42 ||
1563 pix_fmt == V4L2_PIX_FMT_NV12 ||
1564 pix_fmt == V4L2_PIX_FMT_NV21 ||
1565 pix_fmt == V4L2_PIX_FMT_YUV420)
1566 wh_align = 4;
1567 else
1568 wh_align = 1;
1569
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001570 jpeg_bound_align_image(ctx, &w, S5P_JPEG_MIN_WIDTH,
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001571 S5P_JPEG_MAX_WIDTH, wh_align,
1572 &h, S5P_JPEG_MIN_HEIGHT,
1573 S5P_JPEG_MAX_HEIGHT, wh_align);
1574
Andrzej Pietrasiewicz77401dd2015-12-08 12:39:08 -02001575 if (ctx->jpeg->variant->version == SJPEG_EXYNOS4)
1576 padding = PAGE_SIZE;
1577
1578 return (w * h * fmt_depth >> 3) + padding;
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001579}
1580
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001581static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx,
1582 struct v4l2_rect *r);
1583
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001584static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
1585{
1586 struct vb2_queue *vq;
1587 struct s5p_jpeg_q_data *q_data = NULL;
1588 struct v4l2_pix_format *pix = &f->fmt.pix;
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001589 struct v4l2_ctrl *ctrl_subs;
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001590 struct v4l2_rect scale_rect;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001591 unsigned int f_type;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001592
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001593 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001594 if (!vq)
1595 return -EINVAL;
1596
1597 q_data = get_q_data(ct, f->type);
1598 BUG_ON(q_data == NULL);
1599
1600 if (vb2_is_busy(vq)) {
1601 v4l2_err(&ct->jpeg->v4l2_dev, "%s queue busy\n", __func__);
1602 return -EBUSY;
1603 }
1604
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001605 f_type = V4L2_TYPE_IS_OUTPUT(f->type) ?
1606 FMT_TYPE_OUTPUT : FMT_TYPE_CAPTURE;
1607
1608 q_data->fmt = s5p_jpeg_find_format(ct, pix->pixelformat, f_type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001609 q_data->w = pix->width;
1610 q_data->h = pix->height;
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001611 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
1612 /*
1613 * During encoding Exynos4x12 SoCs access wider memory area
1614 * than it results from Image_x and Image_y values written to
1615 * the JPEG_IMAGE_SIZE register. In order to avoid sysmmu
1616 * page fault calculate proper buffer size in such a case.
1617 */
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001618 if (ct->jpeg->variant->hw_ex4_compat &&
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001619 f_type == FMT_TYPE_OUTPUT && ct->mode == S5P_JPEG_ENCODE)
1620 q_data->size = exynos4_jpeg_get_output_buffer_size(ct,
1621 f,
1622 q_data->fmt->depth);
1623 else
1624 q_data->size = q_data->w * q_data->h *
1625 q_data->fmt->depth >> 3;
1626 } else {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001627 q_data->size = pix->sizeimage;
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001628 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001629
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001630 if (f_type == FMT_TYPE_OUTPUT) {
1631 ctrl_subs = v4l2_ctrl_find(&ct->ctrl_handler,
1632 V4L2_CID_JPEG_CHROMA_SUBSAMPLING);
1633 if (ctrl_subs)
1634 v4l2_ctrl_s_ctrl(ctrl_subs, q_data->fmt->subsampling);
Jacek Anaszewskidfd96902014-07-11 12:19:46 -03001635 ct->crop_altered = false;
1636 }
1637
1638 /*
1639 * For decoding init crop_rect with capture buffer dimmensions which
1640 * contain aligned dimensions of the input JPEG image and do it only
1641 * if crop rectangle hasn't been altered by the user space e.g. with
1642 * S_SELECTION ioctl. For encoding assign output buffer dimensions.
1643 */
1644 if (!ct->crop_altered &&
1645 ((ct->mode == S5P_JPEG_DECODE && f_type == FMT_TYPE_CAPTURE) ||
1646 (ct->mode == S5P_JPEG_ENCODE && f_type == FMT_TYPE_OUTPUT))) {
1647 ct->crop_rect.width = pix->width;
1648 ct->crop_rect.height = pix->height;
1649 }
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001650
1651 /*
1652 * Prevent downscaling to YUV420 format by more than 2
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001653 * for Exynos3250/compatible SoC as it produces broken raw image
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001654 * in such cases.
1655 */
1656 if (ct->mode == S5P_JPEG_DECODE &&
1657 f_type == FMT_TYPE_CAPTURE &&
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001658 ct->jpeg->variant->hw3250_compat &&
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001659 pix->pixelformat == V4L2_PIX_FMT_YUV420 &&
1660 ct->scale_factor > 2) {
1661 scale_rect.width = ct->out_q.w / 2;
1662 scale_rect.height = ct->out_q.h / 2;
1663 exynos3250_jpeg_try_downscale(ct, &scale_rect);
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001664 }
1665
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001666 return 0;
1667}
1668
1669static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
1670 struct v4l2_format *f)
1671{
1672 int ret;
1673
1674 ret = s5p_jpeg_try_fmt_vid_cap(file, priv, f);
1675 if (ret)
1676 return ret;
1677
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001678 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001679}
1680
1681static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
1682 struct v4l2_format *f)
1683{
1684 int ret;
1685
1686 ret = s5p_jpeg_try_fmt_vid_out(file, priv, f);
1687 if (ret)
1688 return ret;
1689
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001690 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001691}
1692
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001693static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx,
1694 struct v4l2_rect *r)
1695{
1696 int w_ratio, h_ratio, scale_factor, cur_ratio, i;
1697
1698 w_ratio = ctx->out_q.w / r->width;
1699 h_ratio = ctx->out_q.h / r->height;
1700
1701 scale_factor = w_ratio > h_ratio ? w_ratio : h_ratio;
1702 scale_factor = clamp_val(scale_factor, 1, 8);
1703
1704 /* Align scale ratio to the nearest power of 2 */
1705 for (i = 0; i <= 3; ++i) {
1706 cur_ratio = 1 << i;
1707 if (scale_factor <= cur_ratio) {
1708 ctx->scale_factor = cur_ratio;
1709 break;
1710 }
1711 }
1712
1713 r->width = round_down(ctx->out_q.w / ctx->scale_factor, 2);
1714 r->height = round_down(ctx->out_q.h / ctx->scale_factor, 2);
1715
1716 ctx->crop_rect.width = r->width;
1717 ctx->crop_rect.height = r->height;
1718 ctx->crop_rect.left = 0;
1719 ctx->crop_rect.top = 0;
1720
1721 ctx->crop_altered = true;
1722
1723 return 0;
1724}
1725
1726/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */
1727static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
1728{
1729 if (a->left < b->left || a->top < b->top)
1730 return 0;
1731 if (a->left + a->width > b->left + b->width)
1732 return 0;
1733 if (a->top + a->height > b->top + b->height)
1734 return 0;
1735
1736 return 1;
1737}
1738
1739static int exynos3250_jpeg_try_crop(struct s5p_jpeg_ctx *ctx,
1740 struct v4l2_rect *r)
1741{
1742 struct v4l2_rect base_rect;
1743 int w_step, h_step;
1744
1745 switch (ctx->cap_q.fmt->fourcc) {
1746 case V4L2_PIX_FMT_NV12:
1747 case V4L2_PIX_FMT_NV21:
1748 w_step = 1;
1749 h_step = 2;
1750 break;
1751 case V4L2_PIX_FMT_YUV420:
1752 w_step = 2;
1753 h_step = 2;
1754 break;
1755 default:
1756 w_step = 1;
1757 h_step = 1;
1758 break;
1759 }
1760
1761 base_rect.top = 0;
1762 base_rect.left = 0;
1763 base_rect.width = ctx->out_q.w;
1764 base_rect.height = ctx->out_q.h;
1765
1766 r->width = round_down(r->width, w_step);
1767 r->height = round_down(r->height, h_step);
1768 r->left = round_down(r->left, 2);
1769 r->top = round_down(r->top, 2);
1770
1771 if (!enclosed_rectangle(r, &base_rect))
1772 return -EINVAL;
1773
1774 ctx->crop_rect.left = r->left;
1775 ctx->crop_rect.top = r->top;
1776 ctx->crop_rect.width = r->width;
1777 ctx->crop_rect.height = r->height;
1778
1779 ctx->crop_altered = true;
1780
1781 return 0;
1782}
1783
1784/*
1785 * V4L2 controls
1786 */
1787
Sachin Kamat9f3bd322012-05-10 03:38:40 -03001788static int s5p_jpeg_g_selection(struct file *file, void *priv,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001789 struct v4l2_selection *s)
1790{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001791 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001792
1793 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
Jacek Anaszewski38a6ef32014-04-10 04:32:15 -03001794 s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001795 return -EINVAL;
1796
1797 /* For JPEG blob active == default == bounds */
1798 switch (s->target) {
Sylwester Nawrockic1334822012-05-20 11:17:12 -03001799 case V4L2_SEL_TGT_CROP:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001800 case V4L2_SEL_TGT_CROP_BOUNDS:
1801 case V4L2_SEL_TGT_CROP_DEFAULT:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001802 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
1803 s->r.width = ctx->out_q.w;
1804 s->r.height = ctx->out_q.h;
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001805 s->r.left = 0;
1806 s->r.top = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001807 break;
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001808 case V4L2_SEL_TGT_COMPOSE:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001809 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
1810 case V4L2_SEL_TGT_COMPOSE_PADDED:
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001811 s->r.width = ctx->crop_rect.width;
1812 s->r.height = ctx->crop_rect.height;
1813 s->r.left = ctx->crop_rect.left;
1814 s->r.top = ctx->crop_rect.top;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001815 break;
1816 default:
1817 return -EINVAL;
1818 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001819 return 0;
1820}
1821
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001822/*
1823 * V4L2 controls
1824 */
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001825static int s5p_jpeg_s_selection(struct file *file, void *fh,
1826 struct v4l2_selection *s)
1827{
1828 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
1829 struct v4l2_rect *rect = &s->r;
1830 int ret = -EINVAL;
1831
1832 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1833 return -EINVAL;
1834
1835 if (s->target == V4L2_SEL_TGT_COMPOSE) {
1836 if (ctx->mode != S5P_JPEG_DECODE)
1837 return -EINVAL;
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001838 if (ctx->jpeg->variant->hw3250_compat)
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001839 ret = exynos3250_jpeg_try_downscale(ctx, rect);
1840 } else if (s->target == V4L2_SEL_TGT_CROP) {
1841 if (ctx->mode != S5P_JPEG_ENCODE)
1842 return -EINVAL;
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001843 if (ctx->jpeg->variant->hw3250_compat)
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001844 ret = exynos3250_jpeg_try_crop(ctx, rect);
1845 }
1846
1847 return ret;
1848}
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001849
1850static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001851{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001852 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1853 struct s5p_jpeg *jpeg = ctx->jpeg;
1854 unsigned long flags;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001855
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001856 switch (ctrl->id) {
1857 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1858 spin_lock_irqsave(&jpeg->slock, flags);
Jacek Anaszewski303b0a92013-12-18 11:14:00 -03001859 ctrl->val = s5p_jpeg_to_user_subsampling(ctx);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001860 spin_unlock_irqrestore(&jpeg->slock, flags);
1861 break;
1862 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001863
1864 return 0;
1865}
1866
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001867static int s5p_jpeg_adjust_subs_ctrl(struct s5p_jpeg_ctx *ctx, int *ctrl_val)
1868{
1869 switch (ctx->jpeg->variant->version) {
1870 case SJPEG_S5P:
1871 return 0;
1872 case SJPEG_EXYNOS3250:
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001873 case SJPEG_EXYNOS5420:
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001874 /*
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001875 * The exynos3250/compatible device can produce JPEG image only
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001876 * of 4:4:4 subsampling when given RGB32 source image.
1877 */
1878 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB32)
1879 *ctrl_val = 0;
1880 break;
1881 case SJPEG_EXYNOS4:
1882 /*
1883 * The exynos4x12 device requires input raw image fourcc
1884 * to be V4L2_PIX_FMT_GREY if gray jpeg format
1885 * is to be set.
1886 */
1887 if (ctx->out_q.fmt->fourcc != V4L2_PIX_FMT_GREY &&
1888 *ctrl_val == V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY)
1889 return -EINVAL;
1890 break;
1891 }
1892
1893 /*
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001894 * The exynos4x12 and exynos3250/compatible devices require resulting
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001895 * jpeg subsampling not to be lower than the input raw image
1896 * subsampling.
1897 */
1898 if (ctx->out_q.fmt->subsampling > *ctrl_val)
1899 *ctrl_val = ctx->out_q.fmt->subsampling;
1900
1901 return 0;
1902}
1903
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001904static int s5p_jpeg_try_ctrl(struct v4l2_ctrl *ctrl)
1905{
1906 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1907 unsigned long flags;
1908 int ret = 0;
1909
1910 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1911
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001912 if (ctrl->id == V4L2_CID_JPEG_CHROMA_SUBSAMPLING)
1913 ret = s5p_jpeg_adjust_subs_ctrl(ctx, &ctrl->val);
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001914
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001915 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1916 return ret;
1917}
1918
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001919static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001920{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001921 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1922 unsigned long flags;
1923
1924 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1925
1926 switch (ctrl->id) {
1927 case V4L2_CID_JPEG_COMPRESSION_QUALITY:
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001928 ctx->compr_quality = ctrl->val;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001929 break;
1930 case V4L2_CID_JPEG_RESTART_INTERVAL:
1931 ctx->restart_interval = ctrl->val;
1932 break;
1933 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1934 ctx->subsampling = ctrl->val;
1935 break;
1936 }
1937
1938 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1939 return 0;
1940}
1941
1942static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
1943 .g_volatile_ctrl = s5p_jpeg_g_volatile_ctrl,
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001944 .try_ctrl = s5p_jpeg_try_ctrl,
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001945 .s_ctrl = s5p_jpeg_s_ctrl,
1946};
1947
1948static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
1949{
1950 unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */
1951 struct v4l2_ctrl *ctrl;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001952 int ret;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001953
1954 v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
1955
1956 if (ctx->mode == S5P_JPEG_ENCODE) {
1957 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1958 V4L2_CID_JPEG_COMPRESSION_QUALITY,
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001959 0, 3, 1, S5P_JPEG_COMPR_QUAL_WORST);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001960
1961 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1962 V4L2_CID_JPEG_RESTART_INTERVAL,
1963 0, 3, 0xffff, 0);
Jacek Anaszewskifdf9e2b2013-11-21 13:33:41 -03001964 if (ctx->jpeg->variant->version == SJPEG_S5P)
1965 mask = ~0x06; /* 422, 420 */
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001966 }
1967
1968 ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1969 V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
1970 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask,
1971 V4L2_JPEG_CHROMA_SUBSAMPLING_422);
1972
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001973 if (ctx->ctrl_handler.error) {
1974 ret = ctx->ctrl_handler.error;
1975 goto error_free;
1976 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001977
1978 if (ctx->mode == S5P_JPEG_DECODE)
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001979 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
1980 V4L2_CTRL_FLAG_READ_ONLY;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001981
1982 ret = v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
1983 if (ret < 0)
1984 goto error_free;
1985
1986 return ret;
1987
1988error_free:
1989 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
1990 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001991}
1992
1993static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
1994 .vidioc_querycap = s5p_jpeg_querycap,
1995
1996 .vidioc_enum_fmt_vid_cap = s5p_jpeg_enum_fmt_vid_cap,
1997 .vidioc_enum_fmt_vid_out = s5p_jpeg_enum_fmt_vid_out,
1998
1999 .vidioc_g_fmt_vid_cap = s5p_jpeg_g_fmt,
2000 .vidioc_g_fmt_vid_out = s5p_jpeg_g_fmt,
2001
2002 .vidioc_try_fmt_vid_cap = s5p_jpeg_try_fmt_vid_cap,
2003 .vidioc_try_fmt_vid_out = s5p_jpeg_try_fmt_vid_out,
2004
2005 .vidioc_s_fmt_vid_cap = s5p_jpeg_s_fmt_vid_cap,
2006 .vidioc_s_fmt_vid_out = s5p_jpeg_s_fmt_vid_out,
2007
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002008 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
2009 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
2010 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
2011 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002012
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002013 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
2014 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002015
2016 .vidioc_g_selection = s5p_jpeg_g_selection,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002017 .vidioc_s_selection = s5p_jpeg_s_selection,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002018};
2019
2020/*
2021 * ============================================================================
2022 * mem2mem callbacks
2023 * ============================================================================
2024 */
2025
2026static void s5p_jpeg_device_run(void *priv)
2027{
2028 struct s5p_jpeg_ctx *ctx = priv;
2029 struct s5p_jpeg *jpeg = ctx->jpeg;
2030 struct vb2_buffer *src_buf, *dst_buf;
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002031 unsigned long src_addr, dst_addr, flags;
2032
2033 spin_lock_irqsave(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002034
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002035 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2036 dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002037 src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
2038 dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
2039
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002040 s5p_jpeg_reset(jpeg->regs);
2041 s5p_jpeg_poweron(jpeg->regs);
2042 s5p_jpeg_proc_mode(jpeg->regs, ctx->mode);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002043 if (ctx->mode == S5P_JPEG_ENCODE) {
2044 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002045 s5p_jpeg_input_raw_mode(jpeg->regs,
2046 S5P_JPEG_RAW_IN_565);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002047 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002048 s5p_jpeg_input_raw_mode(jpeg->regs,
2049 S5P_JPEG_RAW_IN_422);
2050 s5p_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
2051 s5p_jpeg_dri(jpeg->regs, ctx->restart_interval);
2052 s5p_jpeg_x(jpeg->regs, ctx->out_q.w);
2053 s5p_jpeg_y(jpeg->regs, ctx->out_q.h);
2054 s5p_jpeg_imgadr(jpeg->regs, src_addr);
2055 s5p_jpeg_jpgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002056
2057 /* ultimately comes from sizeimage from userspace */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002058 s5p_jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002059
2060 /* JPEG RGB to YCbCr conversion matrix */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002061 s5p_jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11);
2062 s5p_jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12);
2063 s5p_jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13);
2064 s5p_jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21);
2065 s5p_jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22);
2066 s5p_jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23);
2067 s5p_jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31);
2068 s5p_jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32);
2069 s5p_jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002070
2071 /*
2072 * JPEG IP allows storing 4 quantization tables
2073 * We fill table 0 for luma and table 1 for chroma
2074 */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03002075 s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
2076 s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002077 /* use table 0 for Y */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002078 s5p_jpeg_qtbl(jpeg->regs, 1, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002079 /* use table 1 for Cb and Cr*/
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002080 s5p_jpeg_qtbl(jpeg->regs, 2, 1);
2081 s5p_jpeg_qtbl(jpeg->regs, 3, 1);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002082
2083 /* Y, Cb, Cr use Huffman table 0 */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002084 s5p_jpeg_htbl_ac(jpeg->regs, 1);
2085 s5p_jpeg_htbl_dc(jpeg->regs, 1);
2086 s5p_jpeg_htbl_ac(jpeg->regs, 2);
2087 s5p_jpeg_htbl_dc(jpeg->regs, 2);
2088 s5p_jpeg_htbl_ac(jpeg->regs, 3);
2089 s5p_jpeg_htbl_dc(jpeg->regs, 3);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03002090 } else { /* S5P_JPEG_DECODE */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002091 s5p_jpeg_rst_int_enable(jpeg->regs, true);
2092 s5p_jpeg_data_num_int_enable(jpeg->regs, true);
2093 s5p_jpeg_final_mcu_num_int_enable(jpeg->regs, true);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03002094 if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002095 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03002096 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002097 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420);
2098 s5p_jpeg_jpgadr(jpeg->regs, src_addr);
2099 s5p_jpeg_imgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002100 }
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002101
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002102 s5p_jpeg_start(jpeg->regs);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002103
2104 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002105}
2106
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002107static void exynos4_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
2108{
2109 struct s5p_jpeg *jpeg = ctx->jpeg;
2110 struct s5p_jpeg_fmt *fmt;
2111 struct vb2_buffer *vb;
Jacek Anaszewski12b05562015-03-05 10:56:25 -03002112 struct s5p_jpeg_addr jpeg_addr = {};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002113 u32 pix_size, padding_bytes = 0;
2114
Tony K Nadackalcb0c3f52014-12-17 04:21:21 -03002115 jpeg_addr.cb = 0;
2116 jpeg_addr.cr = 0;
2117
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002118 pix_size = ctx->cap_q.w * ctx->cap_q.h;
2119
2120 if (ctx->mode == S5P_JPEG_ENCODE) {
2121 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2122 fmt = ctx->out_q.fmt;
2123 if (ctx->out_q.w % 2 && fmt->h_align > 0)
2124 padding_bytes = ctx->out_q.h;
2125 } else {
2126 fmt = ctx->cap_q.fmt;
2127 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
2128 }
2129
2130 jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
2131
2132 if (fmt->colplanes == 2) {
2133 jpeg_addr.cb = jpeg_addr.y + pix_size - padding_bytes;
2134 } else if (fmt->colplanes == 3) {
2135 jpeg_addr.cb = jpeg_addr.y + pix_size;
2136 if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
2137 jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
2138 else
2139 jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
2140 }
2141
2142 exynos4_jpeg_set_frame_buf_address(jpeg->regs, &jpeg_addr);
2143}
2144
2145static void exynos4_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
2146{
2147 struct s5p_jpeg *jpeg = ctx->jpeg;
2148 struct vb2_buffer *vb;
2149 unsigned int jpeg_addr = 0;
2150
2151 if (ctx->mode == S5P_JPEG_ENCODE)
2152 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
2153 else
2154 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2155
2156 jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002157 if (jpeg->variant->version == SJPEG_EXYNOS5433 &&
2158 ctx->mode == S5P_JPEG_DECODE)
2159 jpeg_addr += ctx->out_q.sos;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002160 exynos4_jpeg_set_stream_buf_address(jpeg->regs, jpeg_addr);
2161}
2162
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002163static inline void exynos4_jpeg_set_img_fmt(void __iomem *base,
2164 unsigned int img_fmt)
2165{
2166 __exynos4_jpeg_set_img_fmt(base, img_fmt, SJPEG_EXYNOS4);
2167}
2168
2169static inline void exynos5433_jpeg_set_img_fmt(void __iomem *base,
2170 unsigned int img_fmt)
2171{
2172 __exynos4_jpeg_set_img_fmt(base, img_fmt, SJPEG_EXYNOS5433);
2173}
2174
2175static inline void exynos4_jpeg_set_enc_out_fmt(void __iomem *base,
2176 unsigned int out_fmt)
2177{
2178 __exynos4_jpeg_set_enc_out_fmt(base, out_fmt, SJPEG_EXYNOS4);
2179}
2180
2181static inline void exynos5433_jpeg_set_enc_out_fmt(void __iomem *base,
2182 unsigned int out_fmt)
2183{
2184 __exynos4_jpeg_set_enc_out_fmt(base, out_fmt, SJPEG_EXYNOS5433);
2185}
2186
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002187static void exynos4_jpeg_device_run(void *priv)
2188{
2189 struct s5p_jpeg_ctx *ctx = priv;
2190 struct s5p_jpeg *jpeg = ctx->jpeg;
2191 unsigned int bitstream_size;
2192 unsigned long flags;
2193
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002194 spin_lock_irqsave(&jpeg->slock, flags);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002195
2196 if (ctx->mode == S5P_JPEG_ENCODE) {
2197 exynos4_jpeg_sw_reset(jpeg->regs);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002198 exynos4_jpeg_set_interrupt(jpeg->regs, jpeg->variant->version);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002199 exynos4_jpeg_set_huf_table_enable(jpeg->regs, 1);
2200
2201 exynos4_jpeg_set_huff_tbl(jpeg->regs);
2202
2203 /*
2204 * JPEG IP allows storing 4 quantization tables
2205 * We fill table 0 for luma and table 1 for chroma
2206 */
2207 exynos4_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
2208 exynos4_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
2209
2210 exynos4_jpeg_set_encode_tbl_select(jpeg->regs,
2211 ctx->compr_quality);
2212 exynos4_jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w,
2213 ctx->cap_q.h);
2214
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002215 if (ctx->jpeg->variant->version == SJPEG_EXYNOS4) {
2216 exynos4_jpeg_set_enc_out_fmt(jpeg->regs,
2217 ctx->subsampling);
2218 exynos4_jpeg_set_img_fmt(jpeg->regs,
2219 ctx->out_q.fmt->fourcc);
2220 } else {
2221 exynos5433_jpeg_set_enc_out_fmt(jpeg->regs,
2222 ctx->subsampling);
2223 exynos5433_jpeg_set_img_fmt(jpeg->regs,
2224 ctx->out_q.fmt->fourcc);
2225 }
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002226 exynos4_jpeg_set_img_addr(ctx);
2227 exynos4_jpeg_set_jpeg_addr(ctx);
2228 exynos4_jpeg_set_encode_hoff_cnt(jpeg->regs,
2229 ctx->out_q.fmt->fourcc);
2230 } else {
2231 exynos4_jpeg_sw_reset(jpeg->regs);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002232 exynos4_jpeg_set_interrupt(jpeg->regs,
2233 jpeg->variant->version);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002234 exynos4_jpeg_set_img_addr(ctx);
2235 exynos4_jpeg_set_jpeg_addr(ctx);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002236
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002237 if (jpeg->variant->version == SJPEG_EXYNOS5433) {
2238 exynos4_jpeg_parse_huff_tbl(ctx);
2239 exynos4_jpeg_parse_decode_h_tbl(ctx);
2240
2241 exynos4_jpeg_parse_q_tbl(ctx);
2242 exynos4_jpeg_parse_decode_q_tbl(ctx);
2243
2244 exynos4_jpeg_set_huf_table_enable(jpeg->regs, 1);
2245
2246 exynos4_jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w,
2247 ctx->cap_q.h);
2248 exynos5433_jpeg_set_enc_out_fmt(jpeg->regs,
2249 ctx->subsampling);
2250 exynos5433_jpeg_set_img_fmt(jpeg->regs,
2251 ctx->cap_q.fmt->fourcc);
2252 bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 16);
2253 } else {
2254 exynos4_jpeg_set_img_fmt(jpeg->regs,
2255 ctx->cap_q.fmt->fourcc);
2256 bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 32);
2257 }
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002258
2259 exynos4_jpeg_set_dec_bitstream_size(jpeg->regs, bitstream_size);
2260 }
2261
2262 exynos4_jpeg_set_enc_dec_mode(jpeg->regs, ctx->mode);
2263
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002264 spin_unlock_irqrestore(&jpeg->slock, flags);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002265}
2266
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002267static void exynos3250_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
2268{
2269 struct s5p_jpeg *jpeg = ctx->jpeg;
2270 struct s5p_jpeg_fmt *fmt;
2271 struct vb2_buffer *vb;
Jacek Anaszewski12b05562015-03-05 10:56:25 -03002272 struct s5p_jpeg_addr jpeg_addr = {};
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002273 u32 pix_size;
2274
2275 pix_size = ctx->cap_q.w * ctx->cap_q.h;
2276
2277 if (ctx->mode == S5P_JPEG_ENCODE) {
2278 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2279 fmt = ctx->out_q.fmt;
2280 } else {
2281 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
2282 fmt = ctx->cap_q.fmt;
2283 }
2284
2285 jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
2286
2287 if (fmt->colplanes == 2) {
2288 jpeg_addr.cb = jpeg_addr.y + pix_size;
2289 } else if (fmt->colplanes == 3) {
2290 jpeg_addr.cb = jpeg_addr.y + pix_size;
2291 if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
2292 jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
2293 else
2294 jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
2295 }
2296
2297 exynos3250_jpeg_imgadr(jpeg->regs, &jpeg_addr);
2298}
2299
2300static void exynos3250_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
2301{
2302 struct s5p_jpeg *jpeg = ctx->jpeg;
2303 struct vb2_buffer *vb;
2304 unsigned int jpeg_addr = 0;
2305
2306 if (ctx->mode == S5P_JPEG_ENCODE)
2307 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
2308 else
2309 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2310
2311 jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
2312 exynos3250_jpeg_jpgadr(jpeg->regs, jpeg_addr);
2313}
2314
2315static void exynos3250_jpeg_device_run(void *priv)
2316{
2317 struct s5p_jpeg_ctx *ctx = priv;
2318 struct s5p_jpeg *jpeg = ctx->jpeg;
2319 unsigned long flags;
2320
2321 spin_lock_irqsave(&ctx->jpeg->slock, flags);
2322
2323 exynos3250_jpeg_reset(jpeg->regs);
2324 exynos3250_jpeg_set_dma_num(jpeg->regs);
2325 exynos3250_jpeg_poweron(jpeg->regs);
2326 exynos3250_jpeg_clk_set(jpeg->regs);
2327 exynos3250_jpeg_proc_mode(jpeg->regs, ctx->mode);
2328
2329 if (ctx->mode == S5P_JPEG_ENCODE) {
2330 exynos3250_jpeg_input_raw_fmt(jpeg->regs,
2331 ctx->out_q.fmt->fourcc);
2332 exynos3250_jpeg_dri(jpeg->regs, ctx->restart_interval);
2333
2334 /*
2335 * JPEG IP allows storing 4 quantization tables
2336 * We fill table 0 for luma and table 1 for chroma
2337 */
2338 s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
2339 s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
2340 /* use table 0 for Y */
2341 exynos3250_jpeg_qtbl(jpeg->regs, 1, 0);
2342 /* use table 1 for Cb and Cr*/
2343 exynos3250_jpeg_qtbl(jpeg->regs, 2, 1);
2344 exynos3250_jpeg_qtbl(jpeg->regs, 3, 1);
2345
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03002346 /*
2347 * Some SoCs require setting Huffman tables before each run
2348 */
2349 if (jpeg->variant->htbl_reinit) {
2350 s5p_jpeg_set_hdctbl(jpeg->regs);
2351 s5p_jpeg_set_hdctblg(jpeg->regs);
2352 s5p_jpeg_set_hactbl(jpeg->regs);
2353 s5p_jpeg_set_hactblg(jpeg->regs);
2354 }
2355
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002356 /* Y, Cb, Cr use Huffman table 0 */
2357 exynos3250_jpeg_htbl_ac(jpeg->regs, 1);
2358 exynos3250_jpeg_htbl_dc(jpeg->regs, 1);
2359 exynos3250_jpeg_htbl_ac(jpeg->regs, 2);
2360 exynos3250_jpeg_htbl_dc(jpeg->regs, 2);
2361 exynos3250_jpeg_htbl_ac(jpeg->regs, 3);
2362 exynos3250_jpeg_htbl_dc(jpeg->regs, 3);
2363
2364 exynos3250_jpeg_set_x(jpeg->regs, ctx->crop_rect.width);
2365 exynos3250_jpeg_set_y(jpeg->regs, ctx->crop_rect.height);
2366 exynos3250_jpeg_stride(jpeg->regs, ctx->out_q.fmt->fourcc,
2367 ctx->out_q.w);
2368 exynos3250_jpeg_offset(jpeg->regs, ctx->crop_rect.left,
2369 ctx->crop_rect.top);
2370 exynos3250_jpeg_set_img_addr(ctx);
2371 exynos3250_jpeg_set_jpeg_addr(ctx);
2372 exynos3250_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
2373
2374 /* ultimately comes from sizeimage from userspace */
2375 exynos3250_jpeg_enc_stream_bound(jpeg->regs, ctx->cap_q.size);
2376
2377 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565 ||
2378 ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565X ||
2379 ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB32)
2380 exynos3250_jpeg_set_y16(jpeg->regs, true);
2381 } else {
2382 exynos3250_jpeg_set_img_addr(ctx);
2383 exynos3250_jpeg_set_jpeg_addr(ctx);
2384 exynos3250_jpeg_stride(jpeg->regs, ctx->cap_q.fmt->fourcc,
2385 ctx->cap_q.w);
2386 exynos3250_jpeg_offset(jpeg->regs, 0, 0);
2387 exynos3250_jpeg_dec_scaling_ratio(jpeg->regs,
2388 ctx->scale_factor);
2389 exynos3250_jpeg_dec_stream_size(jpeg->regs, ctx->out_q.size);
2390 exynos3250_jpeg_output_raw_fmt(jpeg->regs,
2391 ctx->cap_q.fmt->fourcc);
2392 }
2393
2394 exynos3250_jpeg_interrupts_enable(jpeg->regs);
2395
2396 /* JPEG RGB to YCbCr conversion matrix */
2397 exynos3250_jpeg_coef(jpeg->regs, ctx->mode);
2398
2399 exynos3250_jpeg_set_timer(jpeg->regs, EXYNOS3250_IRQ_TIMEOUT);
2400 jpeg->irq_status = 0;
2401 exynos3250_jpeg_start(jpeg->regs);
2402
2403 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
2404}
2405
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002406static int s5p_jpeg_job_ready(void *priv)
2407{
2408 struct s5p_jpeg_ctx *ctx = priv;
2409
2410 if (ctx->mode == S5P_JPEG_DECODE)
2411 return ctx->hdr_parsed;
2412 return 1;
2413}
2414
2415static void s5p_jpeg_job_abort(void *priv)
2416{
2417}
2418
2419static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = {
2420 .device_run = s5p_jpeg_device_run,
2421 .job_ready = s5p_jpeg_job_ready,
2422 .job_abort = s5p_jpeg_job_abort,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002423};
2424
2425static struct v4l2_m2m_ops exynos3250_jpeg_m2m_ops = {
2426 .device_run = exynos3250_jpeg_device_run,
2427 .job_ready = s5p_jpeg_job_ready,
2428 .job_abort = s5p_jpeg_job_abort,
2429};
2430
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03002431static struct v4l2_m2m_ops exynos4_jpeg_m2m_ops = {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002432 .device_run = exynos4_jpeg_device_run,
2433 .job_ready = s5p_jpeg_job_ready,
2434 .job_abort = s5p_jpeg_job_abort,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002435};
2436
2437/*
2438 * ============================================================================
2439 * Queue operations
2440 * ============================================================================
2441 */
2442
Marek Szyprowski719c1742012-01-13 05:12:38 -03002443static int s5p_jpeg_queue_setup(struct vb2_queue *vq,
Marek Szyprowski719c1742012-01-13 05:12:38 -03002444 unsigned int *nbuffers, unsigned int *nplanes,
Hans Verkuil36c0f8b2016-04-15 09:15:05 -03002445 unsigned int sizes[], struct device *alloc_devs[])
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002446{
2447 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
2448 struct s5p_jpeg_q_data *q_data = NULL;
2449 unsigned int size, count = *nbuffers;
2450
2451 q_data = get_q_data(ctx, vq->type);
2452 BUG_ON(q_data == NULL);
2453
2454 size = q_data->size;
2455
2456 /*
2457 * header is parsed during decoding and parsed information stored
2458 * in the context so we do not allow another buffer to overwrite it
2459 */
2460 if (ctx->mode == S5P_JPEG_DECODE)
2461 count = 1;
2462
2463 *nbuffers = count;
2464 *nplanes = 1;
2465 sizes[0] = size;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002466
2467 return 0;
2468}
2469
2470static int s5p_jpeg_buf_prepare(struct vb2_buffer *vb)
2471{
2472 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
2473 struct s5p_jpeg_q_data *q_data = NULL;
2474
2475 q_data = get_q_data(ctx, vb->vb2_queue->type);
2476 BUG_ON(q_data == NULL);
2477
2478 if (vb2_plane_size(vb, 0) < q_data->size) {
2479 pr_err("%s data will not fit into plane (%lu < %lu)\n",
2480 __func__, vb2_plane_size(vb, 0),
2481 (long)q_data->size);
2482 return -EINVAL;
2483 }
2484
2485 vb2_set_plane_payload(vb, 0, q_data->size);
2486
2487 return 0;
2488}
2489
2490static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
2491{
Junghak Sung2d700712015-09-22 10:30:30 -03002492 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002493 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
2494
2495 if (ctx->mode == S5P_JPEG_DECODE &&
2496 vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
2497 struct s5p_jpeg_q_data tmp, *q_data;
Shuah Khan605b8922016-07-14 17:01:56 -03002498
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002499 ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp,
2500 (unsigned long)vb2_plane_vaddr(vb, 0),
2501 min((unsigned long)ctx->out_q.size,
Jacek Anaszewskif8433962013-11-21 13:33:09 -03002502 vb2_get_plane_payload(vb, 0)), ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002503 if (!ctx->hdr_parsed) {
2504 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
2505 return;
2506 }
2507
2508 q_data = &ctx->out_q;
2509 q_data->w = tmp.w;
2510 q_data->h = tmp.h;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002511 q_data->sos = tmp.sos;
2512 memcpy(q_data->dht.marker, tmp.dht.marker,
2513 sizeof(tmp.dht.marker));
2514 memcpy(q_data->dht.len, tmp.dht.len, sizeof(tmp.dht.len));
2515 q_data->dht.n = tmp.dht.n;
2516 memcpy(q_data->dqt.marker, tmp.dqt.marker,
2517 sizeof(tmp.dqt.marker));
2518 memcpy(q_data->dqt.len, tmp.dqt.len, sizeof(tmp.dqt.len));
2519 q_data->dqt.n = tmp.dqt.n;
2520 q_data->sof = tmp.sof;
2521 q_data->sof_len = tmp.sof_len;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002522
2523 q_data = &ctx->cap_q;
2524 q_data->w = tmp.w;
2525 q_data->h = tmp.h;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002526 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002527
Junghak Sung2d700712015-09-22 10:30:30 -03002528 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002529}
2530
2531static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
2532{
2533 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
2534 int ret;
2535
2536 ret = pm_runtime_get_sync(ctx->jpeg->dev);
2537
2538 return ret > 0 ? 0 : ret;
2539}
2540
Hans Verkuile37559b2014-04-17 02:47:21 -03002541static void s5p_jpeg_stop_streaming(struct vb2_queue *q)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002542{
2543 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
2544
2545 pm_runtime_put(ctx->jpeg->dev);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002546}
2547
2548static struct vb2_ops s5p_jpeg_qops = {
2549 .queue_setup = s5p_jpeg_queue_setup,
2550 .buf_prepare = s5p_jpeg_buf_prepare,
2551 .buf_queue = s5p_jpeg_buf_queue,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002552 .wait_prepare = vb2_ops_wait_prepare,
2553 .wait_finish = vb2_ops_wait_finish,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002554 .start_streaming = s5p_jpeg_start_streaming,
2555 .stop_streaming = s5p_jpeg_stop_streaming,
2556};
2557
2558static int queue_init(void *priv, struct vb2_queue *src_vq,
2559 struct vb2_queue *dst_vq)
2560{
2561 struct s5p_jpeg_ctx *ctx = priv;
2562 int ret;
2563
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002564 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
2565 src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
2566 src_vq->drv_priv = ctx;
2567 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
2568 src_vq->ops = &s5p_jpeg_qops;
2569 src_vq->mem_ops = &vb2_dma_contig_memops;
Sakari Ailusade48682014-02-25 19:12:19 -03002570 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002571 src_vq->lock = &ctx->jpeg->lock;
Hans Verkuilc781e4a2016-02-15 14:25:09 -02002572 src_vq->dev = ctx->jpeg->dev;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002573
2574 ret = vb2_queue_init(src_vq);
2575 if (ret)
2576 return ret;
2577
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002578 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2579 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
2580 dst_vq->drv_priv = ctx;
2581 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
2582 dst_vq->ops = &s5p_jpeg_qops;
2583 dst_vq->mem_ops = &vb2_dma_contig_memops;
Sakari Ailusade48682014-02-25 19:12:19 -03002584 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002585 dst_vq->lock = &ctx->jpeg->lock;
Hans Verkuilc781e4a2016-02-15 14:25:09 -02002586 dst_vq->dev = ctx->jpeg->dev;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002587
2588 return vb2_queue_init(dst_vq);
2589}
2590
2591/*
2592 * ============================================================================
2593 * ISR
2594 * ============================================================================
2595 */
2596
2597static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
2598{
2599 struct s5p_jpeg *jpeg = dev_id;
2600 struct s5p_jpeg_ctx *curr_ctx;
Junghak Sung2d700712015-09-22 10:30:30 -03002601 struct vb2_v4l2_buffer *src_buf, *dst_buf;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002602 unsigned long payload_size = 0;
2603 enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
2604 bool enc_jpeg_too_large = false;
2605 bool timer_elapsed = false;
2606 bool op_completed = false;
2607
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002608 spin_lock(&jpeg->slock);
2609
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002610 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2611
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002612 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2613 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002614
2615 if (curr_ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002616 enc_jpeg_too_large = s5p_jpeg_enc_stream_stat(jpeg->regs);
2617 timer_elapsed = s5p_jpeg_timer_stat(jpeg->regs);
2618 op_completed = s5p_jpeg_result_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002619 if (curr_ctx->mode == S5P_JPEG_DECODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002620 op_completed = op_completed &&
2621 s5p_jpeg_stream_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002622
2623 if (enc_jpeg_too_large) {
2624 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002625 s5p_jpeg_clear_enc_stream_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002626 } else if (timer_elapsed) {
2627 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002628 s5p_jpeg_clear_timer_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002629 } else if (!op_completed) {
2630 state = VB2_BUF_STATE_ERROR;
2631 } else {
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002632 payload_size = s5p_jpeg_compressed_size(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002633 }
2634
Junghak Sung2d700712015-09-22 10:30:30 -03002635 dst_buf->timecode = src_buf->timecode;
Junghak Sungd6dd6452015-11-03 08:16:37 -02002636 dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
Junghak Sung2d700712015-09-22 10:30:30 -03002637 dst_buf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
2638 dst_buf->flags |=
2639 src_buf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
Kamil Debskiaca326a2013-04-24 10:08:02 -03002640
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002641 v4l2_m2m_buf_done(src_buf, state);
2642 if (curr_ctx->mode == S5P_JPEG_ENCODE)
Junghak Sung2d700712015-09-22 10:30:30 -03002643 vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload_size);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002644 v4l2_m2m_buf_done(dst_buf, state);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002645 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002646
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002647 curr_ctx->subsampling = s5p_jpeg_get_subsampling_mode(jpeg->regs);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002648 spin_unlock(&jpeg->slock);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03002649
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002650 s5p_jpeg_clear_int(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002651
2652 return IRQ_HANDLED;
2653}
2654
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002655static irqreturn_t exynos4_jpeg_irq(int irq, void *priv)
2656{
2657 unsigned int int_status;
Junghak Sung2d700712015-09-22 10:30:30 -03002658 struct vb2_v4l2_buffer *src_vb, *dst_vb;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002659 struct s5p_jpeg *jpeg = priv;
2660 struct s5p_jpeg_ctx *curr_ctx;
2661 unsigned long payload_size = 0;
2662
2663 spin_lock(&jpeg->slock);
2664
2665 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2666
2667 src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2668 dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
2669
2670 int_status = exynos4_jpeg_get_int_status(jpeg->regs);
2671
2672 if (int_status) {
2673 switch (int_status & 0x1f) {
2674 case 0x1:
2675 jpeg->irq_ret = ERR_PROT;
2676 break;
2677 case 0x2:
2678 jpeg->irq_ret = OK_ENC_OR_DEC;
2679 break;
2680 case 0x4:
2681 jpeg->irq_ret = ERR_DEC_INVALID_FORMAT;
2682 break;
2683 case 0x8:
2684 jpeg->irq_ret = ERR_MULTI_SCAN;
2685 break;
2686 case 0x10:
2687 jpeg->irq_ret = ERR_FRAME;
2688 break;
2689 default:
2690 jpeg->irq_ret = ERR_UNKNOWN;
2691 break;
2692 }
2693 } else {
2694 jpeg->irq_ret = ERR_UNKNOWN;
2695 }
2696
2697 if (jpeg->irq_ret == OK_ENC_OR_DEC) {
2698 if (curr_ctx->mode == S5P_JPEG_ENCODE) {
2699 payload_size = exynos4_jpeg_get_stream_size(jpeg->regs);
Junghak Sung2d700712015-09-22 10:30:30 -03002700 vb2_set_plane_payload(&dst_vb->vb2_buf,
2701 0, payload_size);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002702 }
2703 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
2704 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
2705 } else {
2706 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
2707 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
2708 }
2709
2710 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002711 if (jpeg->variant->version == SJPEG_EXYNOS4)
2712 curr_ctx->subsampling = exynos4_jpeg_get_frame_fmt(jpeg->regs);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002713
2714 spin_unlock(&jpeg->slock);
2715 return IRQ_HANDLED;
2716}
2717
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002718static irqreturn_t exynos3250_jpeg_irq(int irq, void *dev_id)
2719{
2720 struct s5p_jpeg *jpeg = dev_id;
2721 struct s5p_jpeg_ctx *curr_ctx;
Junghak Sung2d700712015-09-22 10:30:30 -03002722 struct vb2_v4l2_buffer *src_buf, *dst_buf;
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002723 unsigned long payload_size = 0;
2724 enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
2725 bool interrupt_timeout = false;
2726 u32 irq_status;
2727
2728 spin_lock(&jpeg->slock);
2729
2730 irq_status = exynos3250_jpeg_get_timer_status(jpeg->regs);
2731 if (irq_status & EXYNOS3250_TIMER_INT_STAT) {
2732 exynos3250_jpeg_clear_timer_status(jpeg->regs);
2733 interrupt_timeout = true;
2734 dev_err(jpeg->dev, "Interrupt timeout occurred.\n");
2735 }
2736
2737 irq_status = exynos3250_jpeg_get_int_status(jpeg->regs);
2738 exynos3250_jpeg_clear_int_status(jpeg->regs, irq_status);
2739
2740 jpeg->irq_status |= irq_status;
2741
2742 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2743
2744 if (!curr_ctx)
2745 goto exit_unlock;
2746
2747 if ((irq_status & EXYNOS3250_HEADER_STAT) &&
2748 (curr_ctx->mode == S5P_JPEG_DECODE)) {
2749 exynos3250_jpeg_rstart(jpeg->regs);
2750 goto exit_unlock;
2751 }
2752
2753 if (jpeg->irq_status & (EXYNOS3250_JPEG_DONE |
2754 EXYNOS3250_WDMA_DONE |
2755 EXYNOS3250_RDMA_DONE |
2756 EXYNOS3250_RESULT_STAT))
2757 payload_size = exynos3250_jpeg_compressed_size(jpeg->regs);
2758 else if (interrupt_timeout)
2759 state = VB2_BUF_STATE_ERROR;
2760 else
2761 goto exit_unlock;
2762
2763 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2764 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
2765
Junghak Sung2d700712015-09-22 10:30:30 -03002766 dst_buf->timecode = src_buf->timecode;
Junghak Sungd6dd6452015-11-03 08:16:37 -02002767 dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002768
2769 v4l2_m2m_buf_done(src_buf, state);
2770 if (curr_ctx->mode == S5P_JPEG_ENCODE)
Junghak Sung2d700712015-09-22 10:30:30 -03002771 vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload_size);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002772 v4l2_m2m_buf_done(dst_buf, state);
2773 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
2774
2775 curr_ctx->subsampling =
2776 exynos3250_jpeg_get_subsampling_mode(jpeg->regs);
2777exit_unlock:
2778 spin_unlock(&jpeg->slock);
2779 return IRQ_HANDLED;
2780}
2781
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03002782static void *jpeg_get_drv_data(struct device *dev);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002783
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002784/*
2785 * ============================================================================
2786 * Driver basic infrastructure
2787 * ============================================================================
2788 */
2789
2790static int s5p_jpeg_probe(struct platform_device *pdev)
2791{
2792 struct s5p_jpeg *jpeg;
2793 struct resource *res;
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002794 int i, ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002795
2796 /* JPEG IP abstraction struct */
Sachin Kamat5b58b952012-05-14 06:33:34 -03002797 jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002798 if (!jpeg)
2799 return -ENOMEM;
2800
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03002801 jpeg->variant = jpeg_get_drv_data(&pdev->dev);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002802
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002803 mutex_init(&jpeg->lock);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002804 spin_lock_init(&jpeg->slock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002805 jpeg->dev = &pdev->dev;
2806
2807 /* memory-mapped registers */
2808 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002809
Thierry Redingf23999e2013-01-21 06:09:07 -03002810 jpeg->regs = devm_ioremap_resource(&pdev->dev, res);
2811 if (IS_ERR(jpeg->regs))
2812 return PTR_ERR(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002813
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002814 /* interrupt service routine registration */
2815 jpeg->irq = ret = platform_get_irq(pdev, 0);
2816 if (ret < 0) {
2817 dev_err(&pdev->dev, "cannot find IRQ\n");
Sachin Kamat5b58b952012-05-14 06:33:34 -03002818 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002819 }
2820
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002821 ret = devm_request_irq(&pdev->dev, jpeg->irq, jpeg->variant->jpeg_irq,
2822 0, dev_name(&pdev->dev), jpeg);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002823 if (ret) {
2824 dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
Sachin Kamat5b58b952012-05-14 06:33:34 -03002825 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002826 }
2827
2828 /* clocks */
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002829 for (i = 0; i < jpeg->variant->num_clocks; i++) {
2830 jpeg->clocks[i] = devm_clk_get(&pdev->dev,
2831 jpeg->variant->clk_names[i]);
2832 if (IS_ERR(jpeg->clocks[i])) {
2833 dev_err(&pdev->dev, "failed to get clock: %s\n",
2834 jpeg->variant->clk_names[i]);
2835 return PTR_ERR(jpeg->clocks[i]);
2836 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002837 }
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002838
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002839 /* v4l2 device */
2840 ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
2841 if (ret) {
2842 dev_err(&pdev->dev, "Failed to register v4l2 device\n");
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002843 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002844 }
2845
2846 /* mem2mem device */
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03002847 jpeg->m2m_dev = v4l2_m2m_init(jpeg->variant->m2m_ops);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002848 if (IS_ERR(jpeg->m2m_dev)) {
2849 v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
2850 ret = PTR_ERR(jpeg->m2m_dev);
2851 goto device_register_rollback;
2852 }
2853
Marek Szyprowski712b6172016-05-24 09:16:07 +02002854 vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002855
2856 /* JPEG encoder /dev/videoX node */
2857 jpeg->vfd_encoder = video_device_alloc();
2858 if (!jpeg->vfd_encoder) {
2859 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
2860 ret = -ENOMEM;
Hans Verkuilc781e4a2016-02-15 14:25:09 -02002861 goto m2m_init_rollback;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002862 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03002863 snprintf(jpeg->vfd_encoder->name, sizeof(jpeg->vfd_encoder->name),
2864 "%s-enc", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002865 jpeg->vfd_encoder->fops = &s5p_jpeg_fops;
2866 jpeg->vfd_encoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
2867 jpeg->vfd_encoder->minor = -1;
2868 jpeg->vfd_encoder->release = video_device_release;
2869 jpeg->vfd_encoder->lock = &jpeg->lock;
2870 jpeg->vfd_encoder->v4l2_dev = &jpeg->v4l2_dev;
Hans Verkuil954f3402012-09-05 06:05:50 -03002871 jpeg->vfd_encoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002872
2873 ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
2874 if (ret) {
2875 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
Andrzej Pietrasiewicz7a1d4e72015-07-03 07:04:38 -03002876 video_device_release(jpeg->vfd_encoder);
Hans Verkuilc781e4a2016-02-15 14:25:09 -02002877 goto m2m_init_rollback;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002878 }
2879
2880 video_set_drvdata(jpeg->vfd_encoder, jpeg);
2881 v4l2_info(&jpeg->v4l2_dev,
2882 "encoder device registered as /dev/video%d\n",
2883 jpeg->vfd_encoder->num);
2884
2885 /* JPEG decoder /dev/videoX node */
2886 jpeg->vfd_decoder = video_device_alloc();
2887 if (!jpeg->vfd_decoder) {
2888 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
2889 ret = -ENOMEM;
2890 goto enc_vdev_register_rollback;
2891 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03002892 snprintf(jpeg->vfd_decoder->name, sizeof(jpeg->vfd_decoder->name),
2893 "%s-dec", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002894 jpeg->vfd_decoder->fops = &s5p_jpeg_fops;
2895 jpeg->vfd_decoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
2896 jpeg->vfd_decoder->minor = -1;
2897 jpeg->vfd_decoder->release = video_device_release;
2898 jpeg->vfd_decoder->lock = &jpeg->lock;
2899 jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev;
Jacek Anaszewski7f7d8fe2013-09-11 06:17:45 -03002900 jpeg->vfd_decoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002901
2902 ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
2903 if (ret) {
2904 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
Andrzej Pietrasiewicz7a1d4e72015-07-03 07:04:38 -03002905 video_device_release(jpeg->vfd_decoder);
2906 goto enc_vdev_register_rollback;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002907 }
2908
2909 video_set_drvdata(jpeg->vfd_decoder, jpeg);
2910 v4l2_info(&jpeg->v4l2_dev,
2911 "decoder device registered as /dev/video%d\n",
2912 jpeg->vfd_decoder->num);
2913
2914 /* final statements & power management */
2915 platform_set_drvdata(pdev, jpeg);
2916
2917 pm_runtime_enable(&pdev->dev);
2918
2919 v4l2_info(&jpeg->v4l2_dev, "Samsung S5P JPEG codec\n");
2920
2921 return 0;
2922
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002923enc_vdev_register_rollback:
2924 video_unregister_device(jpeg->vfd_encoder);
2925
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002926m2m_init_rollback:
2927 v4l2_m2m_release(jpeg->m2m_dev);
2928
2929device_register_rollback:
2930 v4l2_device_unregister(&jpeg->v4l2_dev);
2931
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002932 return ret;
2933}
2934
2935static int s5p_jpeg_remove(struct platform_device *pdev)
2936{
2937 struct s5p_jpeg *jpeg = platform_get_drvdata(pdev);
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002938 int i;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002939
2940 pm_runtime_disable(jpeg->dev);
2941
2942 video_unregister_device(jpeg->vfd_decoder);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002943 video_unregister_device(jpeg->vfd_encoder);
Marek Szyprowski712b6172016-05-24 09:16:07 +02002944 vb2_dma_contig_clear_max_seg_size(&pdev->dev);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002945 v4l2_m2m_release(jpeg->m2m_dev);
2946 v4l2_device_unregister(&jpeg->v4l2_dev);
2947
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002948 if (!pm_runtime_status_suspended(&pdev->dev)) {
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002949 for (i = jpeg->variant->num_clocks - 1; i >= 0; i--)
2950 clk_disable_unprepare(jpeg->clocks[i]);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002951 }
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002952
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002953 return 0;
2954}
2955
Rafael J. Wysockie243c7c2014-12-04 01:10:10 +01002956#ifdef CONFIG_PM
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002957static int s5p_jpeg_runtime_suspend(struct device *dev)
2958{
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002959 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002960 int i;
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002961
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002962 for (i = jpeg->variant->num_clocks - 1; i >= 0; i--)
2963 clk_disable_unprepare(jpeg->clocks[i]);
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002964
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002965 return 0;
2966}
2967
2968static int s5p_jpeg_runtime_resume(struct device *dev)
2969{
2970 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002971 unsigned long flags;
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002972 int i, ret;
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002973
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002974 for (i = 0; i < jpeg->variant->num_clocks; i++) {
2975 ret = clk_prepare_enable(jpeg->clocks[i]);
2976 if (ret) {
2977 while (--i > 0)
2978 clk_disable_unprepare(jpeg->clocks[i]);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002979 return ret;
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002980 }
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002981 }
2982
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002983 spin_lock_irqsave(&jpeg->slock, flags);
2984
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002985 /*
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002986 * JPEG IP allows storing two Huffman tables for each component.
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002987 * We fill table 0 for each component and do this here only
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03002988 * for S5PC210 and Exynos3250 SoCs. Exynos4x12 and Exynos542x SoC
2989 * require programming their Huffman tables each time the encoding
2990 * process is initialized, and thus it is accomplished in the
2991 * device_run callback of m2m_ops.
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002992 */
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03002993 if (!jpeg->variant->htbl_reinit) {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002994 s5p_jpeg_set_hdctbl(jpeg->regs);
2995 s5p_jpeg_set_hdctblg(jpeg->regs);
2996 s5p_jpeg_set_hactbl(jpeg->regs);
2997 s5p_jpeg_set_hactblg(jpeg->regs);
2998 }
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03002999
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03003000 spin_unlock_irqrestore(&jpeg->slock, flags);
3001
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003002 return 0;
3003}
Rafael J. Wysockie243c7c2014-12-04 01:10:10 +01003004#endif /* CONFIG_PM */
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003005
Thierry Redingde3767a2014-10-14 07:10:40 -03003006#ifdef CONFIG_PM_SLEEP
Jacek Anaszewskif1347132013-11-25 06:58:13 -03003007static int s5p_jpeg_suspend(struct device *dev)
3008{
3009 if (pm_runtime_suspended(dev))
3010 return 0;
3011
3012 return s5p_jpeg_runtime_suspend(dev);
3013}
3014
3015static int s5p_jpeg_resume(struct device *dev)
3016{
3017 if (pm_runtime_suspended(dev))
3018 return 0;
3019
3020 return s5p_jpeg_runtime_resume(dev);
3021}
Thierry Redingde3767a2014-10-14 07:10:40 -03003022#endif
Jacek Anaszewskif1347132013-11-25 06:58:13 -03003023
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003024static const struct dev_pm_ops s5p_jpeg_pm_ops = {
Jacek Anaszewskif1347132013-11-25 06:58:13 -03003025 SET_SYSTEM_SLEEP_PM_OPS(s5p_jpeg_suspend, s5p_jpeg_resume)
Shuah Khan605b8922016-07-14 17:01:56 -03003026 SET_RUNTIME_PM_OPS(s5p_jpeg_runtime_suspend, s5p_jpeg_runtime_resume,
3027 NULL)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003028};
3029
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003030static struct s5p_jpeg_variant s5p_jpeg_drvdata = {
3031 .version = SJPEG_S5P,
3032 .jpeg_irq = s5p_jpeg_irq,
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03003033 .m2m_ops = &s5p_jpeg_m2m_ops,
Jacek Anaszewskib2451682014-04-10 04:32:11 -03003034 .fmt_ver_flag = SJPEG_FMT_FLAG_S5P,
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03003035 .clk_names = {"jpeg"},
3036 .num_clocks = 1,
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03003037};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003038
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003039static struct s5p_jpeg_variant exynos3250_jpeg_drvdata = {
3040 .version = SJPEG_EXYNOS3250,
3041 .jpeg_irq = exynos3250_jpeg_irq,
3042 .m2m_ops = &exynos3250_jpeg_m2m_ops,
3043 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS3250,
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03003044 .hw3250_compat = 1,
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03003045 .clk_names = {"jpeg", "sclk"},
3046 .num_clocks = 2,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003047};
3048
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003049static struct s5p_jpeg_variant exynos4_jpeg_drvdata = {
3050 .version = SJPEG_EXYNOS4,
3051 .jpeg_irq = exynos4_jpeg_irq,
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03003052 .m2m_ops = &exynos4_jpeg_m2m_ops,
Jacek Anaszewskib2451682014-04-10 04:32:11 -03003053 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS4,
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03003054 .htbl_reinit = 1,
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03003055 .clk_names = {"jpeg"},
3056 .num_clocks = 1,
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03003057 .hw_ex4_compat = 1,
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03003058};
3059
3060static struct s5p_jpeg_variant exynos5420_jpeg_drvdata = {
3061 .version = SJPEG_EXYNOS5420,
3062 .jpeg_irq = exynos3250_jpeg_irq, /* intentionally 3250 */
3063 .m2m_ops = &exynos3250_jpeg_m2m_ops, /* intentionally 3250 */
3064 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS3250, /* intentionally 3250 */
3065 .hw3250_compat = 1,
3066 .htbl_reinit = 1,
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03003067 .clk_names = {"jpeg"},
3068 .num_clocks = 1,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003069};
3070
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03003071static struct s5p_jpeg_variant exynos5433_jpeg_drvdata = {
3072 .version = SJPEG_EXYNOS5433,
3073 .jpeg_irq = exynos4_jpeg_irq,
3074 .m2m_ops = &exynos4_jpeg_m2m_ops,
3075 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS4,
3076 .htbl_reinit = 1,
3077 .clk_names = {"pclk", "aclk", "aclk_xiu", "sclk"},
3078 .num_clocks = 4,
3079 .hw_ex4_compat = 1,
3080};
3081
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003082static const struct of_device_id samsung_jpeg_match[] = {
3083 {
3084 .compatible = "samsung,s5pv210-jpeg",
3085 .data = &s5p_jpeg_drvdata,
3086 }, {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003087 .compatible = "samsung,exynos3250-jpeg",
3088 .data = &exynos3250_jpeg_drvdata,
3089 }, {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003090 .compatible = "samsung,exynos4210-jpeg",
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003091 .data = &exynos4_jpeg_drvdata,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003092 }, {
3093 .compatible = "samsung,exynos4212-jpeg",
3094 .data = &exynos4_jpeg_drvdata,
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03003095 }, {
3096 .compatible = "samsung,exynos5420-jpeg",
3097 .data = &exynos5420_jpeg_drvdata,
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03003098 }, {
3099 .compatible = "samsung,exynos5433-jpeg",
3100 .data = &exynos5433_jpeg_drvdata,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003101 },
3102 {},
3103};
3104
3105MODULE_DEVICE_TABLE(of, samsung_jpeg_match);
3106
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03003107static void *jpeg_get_drv_data(struct device *dev)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003108{
3109 struct s5p_jpeg_variant *driver_data = NULL;
3110 const struct of_device_id *match;
3111
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03003112 if (!IS_ENABLED(CONFIG_OF) || !dev->of_node)
3113 return &s5p_jpeg_drvdata;
3114
3115 match = of_match_node(samsung_jpeg_match, dev->of_node);
3116
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003117 if (match)
3118 driver_data = (struct s5p_jpeg_variant *)match->data;
3119
3120 return driver_data;
3121}
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03003122
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003123static struct platform_driver s5p_jpeg_driver = {
3124 .probe = s5p_jpeg_probe,
3125 .remove = s5p_jpeg_remove,
3126 .driver = {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003127 .of_match_table = of_match_ptr(samsung_jpeg_match),
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003128 .name = S5P_JPEG_M2M_NAME,
3129 .pm = &s5p_jpeg_pm_ops,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003130 },
3131};
3132
Sachin Kamat87e94292012-07-03 05:54:33 -03003133module_platform_driver(s5p_jpeg_driver);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003134
3135MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003136MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003137MODULE_DESCRIPTION("Samsung JPEG codec driver");
3138MODULE_LICENSE("GPL");