blob: a63f4eec366eb6e21704abdf240aad3fef80504b [file] [log] [blame]
Mauro Carvalho Chehab2c3fb082012-08-14 17:31:16 -03001/* linux/drivers/media/platform/s5p-jpeg/jpeg-core.c
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002 *
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003 * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd.
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03004 * http://www.samsung.com
5 *
6 * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03007 * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03008 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/clk.h>
15#include <linux/err.h>
16#include <linux/gfp.h>
17#include <linux/interrupt.h>
18#include <linux/io.h>
19#include <linux/kernel.h>
20#include <linux/module.h>
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -030021#include <linux/of.h>
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030022#include <linux/platform_device.h>
23#include <linux/pm_runtime.h>
24#include <linux/slab.h>
25#include <linux/spinlock.h>
26#include <linux/string.h>
27#include <media/v4l2-mem2mem.h>
28#include <media/v4l2-ioctl.h>
Junghak Sungc1399902015-09-22 10:30:29 -030029#include <media/videobuf2-v4l2.h>
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030030#include <media/videobuf2-dma-contig.h>
31
32#include "jpeg-core.h"
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -030033#include "jpeg-hw-s5p.h"
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030034#include "jpeg-hw-exynos4.h"
Jacek Anaszewski3246fda2014-07-11 12:19:42 -030035#include "jpeg-hw-exynos3250.h"
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030036#include "jpeg-regs.h"
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030037
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030038static struct s5p_jpeg_fmt sjpeg_formats[] = {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030039 {
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -030040 .name = "JPEG JFIF",
41 .fourcc = V4L2_PIX_FMT_JPEG,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030042 .flags = SJPEG_FMT_FLAG_ENC_CAPTURE |
43 SJPEG_FMT_FLAG_DEC_OUTPUT |
44 SJPEG_FMT_FLAG_S5P |
Jacek Anaszewski3246fda2014-07-11 12:19:42 -030045 SJPEG_FMT_FLAG_EXYNOS3250 |
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030046 SJPEG_FMT_FLAG_EXYNOS4,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030047 },
48 {
49 .name = "YUV 4:2:2 packed, YCbYCr",
50 .fourcc = V4L2_PIX_FMT_YUYV,
51 .depth = 16,
52 .colplanes = 1,
53 .h_align = 4,
54 .v_align = 3,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030055 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
56 SJPEG_FMT_FLAG_DEC_CAPTURE |
57 SJPEG_FMT_FLAG_S5P |
58 SJPEG_FMT_NON_RGB,
59 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030060 },
61 {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030062 .name = "YUV 4:2:2 packed, YCbYCr",
63 .fourcc = V4L2_PIX_FMT_YUYV,
64 .depth = 16,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030065 .colplanes = 1,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030066 .h_align = 1,
67 .v_align = 0,
68 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
69 SJPEG_FMT_FLAG_DEC_CAPTURE |
70 SJPEG_FMT_FLAG_EXYNOS4 |
71 SJPEG_FMT_NON_RGB,
72 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
73 },
74 {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -030075 .name = "YUV 4:2:2 packed, YCbYCr",
76 .fourcc = V4L2_PIX_FMT_YUYV,
77 .depth = 16,
78 .colplanes = 1,
79 .h_align = 2,
80 .v_align = 0,
81 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
82 SJPEG_FMT_FLAG_DEC_CAPTURE |
83 SJPEG_FMT_FLAG_EXYNOS3250 |
84 SJPEG_FMT_NON_RGB,
85 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
86 },
87 {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030088 .name = "YUV 4:2:2 packed, YCrYCb",
89 .fourcc = V4L2_PIX_FMT_YVYU,
90 .depth = 16,
91 .colplanes = 1,
92 .h_align = 1,
93 .v_align = 0,
94 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
95 SJPEG_FMT_FLAG_DEC_CAPTURE |
96 SJPEG_FMT_FLAG_EXYNOS4 |
97 SJPEG_FMT_NON_RGB,
98 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
99 },
100 {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300101 .name = "YUV 4:2:2 packed, YCrYCb",
102 .fourcc = V4L2_PIX_FMT_YVYU,
103 .depth = 16,
104 .colplanes = 1,
105 .h_align = 2,
106 .v_align = 0,
107 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
108 SJPEG_FMT_FLAG_DEC_CAPTURE |
109 SJPEG_FMT_FLAG_EXYNOS3250 |
110 SJPEG_FMT_NON_RGB,
111 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
112 },
113 {
114 .name = "YUV 4:2:2 packed, YCrYCb",
115 .fourcc = V4L2_PIX_FMT_UYVY,
116 .depth = 16,
117 .colplanes = 1,
118 .h_align = 2,
119 .v_align = 0,
120 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
121 SJPEG_FMT_FLAG_DEC_CAPTURE |
122 SJPEG_FMT_FLAG_EXYNOS3250 |
123 SJPEG_FMT_NON_RGB,
124 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
125 },
126 {
127 .name = "YUV 4:2:2 packed, YCrYCb",
128 .fourcc = V4L2_PIX_FMT_VYUY,
129 .depth = 16,
130 .colplanes = 1,
131 .h_align = 2,
132 .v_align = 0,
133 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
134 SJPEG_FMT_FLAG_DEC_CAPTURE |
135 SJPEG_FMT_FLAG_EXYNOS3250 |
136 SJPEG_FMT_NON_RGB,
137 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
138 },
139 {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300140 .name = "RGB565",
141 .fourcc = V4L2_PIX_FMT_RGB565,
142 .depth = 16,
143 .colplanes = 1,
144 .h_align = 0,
145 .v_align = 0,
146 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
147 SJPEG_FMT_FLAG_DEC_CAPTURE |
148 SJPEG_FMT_FLAG_EXYNOS4 |
149 SJPEG_FMT_RGB,
150 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
151 },
152 {
153 .name = "RGB565",
154 .fourcc = V4L2_PIX_FMT_RGB565,
155 .depth = 16,
156 .colplanes = 1,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300157 .h_align = 2,
158 .v_align = 0,
159 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
160 SJPEG_FMT_FLAG_DEC_CAPTURE |
161 SJPEG_FMT_FLAG_EXYNOS3250 |
162 SJPEG_FMT_RGB,
163 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
164 },
165 {
166 .name = "RGB565X",
167 .fourcc = V4L2_PIX_FMT_RGB565X,
168 .depth = 16,
169 .colplanes = 1,
170 .h_align = 2,
171 .v_align = 0,
172 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
173 SJPEG_FMT_FLAG_DEC_CAPTURE |
174 SJPEG_FMT_FLAG_EXYNOS3250 |
175 SJPEG_FMT_RGB,
176 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
177 },
178 {
179 .name = "RGB565",
180 .fourcc = V4L2_PIX_FMT_RGB565,
181 .depth = 16,
182 .colplanes = 1,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300183 .h_align = 0,
184 .v_align = 0,
185 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
186 SJPEG_FMT_FLAG_S5P |
187 SJPEG_FMT_RGB,
188 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
189 },
190 {
191 .name = "ARGB8888, 32 bpp",
192 .fourcc = V4L2_PIX_FMT_RGB32,
193 .depth = 32,
194 .colplanes = 1,
195 .h_align = 0,
196 .v_align = 0,
197 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
198 SJPEG_FMT_FLAG_DEC_CAPTURE |
199 SJPEG_FMT_FLAG_EXYNOS4 |
200 SJPEG_FMT_RGB,
201 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
202 },
203 {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300204 .name = "ARGB8888, 32 bpp",
205 .fourcc = V4L2_PIX_FMT_RGB32,
206 .depth = 32,
207 .colplanes = 1,
208 .h_align = 2,
209 .v_align = 0,
210 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
211 SJPEG_FMT_FLAG_DEC_CAPTURE |
212 SJPEG_FMT_FLAG_EXYNOS3250 |
213 SJPEG_FMT_RGB,
214 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
215 },
216 {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300217 .name = "YUV 4:4:4 planar, Y/CbCr",
218 .fourcc = V4L2_PIX_FMT_NV24,
219 .depth = 24,
220 .colplanes = 2,
221 .h_align = 0,
222 .v_align = 0,
223 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
224 SJPEG_FMT_FLAG_DEC_CAPTURE |
225 SJPEG_FMT_FLAG_EXYNOS4 |
226 SJPEG_FMT_NON_RGB,
227 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
228 },
229 {
230 .name = "YUV 4:4:4 planar, Y/CrCb",
231 .fourcc = V4L2_PIX_FMT_NV42,
232 .depth = 24,
233 .colplanes = 2,
234 .h_align = 0,
235 .v_align = 0,
236 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
237 SJPEG_FMT_FLAG_DEC_CAPTURE |
238 SJPEG_FMT_FLAG_EXYNOS4 |
239 SJPEG_FMT_NON_RGB,
240 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
241 },
242 {
243 .name = "YUV 4:2:2 planar, Y/CrCb",
244 .fourcc = V4L2_PIX_FMT_NV61,
245 .depth = 16,
246 .colplanes = 2,
247 .h_align = 1,
248 .v_align = 0,
249 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
250 SJPEG_FMT_FLAG_DEC_CAPTURE |
251 SJPEG_FMT_FLAG_EXYNOS4 |
252 SJPEG_FMT_NON_RGB,
253 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
254 },
255 {
256 .name = "YUV 4:2:2 planar, Y/CbCr",
257 .fourcc = V4L2_PIX_FMT_NV16,
258 .depth = 16,
259 .colplanes = 2,
260 .h_align = 1,
261 .v_align = 0,
262 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
263 SJPEG_FMT_FLAG_DEC_CAPTURE |
264 SJPEG_FMT_FLAG_EXYNOS4 |
265 SJPEG_FMT_NON_RGB,
266 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
267 },
268 {
269 .name = "YUV 4:2:0 planar, Y/CbCr",
270 .fourcc = V4L2_PIX_FMT_NV12,
Jacek Anaszewskia62cffe2014-01-16 08:26:33 -0300271 .depth = 12,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300272 .colplanes = 2,
273 .h_align = 1,
274 .v_align = 1,
275 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
276 SJPEG_FMT_FLAG_DEC_CAPTURE |
277 SJPEG_FMT_FLAG_EXYNOS4 |
278 SJPEG_FMT_NON_RGB,
279 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
280 },
281 {
282 .name = "YUV 4:2:0 planar, Y/CbCr",
283 .fourcc = V4L2_PIX_FMT_NV12,
Jacek Anaszewskia62cffe2014-01-16 08:26:33 -0300284 .depth = 12,
285 .colplanes = 2,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300286 .h_align = 3,
287 .v_align = 3,
288 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
289 SJPEG_FMT_FLAG_DEC_CAPTURE |
290 SJPEG_FMT_FLAG_EXYNOS3250 |
291 SJPEG_FMT_NON_RGB,
292 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
293 },
294 {
295 .name = "YUV 4:2:0 planar, Y/CbCr",
296 .fourcc = V4L2_PIX_FMT_NV12,
297 .depth = 12,
298 .colplanes = 2,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300299 .h_align = 4,
Jacek Anaszewskia62cffe2014-01-16 08:26:33 -0300300 .v_align = 4,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300301 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
302 SJPEG_FMT_FLAG_DEC_CAPTURE |
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300303 SJPEG_FMT_FLAG_S5P |
304 SJPEG_FMT_NON_RGB,
305 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
306 },
307 {
308 .name = "YUV 4:2:0 planar, Y/CrCb",
309 .fourcc = V4L2_PIX_FMT_NV21,
310 .depth = 12,
311 .colplanes = 2,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300312 .h_align = 3,
313 .v_align = 3,
314 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
315 SJPEG_FMT_FLAG_DEC_CAPTURE |
316 SJPEG_FMT_FLAG_EXYNOS3250 |
317 SJPEG_FMT_NON_RGB,
318 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
319 },
320 {
321 .name = "YUV 4:2:0 planar, Y/CrCb",
322 .fourcc = V4L2_PIX_FMT_NV21,
323 .depth = 12,
324 .colplanes = 2,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300325 .h_align = 1,
326 .v_align = 1,
327 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
328 SJPEG_FMT_FLAG_DEC_CAPTURE |
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300329 SJPEG_FMT_FLAG_EXYNOS3250 |
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300330 SJPEG_FMT_FLAG_EXYNOS4 |
331 SJPEG_FMT_NON_RGB,
332 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
333 },
334 {
335 .name = "YUV 4:2:0 contiguous 3-planar, Y/Cb/Cr",
336 .fourcc = V4L2_PIX_FMT_YUV420,
337 .depth = 12,
338 .colplanes = 3,
339 .h_align = 1,
340 .v_align = 1,
341 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
342 SJPEG_FMT_FLAG_DEC_CAPTURE |
343 SJPEG_FMT_FLAG_EXYNOS4 |
344 SJPEG_FMT_NON_RGB,
345 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
346 },
347 {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300348 .name = "YUV 4:2:0 contiguous 3-planar, Y/Cb/Cr",
349 .fourcc = V4L2_PIX_FMT_YUV420,
350 .depth = 12,
351 .colplanes = 3,
352 .h_align = 4,
353 .v_align = 4,
354 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
355 SJPEG_FMT_FLAG_DEC_CAPTURE |
356 SJPEG_FMT_FLAG_EXYNOS3250 |
357 SJPEG_FMT_NON_RGB,
358 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
359 },
360 {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300361 .name = "Gray",
362 .fourcc = V4L2_PIX_FMT_GREY,
363 .depth = 8,
364 .colplanes = 1,
365 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
366 SJPEG_FMT_FLAG_DEC_CAPTURE |
367 SJPEG_FMT_FLAG_EXYNOS4 |
368 SJPEG_FMT_NON_RGB,
369 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300370 },
371};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300372#define SJPEG_NUM_FORMATS ARRAY_SIZE(sjpeg_formats)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300373
374static const unsigned char qtbl_luminance[4][64] = {
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300375 {/*level 0 - high compression quality */
376 20, 16, 25, 39, 50, 46, 62, 68,
377 16, 18, 23, 38, 38, 53, 65, 68,
378 25, 23, 31, 38, 53, 65, 68, 68,
379 39, 38, 38, 53, 65, 68, 68, 68,
380 50, 38, 53, 65, 68, 68, 68, 68,
381 46, 53, 65, 68, 68, 68, 68, 68,
382 62, 65, 68, 68, 68, 68, 68, 68,
383 68, 68, 68, 68, 68, 68, 68, 68
384 },
385 {/* level 1 */
386 16, 11, 11, 16, 23, 27, 31, 30,
387 11, 12, 12, 15, 20, 23, 23, 30,
388 11, 12, 13, 16, 23, 26, 35, 47,
389 16, 15, 16, 23, 26, 37, 47, 64,
390 23, 20, 23, 26, 39, 51, 64, 64,
391 27, 23, 26, 37, 51, 64, 64, 64,
392 31, 23, 35, 47, 64, 64, 64, 64,
393 30, 30, 47, 64, 64, 64, 64, 64
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300394 },
395 {/* level 2 */
396 12, 8, 8, 12, 17, 21, 24, 23,
397 8, 9, 9, 11, 15, 19, 18, 23,
398 8, 9, 10, 12, 19, 20, 27, 36,
399 12, 11, 12, 21, 20, 28, 36, 53,
400 17, 15, 19, 20, 30, 39, 51, 59,
401 21, 19, 20, 28, 39, 51, 59, 59,
402 24, 18, 27, 36, 51, 59, 59, 59,
403 23, 23, 36, 53, 59, 59, 59, 59
404 },
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300405 {/* level 3 - low compression quality */
406 8, 6, 6, 8, 12, 14, 16, 17,
407 6, 6, 6, 8, 10, 13, 12, 15,
408 6, 6, 7, 8, 13, 14, 18, 24,
409 8, 8, 8, 14, 13, 19, 24, 35,
410 12, 10, 13, 13, 20, 26, 34, 39,
411 14, 13, 14, 19, 26, 34, 39, 39,
412 16, 12, 18, 24, 34, 39, 39, 39,
413 17, 15, 24, 35, 39, 39, 39, 39
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300414 }
415};
416
417static const unsigned char qtbl_chrominance[4][64] = {
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300418 {/*level 0 - high compression quality */
419 21, 25, 32, 38, 54, 68, 68, 68,
420 25, 28, 24, 38, 54, 68, 68, 68,
421 32, 24, 32, 43, 66, 68, 68, 68,
422 38, 38, 43, 53, 68, 68, 68, 68,
423 54, 54, 66, 68, 68, 68, 68, 68,
424 68, 68, 68, 68, 68, 68, 68, 68,
425 68, 68, 68, 68, 68, 68, 68, 68,
426 68, 68, 68, 68, 68, 68, 68, 68
427 },
428 {/* level 1 */
429 17, 15, 17, 21, 20, 26, 38, 48,
430 15, 19, 18, 17, 20, 26, 35, 43,
431 17, 18, 20, 22, 26, 30, 46, 53,
432 21, 17, 22, 28, 30, 39, 53, 64,
433 20, 20, 26, 30, 39, 48, 64, 64,
434 26, 26, 30, 39, 48, 63, 64, 64,
435 38, 35, 46, 53, 64, 64, 64, 64,
436 48, 43, 53, 64, 64, 64, 64, 64
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300437 },
438 {/* level 2 */
439 13, 11, 13, 16, 20, 20, 29, 37,
440 11, 14, 14, 14, 16, 20, 26, 32,
441 13, 14, 15, 17, 20, 23, 35, 40,
442 16, 14, 17, 21, 23, 30, 40, 50,
443 20, 16, 20, 23, 30, 37, 50, 59,
444 20, 20, 23, 30, 37, 48, 59, 59,
445 29, 26, 35, 40, 50, 59, 59, 59,
446 37, 32, 40, 50, 59, 59, 59, 59
447 },
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300448 {/* level 3 - low compression quality */
449 9, 8, 9, 11, 14, 17, 19, 24,
450 8, 10, 9, 11, 14, 13, 17, 22,
451 9, 9, 13, 14, 13, 15, 23, 26,
452 11, 11, 14, 14, 15, 20, 26, 33,
453 14, 14, 13, 15, 20, 24, 33, 39,
454 17, 13, 15, 20, 24, 32, 39, 39,
455 19, 17, 23, 26, 33, 39, 39, 39,
456 24, 22, 26, 33, 39, 39, 39, 39
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300457 }
458};
459
460static const unsigned char hdctbl0[16] = {
461 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
462};
463
464static const unsigned char hdctblg0[12] = {
465 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb
466};
467static const unsigned char hactbl0[16] = {
468 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
469};
470static const unsigned char hactblg0[162] = {
471 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
472 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
473 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
474 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
475 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
476 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
477 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
478 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
479 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
480 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
481 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
482 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
483 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
484 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
485 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
486 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
487 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
488 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
489 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
490 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
491 0xf9, 0xfa
492};
493
Jacek Anaszewski337777a2013-11-22 06:13:34 -0300494/*
495 * Fourcc downgrade schema lookup tables for 422 and 420
496 * chroma subsampling - fourcc on each position maps on the
497 * fourcc from the table fourcc_to_dwngrd_schema_id which allows
498 * to get the most suitable fourcc counterpart for the given
499 * downgraded subsampling property.
500 */
501static const u32 subs422_fourcc_dwngrd_schema[] = {
502 V4L2_PIX_FMT_NV16,
503 V4L2_PIX_FMT_NV61,
504};
505
506static const u32 subs420_fourcc_dwngrd_schema[] = {
507 V4L2_PIX_FMT_NV12,
508 V4L2_PIX_FMT_NV21,
509 V4L2_PIX_FMT_NV12,
510 V4L2_PIX_FMT_NV21,
511 V4L2_PIX_FMT_NV12,
512 V4L2_PIX_FMT_NV21,
513 V4L2_PIX_FMT_GREY,
514 V4L2_PIX_FMT_GREY,
515 V4L2_PIX_FMT_GREY,
516 V4L2_PIX_FMT_GREY,
517};
518
519/*
520 * Lookup table for translation of a fourcc to the position
521 * of its downgraded counterpart in the *fourcc_dwngrd_schema
522 * tables.
523 */
524static const u32 fourcc_to_dwngrd_schema_id[] = {
525 V4L2_PIX_FMT_NV24,
526 V4L2_PIX_FMT_NV42,
527 V4L2_PIX_FMT_NV16,
528 V4L2_PIX_FMT_NV61,
529 V4L2_PIX_FMT_YUYV,
530 V4L2_PIX_FMT_YVYU,
531 V4L2_PIX_FMT_NV12,
532 V4L2_PIX_FMT_NV21,
533 V4L2_PIX_FMT_YUV420,
534 V4L2_PIX_FMT_GREY,
535};
536
537static int s5p_jpeg_get_dwngrd_sch_id_by_fourcc(u32 fourcc)
538{
539 int i;
Shuah Khan605b8922016-07-14 17:01:56 -0300540
Jacek Anaszewski337777a2013-11-22 06:13:34 -0300541 for (i = 0; i < ARRAY_SIZE(fourcc_to_dwngrd_schema_id); ++i) {
542 if (fourcc_to_dwngrd_schema_id[i] == fourcc)
543 return i;
544 }
545
546 return -EINVAL;
547}
548
549static int s5p_jpeg_adjust_fourcc_to_subsampling(
550 enum v4l2_jpeg_chroma_subsampling subs,
551 u32 in_fourcc,
552 u32 *out_fourcc,
553 struct s5p_jpeg_ctx *ctx)
554{
555 int dwngrd_sch_id;
556
557 if (ctx->subsampling != V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY) {
558 dwngrd_sch_id =
559 s5p_jpeg_get_dwngrd_sch_id_by_fourcc(in_fourcc);
560 if (dwngrd_sch_id < 0)
561 return -EINVAL;
562 }
563
564 switch (ctx->subsampling) {
565 case V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY:
566 *out_fourcc = V4L2_PIX_FMT_GREY;
567 break;
568 case V4L2_JPEG_CHROMA_SUBSAMPLING_420:
569 if (dwngrd_sch_id >
570 ARRAY_SIZE(subs420_fourcc_dwngrd_schema) - 1)
571 return -EINVAL;
572 *out_fourcc = subs420_fourcc_dwngrd_schema[dwngrd_sch_id];
573 break;
574 case V4L2_JPEG_CHROMA_SUBSAMPLING_422:
575 if (dwngrd_sch_id >
576 ARRAY_SIZE(subs422_fourcc_dwngrd_schema) - 1)
577 return -EINVAL;
578 *out_fourcc = subs422_fourcc_dwngrd_schema[dwngrd_sch_id];
579 break;
580 default:
581 *out_fourcc = V4L2_PIX_FMT_GREY;
582 break;
583 }
584
585 return 0;
586}
587
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300588static int exynos4x12_decoded_subsampling[] = {
589 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
590 V4L2_JPEG_CHROMA_SUBSAMPLING_444,
591 V4L2_JPEG_CHROMA_SUBSAMPLING_422,
592 V4L2_JPEG_CHROMA_SUBSAMPLING_420,
593};
594
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300595static int exynos3250_decoded_subsampling[] = {
596 V4L2_JPEG_CHROMA_SUBSAMPLING_444,
597 V4L2_JPEG_CHROMA_SUBSAMPLING_422,
598 V4L2_JPEG_CHROMA_SUBSAMPLING_420,
599 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
600 -1,
601 -1,
602 V4L2_JPEG_CHROMA_SUBSAMPLING_411,
603};
604
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300605static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c)
606{
607 return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler);
608}
609
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300610static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh)
611{
612 return container_of(fh, struct s5p_jpeg_ctx, fh);
613}
614
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300615static int s5p_jpeg_to_user_subsampling(struct s5p_jpeg_ctx *ctx)
616{
617 WARN_ON(ctx->subsampling > 3);
618
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300619 switch (ctx->jpeg->variant->version) {
620 case SJPEG_S5P:
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300621 if (ctx->subsampling > 2)
622 return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
623 return ctx->subsampling;
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300624 case SJPEG_EXYNOS3250:
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -0300625 case SJPEG_EXYNOS5420:
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300626 if (ctx->subsampling > 3)
627 return V4L2_JPEG_CHROMA_SUBSAMPLING_411;
628 return exynos3250_decoded_subsampling[ctx->subsampling];
629 case SJPEG_EXYNOS4:
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300630 case SJPEG_EXYNOS5433:
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300631 if (ctx->subsampling > 2)
632 return V4L2_JPEG_CHROMA_SUBSAMPLING_420;
633 return exynos4x12_decoded_subsampling[ctx->subsampling];
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300634 default:
635 return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300636 }
637}
638
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300639static inline void s5p_jpeg_set_qtbl(void __iomem *regs,
640 const unsigned char *qtbl,
641 unsigned long tab, int len)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300642{
643 int i;
644
645 for (i = 0; i < len; i++)
646 writel((unsigned int)qtbl[i], regs + tab + (i * 0x04));
647}
648
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300649static inline void s5p_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300650{
651 /* this driver fills quantisation table 0 with data for luma */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300652 s5p_jpeg_set_qtbl(regs, qtbl_luminance[quality],
653 S5P_JPG_QTBL_CONTENT(0),
654 ARRAY_SIZE(qtbl_luminance[quality]));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300655}
656
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300657static inline void s5p_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300658{
659 /* this driver fills quantisation table 1 with data for chroma */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300660 s5p_jpeg_set_qtbl(regs, qtbl_chrominance[quality],
661 S5P_JPG_QTBL_CONTENT(1),
662 ARRAY_SIZE(qtbl_chrominance[quality]));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300663}
664
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300665static inline void s5p_jpeg_set_htbl(void __iomem *regs,
666 const unsigned char *htbl,
667 unsigned long tab, int len)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300668{
669 int i;
670
671 for (i = 0; i < len; i++)
672 writel((unsigned int)htbl[i], regs + tab + (i * 0x04));
673}
674
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300675static inline void s5p_jpeg_set_hdctbl(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300676{
677 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300678 s5p_jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0),
679 ARRAY_SIZE(hdctbl0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300680}
681
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300682static inline void s5p_jpeg_set_hdctblg(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300683{
684 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300685 s5p_jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0),
686 ARRAY_SIZE(hdctblg0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300687}
688
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300689static inline void s5p_jpeg_set_hactbl(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300690{
691 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300692 s5p_jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0),
693 ARRAY_SIZE(hactbl0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300694}
695
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300696static inline void s5p_jpeg_set_hactblg(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300697{
698 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300699 s5p_jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0),
700 ARRAY_SIZE(hactblg0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300701}
702
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300703static inline void exynos4_jpeg_set_tbl(void __iomem *regs,
704 const unsigned char *tbl,
705 unsigned long tab, int len)
706{
707 int i;
708 unsigned int dword;
709
710 for (i = 0; i < len; i += 4) {
711 dword = tbl[i] |
712 (tbl[i + 1] << 8) |
713 (tbl[i + 2] << 16) |
714 (tbl[i + 3] << 24);
715 writel(dword, regs + tab + i);
716 }
717}
718
719static inline void exynos4_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
720{
721 /* this driver fills quantisation table 0 with data for luma */
722 exynos4_jpeg_set_tbl(regs, qtbl_luminance[quality],
723 EXYNOS4_QTBL_CONTENT(0),
724 ARRAY_SIZE(qtbl_luminance[quality]));
725}
726
727static inline void exynos4_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
728{
729 /* this driver fills quantisation table 1 with data for chroma */
730 exynos4_jpeg_set_tbl(regs, qtbl_chrominance[quality],
731 EXYNOS4_QTBL_CONTENT(1),
732 ARRAY_SIZE(qtbl_chrominance[quality]));
733}
734
Mauro Carvalho Chehabaf425be2014-08-26 10:50:23 -0300735static void exynos4_jpeg_set_huff_tbl(void __iomem *base)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300736{
737 exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCLL,
738 ARRAY_SIZE(hdctbl0));
739 exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCCL,
740 ARRAY_SIZE(hdctbl0));
741 exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCLV,
742 ARRAY_SIZE(hdctblg0));
743 exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCCV,
744 ARRAY_SIZE(hdctblg0));
745 exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACLL,
746 ARRAY_SIZE(hactbl0));
747 exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACCL,
748 ARRAY_SIZE(hactbl0));
749 exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACLV,
750 ARRAY_SIZE(hactblg0));
751 exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACCV,
752 ARRAY_SIZE(hactblg0));
753}
754
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300755static inline int __exynos4_huff_tbl(int class, int id, bool lenval)
756{
757 /*
758 * class: 0 - DC, 1 - AC
759 * id: 0 - Y, 1 - Cb/Cr
760 */
761 if (class) {
762 if (id)
763 return lenval ? EXYNOS4_HUFF_TBL_HACCL :
764 EXYNOS4_HUFF_TBL_HACCV;
765 return lenval ? EXYNOS4_HUFF_TBL_HACLL : EXYNOS4_HUFF_TBL_HACLV;
766
767 }
768 /* class == 0 */
769 if (id)
770 return lenval ? EXYNOS4_HUFF_TBL_HDCCL : EXYNOS4_HUFF_TBL_HDCCV;
771
772 return lenval ? EXYNOS4_HUFF_TBL_HDCLL : EXYNOS4_HUFF_TBL_HDCLV;
773}
774
775static inline int exynos4_huff_tbl_len(int class, int id)
776{
777 return __exynos4_huff_tbl(class, id, true);
778}
779
780static inline int exynos4_huff_tbl_val(int class, int id)
781{
782 return __exynos4_huff_tbl(class, id, false);
783}
784
785static int get_byte(struct s5p_jpeg_buffer *buf);
786static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word);
787static void skip(struct s5p_jpeg_buffer *buf, long len);
788
789static void exynos4_jpeg_parse_decode_h_tbl(struct s5p_jpeg_ctx *ctx)
790{
791 struct s5p_jpeg *jpeg = ctx->jpeg;
Ezequiel Garcia208285a2019-02-08 11:17:45 -0500792 struct vb2_v4l2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300793 struct s5p_jpeg_buffer jpeg_buffer;
794 unsigned int word;
795 int c, x, components;
796
797 jpeg_buffer.size = 2; /* Ls */
798 jpeg_buffer.data =
Ezequiel Garcia208285a2019-02-08 11:17:45 -0500799 (unsigned long)vb2_plane_vaddr(&vb->vb2_buf, 0) + ctx->out_q.sos + 2;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300800 jpeg_buffer.curr = 0;
801
802 word = 0;
803
804 if (get_word_be(&jpeg_buffer, &word))
805 return;
806 jpeg_buffer.size = (long)word - 2;
807 jpeg_buffer.data += 2;
808 jpeg_buffer.curr = 0;
809
810 components = get_byte(&jpeg_buffer);
811 if (components == -1)
812 return;
813 while (components--) {
814 c = get_byte(&jpeg_buffer);
815 if (c == -1)
816 return;
817 x = get_byte(&jpeg_buffer);
818 if (x == -1)
819 return;
820 exynos4_jpeg_select_dec_h_tbl(jpeg->regs, c,
821 (((x >> 4) & 0x1) << 1) | (x & 0x1));
822 }
823
824}
825
826static void exynos4_jpeg_parse_huff_tbl(struct s5p_jpeg_ctx *ctx)
827{
828 struct s5p_jpeg *jpeg = ctx->jpeg;
Ezequiel Garcia208285a2019-02-08 11:17:45 -0500829 struct vb2_v4l2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300830 struct s5p_jpeg_buffer jpeg_buffer;
831 unsigned int word;
832 int c, i, n, j;
833
834 for (j = 0; j < ctx->out_q.dht.n; ++j) {
835 jpeg_buffer.size = ctx->out_q.dht.len[j];
Ezequiel Garcia208285a2019-02-08 11:17:45 -0500836 jpeg_buffer.data = (unsigned long)vb2_plane_vaddr(&vb->vb2_buf, 0) +
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300837 ctx->out_q.dht.marker[j];
838 jpeg_buffer.curr = 0;
839
840 word = 0;
841 while (jpeg_buffer.curr < jpeg_buffer.size) {
842 char id, class;
843
844 c = get_byte(&jpeg_buffer);
845 if (c == -1)
846 return;
847 id = c & 0xf;
848 class = (c >> 4) & 0xf;
849 n = 0;
850 for (i = 0; i < 16; ++i) {
851 c = get_byte(&jpeg_buffer);
852 if (c == -1)
853 return;
854 word |= c << ((i % 4) * 8);
855 if ((i + 1) % 4 == 0) {
856 writel(word, jpeg->regs +
857 exynos4_huff_tbl_len(class, id) +
858 (i / 4) * 4);
859 word = 0;
860 }
861 n += c;
862 }
863 word = 0;
864 for (i = 0; i < n; ++i) {
865 c = get_byte(&jpeg_buffer);
866 if (c == -1)
867 return;
868 word |= c << ((i % 4) * 8);
869 if ((i + 1) % 4 == 0) {
870 writel(word, jpeg->regs +
871 exynos4_huff_tbl_val(class, id) +
872 (i / 4) * 4);
873 word = 0;
874 }
875 }
876 if (i % 4) {
877 writel(word, jpeg->regs +
878 exynos4_huff_tbl_val(class, id) + (i / 4) * 4);
879 }
880 word = 0;
881 }
882 }
883}
884
885static void exynos4_jpeg_parse_decode_q_tbl(struct s5p_jpeg_ctx *ctx)
886{
887 struct s5p_jpeg *jpeg = ctx->jpeg;
Ezequiel Garcia208285a2019-02-08 11:17:45 -0500888 struct vb2_v4l2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300889 struct s5p_jpeg_buffer jpeg_buffer;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300890 int c, x, components;
891
892 jpeg_buffer.size = ctx->out_q.sof_len;
893 jpeg_buffer.data =
Ezequiel Garcia208285a2019-02-08 11:17:45 -0500894 (unsigned long)vb2_plane_vaddr(&vb->vb2_buf, 0) + ctx->out_q.sof;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300895 jpeg_buffer.curr = 0;
896
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300897 skip(&jpeg_buffer, 5); /* P, Y, X */
898 components = get_byte(&jpeg_buffer);
899 if (components == -1)
900 return;
901
902 exynos4_jpeg_set_dec_components(jpeg->regs, components);
903
904 while (components--) {
905 c = get_byte(&jpeg_buffer);
906 if (c == -1)
907 return;
908 skip(&jpeg_buffer, 1);
909 x = get_byte(&jpeg_buffer);
910 if (x == -1)
911 return;
912 exynos4_jpeg_select_dec_q_tbl(jpeg->regs, c, x);
913 }
914}
915
916static void exynos4_jpeg_parse_q_tbl(struct s5p_jpeg_ctx *ctx)
917{
918 struct s5p_jpeg *jpeg = ctx->jpeg;
Ezequiel Garcia208285a2019-02-08 11:17:45 -0500919 struct vb2_v4l2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300920 struct s5p_jpeg_buffer jpeg_buffer;
921 unsigned int word;
922 int c, i, j;
923
924 for (j = 0; j < ctx->out_q.dqt.n; ++j) {
925 jpeg_buffer.size = ctx->out_q.dqt.len[j];
Ezequiel Garcia208285a2019-02-08 11:17:45 -0500926 jpeg_buffer.data = (unsigned long)vb2_plane_vaddr(&vb->vb2_buf, 0) +
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300927 ctx->out_q.dqt.marker[j];
928 jpeg_buffer.curr = 0;
929
930 word = 0;
931 while (jpeg_buffer.size - jpeg_buffer.curr >= 65) {
932 char id;
933
934 c = get_byte(&jpeg_buffer);
935 if (c == -1)
936 return;
937 id = c & 0xf;
938 /* nonzero means extended mode - not supported */
939 if ((c >> 4) & 0xf)
940 return;
941 for (i = 0; i < 64; ++i) {
942 c = get_byte(&jpeg_buffer);
943 if (c == -1)
944 return;
945 word |= c << ((i % 4) * 8);
946 if ((i + 1) % 4 == 0) {
947 writel(word, jpeg->regs +
948 EXYNOS4_QTBL_CONTENT(id) + (i / 4) * 4);
949 word = 0;
950 }
951 }
952 word = 0;
953 }
954 }
955}
956
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300957/*
958 * ============================================================================
959 * Device file operations
960 * ============================================================================
961 */
962
963static int queue_init(void *priv, struct vb2_queue *src_vq,
964 struct vb2_queue *dst_vq);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300965static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
966 __u32 pixelformat, unsigned int fmt_type);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300967static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300968
969static int s5p_jpeg_open(struct file *file)
970{
971 struct s5p_jpeg *jpeg = video_drvdata(file);
972 struct video_device *vfd = video_devdata(file);
973 struct s5p_jpeg_ctx *ctx;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300974 struct s5p_jpeg_fmt *out_fmt, *cap_fmt;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300975 int ret = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300976
Sachin Kamatb5146c92012-08-16 08:52:58 -0300977 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300978 if (!ctx)
979 return -ENOMEM;
980
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300981 if (mutex_lock_interruptible(&jpeg->lock)) {
982 ret = -ERESTARTSYS;
983 goto free;
984 }
985
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300986 v4l2_fh_init(&ctx->fh, vfd);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300987 /* Use separate control handler per file handle */
988 ctx->fh.ctrl_handler = &ctx->ctrl_handler;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300989 file->private_data = &ctx->fh;
990 v4l2_fh_add(&ctx->fh);
991
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300992 ctx->jpeg = jpeg;
993 if (vfd == jpeg->vfd_encoder) {
994 ctx->mode = S5P_JPEG_ENCODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300995 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB565,
996 FMT_TYPE_OUTPUT);
997 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
998 FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300999 } else {
1000 ctx->mode = S5P_JPEG_DECODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001001 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
1002 FMT_TYPE_OUTPUT);
1003 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_YUYV,
1004 FMT_TYPE_CAPTURE);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001005 ctx->scale_factor = EXYNOS3250_DEC_SCALE_FACTOR_8_8;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001006 }
1007
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001008 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
1009 if (IS_ERR(ctx->fh.m2m_ctx)) {
1010 ret = PTR_ERR(ctx->fh.m2m_ctx);
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001011 goto error;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001012 }
1013
1014 ctx->out_q.fmt = out_fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001015 ctx->cap_q.fmt = cap_fmt;
1016
1017 ret = s5p_jpeg_controls_create(ctx);
1018 if (ret < 0)
1019 goto error;
1020
Hans Verkuilb0d5cd62012-06-24 06:54:18 -03001021 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001022 return 0;
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001023
1024error:
1025 v4l2_fh_del(&ctx->fh);
1026 v4l2_fh_exit(&ctx->fh);
Hans Verkuilb0d5cd62012-06-24 06:54:18 -03001027 mutex_unlock(&jpeg->lock);
1028free:
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001029 kfree(ctx);
1030 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001031}
1032
1033static int s5p_jpeg_release(struct file *file)
1034{
Hans Verkuilb0d5cd62012-06-24 06:54:18 -03001035 struct s5p_jpeg *jpeg = video_drvdata(file);
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001036 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001037
Hans Verkuilb0d5cd62012-06-24 06:54:18 -03001038 mutex_lock(&jpeg->lock);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001039 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001040 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001041 v4l2_fh_del(&ctx->fh);
1042 v4l2_fh_exit(&ctx->fh);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001043 kfree(ctx);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001044 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001045
1046 return 0;
1047}
1048
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001049static const struct v4l2_file_operations s5p_jpeg_fops = {
1050 .owner = THIS_MODULE,
1051 .open = s5p_jpeg_open,
1052 .release = s5p_jpeg_release,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001053 .poll = v4l2_m2m_fop_poll,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001054 .unlocked_ioctl = video_ioctl2,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001055 .mmap = v4l2_m2m_fop_mmap,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001056};
1057
1058/*
1059 * ============================================================================
1060 * video ioctl operations
1061 * ============================================================================
1062 */
1063
1064static int get_byte(struct s5p_jpeg_buffer *buf)
1065{
1066 if (buf->curr >= buf->size)
1067 return -1;
1068
1069 return ((unsigned char *)buf->data)[buf->curr++];
1070}
1071
1072static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word)
1073{
1074 unsigned int temp;
1075 int byte;
1076
1077 byte = get_byte(buf);
1078 if (byte == -1)
1079 return -1;
1080 temp = byte << 8;
1081 byte = get_byte(buf);
1082 if (byte == -1)
1083 return -1;
1084 *word = (unsigned int)byte | temp;
1085 return 0;
1086}
1087
1088static void skip(struct s5p_jpeg_buffer *buf, long len)
1089{
1090 if (len <= 0)
1091 return;
1092
1093 while (len--)
1094 get_byte(buf);
1095}
1096
1097static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001098 unsigned long buffer, unsigned long size,
1099 struct s5p_jpeg_ctx *ctx)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001100{
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001101 int c, components = 0, notfound, n_dht = 0, n_dqt = 0;
Mauro Carvalho Chehab60813b62017-05-18 10:40:00 -03001102 unsigned int height = 0, width = 0, word, subsampling = 0;
1103 unsigned int sos = 0, sof = 0, sof_len = 0;
1104 unsigned int dht[S5P_JPEG_MAX_MARKER], dht_len[S5P_JPEG_MAX_MARKER];
1105 unsigned int dqt[S5P_JPEG_MAX_MARKER], dqt_len[S5P_JPEG_MAX_MARKER];
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001106 long length;
1107 struct s5p_jpeg_buffer jpeg_buffer;
1108
1109 jpeg_buffer.size = size;
1110 jpeg_buffer.data = buffer;
1111 jpeg_buffer.curr = 0;
1112
1113 notfound = 1;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001114 while (notfound || !sos) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001115 c = get_byte(&jpeg_buffer);
1116 if (c == -1)
Jacek Anaszewskia35f6002014-07-11 12:19:43 -03001117 return false;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001118 if (c != 0xff)
1119 continue;
1120 do
1121 c = get_byte(&jpeg_buffer);
1122 while (c == 0xff);
1123 if (c == -1)
Jacek Anaszewskia35f6002014-07-11 12:19:43 -03001124 return false;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001125 if (c == 0)
1126 continue;
1127 length = 0;
1128 switch (c) {
1129 /* SOF0: baseline JPEG */
1130 case SOF0:
1131 if (get_word_be(&jpeg_buffer, &word))
1132 break;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001133 length = (long)word - 2;
1134 if (!length)
1135 return false;
1136 sof = jpeg_buffer.curr; /* after 0xffc0 */
1137 sof_len = length;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001138 if (get_byte(&jpeg_buffer) == -1)
1139 break;
1140 if (get_word_be(&jpeg_buffer, &height))
1141 break;
1142 if (get_word_be(&jpeg_buffer, &width))
1143 break;
1144 components = get_byte(&jpeg_buffer);
1145 if (components == -1)
1146 break;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001147
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001148 if (components == 1) {
1149 subsampling = 0x33;
1150 } else {
1151 skip(&jpeg_buffer, 1);
1152 subsampling = get_byte(&jpeg_buffer);
1153 skip(&jpeg_buffer, 1);
1154 }
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001155 if (components > 3)
1156 return false;
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001157 skip(&jpeg_buffer, components * 2);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001158 notfound = 0;
1159 break;
1160
1161 case DQT:
1162 if (get_word_be(&jpeg_buffer, &word))
1163 break;
1164 length = (long)word - 2;
1165 if (!length)
1166 return false;
1167 if (n_dqt >= S5P_JPEG_MAX_MARKER)
1168 return false;
1169 dqt[n_dqt] = jpeg_buffer.curr; /* after 0xffdb */
1170 dqt_len[n_dqt++] = length;
1171 skip(&jpeg_buffer, length);
1172 break;
1173
1174 case DHT:
1175 if (get_word_be(&jpeg_buffer, &word))
1176 break;
1177 length = (long)word - 2;
1178 if (!length)
1179 return false;
1180 if (n_dht >= S5P_JPEG_MAX_MARKER)
1181 return false;
1182 dht[n_dht] = jpeg_buffer.curr; /* after 0xffc4 */
1183 dht_len[n_dht++] = length;
1184 skip(&jpeg_buffer, length);
1185 break;
1186
1187 case SOS:
1188 sos = jpeg_buffer.curr - 2; /* 0xffda */
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001189 break;
1190
1191 /* skip payload-less markers */
1192 case RST ... RST + 7:
1193 case SOI:
1194 case EOI:
1195 case TEM:
1196 break;
1197
1198 /* skip uninteresting payload markers */
1199 default:
1200 if (get_word_be(&jpeg_buffer, &word))
1201 break;
1202 length = (long)word - 2;
1203 skip(&jpeg_buffer, length);
1204 break;
1205 }
1206 }
1207 result->w = width;
1208 result->h = height;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001209 result->sos = sos;
1210 result->dht.n = n_dht;
1211 while (n_dht--) {
1212 result->dht.marker[n_dht] = dht[n_dht];
1213 result->dht.len[n_dht] = dht_len[n_dht];
1214 }
1215 result->dqt.n = n_dqt;
1216 while (n_dqt--) {
1217 result->dqt.marker[n_dqt] = dqt[n_dqt];
1218 result->dqt.len[n_dqt] = dqt_len[n_dqt];
1219 }
1220 result->sof = sof;
1221 result->sof_len = sof_len;
1222 result->size = result->components = components;
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001223
1224 switch (subsampling) {
1225 case 0x11:
1226 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444;
1227 break;
1228 case 0x21:
1229 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422;
1230 break;
1231 case 0x22:
1232 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420;
1233 break;
1234 case 0x33:
1235 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
1236 break;
1237 default:
1238 return false;
1239 }
1240
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001241 return !notfound && sos;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001242}
1243
1244static int s5p_jpeg_querycap(struct file *file, void *priv,
1245 struct v4l2_capability *cap)
1246{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001247 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001248
1249 if (ctx->mode == S5P_JPEG_ENCODE) {
Javier Martinez Canillasb9f19f02016-06-16 18:40:33 -03001250 strlcpy(cap->driver, S5P_JPEG_M2M_NAME,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001251 sizeof(cap->driver));
1252 strlcpy(cap->card, S5P_JPEG_M2M_NAME " encoder",
1253 sizeof(cap->card));
1254 } else {
Javier Martinez Canillasb9f19f02016-06-16 18:40:33 -03001255 strlcpy(cap->driver, S5P_JPEG_M2M_NAME,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001256 sizeof(cap->driver));
1257 strlcpy(cap->card, S5P_JPEG_M2M_NAME " decoder",
1258 sizeof(cap->card));
1259 }
Javier Martinez Canillas3b2aa382016-06-16 18:40:32 -03001260 snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
1261 dev_name(ctx->jpeg->dev));
Hans Verkuil8c17e5e2014-11-24 06:37:26 -03001262 cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M;
1263 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001264 return 0;
1265}
1266
Pawe? Chmielb9564972018-12-29 10:46:01 -05001267static int enum_fmt(struct s5p_jpeg_ctx *ctx,
1268 struct s5p_jpeg_fmt *sjpeg_formats, int n,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001269 struct v4l2_fmtdesc *f, u32 type)
1270{
1271 int i, num = 0;
Pawe? Chmielb9564972018-12-29 10:46:01 -05001272 unsigned int fmt_ver_flag = ctx->jpeg->variant->fmt_ver_flag;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001273
1274 for (i = 0; i < n; ++i) {
Pawe? Chmielb9564972018-12-29 10:46:01 -05001275 if (sjpeg_formats[i].flags & type &&
1276 sjpeg_formats[i].flags & fmt_ver_flag) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001277 /* index-th format of type type found ? */
1278 if (num == f->index)
1279 break;
1280 /* Correct type but haven't reached our index yet,
Shuah Khan605b8922016-07-14 17:01:56 -03001281 * just increment per-type index
1282 */
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001283 ++num;
1284 }
1285 }
1286
1287 /* Format not found */
1288 if (i >= n)
1289 return -EINVAL;
1290
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001291 strlcpy(f->description, sjpeg_formats[i].name, sizeof(f->description));
1292 f->pixelformat = sjpeg_formats[i].fourcc;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001293
1294 return 0;
1295}
1296
1297static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
1298 struct v4l2_fmtdesc *f)
1299{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001300 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001301
1302 if (ctx->mode == S5P_JPEG_ENCODE)
Pawe? Chmielb9564972018-12-29 10:46:01 -05001303 return enum_fmt(ctx, sjpeg_formats, SJPEG_NUM_FORMATS, f,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001304 SJPEG_FMT_FLAG_ENC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001305
Pawe? Chmielb9564972018-12-29 10:46:01 -05001306 return enum_fmt(ctx, sjpeg_formats, SJPEG_NUM_FORMATS, f,
1307 SJPEG_FMT_FLAG_DEC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001308}
1309
1310static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
1311 struct v4l2_fmtdesc *f)
1312{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001313 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001314
1315 if (ctx->mode == S5P_JPEG_ENCODE)
Pawe? Chmielb9564972018-12-29 10:46:01 -05001316 return enum_fmt(ctx, sjpeg_formats, SJPEG_NUM_FORMATS, f,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001317 SJPEG_FMT_FLAG_ENC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001318
Pawe? Chmielb9564972018-12-29 10:46:01 -05001319 return enum_fmt(ctx, sjpeg_formats, SJPEG_NUM_FORMATS, f,
1320 SJPEG_FMT_FLAG_DEC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001321}
1322
1323static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx,
1324 enum v4l2_buf_type type)
1325{
1326 if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1327 return &ctx->out_q;
1328 if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1329 return &ctx->cap_q;
1330
1331 return NULL;
1332}
1333
1334static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
1335{
1336 struct vb2_queue *vq;
1337 struct s5p_jpeg_q_data *q_data = NULL;
1338 struct v4l2_pix_format *pix = &f->fmt.pix;
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001339 struct s5p_jpeg_ctx *ct = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001340
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001341 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001342 if (!vq)
1343 return -EINVAL;
1344
1345 if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
1346 ct->mode == S5P_JPEG_DECODE && !ct->hdr_parsed)
1347 return -EINVAL;
1348 q_data = get_q_data(ct, f->type);
1349 BUG_ON(q_data == NULL);
1350
1351 pix->width = q_data->w;
1352 pix->height = q_data->h;
1353 pix->field = V4L2_FIELD_NONE;
1354 pix->pixelformat = q_data->fmt->fourcc;
1355 pix->bytesperline = 0;
1356 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
1357 u32 bpl = q_data->w;
Shuah Khan605b8922016-07-14 17:01:56 -03001358
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001359 if (q_data->fmt->colplanes == 1)
1360 bpl = (bpl * q_data->fmt->depth) >> 3;
1361 pix->bytesperline = bpl;
1362 }
1363 pix->sizeimage = q_data->size;
1364
1365 return 0;
1366}
1367
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001368static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
1369 u32 pixelformat, unsigned int fmt_type)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001370{
Jacek Anaszewskib2451682014-04-10 04:32:11 -03001371 unsigned int k, fmt_flag;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001372
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001373 if (ctx->mode == S5P_JPEG_ENCODE)
1374 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
1375 SJPEG_FMT_FLAG_ENC_OUTPUT :
1376 SJPEG_FMT_FLAG_ENC_CAPTURE;
1377 else
1378 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
1379 SJPEG_FMT_FLAG_DEC_OUTPUT :
1380 SJPEG_FMT_FLAG_DEC_CAPTURE;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001381
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001382 for (k = 0; k < ARRAY_SIZE(sjpeg_formats); k++) {
1383 struct s5p_jpeg_fmt *fmt = &sjpeg_formats[k];
Shuah Khan605b8922016-07-14 17:01:56 -03001384
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001385 if (fmt->fourcc == pixelformat &&
1386 fmt->flags & fmt_flag &&
Jacek Anaszewskib2451682014-04-10 04:32:11 -03001387 fmt->flags & ctx->jpeg->variant->fmt_ver_flag) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001388 return fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001389 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001390 }
1391
1392 return NULL;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001393}
1394
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001395static void jpeg_bound_align_image(struct s5p_jpeg_ctx *ctx,
1396 u32 *w, unsigned int wmin, unsigned int wmax,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001397 unsigned int walign,
1398 u32 *h, unsigned int hmin, unsigned int hmax,
1399 unsigned int halign)
1400{
1401 int width, height, w_step, h_step;
1402
1403 width = *w;
1404 height = *h;
1405
1406 w_step = 1 << walign;
1407 h_step = 1 << halign;
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001408
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001409 if (ctx->jpeg->variant->hw3250_compat) {
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001410 /*
1411 * Rightmost and bottommost pixels are cropped by the
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001412 * Exynos3250/compatible JPEG IP for RGB formats, for the
1413 * specific width and height values respectively. This
1414 * assignment will result in v4l_bound_align_image returning
1415 * dimensions reduced by 1 for the aforementioned cases.
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001416 */
1417 if (w_step == 4 && ((width & 3) == 1)) {
1418 wmax = width;
1419 hmax = height;
1420 }
1421 }
1422
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001423 v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
1424
1425 if (*w < width && (*w + w_step) < wmax)
1426 *w += w_step;
1427 if (*h < height && (*h + h_step) < hmax)
1428 *h += h_step;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001429}
1430
1431static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
1432 struct s5p_jpeg_ctx *ctx, int q_type)
1433{
1434 struct v4l2_pix_format *pix = &f->fmt.pix;
1435
1436 if (pix->field == V4L2_FIELD_ANY)
1437 pix->field = V4L2_FIELD_NONE;
1438 else if (pix->field != V4L2_FIELD_NONE)
1439 return -EINVAL;
1440
1441 /* V4L2 specification suggests the driver corrects the format struct
Shuah Khan605b8922016-07-14 17:01:56 -03001442 * if any of the dimensions is unsupported
1443 */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001444 if (q_type == FMT_TYPE_OUTPUT)
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001445 jpeg_bound_align_image(ctx, &pix->width, S5P_JPEG_MIN_WIDTH,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001446 S5P_JPEG_MAX_WIDTH, 0,
1447 &pix->height, S5P_JPEG_MIN_HEIGHT,
1448 S5P_JPEG_MAX_HEIGHT, 0);
1449 else
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001450 jpeg_bound_align_image(ctx, &pix->width, S5P_JPEG_MIN_WIDTH,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001451 S5P_JPEG_MAX_WIDTH, fmt->h_align,
1452 &pix->height, S5P_JPEG_MIN_HEIGHT,
1453 S5P_JPEG_MAX_HEIGHT, fmt->v_align);
1454
1455 if (fmt->fourcc == V4L2_PIX_FMT_JPEG) {
1456 if (pix->sizeimage <= 0)
1457 pix->sizeimage = PAGE_SIZE;
1458 pix->bytesperline = 0;
1459 } else {
1460 u32 bpl = pix->bytesperline;
1461
1462 if (fmt->colplanes > 1 && bpl < pix->width)
1463 bpl = pix->width; /* planar */
1464
1465 if (fmt->colplanes == 1 && /* packed */
Jacek Anaszewskicc690902013-11-25 06:58:10 -03001466 (bpl << 3) / fmt->depth < pix->width)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001467 bpl = (pix->width * fmt->depth) >> 3;
1468
1469 pix->bytesperline = bpl;
1470 pix->sizeimage = (pix->width * pix->height * fmt->depth) >> 3;
1471 }
1472
1473 return 0;
1474}
1475
1476static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
1477 struct v4l2_format *f)
1478{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001479 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001480 struct v4l2_pix_format *pix = &f->fmt.pix;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001481 struct s5p_jpeg_fmt *fmt;
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001482 int ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001483
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001484 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
1485 FMT_TYPE_CAPTURE);
1486 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001487 v4l2_err(&ctx->jpeg->v4l2_dev,
1488 "Fourcc format (0x%08x) invalid.\n",
1489 f->fmt.pix.pixelformat);
1490 return -EINVAL;
1491 }
1492
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001493 if (!ctx->jpeg->variant->hw_ex4_compat || ctx->mode != S5P_JPEG_DECODE)
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001494 goto exit;
1495
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001496 /*
1497 * The exynos4x12 device requires resulting YUV image
1498 * subsampling not to be lower than the input jpeg subsampling.
1499 * If this requirement is not met then downgrade the requested
1500 * capture format to the one with subsampling equal to the input jpeg.
1501 */
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001502 if ((fmt->flags & SJPEG_FMT_NON_RGB) &&
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001503 (fmt->subsampling < ctx->subsampling)) {
1504 ret = s5p_jpeg_adjust_fourcc_to_subsampling(ctx->subsampling,
1505 fmt->fourcc,
1506 &pix->pixelformat,
1507 ctx);
1508 if (ret < 0)
1509 pix->pixelformat = V4L2_PIX_FMT_GREY;
1510
1511 fmt = s5p_jpeg_find_format(ctx, pix->pixelformat,
1512 FMT_TYPE_CAPTURE);
1513 }
1514
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001515 /*
1516 * Decompression of a JPEG file with 4:2:0 subsampling and odd
1517 * width to the YUV 4:2:0 compliant formats produces a raw image
1518 * with broken luma component. Adjust capture format to RGB565
1519 * in such a case.
1520 */
1521 if (ctx->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_420 &&
1522 (ctx->out_q.w & 1) &&
1523 (pix->pixelformat == V4L2_PIX_FMT_NV12 ||
1524 pix->pixelformat == V4L2_PIX_FMT_NV21 ||
1525 pix->pixelformat == V4L2_PIX_FMT_YUV420)) {
1526 pix->pixelformat = V4L2_PIX_FMT_RGB565;
1527 fmt = s5p_jpeg_find_format(ctx, pix->pixelformat,
1528 FMT_TYPE_CAPTURE);
1529 }
1530
1531exit:
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001532 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001533}
1534
1535static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
1536 struct v4l2_format *f)
1537{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001538 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001539 struct s5p_jpeg_fmt *fmt;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001540
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001541 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
1542 FMT_TYPE_OUTPUT);
1543 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001544 v4l2_err(&ctx->jpeg->v4l2_dev,
1545 "Fourcc format (0x%08x) invalid.\n",
1546 f->fmt.pix.pixelformat);
1547 return -EINVAL;
1548 }
1549
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001550 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001551}
1552
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001553static int exynos4_jpeg_get_output_buffer_size(struct s5p_jpeg_ctx *ctx,
1554 struct v4l2_format *f,
1555 int fmt_depth)
1556{
1557 struct v4l2_pix_format *pix = &f->fmt.pix;
1558 u32 pix_fmt = f->fmt.pix.pixelformat;
1559 int w = pix->width, h = pix->height, wh_align;
Andrzej Pietrasiewicz77401dd2015-12-08 12:39:08 -02001560 int padding = 0;
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001561
1562 if (pix_fmt == V4L2_PIX_FMT_RGB32 ||
Andrzej Pietrasiewicz77401dd2015-12-08 12:39:08 -02001563 pix_fmt == V4L2_PIX_FMT_RGB565 ||
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001564 pix_fmt == V4L2_PIX_FMT_NV24 ||
1565 pix_fmt == V4L2_PIX_FMT_NV42 ||
1566 pix_fmt == V4L2_PIX_FMT_NV12 ||
1567 pix_fmt == V4L2_PIX_FMT_NV21 ||
1568 pix_fmt == V4L2_PIX_FMT_YUV420)
1569 wh_align = 4;
1570 else
1571 wh_align = 1;
1572
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001573 jpeg_bound_align_image(ctx, &w, S5P_JPEG_MIN_WIDTH,
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001574 S5P_JPEG_MAX_WIDTH, wh_align,
1575 &h, S5P_JPEG_MIN_HEIGHT,
1576 S5P_JPEG_MAX_HEIGHT, wh_align);
1577
Andrzej Pietrasiewicz77401dd2015-12-08 12:39:08 -02001578 if (ctx->jpeg->variant->version == SJPEG_EXYNOS4)
1579 padding = PAGE_SIZE;
1580
1581 return (w * h * fmt_depth >> 3) + padding;
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001582}
1583
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001584static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx,
1585 struct v4l2_rect *r);
1586
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001587static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
1588{
1589 struct vb2_queue *vq;
1590 struct s5p_jpeg_q_data *q_data = NULL;
1591 struct v4l2_pix_format *pix = &f->fmt.pix;
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001592 struct v4l2_ctrl *ctrl_subs;
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001593 struct v4l2_rect scale_rect;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001594 unsigned int f_type;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001595
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001596 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001597 if (!vq)
1598 return -EINVAL;
1599
1600 q_data = get_q_data(ct, f->type);
1601 BUG_ON(q_data == NULL);
1602
1603 if (vb2_is_busy(vq)) {
1604 v4l2_err(&ct->jpeg->v4l2_dev, "%s queue busy\n", __func__);
1605 return -EBUSY;
1606 }
1607
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001608 f_type = V4L2_TYPE_IS_OUTPUT(f->type) ?
1609 FMT_TYPE_OUTPUT : FMT_TYPE_CAPTURE;
1610
1611 q_data->fmt = s5p_jpeg_find_format(ct, pix->pixelformat, f_type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001612 q_data->w = pix->width;
1613 q_data->h = pix->height;
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001614 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
1615 /*
1616 * During encoding Exynos4x12 SoCs access wider memory area
1617 * than it results from Image_x and Image_y values written to
1618 * the JPEG_IMAGE_SIZE register. In order to avoid sysmmu
1619 * page fault calculate proper buffer size in such a case.
1620 */
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001621 if (ct->jpeg->variant->hw_ex4_compat &&
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001622 f_type == FMT_TYPE_OUTPUT && ct->mode == S5P_JPEG_ENCODE)
1623 q_data->size = exynos4_jpeg_get_output_buffer_size(ct,
1624 f,
1625 q_data->fmt->depth);
1626 else
1627 q_data->size = q_data->w * q_data->h *
1628 q_data->fmt->depth >> 3;
1629 } else {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001630 q_data->size = pix->sizeimage;
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001631 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001632
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001633 if (f_type == FMT_TYPE_OUTPUT) {
1634 ctrl_subs = v4l2_ctrl_find(&ct->ctrl_handler,
1635 V4L2_CID_JPEG_CHROMA_SUBSAMPLING);
1636 if (ctrl_subs)
1637 v4l2_ctrl_s_ctrl(ctrl_subs, q_data->fmt->subsampling);
Jacek Anaszewskidfd96902014-07-11 12:19:46 -03001638 ct->crop_altered = false;
1639 }
1640
1641 /*
1642 * For decoding init crop_rect with capture buffer dimmensions which
1643 * contain aligned dimensions of the input JPEG image and do it only
1644 * if crop rectangle hasn't been altered by the user space e.g. with
1645 * S_SELECTION ioctl. For encoding assign output buffer dimensions.
1646 */
1647 if (!ct->crop_altered &&
1648 ((ct->mode == S5P_JPEG_DECODE && f_type == FMT_TYPE_CAPTURE) ||
1649 (ct->mode == S5P_JPEG_ENCODE && f_type == FMT_TYPE_OUTPUT))) {
1650 ct->crop_rect.width = pix->width;
1651 ct->crop_rect.height = pix->height;
1652 }
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001653
1654 /*
1655 * Prevent downscaling to YUV420 format by more than 2
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001656 * for Exynos3250/compatible SoC as it produces broken raw image
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001657 * in such cases.
1658 */
1659 if (ct->mode == S5P_JPEG_DECODE &&
1660 f_type == FMT_TYPE_CAPTURE &&
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001661 ct->jpeg->variant->hw3250_compat &&
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001662 pix->pixelformat == V4L2_PIX_FMT_YUV420 &&
1663 ct->scale_factor > 2) {
1664 scale_rect.width = ct->out_q.w / 2;
1665 scale_rect.height = ct->out_q.h / 2;
1666 exynos3250_jpeg_try_downscale(ct, &scale_rect);
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001667 }
1668
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001669 return 0;
1670}
1671
1672static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
1673 struct v4l2_format *f)
1674{
1675 int ret;
1676
1677 ret = s5p_jpeg_try_fmt_vid_cap(file, priv, f);
1678 if (ret)
1679 return ret;
1680
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001681 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001682}
1683
1684static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
1685 struct v4l2_format *f)
1686{
1687 int ret;
1688
1689 ret = s5p_jpeg_try_fmt_vid_out(file, priv, f);
1690 if (ret)
1691 return ret;
1692
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001693 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001694}
1695
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001696static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx,
1697 struct v4l2_rect *r)
1698{
1699 int w_ratio, h_ratio, scale_factor, cur_ratio, i;
1700
1701 w_ratio = ctx->out_q.w / r->width;
1702 h_ratio = ctx->out_q.h / r->height;
1703
1704 scale_factor = w_ratio > h_ratio ? w_ratio : h_ratio;
1705 scale_factor = clamp_val(scale_factor, 1, 8);
1706
1707 /* Align scale ratio to the nearest power of 2 */
1708 for (i = 0; i <= 3; ++i) {
1709 cur_ratio = 1 << i;
1710 if (scale_factor <= cur_ratio) {
1711 ctx->scale_factor = cur_ratio;
1712 break;
1713 }
1714 }
1715
1716 r->width = round_down(ctx->out_q.w / ctx->scale_factor, 2);
1717 r->height = round_down(ctx->out_q.h / ctx->scale_factor, 2);
1718
1719 ctx->crop_rect.width = r->width;
1720 ctx->crop_rect.height = r->height;
1721 ctx->crop_rect.left = 0;
1722 ctx->crop_rect.top = 0;
1723
1724 ctx->crop_altered = true;
1725
1726 return 0;
1727}
1728
1729/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */
1730static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
1731{
1732 if (a->left < b->left || a->top < b->top)
1733 return 0;
1734 if (a->left + a->width > b->left + b->width)
1735 return 0;
1736 if (a->top + a->height > b->top + b->height)
1737 return 0;
1738
1739 return 1;
1740}
1741
1742static int exynos3250_jpeg_try_crop(struct s5p_jpeg_ctx *ctx,
1743 struct v4l2_rect *r)
1744{
1745 struct v4l2_rect base_rect;
1746 int w_step, h_step;
1747
1748 switch (ctx->cap_q.fmt->fourcc) {
1749 case V4L2_PIX_FMT_NV12:
1750 case V4L2_PIX_FMT_NV21:
1751 w_step = 1;
1752 h_step = 2;
1753 break;
1754 case V4L2_PIX_FMT_YUV420:
1755 w_step = 2;
1756 h_step = 2;
1757 break;
1758 default:
1759 w_step = 1;
1760 h_step = 1;
1761 break;
1762 }
1763
1764 base_rect.top = 0;
1765 base_rect.left = 0;
1766 base_rect.width = ctx->out_q.w;
1767 base_rect.height = ctx->out_q.h;
1768
1769 r->width = round_down(r->width, w_step);
1770 r->height = round_down(r->height, h_step);
1771 r->left = round_down(r->left, 2);
1772 r->top = round_down(r->top, 2);
1773
1774 if (!enclosed_rectangle(r, &base_rect))
1775 return -EINVAL;
1776
1777 ctx->crop_rect.left = r->left;
1778 ctx->crop_rect.top = r->top;
1779 ctx->crop_rect.width = r->width;
1780 ctx->crop_rect.height = r->height;
1781
1782 ctx->crop_altered = true;
1783
1784 return 0;
1785}
1786
1787/*
1788 * V4L2 controls
1789 */
1790
Sachin Kamat9f3bd322012-05-10 03:38:40 -03001791static int s5p_jpeg_g_selection(struct file *file, void *priv,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001792 struct v4l2_selection *s)
1793{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001794 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001795
1796 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
Jacek Anaszewski38a6ef32014-04-10 04:32:15 -03001797 s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001798 return -EINVAL;
1799
1800 /* For JPEG blob active == default == bounds */
1801 switch (s->target) {
Sylwester Nawrockic1334822012-05-20 11:17:12 -03001802 case V4L2_SEL_TGT_CROP:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001803 case V4L2_SEL_TGT_CROP_BOUNDS:
1804 case V4L2_SEL_TGT_CROP_DEFAULT:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001805 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
1806 s->r.width = ctx->out_q.w;
1807 s->r.height = ctx->out_q.h;
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001808 s->r.left = 0;
1809 s->r.top = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001810 break;
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001811 case V4L2_SEL_TGT_COMPOSE:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001812 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
1813 case V4L2_SEL_TGT_COMPOSE_PADDED:
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001814 s->r.width = ctx->crop_rect.width;
1815 s->r.height = ctx->crop_rect.height;
1816 s->r.left = ctx->crop_rect.left;
1817 s->r.top = ctx->crop_rect.top;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001818 break;
1819 default:
1820 return -EINVAL;
1821 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001822 return 0;
1823}
1824
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001825/*
1826 * V4L2 controls
1827 */
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001828static int s5p_jpeg_s_selection(struct file *file, void *fh,
1829 struct v4l2_selection *s)
1830{
1831 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
1832 struct v4l2_rect *rect = &s->r;
1833 int ret = -EINVAL;
1834
1835 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1836 return -EINVAL;
1837
1838 if (s->target == V4L2_SEL_TGT_COMPOSE) {
1839 if (ctx->mode != S5P_JPEG_DECODE)
1840 return -EINVAL;
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001841 if (ctx->jpeg->variant->hw3250_compat)
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001842 ret = exynos3250_jpeg_try_downscale(ctx, rect);
1843 } else if (s->target == V4L2_SEL_TGT_CROP) {
1844 if (ctx->mode != S5P_JPEG_ENCODE)
1845 return -EINVAL;
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001846 if (ctx->jpeg->variant->hw3250_compat)
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001847 ret = exynos3250_jpeg_try_crop(ctx, rect);
1848 }
1849
1850 return ret;
1851}
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001852
1853static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001854{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001855 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1856 struct s5p_jpeg *jpeg = ctx->jpeg;
1857 unsigned long flags;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001858
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001859 switch (ctrl->id) {
1860 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1861 spin_lock_irqsave(&jpeg->slock, flags);
Jacek Anaszewski303b0a92013-12-18 11:14:00 -03001862 ctrl->val = s5p_jpeg_to_user_subsampling(ctx);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001863 spin_unlock_irqrestore(&jpeg->slock, flags);
1864 break;
1865 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001866
1867 return 0;
1868}
1869
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001870static int s5p_jpeg_adjust_subs_ctrl(struct s5p_jpeg_ctx *ctx, int *ctrl_val)
1871{
1872 switch (ctx->jpeg->variant->version) {
1873 case SJPEG_S5P:
1874 return 0;
1875 case SJPEG_EXYNOS3250:
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001876 case SJPEG_EXYNOS5420:
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001877 /*
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001878 * The exynos3250/compatible device can produce JPEG image only
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001879 * of 4:4:4 subsampling when given RGB32 source image.
1880 */
1881 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB32)
1882 *ctrl_val = 0;
1883 break;
1884 case SJPEG_EXYNOS4:
1885 /*
1886 * The exynos4x12 device requires input raw image fourcc
1887 * to be V4L2_PIX_FMT_GREY if gray jpeg format
1888 * is to be set.
1889 */
1890 if (ctx->out_q.fmt->fourcc != V4L2_PIX_FMT_GREY &&
1891 *ctrl_val == V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY)
1892 return -EINVAL;
1893 break;
1894 }
1895
1896 /*
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001897 * The exynos4x12 and exynos3250/compatible devices require resulting
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001898 * jpeg subsampling not to be lower than the input raw image
1899 * subsampling.
1900 */
1901 if (ctx->out_q.fmt->subsampling > *ctrl_val)
1902 *ctrl_val = ctx->out_q.fmt->subsampling;
1903
1904 return 0;
1905}
1906
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001907static int s5p_jpeg_try_ctrl(struct v4l2_ctrl *ctrl)
1908{
1909 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1910 unsigned long flags;
1911 int ret = 0;
1912
1913 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1914
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001915 if (ctrl->id == V4L2_CID_JPEG_CHROMA_SUBSAMPLING)
1916 ret = s5p_jpeg_adjust_subs_ctrl(ctx, &ctrl->val);
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001917
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001918 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1919 return ret;
1920}
1921
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001922static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001923{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001924 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1925 unsigned long flags;
1926
1927 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1928
1929 switch (ctrl->id) {
1930 case V4L2_CID_JPEG_COMPRESSION_QUALITY:
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001931 ctx->compr_quality = ctrl->val;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001932 break;
1933 case V4L2_CID_JPEG_RESTART_INTERVAL:
1934 ctx->restart_interval = ctrl->val;
1935 break;
1936 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1937 ctx->subsampling = ctrl->val;
1938 break;
1939 }
1940
1941 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1942 return 0;
1943}
1944
1945static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
1946 .g_volatile_ctrl = s5p_jpeg_g_volatile_ctrl,
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001947 .try_ctrl = s5p_jpeg_try_ctrl,
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001948 .s_ctrl = s5p_jpeg_s_ctrl,
1949};
1950
1951static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
1952{
1953 unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */
1954 struct v4l2_ctrl *ctrl;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001955 int ret;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001956
1957 v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
1958
1959 if (ctx->mode == S5P_JPEG_ENCODE) {
1960 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1961 V4L2_CID_JPEG_COMPRESSION_QUALITY,
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001962 0, 3, 1, S5P_JPEG_COMPR_QUAL_WORST);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001963
1964 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1965 V4L2_CID_JPEG_RESTART_INTERVAL,
Pawe? Chmiel33f5e612019-01-09 13:00:41 -05001966 0, 0xffff, 1, 0);
Jacek Anaszewskifdf9e2b2013-11-21 13:33:41 -03001967 if (ctx->jpeg->variant->version == SJPEG_S5P)
1968 mask = ~0x06; /* 422, 420 */
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001969 }
1970
1971 ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1972 V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
1973 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask,
1974 V4L2_JPEG_CHROMA_SUBSAMPLING_422);
1975
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001976 if (ctx->ctrl_handler.error) {
1977 ret = ctx->ctrl_handler.error;
1978 goto error_free;
1979 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001980
1981 if (ctx->mode == S5P_JPEG_DECODE)
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001982 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
1983 V4L2_CTRL_FLAG_READ_ONLY;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001984
1985 ret = v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
1986 if (ret < 0)
1987 goto error_free;
1988
1989 return ret;
1990
1991error_free:
1992 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
1993 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001994}
1995
1996static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
1997 .vidioc_querycap = s5p_jpeg_querycap,
1998
1999 .vidioc_enum_fmt_vid_cap = s5p_jpeg_enum_fmt_vid_cap,
2000 .vidioc_enum_fmt_vid_out = s5p_jpeg_enum_fmt_vid_out,
2001
2002 .vidioc_g_fmt_vid_cap = s5p_jpeg_g_fmt,
2003 .vidioc_g_fmt_vid_out = s5p_jpeg_g_fmt,
2004
2005 .vidioc_try_fmt_vid_cap = s5p_jpeg_try_fmt_vid_cap,
2006 .vidioc_try_fmt_vid_out = s5p_jpeg_try_fmt_vid_out,
2007
2008 .vidioc_s_fmt_vid_cap = s5p_jpeg_s_fmt_vid_cap,
2009 .vidioc_s_fmt_vid_out = s5p_jpeg_s_fmt_vid_out,
2010
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002011 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
2012 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
2013 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
2014 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002015
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002016 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
2017 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002018
2019 .vidioc_g_selection = s5p_jpeg_g_selection,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002020 .vidioc_s_selection = s5p_jpeg_s_selection,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002021};
2022
2023/*
2024 * ============================================================================
2025 * mem2mem callbacks
2026 * ============================================================================
2027 */
2028
2029static void s5p_jpeg_device_run(void *priv)
2030{
2031 struct s5p_jpeg_ctx *ctx = priv;
2032 struct s5p_jpeg *jpeg = ctx->jpeg;
Ezequiel Garcia208285a2019-02-08 11:17:45 -05002033 struct vb2_v4l2_buffer *src_buf, *dst_buf;
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002034 unsigned long src_addr, dst_addr, flags;
2035
2036 spin_lock_irqsave(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002037
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002038 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2039 dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
Ezequiel Garcia208285a2019-02-08 11:17:45 -05002040 src_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
2041 dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002042
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002043 s5p_jpeg_reset(jpeg->regs);
2044 s5p_jpeg_poweron(jpeg->regs);
2045 s5p_jpeg_proc_mode(jpeg->regs, ctx->mode);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002046 if (ctx->mode == S5P_JPEG_ENCODE) {
2047 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002048 s5p_jpeg_input_raw_mode(jpeg->regs,
2049 S5P_JPEG_RAW_IN_565);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002050 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002051 s5p_jpeg_input_raw_mode(jpeg->regs,
2052 S5P_JPEG_RAW_IN_422);
2053 s5p_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
2054 s5p_jpeg_dri(jpeg->regs, ctx->restart_interval);
2055 s5p_jpeg_x(jpeg->regs, ctx->out_q.w);
2056 s5p_jpeg_y(jpeg->regs, ctx->out_q.h);
2057 s5p_jpeg_imgadr(jpeg->regs, src_addr);
2058 s5p_jpeg_jpgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002059
2060 /* ultimately comes from sizeimage from userspace */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002061 s5p_jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002062
2063 /* JPEG RGB to YCbCr conversion matrix */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002064 s5p_jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11);
2065 s5p_jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12);
2066 s5p_jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13);
2067 s5p_jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21);
2068 s5p_jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22);
2069 s5p_jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23);
2070 s5p_jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31);
2071 s5p_jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32);
2072 s5p_jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002073
2074 /*
2075 * JPEG IP allows storing 4 quantization tables
2076 * We fill table 0 for luma and table 1 for chroma
2077 */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03002078 s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
2079 s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002080 /* use table 0 for Y */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002081 s5p_jpeg_qtbl(jpeg->regs, 1, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002082 /* use table 1 for Cb and Cr*/
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002083 s5p_jpeg_qtbl(jpeg->regs, 2, 1);
2084 s5p_jpeg_qtbl(jpeg->regs, 3, 1);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002085
2086 /* Y, Cb, Cr use Huffman table 0 */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002087 s5p_jpeg_htbl_ac(jpeg->regs, 1);
2088 s5p_jpeg_htbl_dc(jpeg->regs, 1);
2089 s5p_jpeg_htbl_ac(jpeg->regs, 2);
2090 s5p_jpeg_htbl_dc(jpeg->regs, 2);
2091 s5p_jpeg_htbl_ac(jpeg->regs, 3);
2092 s5p_jpeg_htbl_dc(jpeg->regs, 3);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03002093 } else { /* S5P_JPEG_DECODE */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002094 s5p_jpeg_rst_int_enable(jpeg->regs, true);
2095 s5p_jpeg_data_num_int_enable(jpeg->regs, true);
2096 s5p_jpeg_final_mcu_num_int_enable(jpeg->regs, true);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03002097 if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002098 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03002099 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002100 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420);
2101 s5p_jpeg_jpgadr(jpeg->regs, src_addr);
2102 s5p_jpeg_imgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002103 }
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002104
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002105 s5p_jpeg_start(jpeg->regs);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002106
2107 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002108}
2109
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002110static void exynos4_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
2111{
2112 struct s5p_jpeg *jpeg = ctx->jpeg;
2113 struct s5p_jpeg_fmt *fmt;
Ezequiel Garcia208285a2019-02-08 11:17:45 -05002114 struct vb2_v4l2_buffer *vb;
Jacek Anaszewski12b05562015-03-05 10:56:25 -03002115 struct s5p_jpeg_addr jpeg_addr = {};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002116 u32 pix_size, padding_bytes = 0;
2117
Tony K Nadackalcb0c3f52014-12-17 04:21:21 -03002118 jpeg_addr.cb = 0;
2119 jpeg_addr.cr = 0;
2120
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002121 pix_size = ctx->cap_q.w * ctx->cap_q.h;
2122
2123 if (ctx->mode == S5P_JPEG_ENCODE) {
2124 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2125 fmt = ctx->out_q.fmt;
2126 if (ctx->out_q.w % 2 && fmt->h_align > 0)
2127 padding_bytes = ctx->out_q.h;
2128 } else {
2129 fmt = ctx->cap_q.fmt;
2130 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
2131 }
2132
Ezequiel Garcia208285a2019-02-08 11:17:45 -05002133 jpeg_addr.y = vb2_dma_contig_plane_dma_addr(&vb->vb2_buf, 0);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002134
2135 if (fmt->colplanes == 2) {
2136 jpeg_addr.cb = jpeg_addr.y + pix_size - padding_bytes;
2137 } else if (fmt->colplanes == 3) {
2138 jpeg_addr.cb = jpeg_addr.y + pix_size;
2139 if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
2140 jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
2141 else
2142 jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
2143 }
2144
2145 exynos4_jpeg_set_frame_buf_address(jpeg->regs, &jpeg_addr);
2146}
2147
2148static void exynos4_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
2149{
2150 struct s5p_jpeg *jpeg = ctx->jpeg;
Ezequiel Garcia208285a2019-02-08 11:17:45 -05002151 struct vb2_v4l2_buffer *vb;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002152 unsigned int jpeg_addr = 0;
2153
2154 if (ctx->mode == S5P_JPEG_ENCODE)
2155 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
2156 else
2157 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2158
Ezequiel Garcia208285a2019-02-08 11:17:45 -05002159 jpeg_addr = vb2_dma_contig_plane_dma_addr(&vb->vb2_buf, 0);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002160 if (jpeg->variant->version == SJPEG_EXYNOS5433 &&
2161 ctx->mode == S5P_JPEG_DECODE)
2162 jpeg_addr += ctx->out_q.sos;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002163 exynos4_jpeg_set_stream_buf_address(jpeg->regs, jpeg_addr);
2164}
2165
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002166static inline void exynos4_jpeg_set_img_fmt(void __iomem *base,
2167 unsigned int img_fmt)
2168{
2169 __exynos4_jpeg_set_img_fmt(base, img_fmt, SJPEG_EXYNOS4);
2170}
2171
2172static inline void exynos5433_jpeg_set_img_fmt(void __iomem *base,
2173 unsigned int img_fmt)
2174{
2175 __exynos4_jpeg_set_img_fmt(base, img_fmt, SJPEG_EXYNOS5433);
2176}
2177
2178static inline void exynos4_jpeg_set_enc_out_fmt(void __iomem *base,
2179 unsigned int out_fmt)
2180{
2181 __exynos4_jpeg_set_enc_out_fmt(base, out_fmt, SJPEG_EXYNOS4);
2182}
2183
2184static inline void exynos5433_jpeg_set_enc_out_fmt(void __iomem *base,
2185 unsigned int out_fmt)
2186{
2187 __exynos4_jpeg_set_enc_out_fmt(base, out_fmt, SJPEG_EXYNOS5433);
2188}
2189
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002190static void exynos4_jpeg_device_run(void *priv)
2191{
2192 struct s5p_jpeg_ctx *ctx = priv;
2193 struct s5p_jpeg *jpeg = ctx->jpeg;
2194 unsigned int bitstream_size;
2195 unsigned long flags;
2196
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002197 spin_lock_irqsave(&jpeg->slock, flags);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002198
2199 if (ctx->mode == S5P_JPEG_ENCODE) {
2200 exynos4_jpeg_sw_reset(jpeg->regs);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002201 exynos4_jpeg_set_interrupt(jpeg->regs, jpeg->variant->version);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002202 exynos4_jpeg_set_huf_table_enable(jpeg->regs, 1);
2203
2204 exynos4_jpeg_set_huff_tbl(jpeg->regs);
2205
2206 /*
2207 * JPEG IP allows storing 4 quantization tables
2208 * We fill table 0 for luma and table 1 for chroma
2209 */
2210 exynos4_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
2211 exynos4_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
2212
2213 exynos4_jpeg_set_encode_tbl_select(jpeg->regs,
2214 ctx->compr_quality);
2215 exynos4_jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w,
2216 ctx->cap_q.h);
2217
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002218 if (ctx->jpeg->variant->version == SJPEG_EXYNOS4) {
2219 exynos4_jpeg_set_enc_out_fmt(jpeg->regs,
2220 ctx->subsampling);
2221 exynos4_jpeg_set_img_fmt(jpeg->regs,
2222 ctx->out_q.fmt->fourcc);
2223 } else {
2224 exynos5433_jpeg_set_enc_out_fmt(jpeg->regs,
2225 ctx->subsampling);
2226 exynos5433_jpeg_set_img_fmt(jpeg->regs,
2227 ctx->out_q.fmt->fourcc);
2228 }
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002229 exynos4_jpeg_set_img_addr(ctx);
2230 exynos4_jpeg_set_jpeg_addr(ctx);
2231 exynos4_jpeg_set_encode_hoff_cnt(jpeg->regs,
2232 ctx->out_q.fmt->fourcc);
2233 } else {
2234 exynos4_jpeg_sw_reset(jpeg->regs);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002235 exynos4_jpeg_set_interrupt(jpeg->regs,
2236 jpeg->variant->version);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002237 exynos4_jpeg_set_img_addr(ctx);
2238 exynos4_jpeg_set_jpeg_addr(ctx);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002239
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002240 if (jpeg->variant->version == SJPEG_EXYNOS5433) {
2241 exynos4_jpeg_parse_huff_tbl(ctx);
2242 exynos4_jpeg_parse_decode_h_tbl(ctx);
2243
2244 exynos4_jpeg_parse_q_tbl(ctx);
2245 exynos4_jpeg_parse_decode_q_tbl(ctx);
2246
2247 exynos4_jpeg_set_huf_table_enable(jpeg->regs, 1);
2248
2249 exynos4_jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w,
2250 ctx->cap_q.h);
2251 exynos5433_jpeg_set_enc_out_fmt(jpeg->regs,
2252 ctx->subsampling);
2253 exynos5433_jpeg_set_img_fmt(jpeg->regs,
2254 ctx->cap_q.fmt->fourcc);
2255 bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 16);
2256 } else {
2257 exynos4_jpeg_set_img_fmt(jpeg->regs,
2258 ctx->cap_q.fmt->fourcc);
2259 bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 32);
2260 }
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002261
2262 exynos4_jpeg_set_dec_bitstream_size(jpeg->regs, bitstream_size);
2263 }
2264
2265 exynos4_jpeg_set_enc_dec_mode(jpeg->regs, ctx->mode);
2266
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002267 spin_unlock_irqrestore(&jpeg->slock, flags);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002268}
2269
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002270static void exynos3250_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
2271{
2272 struct s5p_jpeg *jpeg = ctx->jpeg;
2273 struct s5p_jpeg_fmt *fmt;
Ezequiel Garcia208285a2019-02-08 11:17:45 -05002274 struct vb2_v4l2_buffer *vb;
Jacek Anaszewski12b05562015-03-05 10:56:25 -03002275 struct s5p_jpeg_addr jpeg_addr = {};
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002276 u32 pix_size;
2277
2278 pix_size = ctx->cap_q.w * ctx->cap_q.h;
2279
2280 if (ctx->mode == S5P_JPEG_ENCODE) {
2281 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2282 fmt = ctx->out_q.fmt;
2283 } else {
2284 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
2285 fmt = ctx->cap_q.fmt;
2286 }
2287
Ezequiel Garcia208285a2019-02-08 11:17:45 -05002288 jpeg_addr.y = vb2_dma_contig_plane_dma_addr(&vb->vb2_buf, 0);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002289
2290 if (fmt->colplanes == 2) {
2291 jpeg_addr.cb = jpeg_addr.y + pix_size;
2292 } else if (fmt->colplanes == 3) {
2293 jpeg_addr.cb = jpeg_addr.y + pix_size;
2294 if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
2295 jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
2296 else
2297 jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
2298 }
2299
2300 exynos3250_jpeg_imgadr(jpeg->regs, &jpeg_addr);
2301}
2302
2303static void exynos3250_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
2304{
2305 struct s5p_jpeg *jpeg = ctx->jpeg;
Ezequiel Garcia208285a2019-02-08 11:17:45 -05002306 struct vb2_v4l2_buffer *vb;
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002307 unsigned int jpeg_addr = 0;
2308
2309 if (ctx->mode == S5P_JPEG_ENCODE)
2310 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
2311 else
2312 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2313
Ezequiel Garcia208285a2019-02-08 11:17:45 -05002314 jpeg_addr = vb2_dma_contig_plane_dma_addr(&vb->vb2_buf, 0);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002315 exynos3250_jpeg_jpgadr(jpeg->regs, jpeg_addr);
2316}
2317
2318static void exynos3250_jpeg_device_run(void *priv)
2319{
2320 struct s5p_jpeg_ctx *ctx = priv;
2321 struct s5p_jpeg *jpeg = ctx->jpeg;
2322 unsigned long flags;
2323
2324 spin_lock_irqsave(&ctx->jpeg->slock, flags);
2325
2326 exynos3250_jpeg_reset(jpeg->regs);
2327 exynos3250_jpeg_set_dma_num(jpeg->regs);
2328 exynos3250_jpeg_poweron(jpeg->regs);
2329 exynos3250_jpeg_clk_set(jpeg->regs);
2330 exynos3250_jpeg_proc_mode(jpeg->regs, ctx->mode);
2331
2332 if (ctx->mode == S5P_JPEG_ENCODE) {
2333 exynos3250_jpeg_input_raw_fmt(jpeg->regs,
2334 ctx->out_q.fmt->fourcc);
2335 exynos3250_jpeg_dri(jpeg->regs, ctx->restart_interval);
2336
2337 /*
2338 * JPEG IP allows storing 4 quantization tables
2339 * We fill table 0 for luma and table 1 for chroma
2340 */
2341 s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
2342 s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
2343 /* use table 0 for Y */
2344 exynos3250_jpeg_qtbl(jpeg->regs, 1, 0);
2345 /* use table 1 for Cb and Cr*/
2346 exynos3250_jpeg_qtbl(jpeg->regs, 2, 1);
2347 exynos3250_jpeg_qtbl(jpeg->regs, 3, 1);
2348
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03002349 /*
2350 * Some SoCs require setting Huffman tables before each run
2351 */
2352 if (jpeg->variant->htbl_reinit) {
2353 s5p_jpeg_set_hdctbl(jpeg->regs);
2354 s5p_jpeg_set_hdctblg(jpeg->regs);
2355 s5p_jpeg_set_hactbl(jpeg->regs);
2356 s5p_jpeg_set_hactblg(jpeg->regs);
2357 }
2358
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002359 /* Y, Cb, Cr use Huffman table 0 */
2360 exynos3250_jpeg_htbl_ac(jpeg->regs, 1);
2361 exynos3250_jpeg_htbl_dc(jpeg->regs, 1);
2362 exynos3250_jpeg_htbl_ac(jpeg->regs, 2);
2363 exynos3250_jpeg_htbl_dc(jpeg->regs, 2);
2364 exynos3250_jpeg_htbl_ac(jpeg->regs, 3);
2365 exynos3250_jpeg_htbl_dc(jpeg->regs, 3);
2366
2367 exynos3250_jpeg_set_x(jpeg->regs, ctx->crop_rect.width);
2368 exynos3250_jpeg_set_y(jpeg->regs, ctx->crop_rect.height);
2369 exynos3250_jpeg_stride(jpeg->regs, ctx->out_q.fmt->fourcc,
2370 ctx->out_q.w);
2371 exynos3250_jpeg_offset(jpeg->regs, ctx->crop_rect.left,
2372 ctx->crop_rect.top);
2373 exynos3250_jpeg_set_img_addr(ctx);
2374 exynos3250_jpeg_set_jpeg_addr(ctx);
2375 exynos3250_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
2376
2377 /* ultimately comes from sizeimage from userspace */
2378 exynos3250_jpeg_enc_stream_bound(jpeg->regs, ctx->cap_q.size);
2379
2380 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565 ||
2381 ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565X ||
2382 ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB32)
2383 exynos3250_jpeg_set_y16(jpeg->regs, true);
2384 } else {
2385 exynos3250_jpeg_set_img_addr(ctx);
2386 exynos3250_jpeg_set_jpeg_addr(ctx);
2387 exynos3250_jpeg_stride(jpeg->regs, ctx->cap_q.fmt->fourcc,
2388 ctx->cap_q.w);
2389 exynos3250_jpeg_offset(jpeg->regs, 0, 0);
2390 exynos3250_jpeg_dec_scaling_ratio(jpeg->regs,
2391 ctx->scale_factor);
2392 exynos3250_jpeg_dec_stream_size(jpeg->regs, ctx->out_q.size);
2393 exynos3250_jpeg_output_raw_fmt(jpeg->regs,
2394 ctx->cap_q.fmt->fourcc);
2395 }
2396
2397 exynos3250_jpeg_interrupts_enable(jpeg->regs);
2398
2399 /* JPEG RGB to YCbCr conversion matrix */
2400 exynos3250_jpeg_coef(jpeg->regs, ctx->mode);
2401
2402 exynos3250_jpeg_set_timer(jpeg->regs, EXYNOS3250_IRQ_TIMEOUT);
2403 jpeg->irq_status = 0;
2404 exynos3250_jpeg_start(jpeg->regs);
2405
2406 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
2407}
2408
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002409static int s5p_jpeg_job_ready(void *priv)
2410{
2411 struct s5p_jpeg_ctx *ctx = priv;
2412
2413 if (ctx->mode == S5P_JPEG_DECODE)
2414 return ctx->hdr_parsed;
2415 return 1;
2416}
2417
2418static void s5p_jpeg_job_abort(void *priv)
2419{
2420}
2421
2422static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = {
2423 .device_run = s5p_jpeg_device_run,
2424 .job_ready = s5p_jpeg_job_ready,
2425 .job_abort = s5p_jpeg_job_abort,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002426};
2427
2428static struct v4l2_m2m_ops exynos3250_jpeg_m2m_ops = {
2429 .device_run = exynos3250_jpeg_device_run,
2430 .job_ready = s5p_jpeg_job_ready,
2431 .job_abort = s5p_jpeg_job_abort,
2432};
2433
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03002434static struct v4l2_m2m_ops exynos4_jpeg_m2m_ops = {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002435 .device_run = exynos4_jpeg_device_run,
2436 .job_ready = s5p_jpeg_job_ready,
2437 .job_abort = s5p_jpeg_job_abort,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002438};
2439
2440/*
2441 * ============================================================================
2442 * Queue operations
2443 * ============================================================================
2444 */
2445
Marek Szyprowski719c1742012-01-13 05:12:38 -03002446static int s5p_jpeg_queue_setup(struct vb2_queue *vq,
Marek Szyprowski719c1742012-01-13 05:12:38 -03002447 unsigned int *nbuffers, unsigned int *nplanes,
Hans Verkuil36c0f8b2016-04-15 09:15:05 -03002448 unsigned int sizes[], struct device *alloc_devs[])
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002449{
2450 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
2451 struct s5p_jpeg_q_data *q_data = NULL;
2452 unsigned int size, count = *nbuffers;
2453
2454 q_data = get_q_data(ctx, vq->type);
2455 BUG_ON(q_data == NULL);
2456
2457 size = q_data->size;
2458
2459 /*
2460 * header is parsed during decoding and parsed information stored
2461 * in the context so we do not allow another buffer to overwrite it
2462 */
2463 if (ctx->mode == S5P_JPEG_DECODE)
2464 count = 1;
2465
2466 *nbuffers = count;
2467 *nplanes = 1;
2468 sizes[0] = size;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002469
2470 return 0;
2471}
2472
2473static int s5p_jpeg_buf_prepare(struct vb2_buffer *vb)
2474{
2475 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
2476 struct s5p_jpeg_q_data *q_data = NULL;
2477
2478 q_data = get_q_data(ctx, vb->vb2_queue->type);
2479 BUG_ON(q_data == NULL);
2480
2481 if (vb2_plane_size(vb, 0) < q_data->size) {
2482 pr_err("%s data will not fit into plane (%lu < %lu)\n",
2483 __func__, vb2_plane_size(vb, 0),
2484 (long)q_data->size);
2485 return -EINVAL;
2486 }
2487
2488 vb2_set_plane_payload(vb, 0, q_data->size);
2489
2490 return 0;
2491}
2492
2493static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
2494{
Junghak Sung2d700712015-09-22 10:30:30 -03002495 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002496 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
2497
2498 if (ctx->mode == S5P_JPEG_DECODE &&
2499 vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
2500 struct s5p_jpeg_q_data tmp, *q_data;
Shuah Khan605b8922016-07-14 17:01:56 -03002501
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002502 ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp,
2503 (unsigned long)vb2_plane_vaddr(vb, 0),
2504 min((unsigned long)ctx->out_q.size,
Jacek Anaszewskif8433962013-11-21 13:33:09 -03002505 vb2_get_plane_payload(vb, 0)), ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002506 if (!ctx->hdr_parsed) {
2507 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
2508 return;
2509 }
2510
2511 q_data = &ctx->out_q;
2512 q_data->w = tmp.w;
2513 q_data->h = tmp.h;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002514 q_data->sos = tmp.sos;
2515 memcpy(q_data->dht.marker, tmp.dht.marker,
2516 sizeof(tmp.dht.marker));
2517 memcpy(q_data->dht.len, tmp.dht.len, sizeof(tmp.dht.len));
2518 q_data->dht.n = tmp.dht.n;
2519 memcpy(q_data->dqt.marker, tmp.dqt.marker,
2520 sizeof(tmp.dqt.marker));
2521 memcpy(q_data->dqt.len, tmp.dqt.len, sizeof(tmp.dqt.len));
2522 q_data->dqt.n = tmp.dqt.n;
2523 q_data->sof = tmp.sof;
2524 q_data->sof_len = tmp.sof_len;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002525
2526 q_data = &ctx->cap_q;
2527 q_data->w = tmp.w;
2528 q_data->h = tmp.h;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002529 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002530
Junghak Sung2d700712015-09-22 10:30:30 -03002531 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002532}
2533
2534static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
2535{
2536 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
2537 int ret;
2538
2539 ret = pm_runtime_get_sync(ctx->jpeg->dev);
2540
2541 return ret > 0 ? 0 : ret;
2542}
2543
Hans Verkuile37559b2014-04-17 02:47:21 -03002544static void s5p_jpeg_stop_streaming(struct vb2_queue *q)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002545{
2546 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
2547
2548 pm_runtime_put(ctx->jpeg->dev);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002549}
2550
Julia Lawallb7b361f2016-09-08 20:59:10 -03002551static const struct vb2_ops s5p_jpeg_qops = {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002552 .queue_setup = s5p_jpeg_queue_setup,
2553 .buf_prepare = s5p_jpeg_buf_prepare,
2554 .buf_queue = s5p_jpeg_buf_queue,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002555 .wait_prepare = vb2_ops_wait_prepare,
2556 .wait_finish = vb2_ops_wait_finish,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002557 .start_streaming = s5p_jpeg_start_streaming,
2558 .stop_streaming = s5p_jpeg_stop_streaming,
2559};
2560
2561static int queue_init(void *priv, struct vb2_queue *src_vq,
2562 struct vb2_queue *dst_vq)
2563{
2564 struct s5p_jpeg_ctx *ctx = priv;
2565 int ret;
2566
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002567 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
2568 src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
2569 src_vq->drv_priv = ctx;
2570 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
2571 src_vq->ops = &s5p_jpeg_qops;
2572 src_vq->mem_ops = &vb2_dma_contig_memops;
Sakari Ailusade48682014-02-25 19:12:19 -03002573 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002574 src_vq->lock = &ctx->jpeg->lock;
Hans Verkuilc781e4a2016-02-15 14:25:09 -02002575 src_vq->dev = ctx->jpeg->dev;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002576
2577 ret = vb2_queue_init(src_vq);
2578 if (ret)
2579 return ret;
2580
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002581 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2582 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
2583 dst_vq->drv_priv = ctx;
2584 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
2585 dst_vq->ops = &s5p_jpeg_qops;
2586 dst_vq->mem_ops = &vb2_dma_contig_memops;
Sakari Ailusade48682014-02-25 19:12:19 -03002587 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002588 dst_vq->lock = &ctx->jpeg->lock;
Hans Verkuilc781e4a2016-02-15 14:25:09 -02002589 dst_vq->dev = ctx->jpeg->dev;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002590
2591 return vb2_queue_init(dst_vq);
2592}
2593
2594/*
2595 * ============================================================================
2596 * ISR
2597 * ============================================================================
2598 */
2599
2600static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
2601{
2602 struct s5p_jpeg *jpeg = dev_id;
2603 struct s5p_jpeg_ctx *curr_ctx;
Junghak Sung2d700712015-09-22 10:30:30 -03002604 struct vb2_v4l2_buffer *src_buf, *dst_buf;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002605 unsigned long payload_size = 0;
2606 enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
2607 bool enc_jpeg_too_large = false;
2608 bool timer_elapsed = false;
2609 bool op_completed = false;
2610
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002611 spin_lock(&jpeg->slock);
2612
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002613 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2614
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002615 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2616 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002617
2618 if (curr_ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002619 enc_jpeg_too_large = s5p_jpeg_enc_stream_stat(jpeg->regs);
2620 timer_elapsed = s5p_jpeg_timer_stat(jpeg->regs);
2621 op_completed = s5p_jpeg_result_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002622 if (curr_ctx->mode == S5P_JPEG_DECODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002623 op_completed = op_completed &&
2624 s5p_jpeg_stream_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002625
2626 if (enc_jpeg_too_large) {
2627 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002628 s5p_jpeg_clear_enc_stream_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002629 } else if (timer_elapsed) {
2630 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002631 s5p_jpeg_clear_timer_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002632 } else if (!op_completed) {
2633 state = VB2_BUF_STATE_ERROR;
2634 } else {
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002635 payload_size = s5p_jpeg_compressed_size(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002636 }
2637
Junghak Sung2d700712015-09-22 10:30:30 -03002638 dst_buf->timecode = src_buf->timecode;
Junghak Sungd6dd6452015-11-03 08:16:37 -02002639 dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
Junghak Sung2d700712015-09-22 10:30:30 -03002640 dst_buf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
2641 dst_buf->flags |=
2642 src_buf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
Kamil Debskiaca326a2013-04-24 10:08:02 -03002643
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002644 v4l2_m2m_buf_done(src_buf, state);
2645 if (curr_ctx->mode == S5P_JPEG_ENCODE)
Junghak Sung2d700712015-09-22 10:30:30 -03002646 vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload_size);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002647 v4l2_m2m_buf_done(dst_buf, state);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002648 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002649
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002650 curr_ctx->subsampling = s5p_jpeg_get_subsampling_mode(jpeg->regs);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002651 spin_unlock(&jpeg->slock);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03002652
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002653 s5p_jpeg_clear_int(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002654
2655 return IRQ_HANDLED;
2656}
2657
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002658static irqreturn_t exynos4_jpeg_irq(int irq, void *priv)
2659{
2660 unsigned int int_status;
Junghak Sung2d700712015-09-22 10:30:30 -03002661 struct vb2_v4l2_buffer *src_vb, *dst_vb;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002662 struct s5p_jpeg *jpeg = priv;
2663 struct s5p_jpeg_ctx *curr_ctx;
2664 unsigned long payload_size = 0;
2665
2666 spin_lock(&jpeg->slock);
2667
2668 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2669
2670 src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2671 dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
2672
2673 int_status = exynos4_jpeg_get_int_status(jpeg->regs);
2674
2675 if (int_status) {
2676 switch (int_status & 0x1f) {
2677 case 0x1:
2678 jpeg->irq_ret = ERR_PROT;
2679 break;
2680 case 0x2:
2681 jpeg->irq_ret = OK_ENC_OR_DEC;
2682 break;
2683 case 0x4:
2684 jpeg->irq_ret = ERR_DEC_INVALID_FORMAT;
2685 break;
2686 case 0x8:
2687 jpeg->irq_ret = ERR_MULTI_SCAN;
2688 break;
2689 case 0x10:
2690 jpeg->irq_ret = ERR_FRAME;
2691 break;
2692 default:
2693 jpeg->irq_ret = ERR_UNKNOWN;
2694 break;
2695 }
2696 } else {
2697 jpeg->irq_ret = ERR_UNKNOWN;
2698 }
2699
2700 if (jpeg->irq_ret == OK_ENC_OR_DEC) {
2701 if (curr_ctx->mode == S5P_JPEG_ENCODE) {
2702 payload_size = exynos4_jpeg_get_stream_size(jpeg->regs);
Junghak Sung2d700712015-09-22 10:30:30 -03002703 vb2_set_plane_payload(&dst_vb->vb2_buf,
2704 0, payload_size);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002705 }
2706 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
2707 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
2708 } else {
2709 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
2710 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
2711 }
2712
2713 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002714 if (jpeg->variant->version == SJPEG_EXYNOS4)
2715 curr_ctx->subsampling = exynos4_jpeg_get_frame_fmt(jpeg->regs);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002716
2717 spin_unlock(&jpeg->slock);
2718 return IRQ_HANDLED;
2719}
2720
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002721static irqreturn_t exynos3250_jpeg_irq(int irq, void *dev_id)
2722{
2723 struct s5p_jpeg *jpeg = dev_id;
2724 struct s5p_jpeg_ctx *curr_ctx;
Junghak Sung2d700712015-09-22 10:30:30 -03002725 struct vb2_v4l2_buffer *src_buf, *dst_buf;
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002726 unsigned long payload_size = 0;
2727 enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
2728 bool interrupt_timeout = false;
2729 u32 irq_status;
2730
2731 spin_lock(&jpeg->slock);
2732
2733 irq_status = exynos3250_jpeg_get_timer_status(jpeg->regs);
2734 if (irq_status & EXYNOS3250_TIMER_INT_STAT) {
2735 exynos3250_jpeg_clear_timer_status(jpeg->regs);
2736 interrupt_timeout = true;
2737 dev_err(jpeg->dev, "Interrupt timeout occurred.\n");
2738 }
2739
2740 irq_status = exynos3250_jpeg_get_int_status(jpeg->regs);
2741 exynos3250_jpeg_clear_int_status(jpeg->regs, irq_status);
2742
2743 jpeg->irq_status |= irq_status;
2744
2745 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2746
2747 if (!curr_ctx)
2748 goto exit_unlock;
2749
2750 if ((irq_status & EXYNOS3250_HEADER_STAT) &&
2751 (curr_ctx->mode == S5P_JPEG_DECODE)) {
2752 exynos3250_jpeg_rstart(jpeg->regs);
2753 goto exit_unlock;
2754 }
2755
2756 if (jpeg->irq_status & (EXYNOS3250_JPEG_DONE |
2757 EXYNOS3250_WDMA_DONE |
2758 EXYNOS3250_RDMA_DONE |
2759 EXYNOS3250_RESULT_STAT))
2760 payload_size = exynos3250_jpeg_compressed_size(jpeg->regs);
2761 else if (interrupt_timeout)
2762 state = VB2_BUF_STATE_ERROR;
2763 else
2764 goto exit_unlock;
2765
2766 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2767 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
2768
Junghak Sung2d700712015-09-22 10:30:30 -03002769 dst_buf->timecode = src_buf->timecode;
Junghak Sungd6dd6452015-11-03 08:16:37 -02002770 dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002771
2772 v4l2_m2m_buf_done(src_buf, state);
2773 if (curr_ctx->mode == S5P_JPEG_ENCODE)
Junghak Sung2d700712015-09-22 10:30:30 -03002774 vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload_size);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002775 v4l2_m2m_buf_done(dst_buf, state);
2776 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
2777
2778 curr_ctx->subsampling =
2779 exynos3250_jpeg_get_subsampling_mode(jpeg->regs);
2780exit_unlock:
2781 spin_unlock(&jpeg->slock);
2782 return IRQ_HANDLED;
2783}
2784
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03002785static void *jpeg_get_drv_data(struct device *dev);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002786
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002787/*
2788 * ============================================================================
2789 * Driver basic infrastructure
2790 * ============================================================================
2791 */
2792
2793static int s5p_jpeg_probe(struct platform_device *pdev)
2794{
2795 struct s5p_jpeg *jpeg;
2796 struct resource *res;
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002797 int i, ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002798
2799 /* JPEG IP abstraction struct */
Sachin Kamat5b58b952012-05-14 06:33:34 -03002800 jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002801 if (!jpeg)
2802 return -ENOMEM;
2803
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03002804 jpeg->variant = jpeg_get_drv_data(&pdev->dev);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002805
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002806 mutex_init(&jpeg->lock);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002807 spin_lock_init(&jpeg->slock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002808 jpeg->dev = &pdev->dev;
2809
2810 /* memory-mapped registers */
2811 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002812
Thierry Redingf23999e2013-01-21 06:09:07 -03002813 jpeg->regs = devm_ioremap_resource(&pdev->dev, res);
2814 if (IS_ERR(jpeg->regs))
2815 return PTR_ERR(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002816
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002817 /* interrupt service routine registration */
2818 jpeg->irq = ret = platform_get_irq(pdev, 0);
2819 if (ret < 0) {
2820 dev_err(&pdev->dev, "cannot find IRQ\n");
Sachin Kamat5b58b952012-05-14 06:33:34 -03002821 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002822 }
2823
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002824 ret = devm_request_irq(&pdev->dev, jpeg->irq, jpeg->variant->jpeg_irq,
2825 0, dev_name(&pdev->dev), jpeg);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002826 if (ret) {
2827 dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
Sachin Kamat5b58b952012-05-14 06:33:34 -03002828 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002829 }
2830
2831 /* clocks */
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002832 for (i = 0; i < jpeg->variant->num_clocks; i++) {
2833 jpeg->clocks[i] = devm_clk_get(&pdev->dev,
2834 jpeg->variant->clk_names[i]);
2835 if (IS_ERR(jpeg->clocks[i])) {
2836 dev_err(&pdev->dev, "failed to get clock: %s\n",
2837 jpeg->variant->clk_names[i]);
2838 return PTR_ERR(jpeg->clocks[i]);
2839 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002840 }
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002841
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002842 /* v4l2 device */
2843 ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
2844 if (ret) {
2845 dev_err(&pdev->dev, "Failed to register v4l2 device\n");
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002846 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002847 }
2848
2849 /* mem2mem device */
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03002850 jpeg->m2m_dev = v4l2_m2m_init(jpeg->variant->m2m_ops);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002851 if (IS_ERR(jpeg->m2m_dev)) {
2852 v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
2853 ret = PTR_ERR(jpeg->m2m_dev);
2854 goto device_register_rollback;
2855 }
2856
Marek Szyprowski712b6172016-05-24 09:16:07 +02002857 vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002858
2859 /* JPEG encoder /dev/videoX node */
2860 jpeg->vfd_encoder = video_device_alloc();
2861 if (!jpeg->vfd_encoder) {
2862 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
2863 ret = -ENOMEM;
Hans Verkuilc781e4a2016-02-15 14:25:09 -02002864 goto m2m_init_rollback;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002865 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03002866 snprintf(jpeg->vfd_encoder->name, sizeof(jpeg->vfd_encoder->name),
2867 "%s-enc", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002868 jpeg->vfd_encoder->fops = &s5p_jpeg_fops;
2869 jpeg->vfd_encoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
2870 jpeg->vfd_encoder->minor = -1;
2871 jpeg->vfd_encoder->release = video_device_release;
2872 jpeg->vfd_encoder->lock = &jpeg->lock;
2873 jpeg->vfd_encoder->v4l2_dev = &jpeg->v4l2_dev;
Hans Verkuil954f3402012-09-05 06:05:50 -03002874 jpeg->vfd_encoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002875
2876 ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
2877 if (ret) {
2878 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
Andrzej Pietrasiewicz7a1d4e72015-07-03 07:04:38 -03002879 video_device_release(jpeg->vfd_encoder);
Hans Verkuilc781e4a2016-02-15 14:25:09 -02002880 goto m2m_init_rollback;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002881 }
2882
2883 video_set_drvdata(jpeg->vfd_encoder, jpeg);
2884 v4l2_info(&jpeg->v4l2_dev,
2885 "encoder device registered as /dev/video%d\n",
2886 jpeg->vfd_encoder->num);
2887
2888 /* JPEG decoder /dev/videoX node */
2889 jpeg->vfd_decoder = video_device_alloc();
2890 if (!jpeg->vfd_decoder) {
2891 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
2892 ret = -ENOMEM;
2893 goto enc_vdev_register_rollback;
2894 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03002895 snprintf(jpeg->vfd_decoder->name, sizeof(jpeg->vfd_decoder->name),
2896 "%s-dec", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002897 jpeg->vfd_decoder->fops = &s5p_jpeg_fops;
2898 jpeg->vfd_decoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
2899 jpeg->vfd_decoder->minor = -1;
2900 jpeg->vfd_decoder->release = video_device_release;
2901 jpeg->vfd_decoder->lock = &jpeg->lock;
2902 jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev;
Jacek Anaszewski7f7d8fe2013-09-11 06:17:45 -03002903 jpeg->vfd_decoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002904
2905 ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
2906 if (ret) {
2907 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
Andrzej Pietrasiewicz7a1d4e72015-07-03 07:04:38 -03002908 video_device_release(jpeg->vfd_decoder);
2909 goto enc_vdev_register_rollback;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002910 }
2911
2912 video_set_drvdata(jpeg->vfd_decoder, jpeg);
2913 v4l2_info(&jpeg->v4l2_dev,
2914 "decoder device registered as /dev/video%d\n",
2915 jpeg->vfd_decoder->num);
2916
2917 /* final statements & power management */
2918 platform_set_drvdata(pdev, jpeg);
2919
2920 pm_runtime_enable(&pdev->dev);
2921
2922 v4l2_info(&jpeg->v4l2_dev, "Samsung S5P JPEG codec\n");
2923
2924 return 0;
2925
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002926enc_vdev_register_rollback:
2927 video_unregister_device(jpeg->vfd_encoder);
2928
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002929m2m_init_rollback:
2930 v4l2_m2m_release(jpeg->m2m_dev);
2931
2932device_register_rollback:
2933 v4l2_device_unregister(&jpeg->v4l2_dev);
2934
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002935 return ret;
2936}
2937
2938static int s5p_jpeg_remove(struct platform_device *pdev)
2939{
2940 struct s5p_jpeg *jpeg = platform_get_drvdata(pdev);
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002941 int i;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002942
2943 pm_runtime_disable(jpeg->dev);
2944
2945 video_unregister_device(jpeg->vfd_decoder);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002946 video_unregister_device(jpeg->vfd_encoder);
Marek Szyprowski712b6172016-05-24 09:16:07 +02002947 vb2_dma_contig_clear_max_seg_size(&pdev->dev);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002948 v4l2_m2m_release(jpeg->m2m_dev);
2949 v4l2_device_unregister(&jpeg->v4l2_dev);
2950
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002951 if (!pm_runtime_status_suspended(&pdev->dev)) {
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002952 for (i = jpeg->variant->num_clocks - 1; i >= 0; i--)
2953 clk_disable_unprepare(jpeg->clocks[i]);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002954 }
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002955
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002956 return 0;
2957}
2958
Rafael J. Wysockie243c7c2014-12-04 01:10:10 +01002959#ifdef CONFIG_PM
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002960static int s5p_jpeg_runtime_suspend(struct device *dev)
2961{
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002962 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002963 int i;
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002964
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002965 for (i = jpeg->variant->num_clocks - 1; i >= 0; i--)
2966 clk_disable_unprepare(jpeg->clocks[i]);
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002967
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002968 return 0;
2969}
2970
2971static int s5p_jpeg_runtime_resume(struct device *dev)
2972{
2973 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002974 unsigned long flags;
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002975 int i, ret;
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002976
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002977 for (i = 0; i < jpeg->variant->num_clocks; i++) {
2978 ret = clk_prepare_enable(jpeg->clocks[i]);
2979 if (ret) {
2980 while (--i > 0)
2981 clk_disable_unprepare(jpeg->clocks[i]);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002982 return ret;
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002983 }
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002984 }
2985
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002986 spin_lock_irqsave(&jpeg->slock, flags);
2987
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002988 /*
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002989 * JPEG IP allows storing two Huffman tables for each component.
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002990 * We fill table 0 for each component and do this here only
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03002991 * for S5PC210 and Exynos3250 SoCs. Exynos4x12 and Exynos542x SoC
2992 * require programming their Huffman tables each time the encoding
2993 * process is initialized, and thus it is accomplished in the
2994 * device_run callback of m2m_ops.
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002995 */
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03002996 if (!jpeg->variant->htbl_reinit) {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002997 s5p_jpeg_set_hdctbl(jpeg->regs);
2998 s5p_jpeg_set_hdctblg(jpeg->regs);
2999 s5p_jpeg_set_hactbl(jpeg->regs);
3000 s5p_jpeg_set_hactblg(jpeg->regs);
3001 }
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03003002
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03003003 spin_unlock_irqrestore(&jpeg->slock, flags);
3004
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003005 return 0;
3006}
Rafael J. Wysockie243c7c2014-12-04 01:10:10 +01003007#endif /* CONFIG_PM */
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003008
3009static const struct dev_pm_ops s5p_jpeg_pm_ops = {
Marek Szyprowski3b92fed2016-08-31 09:55:59 -03003010 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
3011 pm_runtime_force_resume)
Shuah Khan605b8922016-07-14 17:01:56 -03003012 SET_RUNTIME_PM_OPS(s5p_jpeg_runtime_suspend, s5p_jpeg_runtime_resume,
3013 NULL)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003014};
3015
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003016static struct s5p_jpeg_variant s5p_jpeg_drvdata = {
3017 .version = SJPEG_S5P,
3018 .jpeg_irq = s5p_jpeg_irq,
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03003019 .m2m_ops = &s5p_jpeg_m2m_ops,
Jacek Anaszewskib2451682014-04-10 04:32:11 -03003020 .fmt_ver_flag = SJPEG_FMT_FLAG_S5P,
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03003021 .clk_names = {"jpeg"},
3022 .num_clocks = 1,
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03003023};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003024
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003025static struct s5p_jpeg_variant exynos3250_jpeg_drvdata = {
3026 .version = SJPEG_EXYNOS3250,
3027 .jpeg_irq = exynos3250_jpeg_irq,
3028 .m2m_ops = &exynos3250_jpeg_m2m_ops,
3029 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS3250,
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03003030 .hw3250_compat = 1,
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03003031 .clk_names = {"jpeg", "sclk"},
3032 .num_clocks = 2,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003033};
3034
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003035static struct s5p_jpeg_variant exynos4_jpeg_drvdata = {
3036 .version = SJPEG_EXYNOS4,
3037 .jpeg_irq = exynos4_jpeg_irq,
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03003038 .m2m_ops = &exynos4_jpeg_m2m_ops,
Jacek Anaszewskib2451682014-04-10 04:32:11 -03003039 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS4,
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03003040 .htbl_reinit = 1,
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03003041 .clk_names = {"jpeg"},
3042 .num_clocks = 1,
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03003043 .hw_ex4_compat = 1,
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03003044};
3045
3046static struct s5p_jpeg_variant exynos5420_jpeg_drvdata = {
3047 .version = SJPEG_EXYNOS5420,
3048 .jpeg_irq = exynos3250_jpeg_irq, /* intentionally 3250 */
3049 .m2m_ops = &exynos3250_jpeg_m2m_ops, /* intentionally 3250 */
3050 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS3250, /* intentionally 3250 */
3051 .hw3250_compat = 1,
3052 .htbl_reinit = 1,
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03003053 .clk_names = {"jpeg"},
3054 .num_clocks = 1,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003055};
3056
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03003057static struct s5p_jpeg_variant exynos5433_jpeg_drvdata = {
3058 .version = SJPEG_EXYNOS5433,
3059 .jpeg_irq = exynos4_jpeg_irq,
3060 .m2m_ops = &exynos4_jpeg_m2m_ops,
3061 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS4,
3062 .htbl_reinit = 1,
3063 .clk_names = {"pclk", "aclk", "aclk_xiu", "sclk"},
3064 .num_clocks = 4,
3065 .hw_ex4_compat = 1,
3066};
3067
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003068static const struct of_device_id samsung_jpeg_match[] = {
3069 {
3070 .compatible = "samsung,s5pv210-jpeg",
3071 .data = &s5p_jpeg_drvdata,
3072 }, {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003073 .compatible = "samsung,exynos3250-jpeg",
3074 .data = &exynos3250_jpeg_drvdata,
3075 }, {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003076 .compatible = "samsung,exynos4210-jpeg",
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003077 .data = &exynos4_jpeg_drvdata,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003078 }, {
3079 .compatible = "samsung,exynos4212-jpeg",
3080 .data = &exynos4_jpeg_drvdata,
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03003081 }, {
3082 .compatible = "samsung,exynos5420-jpeg",
3083 .data = &exynos5420_jpeg_drvdata,
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03003084 }, {
3085 .compatible = "samsung,exynos5433-jpeg",
3086 .data = &exynos5433_jpeg_drvdata,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003087 },
3088 {},
3089};
3090
3091MODULE_DEVICE_TABLE(of, samsung_jpeg_match);
3092
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03003093static void *jpeg_get_drv_data(struct device *dev)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003094{
3095 struct s5p_jpeg_variant *driver_data = NULL;
3096 const struct of_device_id *match;
3097
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03003098 if (!IS_ENABLED(CONFIG_OF) || !dev->of_node)
3099 return &s5p_jpeg_drvdata;
3100
3101 match = of_match_node(samsung_jpeg_match, dev->of_node);
3102
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003103 if (match)
3104 driver_data = (struct s5p_jpeg_variant *)match->data;
3105
3106 return driver_data;
3107}
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03003108
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003109static struct platform_driver s5p_jpeg_driver = {
3110 .probe = s5p_jpeg_probe,
3111 .remove = s5p_jpeg_remove,
3112 .driver = {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003113 .of_match_table = of_match_ptr(samsung_jpeg_match),
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003114 .name = S5P_JPEG_M2M_NAME,
3115 .pm = &s5p_jpeg_pm_ops,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003116 },
3117};
3118
Sachin Kamat87e94292012-07-03 05:54:33 -03003119module_platform_driver(s5p_jpeg_driver);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003120
3121MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003122MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003123MODULE_DESCRIPTION("Samsung JPEG codec driver");
3124MODULE_LICENSE("GPL");