blob: 47e7eab84d7bb3fd8e5a34897aa16c010c66410f [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;
540 for (i = 0; i < ARRAY_SIZE(fourcc_to_dwngrd_schema_id); ++i) {
541 if (fourcc_to_dwngrd_schema_id[i] == fourcc)
542 return i;
543 }
544
545 return -EINVAL;
546}
547
548static int s5p_jpeg_adjust_fourcc_to_subsampling(
549 enum v4l2_jpeg_chroma_subsampling subs,
550 u32 in_fourcc,
551 u32 *out_fourcc,
552 struct s5p_jpeg_ctx *ctx)
553{
554 int dwngrd_sch_id;
555
556 if (ctx->subsampling != V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY) {
557 dwngrd_sch_id =
558 s5p_jpeg_get_dwngrd_sch_id_by_fourcc(in_fourcc);
559 if (dwngrd_sch_id < 0)
560 return -EINVAL;
561 }
562
563 switch (ctx->subsampling) {
564 case V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY:
565 *out_fourcc = V4L2_PIX_FMT_GREY;
566 break;
567 case V4L2_JPEG_CHROMA_SUBSAMPLING_420:
568 if (dwngrd_sch_id >
569 ARRAY_SIZE(subs420_fourcc_dwngrd_schema) - 1)
570 return -EINVAL;
571 *out_fourcc = subs420_fourcc_dwngrd_schema[dwngrd_sch_id];
572 break;
573 case V4L2_JPEG_CHROMA_SUBSAMPLING_422:
574 if (dwngrd_sch_id >
575 ARRAY_SIZE(subs422_fourcc_dwngrd_schema) - 1)
576 return -EINVAL;
577 *out_fourcc = subs422_fourcc_dwngrd_schema[dwngrd_sch_id];
578 break;
579 default:
580 *out_fourcc = V4L2_PIX_FMT_GREY;
581 break;
582 }
583
584 return 0;
585}
586
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300587static int exynos4x12_decoded_subsampling[] = {
588 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
589 V4L2_JPEG_CHROMA_SUBSAMPLING_444,
590 V4L2_JPEG_CHROMA_SUBSAMPLING_422,
591 V4L2_JPEG_CHROMA_SUBSAMPLING_420,
592};
593
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300594static int exynos3250_decoded_subsampling[] = {
595 V4L2_JPEG_CHROMA_SUBSAMPLING_444,
596 V4L2_JPEG_CHROMA_SUBSAMPLING_422,
597 V4L2_JPEG_CHROMA_SUBSAMPLING_420,
598 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
599 -1,
600 -1,
601 V4L2_JPEG_CHROMA_SUBSAMPLING_411,
602};
603
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300604static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c)
605{
606 return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler);
607}
608
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300609static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh)
610{
611 return container_of(fh, struct s5p_jpeg_ctx, fh);
612}
613
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300614static int s5p_jpeg_to_user_subsampling(struct s5p_jpeg_ctx *ctx)
615{
616 WARN_ON(ctx->subsampling > 3);
617
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300618 switch (ctx->jpeg->variant->version) {
619 case SJPEG_S5P:
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300620 if (ctx->subsampling > 2)
621 return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
622 return ctx->subsampling;
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300623 case SJPEG_EXYNOS3250:
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -0300624 case SJPEG_EXYNOS5420:
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300625 if (ctx->subsampling > 3)
626 return V4L2_JPEG_CHROMA_SUBSAMPLING_411;
627 return exynos3250_decoded_subsampling[ctx->subsampling];
628 case SJPEG_EXYNOS4:
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300629 case SJPEG_EXYNOS5433:
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300630 if (ctx->subsampling > 2)
631 return V4L2_JPEG_CHROMA_SUBSAMPLING_420;
632 return exynos4x12_decoded_subsampling[ctx->subsampling];
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300633 default:
634 return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300635 }
636}
637
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300638static inline void s5p_jpeg_set_qtbl(void __iomem *regs,
639 const unsigned char *qtbl,
640 unsigned long tab, int len)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300641{
642 int i;
643
644 for (i = 0; i < len; i++)
645 writel((unsigned int)qtbl[i], regs + tab + (i * 0x04));
646}
647
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300648static inline void s5p_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300649{
650 /* this driver fills quantisation table 0 with data for luma */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300651 s5p_jpeg_set_qtbl(regs, qtbl_luminance[quality],
652 S5P_JPG_QTBL_CONTENT(0),
653 ARRAY_SIZE(qtbl_luminance[quality]));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300654}
655
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300656static inline void s5p_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300657{
658 /* this driver fills quantisation table 1 with data for chroma */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300659 s5p_jpeg_set_qtbl(regs, qtbl_chrominance[quality],
660 S5P_JPG_QTBL_CONTENT(1),
661 ARRAY_SIZE(qtbl_chrominance[quality]));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300662}
663
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300664static inline void s5p_jpeg_set_htbl(void __iomem *regs,
665 const unsigned char *htbl,
666 unsigned long tab, int len)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300667{
668 int i;
669
670 for (i = 0; i < len; i++)
671 writel((unsigned int)htbl[i], regs + tab + (i * 0x04));
672}
673
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300674static inline void s5p_jpeg_set_hdctbl(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300675{
676 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300677 s5p_jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0),
678 ARRAY_SIZE(hdctbl0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300679}
680
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300681static inline void s5p_jpeg_set_hdctblg(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300682{
683 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300684 s5p_jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0),
685 ARRAY_SIZE(hdctblg0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300686}
687
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300688static inline void s5p_jpeg_set_hactbl(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300689{
690 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300691 s5p_jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0),
692 ARRAY_SIZE(hactbl0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300693}
694
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300695static inline void s5p_jpeg_set_hactblg(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300696{
697 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300698 s5p_jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0),
699 ARRAY_SIZE(hactblg0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300700}
701
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300702static inline void exynos4_jpeg_set_tbl(void __iomem *regs,
703 const unsigned char *tbl,
704 unsigned long tab, int len)
705{
706 int i;
707 unsigned int dword;
708
709 for (i = 0; i < len; i += 4) {
710 dword = tbl[i] |
711 (tbl[i + 1] << 8) |
712 (tbl[i + 2] << 16) |
713 (tbl[i + 3] << 24);
714 writel(dword, regs + tab + i);
715 }
716}
717
718static inline void exynos4_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
719{
720 /* this driver fills quantisation table 0 with data for luma */
721 exynos4_jpeg_set_tbl(regs, qtbl_luminance[quality],
722 EXYNOS4_QTBL_CONTENT(0),
723 ARRAY_SIZE(qtbl_luminance[quality]));
724}
725
726static inline void exynos4_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
727{
728 /* this driver fills quantisation table 1 with data for chroma */
729 exynos4_jpeg_set_tbl(regs, qtbl_chrominance[quality],
730 EXYNOS4_QTBL_CONTENT(1),
731 ARRAY_SIZE(qtbl_chrominance[quality]));
732}
733
Mauro Carvalho Chehabaf425be2014-08-26 10:50:23 -0300734static void exynos4_jpeg_set_huff_tbl(void __iomem *base)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300735{
736 exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCLL,
737 ARRAY_SIZE(hdctbl0));
738 exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCCL,
739 ARRAY_SIZE(hdctbl0));
740 exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCLV,
741 ARRAY_SIZE(hdctblg0));
742 exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCCV,
743 ARRAY_SIZE(hdctblg0));
744 exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACLL,
745 ARRAY_SIZE(hactbl0));
746 exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACCL,
747 ARRAY_SIZE(hactbl0));
748 exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACLV,
749 ARRAY_SIZE(hactblg0));
750 exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACCV,
751 ARRAY_SIZE(hactblg0));
752}
753
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300754static inline int __exynos4_huff_tbl(int class, int id, bool lenval)
755{
756 /*
757 * class: 0 - DC, 1 - AC
758 * id: 0 - Y, 1 - Cb/Cr
759 */
760 if (class) {
761 if (id)
762 return lenval ? EXYNOS4_HUFF_TBL_HACCL :
763 EXYNOS4_HUFF_TBL_HACCV;
764 return lenval ? EXYNOS4_HUFF_TBL_HACLL : EXYNOS4_HUFF_TBL_HACLV;
765
766 }
767 /* class == 0 */
768 if (id)
769 return lenval ? EXYNOS4_HUFF_TBL_HDCCL : EXYNOS4_HUFF_TBL_HDCCV;
770
771 return lenval ? EXYNOS4_HUFF_TBL_HDCLL : EXYNOS4_HUFF_TBL_HDCLV;
772}
773
774static inline int exynos4_huff_tbl_len(int class, int id)
775{
776 return __exynos4_huff_tbl(class, id, true);
777}
778
779static inline int exynos4_huff_tbl_val(int class, int id)
780{
781 return __exynos4_huff_tbl(class, id, false);
782}
783
784static int get_byte(struct s5p_jpeg_buffer *buf);
785static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word);
786static void skip(struct s5p_jpeg_buffer *buf, long len);
787
788static void exynos4_jpeg_parse_decode_h_tbl(struct s5p_jpeg_ctx *ctx)
789{
790 struct s5p_jpeg *jpeg = ctx->jpeg;
791 struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
792 struct s5p_jpeg_buffer jpeg_buffer;
793 unsigned int word;
794 int c, x, components;
795
796 jpeg_buffer.size = 2; /* Ls */
797 jpeg_buffer.data =
798 (unsigned long)vb2_plane_vaddr(vb, 0) + ctx->out_q.sos + 2;
799 jpeg_buffer.curr = 0;
800
801 word = 0;
802
803 if (get_word_be(&jpeg_buffer, &word))
804 return;
805 jpeg_buffer.size = (long)word - 2;
806 jpeg_buffer.data += 2;
807 jpeg_buffer.curr = 0;
808
809 components = get_byte(&jpeg_buffer);
810 if (components == -1)
811 return;
812 while (components--) {
813 c = get_byte(&jpeg_buffer);
814 if (c == -1)
815 return;
816 x = get_byte(&jpeg_buffer);
817 if (x == -1)
818 return;
819 exynos4_jpeg_select_dec_h_tbl(jpeg->regs, c,
820 (((x >> 4) & 0x1) << 1) | (x & 0x1));
821 }
822
823}
824
825static void exynos4_jpeg_parse_huff_tbl(struct s5p_jpeg_ctx *ctx)
826{
827 struct s5p_jpeg *jpeg = ctx->jpeg;
828 struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
829 struct s5p_jpeg_buffer jpeg_buffer;
830 unsigned int word;
831 int c, i, n, j;
832
833 for (j = 0; j < ctx->out_q.dht.n; ++j) {
834 jpeg_buffer.size = ctx->out_q.dht.len[j];
835 jpeg_buffer.data = (unsigned long)vb2_plane_vaddr(vb, 0) +
836 ctx->out_q.dht.marker[j];
837 jpeg_buffer.curr = 0;
838
839 word = 0;
840 while (jpeg_buffer.curr < jpeg_buffer.size) {
841 char id, class;
842
843 c = get_byte(&jpeg_buffer);
844 if (c == -1)
845 return;
846 id = c & 0xf;
847 class = (c >> 4) & 0xf;
848 n = 0;
849 for (i = 0; i < 16; ++i) {
850 c = get_byte(&jpeg_buffer);
851 if (c == -1)
852 return;
853 word |= c << ((i % 4) * 8);
854 if ((i + 1) % 4 == 0) {
855 writel(word, jpeg->regs +
856 exynos4_huff_tbl_len(class, id) +
857 (i / 4) * 4);
858 word = 0;
859 }
860 n += c;
861 }
862 word = 0;
863 for (i = 0; i < n; ++i) {
864 c = get_byte(&jpeg_buffer);
865 if (c == -1)
866 return;
867 word |= c << ((i % 4) * 8);
868 if ((i + 1) % 4 == 0) {
869 writel(word, jpeg->regs +
870 exynos4_huff_tbl_val(class, id) +
871 (i / 4) * 4);
872 word = 0;
873 }
874 }
875 if (i % 4) {
876 writel(word, jpeg->regs +
877 exynos4_huff_tbl_val(class, id) + (i / 4) * 4);
878 }
879 word = 0;
880 }
881 }
882}
883
884static void exynos4_jpeg_parse_decode_q_tbl(struct s5p_jpeg_ctx *ctx)
885{
886 struct s5p_jpeg *jpeg = ctx->jpeg;
887 struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
888 struct s5p_jpeg_buffer jpeg_buffer;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300889 int c, x, components;
890
891 jpeg_buffer.size = ctx->out_q.sof_len;
892 jpeg_buffer.data =
893 (unsigned long)vb2_plane_vaddr(vb, 0) + ctx->out_q.sof;
894 jpeg_buffer.curr = 0;
895
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300896 skip(&jpeg_buffer, 5); /* P, Y, X */
897 components = get_byte(&jpeg_buffer);
898 if (components == -1)
899 return;
900
901 exynos4_jpeg_set_dec_components(jpeg->regs, components);
902
903 while (components--) {
904 c = get_byte(&jpeg_buffer);
905 if (c == -1)
906 return;
907 skip(&jpeg_buffer, 1);
908 x = get_byte(&jpeg_buffer);
909 if (x == -1)
910 return;
911 exynos4_jpeg_select_dec_q_tbl(jpeg->regs, c, x);
912 }
913}
914
915static void exynos4_jpeg_parse_q_tbl(struct s5p_jpeg_ctx *ctx)
916{
917 struct s5p_jpeg *jpeg = ctx->jpeg;
918 struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
919 struct s5p_jpeg_buffer jpeg_buffer;
920 unsigned int word;
921 int c, i, j;
922
923 for (j = 0; j < ctx->out_q.dqt.n; ++j) {
924 jpeg_buffer.size = ctx->out_q.dqt.len[j];
925 jpeg_buffer.data = (unsigned long)vb2_plane_vaddr(vb, 0) +
926 ctx->out_q.dqt.marker[j];
927 jpeg_buffer.curr = 0;
928
929 word = 0;
930 while (jpeg_buffer.size - jpeg_buffer.curr >= 65) {
931 char id;
932
933 c = get_byte(&jpeg_buffer);
934 if (c == -1)
935 return;
936 id = c & 0xf;
937 /* nonzero means extended mode - not supported */
938 if ((c >> 4) & 0xf)
939 return;
940 for (i = 0; i < 64; ++i) {
941 c = get_byte(&jpeg_buffer);
942 if (c == -1)
943 return;
944 word |= c << ((i % 4) * 8);
945 if ((i + 1) % 4 == 0) {
946 writel(word, jpeg->regs +
947 EXYNOS4_QTBL_CONTENT(id) + (i / 4) * 4);
948 word = 0;
949 }
950 }
951 word = 0;
952 }
953 }
954}
955
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300956/*
957 * ============================================================================
958 * Device file operations
959 * ============================================================================
960 */
961
962static int queue_init(void *priv, struct vb2_queue *src_vq,
963 struct vb2_queue *dst_vq);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300964static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
965 __u32 pixelformat, unsigned int fmt_type);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300966static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300967
968static int s5p_jpeg_open(struct file *file)
969{
970 struct s5p_jpeg *jpeg = video_drvdata(file);
971 struct video_device *vfd = video_devdata(file);
972 struct s5p_jpeg_ctx *ctx;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300973 struct s5p_jpeg_fmt *out_fmt, *cap_fmt;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300974 int ret = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300975
Sachin Kamatb5146c92012-08-16 08:52:58 -0300976 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300977 if (!ctx)
978 return -ENOMEM;
979
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300980 if (mutex_lock_interruptible(&jpeg->lock)) {
981 ret = -ERESTARTSYS;
982 goto free;
983 }
984
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300985 v4l2_fh_init(&ctx->fh, vfd);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300986 /* Use separate control handler per file handle */
987 ctx->fh.ctrl_handler = &ctx->ctrl_handler;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300988 file->private_data = &ctx->fh;
989 v4l2_fh_add(&ctx->fh);
990
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300991 ctx->jpeg = jpeg;
992 if (vfd == jpeg->vfd_encoder) {
993 ctx->mode = S5P_JPEG_ENCODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300994 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB565,
995 FMT_TYPE_OUTPUT);
996 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
997 FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300998 } else {
999 ctx->mode = S5P_JPEG_DECODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001000 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
1001 FMT_TYPE_OUTPUT);
1002 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_YUYV,
1003 FMT_TYPE_CAPTURE);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001004 ctx->scale_factor = EXYNOS3250_DEC_SCALE_FACTOR_8_8;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001005 }
1006
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001007 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
1008 if (IS_ERR(ctx->fh.m2m_ctx)) {
1009 ret = PTR_ERR(ctx->fh.m2m_ctx);
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001010 goto error;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001011 }
1012
1013 ctx->out_q.fmt = out_fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001014 ctx->cap_q.fmt = cap_fmt;
1015
1016 ret = s5p_jpeg_controls_create(ctx);
1017 if (ret < 0)
1018 goto error;
1019
Hans Verkuilb0d5cd62012-06-24 06:54:18 -03001020 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001021 return 0;
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001022
1023error:
1024 v4l2_fh_del(&ctx->fh);
1025 v4l2_fh_exit(&ctx->fh);
Hans Verkuilb0d5cd62012-06-24 06:54:18 -03001026 mutex_unlock(&jpeg->lock);
1027free:
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001028 kfree(ctx);
1029 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001030}
1031
1032static int s5p_jpeg_release(struct file *file)
1033{
Hans Verkuilb0d5cd62012-06-24 06:54:18 -03001034 struct s5p_jpeg *jpeg = video_drvdata(file);
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001035 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001036
Hans Verkuilb0d5cd62012-06-24 06:54:18 -03001037 mutex_lock(&jpeg->lock);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001038 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001039 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001040 v4l2_fh_del(&ctx->fh);
1041 v4l2_fh_exit(&ctx->fh);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001042 kfree(ctx);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001043 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001044
1045 return 0;
1046}
1047
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001048static const struct v4l2_file_operations s5p_jpeg_fops = {
1049 .owner = THIS_MODULE,
1050 .open = s5p_jpeg_open,
1051 .release = s5p_jpeg_release,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001052 .poll = v4l2_m2m_fop_poll,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001053 .unlocked_ioctl = video_ioctl2,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001054 .mmap = v4l2_m2m_fop_mmap,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001055};
1056
1057/*
1058 * ============================================================================
1059 * video ioctl operations
1060 * ============================================================================
1061 */
1062
1063static int get_byte(struct s5p_jpeg_buffer *buf)
1064{
1065 if (buf->curr >= buf->size)
1066 return -1;
1067
1068 return ((unsigned char *)buf->data)[buf->curr++];
1069}
1070
1071static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word)
1072{
1073 unsigned int temp;
1074 int byte;
1075
1076 byte = get_byte(buf);
1077 if (byte == -1)
1078 return -1;
1079 temp = byte << 8;
1080 byte = get_byte(buf);
1081 if (byte == -1)
1082 return -1;
1083 *word = (unsigned int)byte | temp;
1084 return 0;
1085}
1086
1087static void skip(struct s5p_jpeg_buffer *buf, long len)
1088{
1089 if (len <= 0)
1090 return;
1091
1092 while (len--)
1093 get_byte(buf);
1094}
1095
1096static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001097 unsigned long buffer, unsigned long size,
1098 struct s5p_jpeg_ctx *ctx)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001099{
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001100 int c, components = 0, notfound, n_dht = 0, n_dqt = 0;
1101 unsigned int height, width, word, subsampling = 0, sos = 0, sof = 0,
1102 sof_len = 0;
1103 unsigned int dht[S5P_JPEG_MAX_MARKER], dht_len[S5P_JPEG_MAX_MARKER],
1104 dqt[S5P_JPEG_MAX_MARKER], dqt_len[S5P_JPEG_MAX_MARKER];
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001105 long length;
1106 struct s5p_jpeg_buffer jpeg_buffer;
1107
1108 jpeg_buffer.size = size;
1109 jpeg_buffer.data = buffer;
1110 jpeg_buffer.curr = 0;
1111
1112 notfound = 1;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001113 while (notfound || !sos) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001114 c = get_byte(&jpeg_buffer);
1115 if (c == -1)
Jacek Anaszewskia35f6002014-07-11 12:19:43 -03001116 return false;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001117 if (c != 0xff)
1118 continue;
1119 do
1120 c = get_byte(&jpeg_buffer);
1121 while (c == 0xff);
1122 if (c == -1)
Jacek Anaszewskia35f6002014-07-11 12:19:43 -03001123 return false;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001124 if (c == 0)
1125 continue;
1126 length = 0;
1127 switch (c) {
1128 /* SOF0: baseline JPEG */
1129 case SOF0:
1130 if (get_word_be(&jpeg_buffer, &word))
1131 break;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001132 length = (long)word - 2;
1133 if (!length)
1134 return false;
1135 sof = jpeg_buffer.curr; /* after 0xffc0 */
1136 sof_len = length;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001137 if (get_byte(&jpeg_buffer) == -1)
1138 break;
1139 if (get_word_be(&jpeg_buffer, &height))
1140 break;
1141 if (get_word_be(&jpeg_buffer, &width))
1142 break;
1143 components = get_byte(&jpeg_buffer);
1144 if (components == -1)
1145 break;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001146
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001147 if (components == 1) {
1148 subsampling = 0x33;
1149 } else {
1150 skip(&jpeg_buffer, 1);
1151 subsampling = get_byte(&jpeg_buffer);
1152 skip(&jpeg_buffer, 1);
1153 }
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001154 if (components > 3)
1155 return false;
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001156 skip(&jpeg_buffer, components * 2);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001157 notfound = 0;
1158 break;
1159
1160 case DQT:
1161 if (get_word_be(&jpeg_buffer, &word))
1162 break;
1163 length = (long)word - 2;
1164 if (!length)
1165 return false;
1166 if (n_dqt >= S5P_JPEG_MAX_MARKER)
1167 return false;
1168 dqt[n_dqt] = jpeg_buffer.curr; /* after 0xffdb */
1169 dqt_len[n_dqt++] = length;
1170 skip(&jpeg_buffer, length);
1171 break;
1172
1173 case DHT:
1174 if (get_word_be(&jpeg_buffer, &word))
1175 break;
1176 length = (long)word - 2;
1177 if (!length)
1178 return false;
1179 if (n_dht >= S5P_JPEG_MAX_MARKER)
1180 return false;
1181 dht[n_dht] = jpeg_buffer.curr; /* after 0xffc4 */
1182 dht_len[n_dht++] = length;
1183 skip(&jpeg_buffer, length);
1184 break;
1185
1186 case SOS:
1187 sos = jpeg_buffer.curr - 2; /* 0xffda */
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001188 break;
1189
1190 /* skip payload-less markers */
1191 case RST ... RST + 7:
1192 case SOI:
1193 case EOI:
1194 case TEM:
1195 break;
1196
1197 /* skip uninteresting payload markers */
1198 default:
1199 if (get_word_be(&jpeg_buffer, &word))
1200 break;
1201 length = (long)word - 2;
1202 skip(&jpeg_buffer, length);
1203 break;
1204 }
1205 }
1206 result->w = width;
1207 result->h = height;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001208 result->sos = sos;
1209 result->dht.n = n_dht;
1210 while (n_dht--) {
1211 result->dht.marker[n_dht] = dht[n_dht];
1212 result->dht.len[n_dht] = dht_len[n_dht];
1213 }
1214 result->dqt.n = n_dqt;
1215 while (n_dqt--) {
1216 result->dqt.marker[n_dqt] = dqt[n_dqt];
1217 result->dqt.len[n_dqt] = dqt_len[n_dqt];
1218 }
1219 result->sof = sof;
1220 result->sof_len = sof_len;
1221 result->size = result->components = components;
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001222
1223 switch (subsampling) {
1224 case 0x11:
1225 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444;
1226 break;
1227 case 0x21:
1228 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422;
1229 break;
1230 case 0x22:
1231 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420;
1232 break;
1233 case 0x33:
1234 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
1235 break;
1236 default:
1237 return false;
1238 }
1239
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001240 return !notfound && sos;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001241}
1242
1243static int s5p_jpeg_querycap(struct file *file, void *priv,
1244 struct v4l2_capability *cap)
1245{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001246 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001247
1248 if (ctx->mode == S5P_JPEG_ENCODE) {
Javier Martinez Canillasb9f19f02016-06-16 18:40:33 -03001249 strlcpy(cap->driver, S5P_JPEG_M2M_NAME,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001250 sizeof(cap->driver));
1251 strlcpy(cap->card, S5P_JPEG_M2M_NAME " encoder",
1252 sizeof(cap->card));
1253 } else {
Javier Martinez Canillasb9f19f02016-06-16 18:40:33 -03001254 strlcpy(cap->driver, S5P_JPEG_M2M_NAME,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001255 sizeof(cap->driver));
1256 strlcpy(cap->card, S5P_JPEG_M2M_NAME " decoder",
1257 sizeof(cap->card));
1258 }
Javier Martinez Canillas3b2aa382016-06-16 18:40:32 -03001259 snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
1260 dev_name(ctx->jpeg->dev));
Hans Verkuil8c17e5e2014-11-24 06:37:26 -03001261 cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M;
1262 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001263 return 0;
1264}
1265
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001266static int enum_fmt(struct s5p_jpeg_fmt *sjpeg_formats, int n,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001267 struct v4l2_fmtdesc *f, u32 type)
1268{
1269 int i, num = 0;
1270
1271 for (i = 0; i < n; ++i) {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001272 if (sjpeg_formats[i].flags & type) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001273 /* index-th format of type type found ? */
1274 if (num == f->index)
1275 break;
1276 /* Correct type but haven't reached our index yet,
1277 * just increment per-type index */
1278 ++num;
1279 }
1280 }
1281
1282 /* Format not found */
1283 if (i >= n)
1284 return -EINVAL;
1285
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001286 strlcpy(f->description, sjpeg_formats[i].name, sizeof(f->description));
1287 f->pixelformat = sjpeg_formats[i].fourcc;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001288
1289 return 0;
1290}
1291
1292static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
1293 struct v4l2_fmtdesc *f)
1294{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001295 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001296
1297 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001298 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1299 SJPEG_FMT_FLAG_ENC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001300
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001301 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1302 SJPEG_FMT_FLAG_DEC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001303}
1304
1305static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
1306 struct v4l2_fmtdesc *f)
1307{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001308 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001309
1310 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001311 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1312 SJPEG_FMT_FLAG_ENC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001313
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001314 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1315 SJPEG_FMT_FLAG_DEC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001316}
1317
1318static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx,
1319 enum v4l2_buf_type type)
1320{
1321 if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1322 return &ctx->out_q;
1323 if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1324 return &ctx->cap_q;
1325
1326 return NULL;
1327}
1328
1329static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
1330{
1331 struct vb2_queue *vq;
1332 struct s5p_jpeg_q_data *q_data = NULL;
1333 struct v4l2_pix_format *pix = &f->fmt.pix;
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001334 struct s5p_jpeg_ctx *ct = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001335
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001336 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001337 if (!vq)
1338 return -EINVAL;
1339
1340 if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
1341 ct->mode == S5P_JPEG_DECODE && !ct->hdr_parsed)
1342 return -EINVAL;
1343 q_data = get_q_data(ct, f->type);
1344 BUG_ON(q_data == NULL);
1345
1346 pix->width = q_data->w;
1347 pix->height = q_data->h;
1348 pix->field = V4L2_FIELD_NONE;
1349 pix->pixelformat = q_data->fmt->fourcc;
1350 pix->bytesperline = 0;
1351 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
1352 u32 bpl = q_data->w;
1353 if (q_data->fmt->colplanes == 1)
1354 bpl = (bpl * q_data->fmt->depth) >> 3;
1355 pix->bytesperline = bpl;
1356 }
1357 pix->sizeimage = q_data->size;
1358
1359 return 0;
1360}
1361
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001362static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
1363 u32 pixelformat, unsigned int fmt_type)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001364{
Jacek Anaszewskib2451682014-04-10 04:32:11 -03001365 unsigned int k, fmt_flag;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001366
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001367 if (ctx->mode == S5P_JPEG_ENCODE)
1368 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
1369 SJPEG_FMT_FLAG_ENC_OUTPUT :
1370 SJPEG_FMT_FLAG_ENC_CAPTURE;
1371 else
1372 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
1373 SJPEG_FMT_FLAG_DEC_OUTPUT :
1374 SJPEG_FMT_FLAG_DEC_CAPTURE;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001375
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001376 for (k = 0; k < ARRAY_SIZE(sjpeg_formats); k++) {
1377 struct s5p_jpeg_fmt *fmt = &sjpeg_formats[k];
1378 if (fmt->fourcc == pixelformat &&
1379 fmt->flags & fmt_flag &&
Jacek Anaszewskib2451682014-04-10 04:32:11 -03001380 fmt->flags & ctx->jpeg->variant->fmt_ver_flag) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001381 return fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001382 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001383 }
1384
1385 return NULL;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001386}
1387
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001388static void jpeg_bound_align_image(struct s5p_jpeg_ctx *ctx,
1389 u32 *w, unsigned int wmin, unsigned int wmax,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001390 unsigned int walign,
1391 u32 *h, unsigned int hmin, unsigned int hmax,
1392 unsigned int halign)
1393{
1394 int width, height, w_step, h_step;
1395
1396 width = *w;
1397 height = *h;
1398
1399 w_step = 1 << walign;
1400 h_step = 1 << halign;
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001401
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001402 if (ctx->jpeg->variant->hw3250_compat) {
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001403 /*
1404 * Rightmost and bottommost pixels are cropped by the
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001405 * Exynos3250/compatible JPEG IP for RGB formats, for the
1406 * specific width and height values respectively. This
1407 * assignment will result in v4l_bound_align_image returning
1408 * dimensions reduced by 1 for the aforementioned cases.
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001409 */
1410 if (w_step == 4 && ((width & 3) == 1)) {
1411 wmax = width;
1412 hmax = height;
1413 }
1414 }
1415
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001416 v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
1417
1418 if (*w < width && (*w + w_step) < wmax)
1419 *w += w_step;
1420 if (*h < height && (*h + h_step) < hmax)
1421 *h += h_step;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001422}
1423
1424static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
1425 struct s5p_jpeg_ctx *ctx, int q_type)
1426{
1427 struct v4l2_pix_format *pix = &f->fmt.pix;
1428
1429 if (pix->field == V4L2_FIELD_ANY)
1430 pix->field = V4L2_FIELD_NONE;
1431 else if (pix->field != V4L2_FIELD_NONE)
1432 return -EINVAL;
1433
1434 /* V4L2 specification suggests the driver corrects the format struct
1435 * if any of the dimensions is unsupported */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001436 if (q_type == FMT_TYPE_OUTPUT)
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001437 jpeg_bound_align_image(ctx, &pix->width, S5P_JPEG_MIN_WIDTH,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001438 S5P_JPEG_MAX_WIDTH, 0,
1439 &pix->height, S5P_JPEG_MIN_HEIGHT,
1440 S5P_JPEG_MAX_HEIGHT, 0);
1441 else
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, fmt->h_align,
1444 &pix->height, S5P_JPEG_MIN_HEIGHT,
1445 S5P_JPEG_MAX_HEIGHT, fmt->v_align);
1446
1447 if (fmt->fourcc == V4L2_PIX_FMT_JPEG) {
1448 if (pix->sizeimage <= 0)
1449 pix->sizeimage = PAGE_SIZE;
1450 pix->bytesperline = 0;
1451 } else {
1452 u32 bpl = pix->bytesperline;
1453
1454 if (fmt->colplanes > 1 && bpl < pix->width)
1455 bpl = pix->width; /* planar */
1456
1457 if (fmt->colplanes == 1 && /* packed */
Jacek Anaszewskicc690902013-11-25 06:58:10 -03001458 (bpl << 3) / fmt->depth < pix->width)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001459 bpl = (pix->width * fmt->depth) >> 3;
1460
1461 pix->bytesperline = bpl;
1462 pix->sizeimage = (pix->width * pix->height * fmt->depth) >> 3;
1463 }
1464
1465 return 0;
1466}
1467
1468static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
1469 struct v4l2_format *f)
1470{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001471 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001472 struct v4l2_pix_format *pix = &f->fmt.pix;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001473 struct s5p_jpeg_fmt *fmt;
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001474 int ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001475
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001476 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
1477 FMT_TYPE_CAPTURE);
1478 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001479 v4l2_err(&ctx->jpeg->v4l2_dev,
1480 "Fourcc format (0x%08x) invalid.\n",
1481 f->fmt.pix.pixelformat);
1482 return -EINVAL;
1483 }
1484
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001485 if (!ctx->jpeg->variant->hw_ex4_compat || ctx->mode != S5P_JPEG_DECODE)
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001486 goto exit;
1487
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001488 /*
1489 * The exynos4x12 device requires resulting YUV image
1490 * subsampling not to be lower than the input jpeg subsampling.
1491 * If this requirement is not met then downgrade the requested
1492 * capture format to the one with subsampling equal to the input jpeg.
1493 */
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001494 if ((fmt->flags & SJPEG_FMT_NON_RGB) &&
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001495 (fmt->subsampling < ctx->subsampling)) {
1496 ret = s5p_jpeg_adjust_fourcc_to_subsampling(ctx->subsampling,
1497 fmt->fourcc,
1498 &pix->pixelformat,
1499 ctx);
1500 if (ret < 0)
1501 pix->pixelformat = V4L2_PIX_FMT_GREY;
1502
1503 fmt = s5p_jpeg_find_format(ctx, pix->pixelformat,
1504 FMT_TYPE_CAPTURE);
1505 }
1506
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001507 /*
1508 * Decompression of a JPEG file with 4:2:0 subsampling and odd
1509 * width to the YUV 4:2:0 compliant formats produces a raw image
1510 * with broken luma component. Adjust capture format to RGB565
1511 * in such a case.
1512 */
1513 if (ctx->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_420 &&
1514 (ctx->out_q.w & 1) &&
1515 (pix->pixelformat == V4L2_PIX_FMT_NV12 ||
1516 pix->pixelformat == V4L2_PIX_FMT_NV21 ||
1517 pix->pixelformat == V4L2_PIX_FMT_YUV420)) {
1518 pix->pixelformat = V4L2_PIX_FMT_RGB565;
1519 fmt = s5p_jpeg_find_format(ctx, pix->pixelformat,
1520 FMT_TYPE_CAPTURE);
1521 }
1522
1523exit:
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001524 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001525}
1526
1527static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
1528 struct v4l2_format *f)
1529{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001530 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001531 struct s5p_jpeg_fmt *fmt;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001532
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001533 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
1534 FMT_TYPE_OUTPUT);
1535 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001536 v4l2_err(&ctx->jpeg->v4l2_dev,
1537 "Fourcc format (0x%08x) invalid.\n",
1538 f->fmt.pix.pixelformat);
1539 return -EINVAL;
1540 }
1541
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001542 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001543}
1544
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001545static int exynos4_jpeg_get_output_buffer_size(struct s5p_jpeg_ctx *ctx,
1546 struct v4l2_format *f,
1547 int fmt_depth)
1548{
1549 struct v4l2_pix_format *pix = &f->fmt.pix;
1550 u32 pix_fmt = f->fmt.pix.pixelformat;
1551 int w = pix->width, h = pix->height, wh_align;
Andrzej Pietrasiewicz77401dd2015-12-08 12:39:08 -02001552 int padding = 0;
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001553
1554 if (pix_fmt == V4L2_PIX_FMT_RGB32 ||
Andrzej Pietrasiewicz77401dd2015-12-08 12:39:08 -02001555 pix_fmt == V4L2_PIX_FMT_RGB565 ||
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001556 pix_fmt == V4L2_PIX_FMT_NV24 ||
1557 pix_fmt == V4L2_PIX_FMT_NV42 ||
1558 pix_fmt == V4L2_PIX_FMT_NV12 ||
1559 pix_fmt == V4L2_PIX_FMT_NV21 ||
1560 pix_fmt == V4L2_PIX_FMT_YUV420)
1561 wh_align = 4;
1562 else
1563 wh_align = 1;
1564
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001565 jpeg_bound_align_image(ctx, &w, S5P_JPEG_MIN_WIDTH,
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001566 S5P_JPEG_MAX_WIDTH, wh_align,
1567 &h, S5P_JPEG_MIN_HEIGHT,
1568 S5P_JPEG_MAX_HEIGHT, wh_align);
1569
Andrzej Pietrasiewicz77401dd2015-12-08 12:39:08 -02001570 if (ctx->jpeg->variant->version == SJPEG_EXYNOS4)
1571 padding = PAGE_SIZE;
1572
1573 return (w * h * fmt_depth >> 3) + padding;
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001574}
1575
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001576static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx,
1577 struct v4l2_rect *r);
1578
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001579static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
1580{
1581 struct vb2_queue *vq;
1582 struct s5p_jpeg_q_data *q_data = NULL;
1583 struct v4l2_pix_format *pix = &f->fmt.pix;
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001584 struct v4l2_ctrl *ctrl_subs;
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001585 struct v4l2_rect scale_rect;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001586 unsigned int f_type;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001587
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001588 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001589 if (!vq)
1590 return -EINVAL;
1591
1592 q_data = get_q_data(ct, f->type);
1593 BUG_ON(q_data == NULL);
1594
1595 if (vb2_is_busy(vq)) {
1596 v4l2_err(&ct->jpeg->v4l2_dev, "%s queue busy\n", __func__);
1597 return -EBUSY;
1598 }
1599
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001600 f_type = V4L2_TYPE_IS_OUTPUT(f->type) ?
1601 FMT_TYPE_OUTPUT : FMT_TYPE_CAPTURE;
1602
1603 q_data->fmt = s5p_jpeg_find_format(ct, pix->pixelformat, f_type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001604 q_data->w = pix->width;
1605 q_data->h = pix->height;
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001606 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
1607 /*
1608 * During encoding Exynos4x12 SoCs access wider memory area
1609 * than it results from Image_x and Image_y values written to
1610 * the JPEG_IMAGE_SIZE register. In order to avoid sysmmu
1611 * page fault calculate proper buffer size in such a case.
1612 */
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001613 if (ct->jpeg->variant->hw_ex4_compat &&
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001614 f_type == FMT_TYPE_OUTPUT && ct->mode == S5P_JPEG_ENCODE)
1615 q_data->size = exynos4_jpeg_get_output_buffer_size(ct,
1616 f,
1617 q_data->fmt->depth);
1618 else
1619 q_data->size = q_data->w * q_data->h *
1620 q_data->fmt->depth >> 3;
1621 } else {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001622 q_data->size = pix->sizeimage;
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001623 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001624
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001625 if (f_type == FMT_TYPE_OUTPUT) {
1626 ctrl_subs = v4l2_ctrl_find(&ct->ctrl_handler,
1627 V4L2_CID_JPEG_CHROMA_SUBSAMPLING);
1628 if (ctrl_subs)
1629 v4l2_ctrl_s_ctrl(ctrl_subs, q_data->fmt->subsampling);
Jacek Anaszewskidfd96902014-07-11 12:19:46 -03001630 ct->crop_altered = false;
1631 }
1632
1633 /*
1634 * For decoding init crop_rect with capture buffer dimmensions which
1635 * contain aligned dimensions of the input JPEG image and do it only
1636 * if crop rectangle hasn't been altered by the user space e.g. with
1637 * S_SELECTION ioctl. For encoding assign output buffer dimensions.
1638 */
1639 if (!ct->crop_altered &&
1640 ((ct->mode == S5P_JPEG_DECODE && f_type == FMT_TYPE_CAPTURE) ||
1641 (ct->mode == S5P_JPEG_ENCODE && f_type == FMT_TYPE_OUTPUT))) {
1642 ct->crop_rect.width = pix->width;
1643 ct->crop_rect.height = pix->height;
1644 }
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001645
1646 /*
1647 * Prevent downscaling to YUV420 format by more than 2
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001648 * for Exynos3250/compatible SoC as it produces broken raw image
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001649 * in such cases.
1650 */
1651 if (ct->mode == S5P_JPEG_DECODE &&
1652 f_type == FMT_TYPE_CAPTURE &&
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001653 ct->jpeg->variant->hw3250_compat &&
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001654 pix->pixelformat == V4L2_PIX_FMT_YUV420 &&
1655 ct->scale_factor > 2) {
1656 scale_rect.width = ct->out_q.w / 2;
1657 scale_rect.height = ct->out_q.h / 2;
1658 exynos3250_jpeg_try_downscale(ct, &scale_rect);
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001659 }
1660
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001661 return 0;
1662}
1663
1664static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
1665 struct v4l2_format *f)
1666{
1667 int ret;
1668
1669 ret = s5p_jpeg_try_fmt_vid_cap(file, priv, f);
1670 if (ret)
1671 return ret;
1672
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001673 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001674}
1675
1676static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
1677 struct v4l2_format *f)
1678{
1679 int ret;
1680
1681 ret = s5p_jpeg_try_fmt_vid_out(file, priv, f);
1682 if (ret)
1683 return ret;
1684
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001685 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001686}
1687
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001688static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx,
1689 struct v4l2_rect *r)
1690{
1691 int w_ratio, h_ratio, scale_factor, cur_ratio, i;
1692
1693 w_ratio = ctx->out_q.w / r->width;
1694 h_ratio = ctx->out_q.h / r->height;
1695
1696 scale_factor = w_ratio > h_ratio ? w_ratio : h_ratio;
1697 scale_factor = clamp_val(scale_factor, 1, 8);
1698
1699 /* Align scale ratio to the nearest power of 2 */
1700 for (i = 0; i <= 3; ++i) {
1701 cur_ratio = 1 << i;
1702 if (scale_factor <= cur_ratio) {
1703 ctx->scale_factor = cur_ratio;
1704 break;
1705 }
1706 }
1707
1708 r->width = round_down(ctx->out_q.w / ctx->scale_factor, 2);
1709 r->height = round_down(ctx->out_q.h / ctx->scale_factor, 2);
1710
1711 ctx->crop_rect.width = r->width;
1712 ctx->crop_rect.height = r->height;
1713 ctx->crop_rect.left = 0;
1714 ctx->crop_rect.top = 0;
1715
1716 ctx->crop_altered = true;
1717
1718 return 0;
1719}
1720
1721/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */
1722static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
1723{
1724 if (a->left < b->left || a->top < b->top)
1725 return 0;
1726 if (a->left + a->width > b->left + b->width)
1727 return 0;
1728 if (a->top + a->height > b->top + b->height)
1729 return 0;
1730
1731 return 1;
1732}
1733
1734static int exynos3250_jpeg_try_crop(struct s5p_jpeg_ctx *ctx,
1735 struct v4l2_rect *r)
1736{
1737 struct v4l2_rect base_rect;
1738 int w_step, h_step;
1739
1740 switch (ctx->cap_q.fmt->fourcc) {
1741 case V4L2_PIX_FMT_NV12:
1742 case V4L2_PIX_FMT_NV21:
1743 w_step = 1;
1744 h_step = 2;
1745 break;
1746 case V4L2_PIX_FMT_YUV420:
1747 w_step = 2;
1748 h_step = 2;
1749 break;
1750 default:
1751 w_step = 1;
1752 h_step = 1;
1753 break;
1754 }
1755
1756 base_rect.top = 0;
1757 base_rect.left = 0;
1758 base_rect.width = ctx->out_q.w;
1759 base_rect.height = ctx->out_q.h;
1760
1761 r->width = round_down(r->width, w_step);
1762 r->height = round_down(r->height, h_step);
1763 r->left = round_down(r->left, 2);
1764 r->top = round_down(r->top, 2);
1765
1766 if (!enclosed_rectangle(r, &base_rect))
1767 return -EINVAL;
1768
1769 ctx->crop_rect.left = r->left;
1770 ctx->crop_rect.top = r->top;
1771 ctx->crop_rect.width = r->width;
1772 ctx->crop_rect.height = r->height;
1773
1774 ctx->crop_altered = true;
1775
1776 return 0;
1777}
1778
1779/*
1780 * V4L2 controls
1781 */
1782
Sachin Kamat9f3bd322012-05-10 03:38:40 -03001783static int s5p_jpeg_g_selection(struct file *file, void *priv,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001784 struct v4l2_selection *s)
1785{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001786 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001787
1788 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
Jacek Anaszewski38a6ef32014-04-10 04:32:15 -03001789 s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001790 return -EINVAL;
1791
1792 /* For JPEG blob active == default == bounds */
1793 switch (s->target) {
Sylwester Nawrockic1334822012-05-20 11:17:12 -03001794 case V4L2_SEL_TGT_CROP:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001795 case V4L2_SEL_TGT_CROP_BOUNDS:
1796 case V4L2_SEL_TGT_CROP_DEFAULT:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001797 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
1798 s->r.width = ctx->out_q.w;
1799 s->r.height = ctx->out_q.h;
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001800 s->r.left = 0;
1801 s->r.top = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001802 break;
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001803 case V4L2_SEL_TGT_COMPOSE:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001804 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
1805 case V4L2_SEL_TGT_COMPOSE_PADDED:
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001806 s->r.width = ctx->crop_rect.width;
1807 s->r.height = ctx->crop_rect.height;
1808 s->r.left = ctx->crop_rect.left;
1809 s->r.top = ctx->crop_rect.top;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001810 break;
1811 default:
1812 return -EINVAL;
1813 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001814 return 0;
1815}
1816
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001817/*
1818 * V4L2 controls
1819 */
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001820static int s5p_jpeg_s_selection(struct file *file, void *fh,
1821 struct v4l2_selection *s)
1822{
1823 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
1824 struct v4l2_rect *rect = &s->r;
1825 int ret = -EINVAL;
1826
1827 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1828 return -EINVAL;
1829
1830 if (s->target == V4L2_SEL_TGT_COMPOSE) {
1831 if (ctx->mode != S5P_JPEG_DECODE)
1832 return -EINVAL;
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001833 if (ctx->jpeg->variant->hw3250_compat)
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001834 ret = exynos3250_jpeg_try_downscale(ctx, rect);
1835 } else if (s->target == V4L2_SEL_TGT_CROP) {
1836 if (ctx->mode != S5P_JPEG_ENCODE)
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_crop(ctx, rect);
1840 }
1841
1842 return ret;
1843}
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001844
1845static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001846{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001847 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1848 struct s5p_jpeg *jpeg = ctx->jpeg;
1849 unsigned long flags;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001850
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001851 switch (ctrl->id) {
1852 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1853 spin_lock_irqsave(&jpeg->slock, flags);
Jacek Anaszewski303b0a92013-12-18 11:14:00 -03001854 ctrl->val = s5p_jpeg_to_user_subsampling(ctx);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001855 spin_unlock_irqrestore(&jpeg->slock, flags);
1856 break;
1857 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001858
1859 return 0;
1860}
1861
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001862static int s5p_jpeg_adjust_subs_ctrl(struct s5p_jpeg_ctx *ctx, int *ctrl_val)
1863{
1864 switch (ctx->jpeg->variant->version) {
1865 case SJPEG_S5P:
1866 return 0;
1867 case SJPEG_EXYNOS3250:
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001868 case SJPEG_EXYNOS5420:
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001869 /*
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001870 * The exynos3250/compatible device can produce JPEG image only
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001871 * of 4:4:4 subsampling when given RGB32 source image.
1872 */
1873 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB32)
1874 *ctrl_val = 0;
1875 break;
1876 case SJPEG_EXYNOS4:
1877 /*
1878 * The exynos4x12 device requires input raw image fourcc
1879 * to be V4L2_PIX_FMT_GREY if gray jpeg format
1880 * is to be set.
1881 */
1882 if (ctx->out_q.fmt->fourcc != V4L2_PIX_FMT_GREY &&
1883 *ctrl_val == V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY)
1884 return -EINVAL;
1885 break;
1886 }
1887
1888 /*
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001889 * The exynos4x12 and exynos3250/compatible devices require resulting
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001890 * jpeg subsampling not to be lower than the input raw image
1891 * subsampling.
1892 */
1893 if (ctx->out_q.fmt->subsampling > *ctrl_val)
1894 *ctrl_val = ctx->out_q.fmt->subsampling;
1895
1896 return 0;
1897}
1898
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001899static int s5p_jpeg_try_ctrl(struct v4l2_ctrl *ctrl)
1900{
1901 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1902 unsigned long flags;
1903 int ret = 0;
1904
1905 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1906
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001907 if (ctrl->id == V4L2_CID_JPEG_CHROMA_SUBSAMPLING)
1908 ret = s5p_jpeg_adjust_subs_ctrl(ctx, &ctrl->val);
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001909
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001910 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1911 return ret;
1912}
1913
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001914static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001915{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001916 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1917 unsigned long flags;
1918
1919 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1920
1921 switch (ctrl->id) {
1922 case V4L2_CID_JPEG_COMPRESSION_QUALITY:
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001923 ctx->compr_quality = ctrl->val;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001924 break;
1925 case V4L2_CID_JPEG_RESTART_INTERVAL:
1926 ctx->restart_interval = ctrl->val;
1927 break;
1928 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1929 ctx->subsampling = ctrl->val;
1930 break;
1931 }
1932
1933 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1934 return 0;
1935}
1936
1937static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
1938 .g_volatile_ctrl = s5p_jpeg_g_volatile_ctrl,
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001939 .try_ctrl = s5p_jpeg_try_ctrl,
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001940 .s_ctrl = s5p_jpeg_s_ctrl,
1941};
1942
1943static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
1944{
1945 unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */
1946 struct v4l2_ctrl *ctrl;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001947 int ret;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001948
1949 v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
1950
1951 if (ctx->mode == S5P_JPEG_ENCODE) {
1952 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1953 V4L2_CID_JPEG_COMPRESSION_QUALITY,
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001954 0, 3, 1, S5P_JPEG_COMPR_QUAL_WORST);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001955
1956 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1957 V4L2_CID_JPEG_RESTART_INTERVAL,
1958 0, 3, 0xffff, 0);
Jacek Anaszewskifdf9e2b2013-11-21 13:33:41 -03001959 if (ctx->jpeg->variant->version == SJPEG_S5P)
1960 mask = ~0x06; /* 422, 420 */
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001961 }
1962
1963 ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1964 V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
1965 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask,
1966 V4L2_JPEG_CHROMA_SUBSAMPLING_422);
1967
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001968 if (ctx->ctrl_handler.error) {
1969 ret = ctx->ctrl_handler.error;
1970 goto error_free;
1971 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001972
1973 if (ctx->mode == S5P_JPEG_DECODE)
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001974 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
1975 V4L2_CTRL_FLAG_READ_ONLY;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001976
1977 ret = v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
1978 if (ret < 0)
1979 goto error_free;
1980
1981 return ret;
1982
1983error_free:
1984 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
1985 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001986}
1987
1988static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
1989 .vidioc_querycap = s5p_jpeg_querycap,
1990
1991 .vidioc_enum_fmt_vid_cap = s5p_jpeg_enum_fmt_vid_cap,
1992 .vidioc_enum_fmt_vid_out = s5p_jpeg_enum_fmt_vid_out,
1993
1994 .vidioc_g_fmt_vid_cap = s5p_jpeg_g_fmt,
1995 .vidioc_g_fmt_vid_out = s5p_jpeg_g_fmt,
1996
1997 .vidioc_try_fmt_vid_cap = s5p_jpeg_try_fmt_vid_cap,
1998 .vidioc_try_fmt_vid_out = s5p_jpeg_try_fmt_vid_out,
1999
2000 .vidioc_s_fmt_vid_cap = s5p_jpeg_s_fmt_vid_cap,
2001 .vidioc_s_fmt_vid_out = s5p_jpeg_s_fmt_vid_out,
2002
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002003 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
2004 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
2005 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
2006 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002007
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002008 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
2009 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002010
2011 .vidioc_g_selection = s5p_jpeg_g_selection,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002012 .vidioc_s_selection = s5p_jpeg_s_selection,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002013};
2014
2015/*
2016 * ============================================================================
2017 * mem2mem callbacks
2018 * ============================================================================
2019 */
2020
2021static void s5p_jpeg_device_run(void *priv)
2022{
2023 struct s5p_jpeg_ctx *ctx = priv;
2024 struct s5p_jpeg *jpeg = ctx->jpeg;
2025 struct vb2_buffer *src_buf, *dst_buf;
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002026 unsigned long src_addr, dst_addr, flags;
2027
2028 spin_lock_irqsave(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002029
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002030 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2031 dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002032 src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
2033 dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
2034
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002035 s5p_jpeg_reset(jpeg->regs);
2036 s5p_jpeg_poweron(jpeg->regs);
2037 s5p_jpeg_proc_mode(jpeg->regs, ctx->mode);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002038 if (ctx->mode == S5P_JPEG_ENCODE) {
2039 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002040 s5p_jpeg_input_raw_mode(jpeg->regs,
2041 S5P_JPEG_RAW_IN_565);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002042 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002043 s5p_jpeg_input_raw_mode(jpeg->regs,
2044 S5P_JPEG_RAW_IN_422);
2045 s5p_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
2046 s5p_jpeg_dri(jpeg->regs, ctx->restart_interval);
2047 s5p_jpeg_x(jpeg->regs, ctx->out_q.w);
2048 s5p_jpeg_y(jpeg->regs, ctx->out_q.h);
2049 s5p_jpeg_imgadr(jpeg->regs, src_addr);
2050 s5p_jpeg_jpgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002051
2052 /* ultimately comes from sizeimage from userspace */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002053 s5p_jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002054
2055 /* JPEG RGB to YCbCr conversion matrix */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002056 s5p_jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11);
2057 s5p_jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12);
2058 s5p_jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13);
2059 s5p_jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21);
2060 s5p_jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22);
2061 s5p_jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23);
2062 s5p_jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31);
2063 s5p_jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32);
2064 s5p_jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002065
2066 /*
2067 * JPEG IP allows storing 4 quantization tables
2068 * We fill table 0 for luma and table 1 for chroma
2069 */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03002070 s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
2071 s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002072 /* use table 0 for Y */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002073 s5p_jpeg_qtbl(jpeg->regs, 1, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002074 /* use table 1 for Cb and Cr*/
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002075 s5p_jpeg_qtbl(jpeg->regs, 2, 1);
2076 s5p_jpeg_qtbl(jpeg->regs, 3, 1);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002077
2078 /* Y, Cb, Cr use Huffman table 0 */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002079 s5p_jpeg_htbl_ac(jpeg->regs, 1);
2080 s5p_jpeg_htbl_dc(jpeg->regs, 1);
2081 s5p_jpeg_htbl_ac(jpeg->regs, 2);
2082 s5p_jpeg_htbl_dc(jpeg->regs, 2);
2083 s5p_jpeg_htbl_ac(jpeg->regs, 3);
2084 s5p_jpeg_htbl_dc(jpeg->regs, 3);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03002085 } else { /* S5P_JPEG_DECODE */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002086 s5p_jpeg_rst_int_enable(jpeg->regs, true);
2087 s5p_jpeg_data_num_int_enable(jpeg->regs, true);
2088 s5p_jpeg_final_mcu_num_int_enable(jpeg->regs, true);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03002089 if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002090 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03002091 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002092 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420);
2093 s5p_jpeg_jpgadr(jpeg->regs, src_addr);
2094 s5p_jpeg_imgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002095 }
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002096
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002097 s5p_jpeg_start(jpeg->regs);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002098
2099 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002100}
2101
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002102static void exynos4_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
2103{
2104 struct s5p_jpeg *jpeg = ctx->jpeg;
2105 struct s5p_jpeg_fmt *fmt;
2106 struct vb2_buffer *vb;
Jacek Anaszewski12b05562015-03-05 10:56:25 -03002107 struct s5p_jpeg_addr jpeg_addr = {};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002108 u32 pix_size, padding_bytes = 0;
2109
Tony K Nadackalcb0c3f52014-12-17 04:21:21 -03002110 jpeg_addr.cb = 0;
2111 jpeg_addr.cr = 0;
2112
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002113 pix_size = ctx->cap_q.w * ctx->cap_q.h;
2114
2115 if (ctx->mode == S5P_JPEG_ENCODE) {
2116 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2117 fmt = ctx->out_q.fmt;
2118 if (ctx->out_q.w % 2 && fmt->h_align > 0)
2119 padding_bytes = ctx->out_q.h;
2120 } else {
2121 fmt = ctx->cap_q.fmt;
2122 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
2123 }
2124
2125 jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
2126
2127 if (fmt->colplanes == 2) {
2128 jpeg_addr.cb = jpeg_addr.y + pix_size - padding_bytes;
2129 } else if (fmt->colplanes == 3) {
2130 jpeg_addr.cb = jpeg_addr.y + pix_size;
2131 if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
2132 jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
2133 else
2134 jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
2135 }
2136
2137 exynos4_jpeg_set_frame_buf_address(jpeg->regs, &jpeg_addr);
2138}
2139
2140static void exynos4_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
2141{
2142 struct s5p_jpeg *jpeg = ctx->jpeg;
2143 struct vb2_buffer *vb;
2144 unsigned int jpeg_addr = 0;
2145
2146 if (ctx->mode == S5P_JPEG_ENCODE)
2147 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
2148 else
2149 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2150
2151 jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002152 if (jpeg->variant->version == SJPEG_EXYNOS5433 &&
2153 ctx->mode == S5P_JPEG_DECODE)
2154 jpeg_addr += ctx->out_q.sos;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002155 exynos4_jpeg_set_stream_buf_address(jpeg->regs, jpeg_addr);
2156}
2157
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002158static inline void exynos4_jpeg_set_img_fmt(void __iomem *base,
2159 unsigned int img_fmt)
2160{
2161 __exynos4_jpeg_set_img_fmt(base, img_fmt, SJPEG_EXYNOS4);
2162}
2163
2164static inline void exynos5433_jpeg_set_img_fmt(void __iomem *base,
2165 unsigned int img_fmt)
2166{
2167 __exynos4_jpeg_set_img_fmt(base, img_fmt, SJPEG_EXYNOS5433);
2168}
2169
2170static inline void exynos4_jpeg_set_enc_out_fmt(void __iomem *base,
2171 unsigned int out_fmt)
2172{
2173 __exynos4_jpeg_set_enc_out_fmt(base, out_fmt, SJPEG_EXYNOS4);
2174}
2175
2176static inline void exynos5433_jpeg_set_enc_out_fmt(void __iomem *base,
2177 unsigned int out_fmt)
2178{
2179 __exynos4_jpeg_set_enc_out_fmt(base, out_fmt, SJPEG_EXYNOS5433);
2180}
2181
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002182static void exynos4_jpeg_device_run(void *priv)
2183{
2184 struct s5p_jpeg_ctx *ctx = priv;
2185 struct s5p_jpeg *jpeg = ctx->jpeg;
2186 unsigned int bitstream_size;
2187 unsigned long flags;
2188
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002189 spin_lock_irqsave(&jpeg->slock, flags);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002190
2191 if (ctx->mode == S5P_JPEG_ENCODE) {
2192 exynos4_jpeg_sw_reset(jpeg->regs);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002193 exynos4_jpeg_set_interrupt(jpeg->regs, jpeg->variant->version);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002194 exynos4_jpeg_set_huf_table_enable(jpeg->regs, 1);
2195
2196 exynos4_jpeg_set_huff_tbl(jpeg->regs);
2197
2198 /*
2199 * JPEG IP allows storing 4 quantization tables
2200 * We fill table 0 for luma and table 1 for chroma
2201 */
2202 exynos4_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
2203 exynos4_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
2204
2205 exynos4_jpeg_set_encode_tbl_select(jpeg->regs,
2206 ctx->compr_quality);
2207 exynos4_jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w,
2208 ctx->cap_q.h);
2209
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002210 if (ctx->jpeg->variant->version == SJPEG_EXYNOS4) {
2211 exynos4_jpeg_set_enc_out_fmt(jpeg->regs,
2212 ctx->subsampling);
2213 exynos4_jpeg_set_img_fmt(jpeg->regs,
2214 ctx->out_q.fmt->fourcc);
2215 } else {
2216 exynos5433_jpeg_set_enc_out_fmt(jpeg->regs,
2217 ctx->subsampling);
2218 exynos5433_jpeg_set_img_fmt(jpeg->regs,
2219 ctx->out_q.fmt->fourcc);
2220 }
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002221 exynos4_jpeg_set_img_addr(ctx);
2222 exynos4_jpeg_set_jpeg_addr(ctx);
2223 exynos4_jpeg_set_encode_hoff_cnt(jpeg->regs,
2224 ctx->out_q.fmt->fourcc);
2225 } else {
2226 exynos4_jpeg_sw_reset(jpeg->regs);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002227 exynos4_jpeg_set_interrupt(jpeg->regs,
2228 jpeg->variant->version);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002229 exynos4_jpeg_set_img_addr(ctx);
2230 exynos4_jpeg_set_jpeg_addr(ctx);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002231
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002232 if (jpeg->variant->version == SJPEG_EXYNOS5433) {
2233 exynos4_jpeg_parse_huff_tbl(ctx);
2234 exynos4_jpeg_parse_decode_h_tbl(ctx);
2235
2236 exynos4_jpeg_parse_q_tbl(ctx);
2237 exynos4_jpeg_parse_decode_q_tbl(ctx);
2238
2239 exynos4_jpeg_set_huf_table_enable(jpeg->regs, 1);
2240
2241 exynos4_jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w,
2242 ctx->cap_q.h);
2243 exynos5433_jpeg_set_enc_out_fmt(jpeg->regs,
2244 ctx->subsampling);
2245 exynos5433_jpeg_set_img_fmt(jpeg->regs,
2246 ctx->cap_q.fmt->fourcc);
2247 bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 16);
2248 } else {
2249 exynos4_jpeg_set_img_fmt(jpeg->regs,
2250 ctx->cap_q.fmt->fourcc);
2251 bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 32);
2252 }
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002253
2254 exynos4_jpeg_set_dec_bitstream_size(jpeg->regs, bitstream_size);
2255 }
2256
2257 exynos4_jpeg_set_enc_dec_mode(jpeg->regs, ctx->mode);
2258
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002259 spin_unlock_irqrestore(&jpeg->slock, flags);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002260}
2261
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002262static void exynos3250_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
2263{
2264 struct s5p_jpeg *jpeg = ctx->jpeg;
2265 struct s5p_jpeg_fmt *fmt;
2266 struct vb2_buffer *vb;
Jacek Anaszewski12b05562015-03-05 10:56:25 -03002267 struct s5p_jpeg_addr jpeg_addr = {};
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002268 u32 pix_size;
2269
2270 pix_size = ctx->cap_q.w * ctx->cap_q.h;
2271
2272 if (ctx->mode == S5P_JPEG_ENCODE) {
2273 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2274 fmt = ctx->out_q.fmt;
2275 } else {
2276 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
2277 fmt = ctx->cap_q.fmt;
2278 }
2279
2280 jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
2281
2282 if (fmt->colplanes == 2) {
2283 jpeg_addr.cb = jpeg_addr.y + pix_size;
2284 } else if (fmt->colplanes == 3) {
2285 jpeg_addr.cb = jpeg_addr.y + pix_size;
2286 if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
2287 jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
2288 else
2289 jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
2290 }
2291
2292 exynos3250_jpeg_imgadr(jpeg->regs, &jpeg_addr);
2293}
2294
2295static void exynos3250_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
2296{
2297 struct s5p_jpeg *jpeg = ctx->jpeg;
2298 struct vb2_buffer *vb;
2299 unsigned int jpeg_addr = 0;
2300
2301 if (ctx->mode == S5P_JPEG_ENCODE)
2302 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
2303 else
2304 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2305
2306 jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
2307 exynos3250_jpeg_jpgadr(jpeg->regs, jpeg_addr);
2308}
2309
2310static void exynos3250_jpeg_device_run(void *priv)
2311{
2312 struct s5p_jpeg_ctx *ctx = priv;
2313 struct s5p_jpeg *jpeg = ctx->jpeg;
2314 unsigned long flags;
2315
2316 spin_lock_irqsave(&ctx->jpeg->slock, flags);
2317
2318 exynos3250_jpeg_reset(jpeg->regs);
2319 exynos3250_jpeg_set_dma_num(jpeg->regs);
2320 exynos3250_jpeg_poweron(jpeg->regs);
2321 exynos3250_jpeg_clk_set(jpeg->regs);
2322 exynos3250_jpeg_proc_mode(jpeg->regs, ctx->mode);
2323
2324 if (ctx->mode == S5P_JPEG_ENCODE) {
2325 exynos3250_jpeg_input_raw_fmt(jpeg->regs,
2326 ctx->out_q.fmt->fourcc);
2327 exynos3250_jpeg_dri(jpeg->regs, ctx->restart_interval);
2328
2329 /*
2330 * JPEG IP allows storing 4 quantization tables
2331 * We fill table 0 for luma and table 1 for chroma
2332 */
2333 s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
2334 s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
2335 /* use table 0 for Y */
2336 exynos3250_jpeg_qtbl(jpeg->regs, 1, 0);
2337 /* use table 1 for Cb and Cr*/
2338 exynos3250_jpeg_qtbl(jpeg->regs, 2, 1);
2339 exynos3250_jpeg_qtbl(jpeg->regs, 3, 1);
2340
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03002341 /*
2342 * Some SoCs require setting Huffman tables before each run
2343 */
2344 if (jpeg->variant->htbl_reinit) {
2345 s5p_jpeg_set_hdctbl(jpeg->regs);
2346 s5p_jpeg_set_hdctblg(jpeg->regs);
2347 s5p_jpeg_set_hactbl(jpeg->regs);
2348 s5p_jpeg_set_hactblg(jpeg->regs);
2349 }
2350
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002351 /* Y, Cb, Cr use Huffman table 0 */
2352 exynos3250_jpeg_htbl_ac(jpeg->regs, 1);
2353 exynos3250_jpeg_htbl_dc(jpeg->regs, 1);
2354 exynos3250_jpeg_htbl_ac(jpeg->regs, 2);
2355 exynos3250_jpeg_htbl_dc(jpeg->regs, 2);
2356 exynos3250_jpeg_htbl_ac(jpeg->regs, 3);
2357 exynos3250_jpeg_htbl_dc(jpeg->regs, 3);
2358
2359 exynos3250_jpeg_set_x(jpeg->regs, ctx->crop_rect.width);
2360 exynos3250_jpeg_set_y(jpeg->regs, ctx->crop_rect.height);
2361 exynos3250_jpeg_stride(jpeg->regs, ctx->out_q.fmt->fourcc,
2362 ctx->out_q.w);
2363 exynos3250_jpeg_offset(jpeg->regs, ctx->crop_rect.left,
2364 ctx->crop_rect.top);
2365 exynos3250_jpeg_set_img_addr(ctx);
2366 exynos3250_jpeg_set_jpeg_addr(ctx);
2367 exynos3250_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
2368
2369 /* ultimately comes from sizeimage from userspace */
2370 exynos3250_jpeg_enc_stream_bound(jpeg->regs, ctx->cap_q.size);
2371
2372 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565 ||
2373 ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565X ||
2374 ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB32)
2375 exynos3250_jpeg_set_y16(jpeg->regs, true);
2376 } else {
2377 exynos3250_jpeg_set_img_addr(ctx);
2378 exynos3250_jpeg_set_jpeg_addr(ctx);
2379 exynos3250_jpeg_stride(jpeg->regs, ctx->cap_q.fmt->fourcc,
2380 ctx->cap_q.w);
2381 exynos3250_jpeg_offset(jpeg->regs, 0, 0);
2382 exynos3250_jpeg_dec_scaling_ratio(jpeg->regs,
2383 ctx->scale_factor);
2384 exynos3250_jpeg_dec_stream_size(jpeg->regs, ctx->out_q.size);
2385 exynos3250_jpeg_output_raw_fmt(jpeg->regs,
2386 ctx->cap_q.fmt->fourcc);
2387 }
2388
2389 exynos3250_jpeg_interrupts_enable(jpeg->regs);
2390
2391 /* JPEG RGB to YCbCr conversion matrix */
2392 exynos3250_jpeg_coef(jpeg->regs, ctx->mode);
2393
2394 exynos3250_jpeg_set_timer(jpeg->regs, EXYNOS3250_IRQ_TIMEOUT);
2395 jpeg->irq_status = 0;
2396 exynos3250_jpeg_start(jpeg->regs);
2397
2398 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
2399}
2400
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002401static int s5p_jpeg_job_ready(void *priv)
2402{
2403 struct s5p_jpeg_ctx *ctx = priv;
2404
2405 if (ctx->mode == S5P_JPEG_DECODE)
2406 return ctx->hdr_parsed;
2407 return 1;
2408}
2409
2410static void s5p_jpeg_job_abort(void *priv)
2411{
2412}
2413
2414static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = {
2415 .device_run = s5p_jpeg_device_run,
2416 .job_ready = s5p_jpeg_job_ready,
2417 .job_abort = s5p_jpeg_job_abort,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002418};
2419
2420static struct v4l2_m2m_ops exynos3250_jpeg_m2m_ops = {
2421 .device_run = exynos3250_jpeg_device_run,
2422 .job_ready = s5p_jpeg_job_ready,
2423 .job_abort = s5p_jpeg_job_abort,
2424};
2425
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03002426static struct v4l2_m2m_ops exynos4_jpeg_m2m_ops = {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002427 .device_run = exynos4_jpeg_device_run,
2428 .job_ready = s5p_jpeg_job_ready,
2429 .job_abort = s5p_jpeg_job_abort,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002430};
2431
2432/*
2433 * ============================================================================
2434 * Queue operations
2435 * ============================================================================
2436 */
2437
Marek Szyprowski719c1742012-01-13 05:12:38 -03002438static int s5p_jpeg_queue_setup(struct vb2_queue *vq,
Marek Szyprowski719c1742012-01-13 05:12:38 -03002439 unsigned int *nbuffers, unsigned int *nplanes,
Hans Verkuil36c0f8b2016-04-15 09:15:05 -03002440 unsigned int sizes[], struct device *alloc_devs[])
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002441{
2442 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
2443 struct s5p_jpeg_q_data *q_data = NULL;
2444 unsigned int size, count = *nbuffers;
2445
2446 q_data = get_q_data(ctx, vq->type);
2447 BUG_ON(q_data == NULL);
2448
2449 size = q_data->size;
2450
2451 /*
2452 * header is parsed during decoding and parsed information stored
2453 * in the context so we do not allow another buffer to overwrite it
2454 */
2455 if (ctx->mode == S5P_JPEG_DECODE)
2456 count = 1;
2457
2458 *nbuffers = count;
2459 *nplanes = 1;
2460 sizes[0] = size;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002461
2462 return 0;
2463}
2464
2465static int s5p_jpeg_buf_prepare(struct vb2_buffer *vb)
2466{
2467 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
2468 struct s5p_jpeg_q_data *q_data = NULL;
2469
2470 q_data = get_q_data(ctx, vb->vb2_queue->type);
2471 BUG_ON(q_data == NULL);
2472
2473 if (vb2_plane_size(vb, 0) < q_data->size) {
2474 pr_err("%s data will not fit into plane (%lu < %lu)\n",
2475 __func__, vb2_plane_size(vb, 0),
2476 (long)q_data->size);
2477 return -EINVAL;
2478 }
2479
2480 vb2_set_plane_payload(vb, 0, q_data->size);
2481
2482 return 0;
2483}
2484
2485static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
2486{
Junghak Sung2d700712015-09-22 10:30:30 -03002487 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002488 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
2489
2490 if (ctx->mode == S5P_JPEG_DECODE &&
2491 vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
2492 struct s5p_jpeg_q_data tmp, *q_data;
2493 ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp,
2494 (unsigned long)vb2_plane_vaddr(vb, 0),
2495 min((unsigned long)ctx->out_q.size,
Jacek Anaszewskif8433962013-11-21 13:33:09 -03002496 vb2_get_plane_payload(vb, 0)), ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002497 if (!ctx->hdr_parsed) {
2498 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
2499 return;
2500 }
2501
2502 q_data = &ctx->out_q;
2503 q_data->w = tmp.w;
2504 q_data->h = tmp.h;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002505 q_data->sos = tmp.sos;
2506 memcpy(q_data->dht.marker, tmp.dht.marker,
2507 sizeof(tmp.dht.marker));
2508 memcpy(q_data->dht.len, tmp.dht.len, sizeof(tmp.dht.len));
2509 q_data->dht.n = tmp.dht.n;
2510 memcpy(q_data->dqt.marker, tmp.dqt.marker,
2511 sizeof(tmp.dqt.marker));
2512 memcpy(q_data->dqt.len, tmp.dqt.len, sizeof(tmp.dqt.len));
2513 q_data->dqt.n = tmp.dqt.n;
2514 q_data->sof = tmp.sof;
2515 q_data->sof_len = tmp.sof_len;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002516
2517 q_data = &ctx->cap_q;
2518 q_data->w = tmp.w;
2519 q_data->h = tmp.h;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002520 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002521
Junghak Sung2d700712015-09-22 10:30:30 -03002522 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002523}
2524
2525static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
2526{
2527 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
2528 int ret;
2529
2530 ret = pm_runtime_get_sync(ctx->jpeg->dev);
2531
2532 return ret > 0 ? 0 : ret;
2533}
2534
Hans Verkuile37559b2014-04-17 02:47:21 -03002535static void s5p_jpeg_stop_streaming(struct vb2_queue *q)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002536{
2537 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
2538
2539 pm_runtime_put(ctx->jpeg->dev);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002540}
2541
2542static struct vb2_ops s5p_jpeg_qops = {
2543 .queue_setup = s5p_jpeg_queue_setup,
2544 .buf_prepare = s5p_jpeg_buf_prepare,
2545 .buf_queue = s5p_jpeg_buf_queue,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002546 .wait_prepare = vb2_ops_wait_prepare,
2547 .wait_finish = vb2_ops_wait_finish,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002548 .start_streaming = s5p_jpeg_start_streaming,
2549 .stop_streaming = s5p_jpeg_stop_streaming,
2550};
2551
2552static int queue_init(void *priv, struct vb2_queue *src_vq,
2553 struct vb2_queue *dst_vq)
2554{
2555 struct s5p_jpeg_ctx *ctx = priv;
2556 int ret;
2557
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002558 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
2559 src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
2560 src_vq->drv_priv = ctx;
2561 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
2562 src_vq->ops = &s5p_jpeg_qops;
2563 src_vq->mem_ops = &vb2_dma_contig_memops;
Sakari Ailusade48682014-02-25 19:12:19 -03002564 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002565 src_vq->lock = &ctx->jpeg->lock;
Hans Verkuilc781e4a2016-02-15 14:25:09 -02002566 src_vq->dev = ctx->jpeg->dev;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002567
2568 ret = vb2_queue_init(src_vq);
2569 if (ret)
2570 return ret;
2571
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002572 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2573 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
2574 dst_vq->drv_priv = ctx;
2575 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
2576 dst_vq->ops = &s5p_jpeg_qops;
2577 dst_vq->mem_ops = &vb2_dma_contig_memops;
Sakari Ailusade48682014-02-25 19:12:19 -03002578 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002579 dst_vq->lock = &ctx->jpeg->lock;
Hans Verkuilc781e4a2016-02-15 14:25:09 -02002580 dst_vq->dev = ctx->jpeg->dev;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002581
2582 return vb2_queue_init(dst_vq);
2583}
2584
2585/*
2586 * ============================================================================
2587 * ISR
2588 * ============================================================================
2589 */
2590
2591static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
2592{
2593 struct s5p_jpeg *jpeg = dev_id;
2594 struct s5p_jpeg_ctx *curr_ctx;
Junghak Sung2d700712015-09-22 10:30:30 -03002595 struct vb2_v4l2_buffer *src_buf, *dst_buf;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002596 unsigned long payload_size = 0;
2597 enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
2598 bool enc_jpeg_too_large = false;
2599 bool timer_elapsed = false;
2600 bool op_completed = false;
2601
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002602 spin_lock(&jpeg->slock);
2603
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002604 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2605
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002606 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2607 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002608
2609 if (curr_ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002610 enc_jpeg_too_large = s5p_jpeg_enc_stream_stat(jpeg->regs);
2611 timer_elapsed = s5p_jpeg_timer_stat(jpeg->regs);
2612 op_completed = s5p_jpeg_result_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002613 if (curr_ctx->mode == S5P_JPEG_DECODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002614 op_completed = op_completed &&
2615 s5p_jpeg_stream_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002616
2617 if (enc_jpeg_too_large) {
2618 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002619 s5p_jpeg_clear_enc_stream_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002620 } else if (timer_elapsed) {
2621 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002622 s5p_jpeg_clear_timer_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002623 } else if (!op_completed) {
2624 state = VB2_BUF_STATE_ERROR;
2625 } else {
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002626 payload_size = s5p_jpeg_compressed_size(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002627 }
2628
Junghak Sung2d700712015-09-22 10:30:30 -03002629 dst_buf->timecode = src_buf->timecode;
Junghak Sungd6dd6452015-11-03 08:16:37 -02002630 dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
Junghak Sung2d700712015-09-22 10:30:30 -03002631 dst_buf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
2632 dst_buf->flags |=
2633 src_buf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
Kamil Debskiaca326a2013-04-24 10:08:02 -03002634
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002635 v4l2_m2m_buf_done(src_buf, state);
2636 if (curr_ctx->mode == S5P_JPEG_ENCODE)
Junghak Sung2d700712015-09-22 10:30:30 -03002637 vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload_size);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002638 v4l2_m2m_buf_done(dst_buf, state);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002639 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002640
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002641 curr_ctx->subsampling = s5p_jpeg_get_subsampling_mode(jpeg->regs);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002642 spin_unlock(&jpeg->slock);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03002643
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002644 s5p_jpeg_clear_int(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002645
2646 return IRQ_HANDLED;
2647}
2648
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002649static irqreturn_t exynos4_jpeg_irq(int irq, void *priv)
2650{
2651 unsigned int int_status;
Junghak Sung2d700712015-09-22 10:30:30 -03002652 struct vb2_v4l2_buffer *src_vb, *dst_vb;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002653 struct s5p_jpeg *jpeg = priv;
2654 struct s5p_jpeg_ctx *curr_ctx;
2655 unsigned long payload_size = 0;
2656
2657 spin_lock(&jpeg->slock);
2658
2659 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2660
2661 src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2662 dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
2663
2664 int_status = exynos4_jpeg_get_int_status(jpeg->regs);
2665
2666 if (int_status) {
2667 switch (int_status & 0x1f) {
2668 case 0x1:
2669 jpeg->irq_ret = ERR_PROT;
2670 break;
2671 case 0x2:
2672 jpeg->irq_ret = OK_ENC_OR_DEC;
2673 break;
2674 case 0x4:
2675 jpeg->irq_ret = ERR_DEC_INVALID_FORMAT;
2676 break;
2677 case 0x8:
2678 jpeg->irq_ret = ERR_MULTI_SCAN;
2679 break;
2680 case 0x10:
2681 jpeg->irq_ret = ERR_FRAME;
2682 break;
2683 default:
2684 jpeg->irq_ret = ERR_UNKNOWN;
2685 break;
2686 }
2687 } else {
2688 jpeg->irq_ret = ERR_UNKNOWN;
2689 }
2690
2691 if (jpeg->irq_ret == OK_ENC_OR_DEC) {
2692 if (curr_ctx->mode == S5P_JPEG_ENCODE) {
2693 payload_size = exynos4_jpeg_get_stream_size(jpeg->regs);
Junghak Sung2d700712015-09-22 10:30:30 -03002694 vb2_set_plane_payload(&dst_vb->vb2_buf,
2695 0, payload_size);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002696 }
2697 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
2698 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
2699 } else {
2700 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
2701 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
2702 }
2703
2704 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002705 if (jpeg->variant->version == SJPEG_EXYNOS4)
2706 curr_ctx->subsampling = exynos4_jpeg_get_frame_fmt(jpeg->regs);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002707
2708 spin_unlock(&jpeg->slock);
2709 return IRQ_HANDLED;
2710}
2711
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002712static irqreturn_t exynos3250_jpeg_irq(int irq, void *dev_id)
2713{
2714 struct s5p_jpeg *jpeg = dev_id;
2715 struct s5p_jpeg_ctx *curr_ctx;
Junghak Sung2d700712015-09-22 10:30:30 -03002716 struct vb2_v4l2_buffer *src_buf, *dst_buf;
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002717 unsigned long payload_size = 0;
2718 enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
2719 bool interrupt_timeout = false;
2720 u32 irq_status;
2721
2722 spin_lock(&jpeg->slock);
2723
2724 irq_status = exynos3250_jpeg_get_timer_status(jpeg->regs);
2725 if (irq_status & EXYNOS3250_TIMER_INT_STAT) {
2726 exynos3250_jpeg_clear_timer_status(jpeg->regs);
2727 interrupt_timeout = true;
2728 dev_err(jpeg->dev, "Interrupt timeout occurred.\n");
2729 }
2730
2731 irq_status = exynos3250_jpeg_get_int_status(jpeg->regs);
2732 exynos3250_jpeg_clear_int_status(jpeg->regs, irq_status);
2733
2734 jpeg->irq_status |= irq_status;
2735
2736 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2737
2738 if (!curr_ctx)
2739 goto exit_unlock;
2740
2741 if ((irq_status & EXYNOS3250_HEADER_STAT) &&
2742 (curr_ctx->mode == S5P_JPEG_DECODE)) {
2743 exynos3250_jpeg_rstart(jpeg->regs);
2744 goto exit_unlock;
2745 }
2746
2747 if (jpeg->irq_status & (EXYNOS3250_JPEG_DONE |
2748 EXYNOS3250_WDMA_DONE |
2749 EXYNOS3250_RDMA_DONE |
2750 EXYNOS3250_RESULT_STAT))
2751 payload_size = exynos3250_jpeg_compressed_size(jpeg->regs);
2752 else if (interrupt_timeout)
2753 state = VB2_BUF_STATE_ERROR;
2754 else
2755 goto exit_unlock;
2756
2757 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2758 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
2759
Junghak Sung2d700712015-09-22 10:30:30 -03002760 dst_buf->timecode = src_buf->timecode;
Junghak Sungd6dd6452015-11-03 08:16:37 -02002761 dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002762
2763 v4l2_m2m_buf_done(src_buf, state);
2764 if (curr_ctx->mode == S5P_JPEG_ENCODE)
Junghak Sung2d700712015-09-22 10:30:30 -03002765 vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload_size);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002766 v4l2_m2m_buf_done(dst_buf, state);
2767 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
2768
2769 curr_ctx->subsampling =
2770 exynos3250_jpeg_get_subsampling_mode(jpeg->regs);
2771exit_unlock:
2772 spin_unlock(&jpeg->slock);
2773 return IRQ_HANDLED;
2774}
2775
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03002776static void *jpeg_get_drv_data(struct device *dev);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002777
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002778/*
2779 * ============================================================================
2780 * Driver basic infrastructure
2781 * ============================================================================
2782 */
2783
2784static int s5p_jpeg_probe(struct platform_device *pdev)
2785{
2786 struct s5p_jpeg *jpeg;
2787 struct resource *res;
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002788 int i, ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002789
2790 /* JPEG IP abstraction struct */
Sachin Kamat5b58b952012-05-14 06:33:34 -03002791 jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002792 if (!jpeg)
2793 return -ENOMEM;
2794
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03002795 jpeg->variant = jpeg_get_drv_data(&pdev->dev);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002796
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002797 mutex_init(&jpeg->lock);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002798 spin_lock_init(&jpeg->slock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002799 jpeg->dev = &pdev->dev;
2800
2801 /* memory-mapped registers */
2802 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002803
Thierry Redingf23999e2013-01-21 06:09:07 -03002804 jpeg->regs = devm_ioremap_resource(&pdev->dev, res);
2805 if (IS_ERR(jpeg->regs))
2806 return PTR_ERR(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002807
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002808 /* interrupt service routine registration */
2809 jpeg->irq = ret = platform_get_irq(pdev, 0);
2810 if (ret < 0) {
2811 dev_err(&pdev->dev, "cannot find IRQ\n");
Sachin Kamat5b58b952012-05-14 06:33:34 -03002812 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002813 }
2814
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002815 ret = devm_request_irq(&pdev->dev, jpeg->irq, jpeg->variant->jpeg_irq,
2816 0, dev_name(&pdev->dev), jpeg);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002817 if (ret) {
2818 dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
Sachin Kamat5b58b952012-05-14 06:33:34 -03002819 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002820 }
2821
2822 /* clocks */
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002823 for (i = 0; i < jpeg->variant->num_clocks; i++) {
2824 jpeg->clocks[i] = devm_clk_get(&pdev->dev,
2825 jpeg->variant->clk_names[i]);
2826 if (IS_ERR(jpeg->clocks[i])) {
2827 dev_err(&pdev->dev, "failed to get clock: %s\n",
2828 jpeg->variant->clk_names[i]);
2829 return PTR_ERR(jpeg->clocks[i]);
2830 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002831 }
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002832
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002833 /* v4l2 device */
2834 ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
2835 if (ret) {
2836 dev_err(&pdev->dev, "Failed to register v4l2 device\n");
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002837 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002838 }
2839
2840 /* mem2mem device */
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03002841 jpeg->m2m_dev = v4l2_m2m_init(jpeg->variant->m2m_ops);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002842 if (IS_ERR(jpeg->m2m_dev)) {
2843 v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
2844 ret = PTR_ERR(jpeg->m2m_dev);
2845 goto device_register_rollback;
2846 }
2847
Marek Szyprowski712b6172016-05-24 09:16:07 +02002848 vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002849
2850 /* JPEG encoder /dev/videoX node */
2851 jpeg->vfd_encoder = video_device_alloc();
2852 if (!jpeg->vfd_encoder) {
2853 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
2854 ret = -ENOMEM;
Hans Verkuilc781e4a2016-02-15 14:25:09 -02002855 goto m2m_init_rollback;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002856 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03002857 snprintf(jpeg->vfd_encoder->name, sizeof(jpeg->vfd_encoder->name),
2858 "%s-enc", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002859 jpeg->vfd_encoder->fops = &s5p_jpeg_fops;
2860 jpeg->vfd_encoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
2861 jpeg->vfd_encoder->minor = -1;
2862 jpeg->vfd_encoder->release = video_device_release;
2863 jpeg->vfd_encoder->lock = &jpeg->lock;
2864 jpeg->vfd_encoder->v4l2_dev = &jpeg->v4l2_dev;
Hans Verkuil954f3402012-09-05 06:05:50 -03002865 jpeg->vfd_encoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002866
2867 ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
2868 if (ret) {
2869 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
Andrzej Pietrasiewicz7a1d4e72015-07-03 07:04:38 -03002870 video_device_release(jpeg->vfd_encoder);
Hans Verkuilc781e4a2016-02-15 14:25:09 -02002871 goto m2m_init_rollback;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002872 }
2873
2874 video_set_drvdata(jpeg->vfd_encoder, jpeg);
2875 v4l2_info(&jpeg->v4l2_dev,
2876 "encoder device registered as /dev/video%d\n",
2877 jpeg->vfd_encoder->num);
2878
2879 /* JPEG decoder /dev/videoX node */
2880 jpeg->vfd_decoder = video_device_alloc();
2881 if (!jpeg->vfd_decoder) {
2882 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
2883 ret = -ENOMEM;
2884 goto enc_vdev_register_rollback;
2885 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03002886 snprintf(jpeg->vfd_decoder->name, sizeof(jpeg->vfd_decoder->name),
2887 "%s-dec", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002888 jpeg->vfd_decoder->fops = &s5p_jpeg_fops;
2889 jpeg->vfd_decoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
2890 jpeg->vfd_decoder->minor = -1;
2891 jpeg->vfd_decoder->release = video_device_release;
2892 jpeg->vfd_decoder->lock = &jpeg->lock;
2893 jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev;
Jacek Anaszewski7f7d8fe2013-09-11 06:17:45 -03002894 jpeg->vfd_decoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002895
2896 ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
2897 if (ret) {
2898 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
Andrzej Pietrasiewicz7a1d4e72015-07-03 07:04:38 -03002899 video_device_release(jpeg->vfd_decoder);
2900 goto enc_vdev_register_rollback;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002901 }
2902
2903 video_set_drvdata(jpeg->vfd_decoder, jpeg);
2904 v4l2_info(&jpeg->v4l2_dev,
2905 "decoder device registered as /dev/video%d\n",
2906 jpeg->vfd_decoder->num);
2907
2908 /* final statements & power management */
2909 platform_set_drvdata(pdev, jpeg);
2910
2911 pm_runtime_enable(&pdev->dev);
2912
2913 v4l2_info(&jpeg->v4l2_dev, "Samsung S5P JPEG codec\n");
2914
2915 return 0;
2916
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002917enc_vdev_register_rollback:
2918 video_unregister_device(jpeg->vfd_encoder);
2919
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002920m2m_init_rollback:
2921 v4l2_m2m_release(jpeg->m2m_dev);
2922
2923device_register_rollback:
2924 v4l2_device_unregister(&jpeg->v4l2_dev);
2925
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002926 return ret;
2927}
2928
2929static int s5p_jpeg_remove(struct platform_device *pdev)
2930{
2931 struct s5p_jpeg *jpeg = platform_get_drvdata(pdev);
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002932 int i;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002933
2934 pm_runtime_disable(jpeg->dev);
2935
2936 video_unregister_device(jpeg->vfd_decoder);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002937 video_unregister_device(jpeg->vfd_encoder);
Marek Szyprowski712b6172016-05-24 09:16:07 +02002938 vb2_dma_contig_clear_max_seg_size(&pdev->dev);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002939 v4l2_m2m_release(jpeg->m2m_dev);
2940 v4l2_device_unregister(&jpeg->v4l2_dev);
2941
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002942 if (!pm_runtime_status_suspended(&pdev->dev)) {
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002943 for (i = jpeg->variant->num_clocks - 1; i >= 0; i--)
2944 clk_disable_unprepare(jpeg->clocks[i]);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002945 }
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002946
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002947 return 0;
2948}
2949
Rafael J. Wysockie243c7c2014-12-04 01:10:10 +01002950#ifdef CONFIG_PM
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002951static int s5p_jpeg_runtime_suspend(struct device *dev)
2952{
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002953 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002954 int i;
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002955
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002956 for (i = jpeg->variant->num_clocks - 1; i >= 0; i--)
2957 clk_disable_unprepare(jpeg->clocks[i]);
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002958
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002959 return 0;
2960}
2961
2962static int s5p_jpeg_runtime_resume(struct device *dev)
2963{
2964 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002965 unsigned long flags;
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002966 int i, ret;
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002967
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002968 for (i = 0; i < jpeg->variant->num_clocks; i++) {
2969 ret = clk_prepare_enable(jpeg->clocks[i]);
2970 if (ret) {
2971 while (--i > 0)
2972 clk_disable_unprepare(jpeg->clocks[i]);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002973 return ret;
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002974 }
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002975 }
2976
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002977 spin_lock_irqsave(&jpeg->slock, flags);
2978
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002979 /*
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002980 * JPEG IP allows storing two Huffman tables for each component.
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002981 * We fill table 0 for each component and do this here only
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03002982 * for S5PC210 and Exynos3250 SoCs. Exynos4x12 and Exynos542x SoC
2983 * require programming their Huffman tables each time the encoding
2984 * process is initialized, and thus it is accomplished in the
2985 * device_run callback of m2m_ops.
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002986 */
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03002987 if (!jpeg->variant->htbl_reinit) {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002988 s5p_jpeg_set_hdctbl(jpeg->regs);
2989 s5p_jpeg_set_hdctblg(jpeg->regs);
2990 s5p_jpeg_set_hactbl(jpeg->regs);
2991 s5p_jpeg_set_hactblg(jpeg->regs);
2992 }
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03002993
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002994 spin_unlock_irqrestore(&jpeg->slock, flags);
2995
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002996 return 0;
2997}
Rafael J. Wysockie243c7c2014-12-04 01:10:10 +01002998#endif /* CONFIG_PM */
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002999
Thierry Redingde3767a2014-10-14 07:10:40 -03003000#ifdef CONFIG_PM_SLEEP
Jacek Anaszewskif1347132013-11-25 06:58:13 -03003001static int s5p_jpeg_suspend(struct device *dev)
3002{
3003 if (pm_runtime_suspended(dev))
3004 return 0;
3005
3006 return s5p_jpeg_runtime_suspend(dev);
3007}
3008
3009static int s5p_jpeg_resume(struct device *dev)
3010{
3011 if (pm_runtime_suspended(dev))
3012 return 0;
3013
3014 return s5p_jpeg_runtime_resume(dev);
3015}
Thierry Redingde3767a2014-10-14 07:10:40 -03003016#endif
Jacek Anaszewskif1347132013-11-25 06:58:13 -03003017
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003018static const struct dev_pm_ops s5p_jpeg_pm_ops = {
Jacek Anaszewskif1347132013-11-25 06:58:13 -03003019 SET_SYSTEM_SLEEP_PM_OPS(s5p_jpeg_suspend, s5p_jpeg_resume)
3020 SET_RUNTIME_PM_OPS(s5p_jpeg_runtime_suspend, s5p_jpeg_runtime_resume, NULL)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003021};
3022
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003023static struct s5p_jpeg_variant s5p_jpeg_drvdata = {
3024 .version = SJPEG_S5P,
3025 .jpeg_irq = s5p_jpeg_irq,
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03003026 .m2m_ops = &s5p_jpeg_m2m_ops,
Jacek Anaszewskib2451682014-04-10 04:32:11 -03003027 .fmt_ver_flag = SJPEG_FMT_FLAG_S5P,
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03003028 .clk_names = {"jpeg"},
3029 .num_clocks = 1,
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03003030};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003031
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003032static struct s5p_jpeg_variant exynos3250_jpeg_drvdata = {
3033 .version = SJPEG_EXYNOS3250,
3034 .jpeg_irq = exynos3250_jpeg_irq,
3035 .m2m_ops = &exynos3250_jpeg_m2m_ops,
3036 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS3250,
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03003037 .hw3250_compat = 1,
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03003038 .clk_names = {"jpeg", "sclk"},
3039 .num_clocks = 2,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003040};
3041
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003042static struct s5p_jpeg_variant exynos4_jpeg_drvdata = {
3043 .version = SJPEG_EXYNOS4,
3044 .jpeg_irq = exynos4_jpeg_irq,
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03003045 .m2m_ops = &exynos4_jpeg_m2m_ops,
Jacek Anaszewskib2451682014-04-10 04:32:11 -03003046 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS4,
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03003047 .htbl_reinit = 1,
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03003048 .clk_names = {"jpeg"},
3049 .num_clocks = 1,
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03003050 .hw_ex4_compat = 1,
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03003051};
3052
3053static struct s5p_jpeg_variant exynos5420_jpeg_drvdata = {
3054 .version = SJPEG_EXYNOS5420,
3055 .jpeg_irq = exynos3250_jpeg_irq, /* intentionally 3250 */
3056 .m2m_ops = &exynos3250_jpeg_m2m_ops, /* intentionally 3250 */
3057 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS3250, /* intentionally 3250 */
3058 .hw3250_compat = 1,
3059 .htbl_reinit = 1,
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03003060 .clk_names = {"jpeg"},
3061 .num_clocks = 1,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003062};
3063
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03003064static struct s5p_jpeg_variant exynos5433_jpeg_drvdata = {
3065 .version = SJPEG_EXYNOS5433,
3066 .jpeg_irq = exynos4_jpeg_irq,
3067 .m2m_ops = &exynos4_jpeg_m2m_ops,
3068 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS4,
3069 .htbl_reinit = 1,
3070 .clk_names = {"pclk", "aclk", "aclk_xiu", "sclk"},
3071 .num_clocks = 4,
3072 .hw_ex4_compat = 1,
3073};
3074
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003075static const struct of_device_id samsung_jpeg_match[] = {
3076 {
3077 .compatible = "samsung,s5pv210-jpeg",
3078 .data = &s5p_jpeg_drvdata,
3079 }, {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003080 .compatible = "samsung,exynos3250-jpeg",
3081 .data = &exynos3250_jpeg_drvdata,
3082 }, {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003083 .compatible = "samsung,exynos4210-jpeg",
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003084 .data = &exynos4_jpeg_drvdata,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003085 }, {
3086 .compatible = "samsung,exynos4212-jpeg",
3087 .data = &exynos4_jpeg_drvdata,
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03003088 }, {
3089 .compatible = "samsung,exynos5420-jpeg",
3090 .data = &exynos5420_jpeg_drvdata,
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03003091 }, {
3092 .compatible = "samsung,exynos5433-jpeg",
3093 .data = &exynos5433_jpeg_drvdata,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003094 },
3095 {},
3096};
3097
3098MODULE_DEVICE_TABLE(of, samsung_jpeg_match);
3099
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03003100static void *jpeg_get_drv_data(struct device *dev)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003101{
3102 struct s5p_jpeg_variant *driver_data = NULL;
3103 const struct of_device_id *match;
3104
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03003105 if (!IS_ENABLED(CONFIG_OF) || !dev->of_node)
3106 return &s5p_jpeg_drvdata;
3107
3108 match = of_match_node(samsung_jpeg_match, dev->of_node);
3109
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003110 if (match)
3111 driver_data = (struct s5p_jpeg_variant *)match->data;
3112
3113 return driver_data;
3114}
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03003115
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003116static struct platform_driver s5p_jpeg_driver = {
3117 .probe = s5p_jpeg_probe,
3118 .remove = s5p_jpeg_remove,
3119 .driver = {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003120 .of_match_table = of_match_ptr(samsung_jpeg_match),
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003121 .name = S5P_JPEG_M2M_NAME,
3122 .pm = &s5p_jpeg_pm_ops,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003123 },
3124};
3125
Sachin Kamat87e94292012-07-03 05:54:33 -03003126module_platform_driver(s5p_jpeg_driver);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003127
3128MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003129MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003130MODULE_DESCRIPTION("Samsung JPEG codec driver");
3131MODULE_LICENSE("GPL");