blob: c3b13a630edfcf4ce0826e2af1d6bfdbf9b46ff0 [file] [log] [blame]
Mauro Carvalho Chehab2c3fb082012-08-14 17:31:16 -03001/* linux/drivers/media/platform/s5p-jpeg/jpeg-core.c
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002 *
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003 * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd.
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03004 * http://www.samsung.com
5 *
6 * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03007 * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03008 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/clk.h>
15#include <linux/err.h>
16#include <linux/gfp.h>
17#include <linux/interrupt.h>
18#include <linux/io.h>
19#include <linux/kernel.h>
20#include <linux/module.h>
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -030021#include <linux/of.h>
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030022#include <linux/platform_device.h>
23#include <linux/pm_runtime.h>
24#include <linux/slab.h>
25#include <linux/spinlock.h>
26#include <linux/string.h>
27#include <media/v4l2-mem2mem.h>
28#include <media/v4l2-ioctl.h>
Junghak Sungc1399902015-09-22 10:30:29 -030029#include <media/videobuf2-v4l2.h>
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030030#include <media/videobuf2-dma-contig.h>
31
32#include "jpeg-core.h"
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -030033#include "jpeg-hw-s5p.h"
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030034#include "jpeg-hw-exynos4.h"
Jacek Anaszewski3246fda2014-07-11 12:19:42 -030035#include "jpeg-hw-exynos3250.h"
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030036#include "jpeg-regs.h"
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030037
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030038static struct s5p_jpeg_fmt sjpeg_formats[] = {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030039 {
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -030040 .name = "JPEG JFIF",
41 .fourcc = V4L2_PIX_FMT_JPEG,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030042 .flags = SJPEG_FMT_FLAG_ENC_CAPTURE |
43 SJPEG_FMT_FLAG_DEC_OUTPUT |
44 SJPEG_FMT_FLAG_S5P |
Jacek Anaszewski3246fda2014-07-11 12:19:42 -030045 SJPEG_FMT_FLAG_EXYNOS3250 |
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030046 SJPEG_FMT_FLAG_EXYNOS4,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030047 },
48 {
49 .name = "YUV 4:2:2 packed, YCbYCr",
50 .fourcc = V4L2_PIX_FMT_YUYV,
51 .depth = 16,
52 .colplanes = 1,
53 .h_align = 4,
54 .v_align = 3,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030055 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
56 SJPEG_FMT_FLAG_DEC_CAPTURE |
57 SJPEG_FMT_FLAG_S5P |
58 SJPEG_FMT_NON_RGB,
59 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030060 },
61 {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030062 .name = "YUV 4:2:2 packed, YCbYCr",
63 .fourcc = V4L2_PIX_FMT_YUYV,
64 .depth = 16,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030065 .colplanes = 1,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030066 .h_align = 1,
67 .v_align = 0,
68 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
69 SJPEG_FMT_FLAG_DEC_CAPTURE |
70 SJPEG_FMT_FLAG_EXYNOS4 |
71 SJPEG_FMT_NON_RGB,
72 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
73 },
74 {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -030075 .name = "YUV 4:2:2 packed, YCbYCr",
76 .fourcc = V4L2_PIX_FMT_YUYV,
77 .depth = 16,
78 .colplanes = 1,
79 .h_align = 2,
80 .v_align = 0,
81 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
82 SJPEG_FMT_FLAG_DEC_CAPTURE |
83 SJPEG_FMT_FLAG_EXYNOS3250 |
84 SJPEG_FMT_NON_RGB,
85 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
86 },
87 {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030088 .name = "YUV 4:2:2 packed, YCrYCb",
89 .fourcc = V4L2_PIX_FMT_YVYU,
90 .depth = 16,
91 .colplanes = 1,
92 .h_align = 1,
93 .v_align = 0,
94 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
95 SJPEG_FMT_FLAG_DEC_CAPTURE |
96 SJPEG_FMT_FLAG_EXYNOS4 |
97 SJPEG_FMT_NON_RGB,
98 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
99 },
100 {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300101 .name = "YUV 4:2:2 packed, YCrYCb",
102 .fourcc = V4L2_PIX_FMT_YVYU,
103 .depth = 16,
104 .colplanes = 1,
105 .h_align = 2,
106 .v_align = 0,
107 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
108 SJPEG_FMT_FLAG_DEC_CAPTURE |
109 SJPEG_FMT_FLAG_EXYNOS3250 |
110 SJPEG_FMT_NON_RGB,
111 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
112 },
113 {
114 .name = "YUV 4:2:2 packed, YCrYCb",
115 .fourcc = V4L2_PIX_FMT_UYVY,
116 .depth = 16,
117 .colplanes = 1,
118 .h_align = 2,
119 .v_align = 0,
120 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
121 SJPEG_FMT_FLAG_DEC_CAPTURE |
122 SJPEG_FMT_FLAG_EXYNOS3250 |
123 SJPEG_FMT_NON_RGB,
124 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
125 },
126 {
127 .name = "YUV 4:2:2 packed, YCrYCb",
128 .fourcc = V4L2_PIX_FMT_VYUY,
129 .depth = 16,
130 .colplanes = 1,
131 .h_align = 2,
132 .v_align = 0,
133 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
134 SJPEG_FMT_FLAG_DEC_CAPTURE |
135 SJPEG_FMT_FLAG_EXYNOS3250 |
136 SJPEG_FMT_NON_RGB,
137 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
138 },
139 {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300140 .name = "RGB565",
141 .fourcc = V4L2_PIX_FMT_RGB565,
142 .depth = 16,
143 .colplanes = 1,
144 .h_align = 0,
145 .v_align = 0,
146 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
147 SJPEG_FMT_FLAG_DEC_CAPTURE |
148 SJPEG_FMT_FLAG_EXYNOS4 |
149 SJPEG_FMT_RGB,
150 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
151 },
152 {
153 .name = "RGB565",
154 .fourcc = V4L2_PIX_FMT_RGB565,
155 .depth = 16,
156 .colplanes = 1,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300157 .h_align = 2,
158 .v_align = 0,
159 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
160 SJPEG_FMT_FLAG_DEC_CAPTURE |
161 SJPEG_FMT_FLAG_EXYNOS3250 |
162 SJPEG_FMT_RGB,
163 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
164 },
165 {
166 .name = "RGB565X",
167 .fourcc = V4L2_PIX_FMT_RGB565X,
168 .depth = 16,
169 .colplanes = 1,
170 .h_align = 2,
171 .v_align = 0,
172 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
173 SJPEG_FMT_FLAG_DEC_CAPTURE |
174 SJPEG_FMT_FLAG_EXYNOS3250 |
175 SJPEG_FMT_RGB,
176 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
177 },
178 {
179 .name = "RGB565",
180 .fourcc = V4L2_PIX_FMT_RGB565,
181 .depth = 16,
182 .colplanes = 1,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300183 .h_align = 0,
184 .v_align = 0,
185 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
186 SJPEG_FMT_FLAG_S5P |
187 SJPEG_FMT_RGB,
188 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
189 },
190 {
191 .name = "ARGB8888, 32 bpp",
192 .fourcc = V4L2_PIX_FMT_RGB32,
193 .depth = 32,
194 .colplanes = 1,
195 .h_align = 0,
196 .v_align = 0,
197 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
198 SJPEG_FMT_FLAG_DEC_CAPTURE |
199 SJPEG_FMT_FLAG_EXYNOS4 |
200 SJPEG_FMT_RGB,
201 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
202 },
203 {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300204 .name = "ARGB8888, 32 bpp",
205 .fourcc = V4L2_PIX_FMT_RGB32,
206 .depth = 32,
207 .colplanes = 1,
208 .h_align = 2,
209 .v_align = 0,
210 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
211 SJPEG_FMT_FLAG_DEC_CAPTURE |
212 SJPEG_FMT_FLAG_EXYNOS3250 |
213 SJPEG_FMT_RGB,
214 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
215 },
216 {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300217 .name = "YUV 4:4:4 planar, Y/CbCr",
218 .fourcc = V4L2_PIX_FMT_NV24,
219 .depth = 24,
220 .colplanes = 2,
221 .h_align = 0,
222 .v_align = 0,
223 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
224 SJPEG_FMT_FLAG_DEC_CAPTURE |
225 SJPEG_FMT_FLAG_EXYNOS4 |
226 SJPEG_FMT_NON_RGB,
227 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
228 },
229 {
230 .name = "YUV 4:4:4 planar, Y/CrCb",
231 .fourcc = V4L2_PIX_FMT_NV42,
232 .depth = 24,
233 .colplanes = 2,
234 .h_align = 0,
235 .v_align = 0,
236 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
237 SJPEG_FMT_FLAG_DEC_CAPTURE |
238 SJPEG_FMT_FLAG_EXYNOS4 |
239 SJPEG_FMT_NON_RGB,
240 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
241 },
242 {
243 .name = "YUV 4:2:2 planar, Y/CrCb",
244 .fourcc = V4L2_PIX_FMT_NV61,
245 .depth = 16,
246 .colplanes = 2,
247 .h_align = 1,
248 .v_align = 0,
249 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
250 SJPEG_FMT_FLAG_DEC_CAPTURE |
251 SJPEG_FMT_FLAG_EXYNOS4 |
252 SJPEG_FMT_NON_RGB,
253 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
254 },
255 {
256 .name = "YUV 4:2:2 planar, Y/CbCr",
257 .fourcc = V4L2_PIX_FMT_NV16,
258 .depth = 16,
259 .colplanes = 2,
260 .h_align = 1,
261 .v_align = 0,
262 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
263 SJPEG_FMT_FLAG_DEC_CAPTURE |
264 SJPEG_FMT_FLAG_EXYNOS4 |
265 SJPEG_FMT_NON_RGB,
266 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
267 },
268 {
269 .name = "YUV 4:2:0 planar, Y/CbCr",
270 .fourcc = V4L2_PIX_FMT_NV12,
Jacek Anaszewskia62cffe2014-01-16 08:26:33 -0300271 .depth = 12,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300272 .colplanes = 2,
273 .h_align = 1,
274 .v_align = 1,
275 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
276 SJPEG_FMT_FLAG_DEC_CAPTURE |
277 SJPEG_FMT_FLAG_EXYNOS4 |
278 SJPEG_FMT_NON_RGB,
279 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
280 },
281 {
282 .name = "YUV 4:2:0 planar, Y/CbCr",
283 .fourcc = V4L2_PIX_FMT_NV12,
Jacek Anaszewskia62cffe2014-01-16 08:26:33 -0300284 .depth = 12,
285 .colplanes = 2,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300286 .h_align = 3,
287 .v_align = 3,
288 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
289 SJPEG_FMT_FLAG_DEC_CAPTURE |
290 SJPEG_FMT_FLAG_EXYNOS3250 |
291 SJPEG_FMT_NON_RGB,
292 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
293 },
294 {
295 .name = "YUV 4:2:0 planar, Y/CbCr",
296 .fourcc = V4L2_PIX_FMT_NV12,
297 .depth = 12,
298 .colplanes = 2,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300299 .h_align = 4,
Jacek Anaszewskia62cffe2014-01-16 08:26:33 -0300300 .v_align = 4,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300301 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
302 SJPEG_FMT_FLAG_DEC_CAPTURE |
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300303 SJPEG_FMT_FLAG_S5P |
304 SJPEG_FMT_NON_RGB,
305 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
306 },
307 {
308 .name = "YUV 4:2:0 planar, Y/CrCb",
309 .fourcc = V4L2_PIX_FMT_NV21,
310 .depth = 12,
311 .colplanes = 2,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300312 .h_align = 3,
313 .v_align = 3,
314 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
315 SJPEG_FMT_FLAG_DEC_CAPTURE |
316 SJPEG_FMT_FLAG_EXYNOS3250 |
317 SJPEG_FMT_NON_RGB,
318 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
319 },
320 {
321 .name = "YUV 4:2:0 planar, Y/CrCb",
322 .fourcc = V4L2_PIX_FMT_NV21,
323 .depth = 12,
324 .colplanes = 2,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300325 .h_align = 1,
326 .v_align = 1,
327 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
328 SJPEG_FMT_FLAG_DEC_CAPTURE |
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300329 SJPEG_FMT_FLAG_EXYNOS3250 |
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300330 SJPEG_FMT_FLAG_EXYNOS4 |
331 SJPEG_FMT_NON_RGB,
332 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
333 },
334 {
335 .name = "YUV 4:2:0 contiguous 3-planar, Y/Cb/Cr",
336 .fourcc = V4L2_PIX_FMT_YUV420,
337 .depth = 12,
338 .colplanes = 3,
339 .h_align = 1,
340 .v_align = 1,
341 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
342 SJPEG_FMT_FLAG_DEC_CAPTURE |
343 SJPEG_FMT_FLAG_EXYNOS4 |
344 SJPEG_FMT_NON_RGB,
345 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
346 },
347 {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300348 .name = "YUV 4:2:0 contiguous 3-planar, Y/Cb/Cr",
349 .fourcc = V4L2_PIX_FMT_YUV420,
350 .depth = 12,
351 .colplanes = 3,
352 .h_align = 4,
353 .v_align = 4,
354 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
355 SJPEG_FMT_FLAG_DEC_CAPTURE |
356 SJPEG_FMT_FLAG_EXYNOS3250 |
357 SJPEG_FMT_NON_RGB,
358 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
359 },
360 {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300361 .name = "Gray",
362 .fourcc = V4L2_PIX_FMT_GREY,
363 .depth = 8,
364 .colplanes = 1,
365 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
366 SJPEG_FMT_FLAG_DEC_CAPTURE |
367 SJPEG_FMT_FLAG_EXYNOS4 |
368 SJPEG_FMT_NON_RGB,
369 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300370 },
371};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300372#define SJPEG_NUM_FORMATS ARRAY_SIZE(sjpeg_formats)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300373
374static const unsigned char qtbl_luminance[4][64] = {
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300375 {/*level 0 - high compression quality */
376 20, 16, 25, 39, 50, 46, 62, 68,
377 16, 18, 23, 38, 38, 53, 65, 68,
378 25, 23, 31, 38, 53, 65, 68, 68,
379 39, 38, 38, 53, 65, 68, 68, 68,
380 50, 38, 53, 65, 68, 68, 68, 68,
381 46, 53, 65, 68, 68, 68, 68, 68,
382 62, 65, 68, 68, 68, 68, 68, 68,
383 68, 68, 68, 68, 68, 68, 68, 68
384 },
385 {/* level 1 */
386 16, 11, 11, 16, 23, 27, 31, 30,
387 11, 12, 12, 15, 20, 23, 23, 30,
388 11, 12, 13, 16, 23, 26, 35, 47,
389 16, 15, 16, 23, 26, 37, 47, 64,
390 23, 20, 23, 26, 39, 51, 64, 64,
391 27, 23, 26, 37, 51, 64, 64, 64,
392 31, 23, 35, 47, 64, 64, 64, 64,
393 30, 30, 47, 64, 64, 64, 64, 64
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300394 },
395 {/* level 2 */
396 12, 8, 8, 12, 17, 21, 24, 23,
397 8, 9, 9, 11, 15, 19, 18, 23,
398 8, 9, 10, 12, 19, 20, 27, 36,
399 12, 11, 12, 21, 20, 28, 36, 53,
400 17, 15, 19, 20, 30, 39, 51, 59,
401 21, 19, 20, 28, 39, 51, 59, 59,
402 24, 18, 27, 36, 51, 59, 59, 59,
403 23, 23, 36, 53, 59, 59, 59, 59
404 },
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300405 {/* level 3 - low compression quality */
406 8, 6, 6, 8, 12, 14, 16, 17,
407 6, 6, 6, 8, 10, 13, 12, 15,
408 6, 6, 7, 8, 13, 14, 18, 24,
409 8, 8, 8, 14, 13, 19, 24, 35,
410 12, 10, 13, 13, 20, 26, 34, 39,
411 14, 13, 14, 19, 26, 34, 39, 39,
412 16, 12, 18, 24, 34, 39, 39, 39,
413 17, 15, 24, 35, 39, 39, 39, 39
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300414 }
415};
416
417static const unsigned char qtbl_chrominance[4][64] = {
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300418 {/*level 0 - high compression quality */
419 21, 25, 32, 38, 54, 68, 68, 68,
420 25, 28, 24, 38, 54, 68, 68, 68,
421 32, 24, 32, 43, 66, 68, 68, 68,
422 38, 38, 43, 53, 68, 68, 68, 68,
423 54, 54, 66, 68, 68, 68, 68, 68,
424 68, 68, 68, 68, 68, 68, 68, 68,
425 68, 68, 68, 68, 68, 68, 68, 68,
426 68, 68, 68, 68, 68, 68, 68, 68
427 },
428 {/* level 1 */
429 17, 15, 17, 21, 20, 26, 38, 48,
430 15, 19, 18, 17, 20, 26, 35, 43,
431 17, 18, 20, 22, 26, 30, 46, 53,
432 21, 17, 22, 28, 30, 39, 53, 64,
433 20, 20, 26, 30, 39, 48, 64, 64,
434 26, 26, 30, 39, 48, 63, 64, 64,
435 38, 35, 46, 53, 64, 64, 64, 64,
436 48, 43, 53, 64, 64, 64, 64, 64
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300437 },
438 {/* level 2 */
439 13, 11, 13, 16, 20, 20, 29, 37,
440 11, 14, 14, 14, 16, 20, 26, 32,
441 13, 14, 15, 17, 20, 23, 35, 40,
442 16, 14, 17, 21, 23, 30, 40, 50,
443 20, 16, 20, 23, 30, 37, 50, 59,
444 20, 20, 23, 30, 37, 48, 59, 59,
445 29, 26, 35, 40, 50, 59, 59, 59,
446 37, 32, 40, 50, 59, 59, 59, 59
447 },
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300448 {/* level 3 - low compression quality */
449 9, 8, 9, 11, 14, 17, 19, 24,
450 8, 10, 9, 11, 14, 13, 17, 22,
451 9, 9, 13, 14, 13, 15, 23, 26,
452 11, 11, 14, 14, 15, 20, 26, 33,
453 14, 14, 13, 15, 20, 24, 33, 39,
454 17, 13, 15, 20, 24, 32, 39, 39,
455 19, 17, 23, 26, 33, 39, 39, 39,
456 24, 22, 26, 33, 39, 39, 39, 39
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300457 }
458};
459
460static const unsigned char hdctbl0[16] = {
461 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
462};
463
464static const unsigned char hdctblg0[12] = {
465 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb
466};
467static const unsigned char hactbl0[16] = {
468 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
469};
470static const unsigned char hactblg0[162] = {
471 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
472 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
473 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
474 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
475 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
476 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
477 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
478 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
479 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
480 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
481 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
482 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
483 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
484 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
485 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
486 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
487 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
488 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
489 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
490 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
491 0xf9, 0xfa
492};
493
Jacek Anaszewski337777a2013-11-22 06:13:34 -0300494/*
495 * Fourcc downgrade schema lookup tables for 422 and 420
496 * chroma subsampling - fourcc on each position maps on the
497 * fourcc from the table fourcc_to_dwngrd_schema_id which allows
498 * to get the most suitable fourcc counterpart for the given
499 * downgraded subsampling property.
500 */
501static const u32 subs422_fourcc_dwngrd_schema[] = {
502 V4L2_PIX_FMT_NV16,
503 V4L2_PIX_FMT_NV61,
504};
505
506static const u32 subs420_fourcc_dwngrd_schema[] = {
507 V4L2_PIX_FMT_NV12,
508 V4L2_PIX_FMT_NV21,
509 V4L2_PIX_FMT_NV12,
510 V4L2_PIX_FMT_NV21,
511 V4L2_PIX_FMT_NV12,
512 V4L2_PIX_FMT_NV21,
513 V4L2_PIX_FMT_GREY,
514 V4L2_PIX_FMT_GREY,
515 V4L2_PIX_FMT_GREY,
516 V4L2_PIX_FMT_GREY,
517};
518
519/*
520 * Lookup table for translation of a fourcc to the position
521 * of its downgraded counterpart in the *fourcc_dwngrd_schema
522 * tables.
523 */
524static const u32 fourcc_to_dwngrd_schema_id[] = {
525 V4L2_PIX_FMT_NV24,
526 V4L2_PIX_FMT_NV42,
527 V4L2_PIX_FMT_NV16,
528 V4L2_PIX_FMT_NV61,
529 V4L2_PIX_FMT_YUYV,
530 V4L2_PIX_FMT_YVYU,
531 V4L2_PIX_FMT_NV12,
532 V4L2_PIX_FMT_NV21,
533 V4L2_PIX_FMT_YUV420,
534 V4L2_PIX_FMT_GREY,
535};
536
537static int s5p_jpeg_get_dwngrd_sch_id_by_fourcc(u32 fourcc)
538{
539 int i;
540 for (i = 0; i < ARRAY_SIZE(fourcc_to_dwngrd_schema_id); ++i) {
541 if (fourcc_to_dwngrd_schema_id[i] == fourcc)
542 return i;
543 }
544
545 return -EINVAL;
546}
547
548static int s5p_jpeg_adjust_fourcc_to_subsampling(
549 enum v4l2_jpeg_chroma_subsampling subs,
550 u32 in_fourcc,
551 u32 *out_fourcc,
552 struct s5p_jpeg_ctx *ctx)
553{
554 int dwngrd_sch_id;
555
556 if (ctx->subsampling != V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY) {
557 dwngrd_sch_id =
558 s5p_jpeg_get_dwngrd_sch_id_by_fourcc(in_fourcc);
559 if (dwngrd_sch_id < 0)
560 return -EINVAL;
561 }
562
563 switch (ctx->subsampling) {
564 case V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY:
565 *out_fourcc = V4L2_PIX_FMT_GREY;
566 break;
567 case V4L2_JPEG_CHROMA_SUBSAMPLING_420:
568 if (dwngrd_sch_id >
569 ARRAY_SIZE(subs420_fourcc_dwngrd_schema) - 1)
570 return -EINVAL;
571 *out_fourcc = subs420_fourcc_dwngrd_schema[dwngrd_sch_id];
572 break;
573 case V4L2_JPEG_CHROMA_SUBSAMPLING_422:
574 if (dwngrd_sch_id >
575 ARRAY_SIZE(subs422_fourcc_dwngrd_schema) - 1)
576 return -EINVAL;
577 *out_fourcc = subs422_fourcc_dwngrd_schema[dwngrd_sch_id];
578 break;
579 default:
580 *out_fourcc = V4L2_PIX_FMT_GREY;
581 break;
582 }
583
584 return 0;
585}
586
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300587static int exynos4x12_decoded_subsampling[] = {
588 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
589 V4L2_JPEG_CHROMA_SUBSAMPLING_444,
590 V4L2_JPEG_CHROMA_SUBSAMPLING_422,
591 V4L2_JPEG_CHROMA_SUBSAMPLING_420,
592};
593
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300594static int exynos3250_decoded_subsampling[] = {
595 V4L2_JPEG_CHROMA_SUBSAMPLING_444,
596 V4L2_JPEG_CHROMA_SUBSAMPLING_422,
597 V4L2_JPEG_CHROMA_SUBSAMPLING_420,
598 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
599 -1,
600 -1,
601 V4L2_JPEG_CHROMA_SUBSAMPLING_411,
602};
603
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300604static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c)
605{
606 return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler);
607}
608
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300609static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh)
610{
611 return container_of(fh, struct s5p_jpeg_ctx, fh);
612}
613
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300614static int s5p_jpeg_to_user_subsampling(struct s5p_jpeg_ctx *ctx)
615{
616 WARN_ON(ctx->subsampling > 3);
617
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300618 switch (ctx->jpeg->variant->version) {
619 case SJPEG_S5P:
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300620 if (ctx->subsampling > 2)
621 return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
622 return ctx->subsampling;
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300623 case SJPEG_EXYNOS3250:
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -0300624 case SJPEG_EXYNOS5420:
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300625 if (ctx->subsampling > 3)
626 return V4L2_JPEG_CHROMA_SUBSAMPLING_411;
627 return exynos3250_decoded_subsampling[ctx->subsampling];
628 case SJPEG_EXYNOS4:
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300629 case SJPEG_EXYNOS5433:
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300630 if (ctx->subsampling > 2)
631 return V4L2_JPEG_CHROMA_SUBSAMPLING_420;
632 return exynos4x12_decoded_subsampling[ctx->subsampling];
Jacek Anaszewski3246fda2014-07-11 12:19:42 -0300633 default:
634 return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300635 }
636}
637
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300638static inline void s5p_jpeg_set_qtbl(void __iomem *regs,
639 const unsigned char *qtbl,
640 unsigned long tab, int len)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300641{
642 int i;
643
644 for (i = 0; i < len; i++)
645 writel((unsigned int)qtbl[i], regs + tab + (i * 0x04));
646}
647
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300648static inline void s5p_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300649{
650 /* this driver fills quantisation table 0 with data for luma */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300651 s5p_jpeg_set_qtbl(regs, qtbl_luminance[quality],
652 S5P_JPG_QTBL_CONTENT(0),
653 ARRAY_SIZE(qtbl_luminance[quality]));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300654}
655
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300656static inline void s5p_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300657{
658 /* this driver fills quantisation table 1 with data for chroma */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300659 s5p_jpeg_set_qtbl(regs, qtbl_chrominance[quality],
660 S5P_JPG_QTBL_CONTENT(1),
661 ARRAY_SIZE(qtbl_chrominance[quality]));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300662}
663
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300664static inline void s5p_jpeg_set_htbl(void __iomem *regs,
665 const unsigned char *htbl,
666 unsigned long tab, int len)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300667{
668 int i;
669
670 for (i = 0; i < len; i++)
671 writel((unsigned int)htbl[i], regs + tab + (i * 0x04));
672}
673
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300674static inline void s5p_jpeg_set_hdctbl(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300675{
676 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300677 s5p_jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0),
678 ARRAY_SIZE(hdctbl0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300679}
680
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300681static inline void s5p_jpeg_set_hdctblg(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300682{
683 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300684 s5p_jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0),
685 ARRAY_SIZE(hdctblg0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300686}
687
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300688static inline void s5p_jpeg_set_hactbl(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300689{
690 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300691 s5p_jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0),
692 ARRAY_SIZE(hactbl0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300693}
694
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300695static inline void s5p_jpeg_set_hactblg(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300696{
697 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300698 s5p_jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0),
699 ARRAY_SIZE(hactblg0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300700}
701
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300702static inline void exynos4_jpeg_set_tbl(void __iomem *regs,
703 const unsigned char *tbl,
704 unsigned long tab, int len)
705{
706 int i;
707 unsigned int dword;
708
709 for (i = 0; i < len; i += 4) {
710 dword = tbl[i] |
711 (tbl[i + 1] << 8) |
712 (tbl[i + 2] << 16) |
713 (tbl[i + 3] << 24);
714 writel(dword, regs + tab + i);
715 }
716}
717
718static inline void exynos4_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
719{
720 /* this driver fills quantisation table 0 with data for luma */
721 exynos4_jpeg_set_tbl(regs, qtbl_luminance[quality],
722 EXYNOS4_QTBL_CONTENT(0),
723 ARRAY_SIZE(qtbl_luminance[quality]));
724}
725
726static inline void exynos4_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
727{
728 /* this driver fills quantisation table 1 with data for chroma */
729 exynos4_jpeg_set_tbl(regs, qtbl_chrominance[quality],
730 EXYNOS4_QTBL_CONTENT(1),
731 ARRAY_SIZE(qtbl_chrominance[quality]));
732}
733
Mauro Carvalho Chehabaf425be2014-08-26 10:50:23 -0300734static void exynos4_jpeg_set_huff_tbl(void __iomem *base)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300735{
736 exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCLL,
737 ARRAY_SIZE(hdctbl0));
738 exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCCL,
739 ARRAY_SIZE(hdctbl0));
740 exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCLV,
741 ARRAY_SIZE(hdctblg0));
742 exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCCV,
743 ARRAY_SIZE(hdctblg0));
744 exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACLL,
745 ARRAY_SIZE(hactbl0));
746 exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACCL,
747 ARRAY_SIZE(hactbl0));
748 exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACLV,
749 ARRAY_SIZE(hactblg0));
750 exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACCV,
751 ARRAY_SIZE(hactblg0));
752}
753
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300754static inline int __exynos4_huff_tbl(int class, int id, bool lenval)
755{
756 /*
757 * class: 0 - DC, 1 - AC
758 * id: 0 - Y, 1 - Cb/Cr
759 */
760 if (class) {
761 if (id)
762 return lenval ? EXYNOS4_HUFF_TBL_HACCL :
763 EXYNOS4_HUFF_TBL_HACCV;
764 return lenval ? EXYNOS4_HUFF_TBL_HACLL : EXYNOS4_HUFF_TBL_HACLV;
765
766 }
767 /* class == 0 */
768 if (id)
769 return lenval ? EXYNOS4_HUFF_TBL_HDCCL : EXYNOS4_HUFF_TBL_HDCCV;
770
771 return lenval ? EXYNOS4_HUFF_TBL_HDCLL : EXYNOS4_HUFF_TBL_HDCLV;
772}
773
774static inline int exynos4_huff_tbl_len(int class, int id)
775{
776 return __exynos4_huff_tbl(class, id, true);
777}
778
779static inline int exynos4_huff_tbl_val(int class, int id)
780{
781 return __exynos4_huff_tbl(class, id, false);
782}
783
784static int get_byte(struct s5p_jpeg_buffer *buf);
785static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word);
786static void skip(struct s5p_jpeg_buffer *buf, long len);
787
788static void exynos4_jpeg_parse_decode_h_tbl(struct s5p_jpeg_ctx *ctx)
789{
790 struct s5p_jpeg *jpeg = ctx->jpeg;
791 struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
792 struct s5p_jpeg_buffer jpeg_buffer;
793 unsigned int word;
794 int c, x, components;
795
796 jpeg_buffer.size = 2; /* Ls */
797 jpeg_buffer.data =
798 (unsigned long)vb2_plane_vaddr(vb, 0) + ctx->out_q.sos + 2;
799 jpeg_buffer.curr = 0;
800
801 word = 0;
802
803 if (get_word_be(&jpeg_buffer, &word))
804 return;
805 jpeg_buffer.size = (long)word - 2;
806 jpeg_buffer.data += 2;
807 jpeg_buffer.curr = 0;
808
809 components = get_byte(&jpeg_buffer);
810 if (components == -1)
811 return;
812 while (components--) {
813 c = get_byte(&jpeg_buffer);
814 if (c == -1)
815 return;
816 x = get_byte(&jpeg_buffer);
817 if (x == -1)
818 return;
819 exynos4_jpeg_select_dec_h_tbl(jpeg->regs, c,
820 (((x >> 4) & 0x1) << 1) | (x & 0x1));
821 }
822
823}
824
825static void exynos4_jpeg_parse_huff_tbl(struct s5p_jpeg_ctx *ctx)
826{
827 struct s5p_jpeg *jpeg = ctx->jpeg;
828 struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
829 struct s5p_jpeg_buffer jpeg_buffer;
830 unsigned int word;
831 int c, i, n, j;
832
833 for (j = 0; j < ctx->out_q.dht.n; ++j) {
834 jpeg_buffer.size = ctx->out_q.dht.len[j];
835 jpeg_buffer.data = (unsigned long)vb2_plane_vaddr(vb, 0) +
836 ctx->out_q.dht.marker[j];
837 jpeg_buffer.curr = 0;
838
839 word = 0;
840 while (jpeg_buffer.curr < jpeg_buffer.size) {
841 char id, class;
842
843 c = get_byte(&jpeg_buffer);
844 if (c == -1)
845 return;
846 id = c & 0xf;
847 class = (c >> 4) & 0xf;
848 n = 0;
849 for (i = 0; i < 16; ++i) {
850 c = get_byte(&jpeg_buffer);
851 if (c == -1)
852 return;
853 word |= c << ((i % 4) * 8);
854 if ((i + 1) % 4 == 0) {
855 writel(word, jpeg->regs +
856 exynos4_huff_tbl_len(class, id) +
857 (i / 4) * 4);
858 word = 0;
859 }
860 n += c;
861 }
862 word = 0;
863 for (i = 0; i < n; ++i) {
864 c = get_byte(&jpeg_buffer);
865 if (c == -1)
866 return;
867 word |= c << ((i % 4) * 8);
868 if ((i + 1) % 4 == 0) {
869 writel(word, jpeg->regs +
870 exynos4_huff_tbl_val(class, id) +
871 (i / 4) * 4);
872 word = 0;
873 }
874 }
875 if (i % 4) {
876 writel(word, jpeg->regs +
877 exynos4_huff_tbl_val(class, id) + (i / 4) * 4);
878 }
879 word = 0;
880 }
881 }
882}
883
884static void exynos4_jpeg_parse_decode_q_tbl(struct s5p_jpeg_ctx *ctx)
885{
886 struct s5p_jpeg *jpeg = ctx->jpeg;
887 struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
888 struct s5p_jpeg_buffer jpeg_buffer;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300889 int c, x, components;
890
891 jpeg_buffer.size = ctx->out_q.sof_len;
892 jpeg_buffer.data =
893 (unsigned long)vb2_plane_vaddr(vb, 0) + ctx->out_q.sof;
894 jpeg_buffer.curr = 0;
895
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -0300896 skip(&jpeg_buffer, 5); /* P, Y, X */
897 components = get_byte(&jpeg_buffer);
898 if (components == -1)
899 return;
900
901 exynos4_jpeg_set_dec_components(jpeg->regs, components);
902
903 while (components--) {
904 c = get_byte(&jpeg_buffer);
905 if (c == -1)
906 return;
907 skip(&jpeg_buffer, 1);
908 x = get_byte(&jpeg_buffer);
909 if (x == -1)
910 return;
911 exynos4_jpeg_select_dec_q_tbl(jpeg->regs, c, x);
912 }
913}
914
915static void exynos4_jpeg_parse_q_tbl(struct s5p_jpeg_ctx *ctx)
916{
917 struct s5p_jpeg *jpeg = ctx->jpeg;
918 struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
919 struct s5p_jpeg_buffer jpeg_buffer;
920 unsigned int word;
921 int c, i, j;
922
923 for (j = 0; j < ctx->out_q.dqt.n; ++j) {
924 jpeg_buffer.size = ctx->out_q.dqt.len[j];
925 jpeg_buffer.data = (unsigned long)vb2_plane_vaddr(vb, 0) +
926 ctx->out_q.dqt.marker[j];
927 jpeg_buffer.curr = 0;
928
929 word = 0;
930 while (jpeg_buffer.size - jpeg_buffer.curr >= 65) {
931 char id;
932
933 c = get_byte(&jpeg_buffer);
934 if (c == -1)
935 return;
936 id = c & 0xf;
937 /* nonzero means extended mode - not supported */
938 if ((c >> 4) & 0xf)
939 return;
940 for (i = 0; i < 64; ++i) {
941 c = get_byte(&jpeg_buffer);
942 if (c == -1)
943 return;
944 word |= c << ((i % 4) * 8);
945 if ((i + 1) % 4 == 0) {
946 writel(word, jpeg->regs +
947 EXYNOS4_QTBL_CONTENT(id) + (i / 4) * 4);
948 word = 0;
949 }
950 }
951 word = 0;
952 }
953 }
954}
955
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300956/*
957 * ============================================================================
958 * Device file operations
959 * ============================================================================
960 */
961
962static int queue_init(void *priv, struct vb2_queue *src_vq,
963 struct vb2_queue *dst_vq);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300964static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
965 __u32 pixelformat, unsigned int fmt_type);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300966static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300967
968static int s5p_jpeg_open(struct file *file)
969{
970 struct s5p_jpeg *jpeg = video_drvdata(file);
971 struct video_device *vfd = video_devdata(file);
972 struct s5p_jpeg_ctx *ctx;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300973 struct s5p_jpeg_fmt *out_fmt, *cap_fmt;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300974 int ret = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300975
Sachin Kamatb5146c92012-08-16 08:52:58 -0300976 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300977 if (!ctx)
978 return -ENOMEM;
979
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300980 if (mutex_lock_interruptible(&jpeg->lock)) {
981 ret = -ERESTARTSYS;
982 goto free;
983 }
984
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300985 v4l2_fh_init(&ctx->fh, vfd);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300986 /* Use separate control handler per file handle */
987 ctx->fh.ctrl_handler = &ctx->ctrl_handler;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300988 file->private_data = &ctx->fh;
989 v4l2_fh_add(&ctx->fh);
990
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300991 ctx->jpeg = jpeg;
992 if (vfd == jpeg->vfd_encoder) {
993 ctx->mode = S5P_JPEG_ENCODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300994 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB565,
995 FMT_TYPE_OUTPUT);
996 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
997 FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300998 } else {
999 ctx->mode = S5P_JPEG_DECODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001000 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
1001 FMT_TYPE_OUTPUT);
1002 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_YUYV,
1003 FMT_TYPE_CAPTURE);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001004 ctx->scale_factor = EXYNOS3250_DEC_SCALE_FACTOR_8_8;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001005 }
1006
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001007 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
1008 if (IS_ERR(ctx->fh.m2m_ctx)) {
1009 ret = PTR_ERR(ctx->fh.m2m_ctx);
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001010 goto error;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001011 }
1012
1013 ctx->out_q.fmt = out_fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001014 ctx->cap_q.fmt = cap_fmt;
1015
1016 ret = s5p_jpeg_controls_create(ctx);
1017 if (ret < 0)
1018 goto error;
1019
Hans Verkuilb0d5cd62012-06-24 06:54:18 -03001020 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001021 return 0;
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001022
1023error:
1024 v4l2_fh_del(&ctx->fh);
1025 v4l2_fh_exit(&ctx->fh);
Hans Verkuilb0d5cd62012-06-24 06:54:18 -03001026 mutex_unlock(&jpeg->lock);
1027free:
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001028 kfree(ctx);
1029 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001030}
1031
1032static int s5p_jpeg_release(struct file *file)
1033{
Hans Verkuilb0d5cd62012-06-24 06:54:18 -03001034 struct s5p_jpeg *jpeg = video_drvdata(file);
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001035 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001036
Hans Verkuilb0d5cd62012-06-24 06:54:18 -03001037 mutex_lock(&jpeg->lock);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001038 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001039 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001040 v4l2_fh_del(&ctx->fh);
1041 v4l2_fh_exit(&ctx->fh);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001042 kfree(ctx);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001043 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001044
1045 return 0;
1046}
1047
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001048static const struct v4l2_file_operations s5p_jpeg_fops = {
1049 .owner = THIS_MODULE,
1050 .open = s5p_jpeg_open,
1051 .release = s5p_jpeg_release,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001052 .poll = v4l2_m2m_fop_poll,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001053 .unlocked_ioctl = video_ioctl2,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001054 .mmap = v4l2_m2m_fop_mmap,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001055};
1056
1057/*
1058 * ============================================================================
1059 * video ioctl operations
1060 * ============================================================================
1061 */
1062
1063static int get_byte(struct s5p_jpeg_buffer *buf)
1064{
1065 if (buf->curr >= buf->size)
1066 return -1;
1067
1068 return ((unsigned char *)buf->data)[buf->curr++];
1069}
1070
1071static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word)
1072{
1073 unsigned int temp;
1074 int byte;
1075
1076 byte = get_byte(buf);
1077 if (byte == -1)
1078 return -1;
1079 temp = byte << 8;
1080 byte = get_byte(buf);
1081 if (byte == -1)
1082 return -1;
1083 *word = (unsigned int)byte | temp;
1084 return 0;
1085}
1086
1087static void skip(struct s5p_jpeg_buffer *buf, long len)
1088{
1089 if (len <= 0)
1090 return;
1091
1092 while (len--)
1093 get_byte(buf);
1094}
1095
1096static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001097 unsigned long buffer, unsigned long size,
1098 struct s5p_jpeg_ctx *ctx)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001099{
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001100 int c, components = 0, notfound, n_dht = 0, n_dqt = 0;
1101 unsigned int height, width, word, subsampling = 0, sos = 0, sof = 0,
1102 sof_len = 0;
1103 unsigned int dht[S5P_JPEG_MAX_MARKER], dht_len[S5P_JPEG_MAX_MARKER],
1104 dqt[S5P_JPEG_MAX_MARKER], dqt_len[S5P_JPEG_MAX_MARKER];
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001105 long length;
1106 struct s5p_jpeg_buffer jpeg_buffer;
1107
1108 jpeg_buffer.size = size;
1109 jpeg_buffer.data = buffer;
1110 jpeg_buffer.curr = 0;
1111
1112 notfound = 1;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001113 while (notfound || !sos) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001114 c = get_byte(&jpeg_buffer);
1115 if (c == -1)
Jacek Anaszewskia35f6002014-07-11 12:19:43 -03001116 return false;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001117 if (c != 0xff)
1118 continue;
1119 do
1120 c = get_byte(&jpeg_buffer);
1121 while (c == 0xff);
1122 if (c == -1)
Jacek Anaszewskia35f6002014-07-11 12:19:43 -03001123 return false;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001124 if (c == 0)
1125 continue;
1126 length = 0;
1127 switch (c) {
1128 /* SOF0: baseline JPEG */
1129 case SOF0:
1130 if (get_word_be(&jpeg_buffer, &word))
1131 break;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001132 length = (long)word - 2;
1133 if (!length)
1134 return false;
1135 sof = jpeg_buffer.curr; /* after 0xffc0 */
1136 sof_len = length;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001137 if (get_byte(&jpeg_buffer) == -1)
1138 break;
1139 if (get_word_be(&jpeg_buffer, &height))
1140 break;
1141 if (get_word_be(&jpeg_buffer, &width))
1142 break;
1143 components = get_byte(&jpeg_buffer);
1144 if (components == -1)
1145 break;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001146
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001147 if (components == 1) {
1148 subsampling = 0x33;
1149 } else {
1150 skip(&jpeg_buffer, 1);
1151 subsampling = get_byte(&jpeg_buffer);
1152 skip(&jpeg_buffer, 1);
1153 }
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001154 if (components > 3)
1155 return false;
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001156 skip(&jpeg_buffer, components * 2);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001157 notfound = 0;
1158 break;
1159
1160 case DQT:
1161 if (get_word_be(&jpeg_buffer, &word))
1162 break;
1163 length = (long)word - 2;
1164 if (!length)
1165 return false;
1166 if (n_dqt >= S5P_JPEG_MAX_MARKER)
1167 return false;
1168 dqt[n_dqt] = jpeg_buffer.curr; /* after 0xffdb */
1169 dqt_len[n_dqt++] = length;
1170 skip(&jpeg_buffer, length);
1171 break;
1172
1173 case DHT:
1174 if (get_word_be(&jpeg_buffer, &word))
1175 break;
1176 length = (long)word - 2;
1177 if (!length)
1178 return false;
1179 if (n_dht >= S5P_JPEG_MAX_MARKER)
1180 return false;
1181 dht[n_dht] = jpeg_buffer.curr; /* after 0xffc4 */
1182 dht_len[n_dht++] = length;
1183 skip(&jpeg_buffer, length);
1184 break;
1185
1186 case SOS:
1187 sos = jpeg_buffer.curr - 2; /* 0xffda */
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001188 break;
1189
1190 /* skip payload-less markers */
1191 case RST ... RST + 7:
1192 case SOI:
1193 case EOI:
1194 case TEM:
1195 break;
1196
1197 /* skip uninteresting payload markers */
1198 default:
1199 if (get_word_be(&jpeg_buffer, &word))
1200 break;
1201 length = (long)word - 2;
1202 skip(&jpeg_buffer, length);
1203 break;
1204 }
1205 }
1206 result->w = width;
1207 result->h = height;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001208 result->sos = sos;
1209 result->dht.n = n_dht;
1210 while (n_dht--) {
1211 result->dht.marker[n_dht] = dht[n_dht];
1212 result->dht.len[n_dht] = dht_len[n_dht];
1213 }
1214 result->dqt.n = n_dqt;
1215 while (n_dqt--) {
1216 result->dqt.marker[n_dqt] = dqt[n_dqt];
1217 result->dqt.len[n_dqt] = dqt_len[n_dqt];
1218 }
1219 result->sof = sof;
1220 result->sof_len = sof_len;
1221 result->size = result->components = components;
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001222
1223 switch (subsampling) {
1224 case 0x11:
1225 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444;
1226 break;
1227 case 0x21:
1228 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422;
1229 break;
1230 case 0x22:
1231 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420;
1232 break;
1233 case 0x33:
1234 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
1235 break;
1236 default:
1237 return false;
1238 }
1239
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001240 return !notfound && sos;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001241}
1242
1243static int s5p_jpeg_querycap(struct file *file, void *priv,
1244 struct v4l2_capability *cap)
1245{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001246 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001247
1248 if (ctx->mode == S5P_JPEG_ENCODE) {
1249 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder",
1250 sizeof(cap->driver));
1251 strlcpy(cap->card, S5P_JPEG_M2M_NAME " encoder",
1252 sizeof(cap->card));
1253 } else {
1254 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " decoder",
1255 sizeof(cap->driver));
1256 strlcpy(cap->card, S5P_JPEG_M2M_NAME " decoder",
1257 sizeof(cap->card));
1258 }
1259 cap->bus_info[0] = 0;
Hans Verkuil8c17e5e2014-11-24 06:37:26 -03001260 cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M;
1261 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001262 return 0;
1263}
1264
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001265static int enum_fmt(struct s5p_jpeg_fmt *sjpeg_formats, int n,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001266 struct v4l2_fmtdesc *f, u32 type)
1267{
1268 int i, num = 0;
1269
1270 for (i = 0; i < n; ++i) {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001271 if (sjpeg_formats[i].flags & type) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001272 /* index-th format of type type found ? */
1273 if (num == f->index)
1274 break;
1275 /* Correct type but haven't reached our index yet,
1276 * just increment per-type index */
1277 ++num;
1278 }
1279 }
1280
1281 /* Format not found */
1282 if (i >= n)
1283 return -EINVAL;
1284
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001285 strlcpy(f->description, sjpeg_formats[i].name, sizeof(f->description));
1286 f->pixelformat = sjpeg_formats[i].fourcc;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001287
1288 return 0;
1289}
1290
1291static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
1292 struct v4l2_fmtdesc *f)
1293{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001294 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001295
1296 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001297 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1298 SJPEG_FMT_FLAG_ENC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001299
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001300 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1301 SJPEG_FMT_FLAG_DEC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001302}
1303
1304static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
1305 struct v4l2_fmtdesc *f)
1306{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001307 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001308
1309 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001310 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1311 SJPEG_FMT_FLAG_ENC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001312
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001313 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1314 SJPEG_FMT_FLAG_DEC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001315}
1316
1317static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx,
1318 enum v4l2_buf_type type)
1319{
1320 if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1321 return &ctx->out_q;
1322 if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1323 return &ctx->cap_q;
1324
1325 return NULL;
1326}
1327
1328static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
1329{
1330 struct vb2_queue *vq;
1331 struct s5p_jpeg_q_data *q_data = NULL;
1332 struct v4l2_pix_format *pix = &f->fmt.pix;
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001333 struct s5p_jpeg_ctx *ct = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001334
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001335 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001336 if (!vq)
1337 return -EINVAL;
1338
1339 if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
1340 ct->mode == S5P_JPEG_DECODE && !ct->hdr_parsed)
1341 return -EINVAL;
1342 q_data = get_q_data(ct, f->type);
1343 BUG_ON(q_data == NULL);
1344
1345 pix->width = q_data->w;
1346 pix->height = q_data->h;
1347 pix->field = V4L2_FIELD_NONE;
1348 pix->pixelformat = q_data->fmt->fourcc;
1349 pix->bytesperline = 0;
1350 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
1351 u32 bpl = q_data->w;
1352 if (q_data->fmt->colplanes == 1)
1353 bpl = (bpl * q_data->fmt->depth) >> 3;
1354 pix->bytesperline = bpl;
1355 }
1356 pix->sizeimage = q_data->size;
1357
1358 return 0;
1359}
1360
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001361static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
1362 u32 pixelformat, unsigned int fmt_type)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001363{
Jacek Anaszewskib2451682014-04-10 04:32:11 -03001364 unsigned int k, fmt_flag;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001365
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001366 if (ctx->mode == S5P_JPEG_ENCODE)
1367 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
1368 SJPEG_FMT_FLAG_ENC_OUTPUT :
1369 SJPEG_FMT_FLAG_ENC_CAPTURE;
1370 else
1371 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
1372 SJPEG_FMT_FLAG_DEC_OUTPUT :
1373 SJPEG_FMT_FLAG_DEC_CAPTURE;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001374
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001375 for (k = 0; k < ARRAY_SIZE(sjpeg_formats); k++) {
1376 struct s5p_jpeg_fmt *fmt = &sjpeg_formats[k];
1377 if (fmt->fourcc == pixelformat &&
1378 fmt->flags & fmt_flag &&
Jacek Anaszewskib2451682014-04-10 04:32:11 -03001379 fmt->flags & ctx->jpeg->variant->fmt_ver_flag) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001380 return fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001381 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001382 }
1383
1384 return NULL;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001385}
1386
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001387static void jpeg_bound_align_image(struct s5p_jpeg_ctx *ctx,
1388 u32 *w, unsigned int wmin, unsigned int wmax,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001389 unsigned int walign,
1390 u32 *h, unsigned int hmin, unsigned int hmax,
1391 unsigned int halign)
1392{
1393 int width, height, w_step, h_step;
1394
1395 width = *w;
1396 height = *h;
1397
1398 w_step = 1 << walign;
1399 h_step = 1 << halign;
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001400
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001401 if (ctx->jpeg->variant->hw3250_compat) {
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001402 /*
1403 * Rightmost and bottommost pixels are cropped by the
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001404 * Exynos3250/compatible JPEG IP for RGB formats, for the
1405 * specific width and height values respectively. This
1406 * assignment will result in v4l_bound_align_image returning
1407 * dimensions reduced by 1 for the aforementioned cases.
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001408 */
1409 if (w_step == 4 && ((width & 3) == 1)) {
1410 wmax = width;
1411 hmax = height;
1412 }
1413 }
1414
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001415 v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
1416
1417 if (*w < width && (*w + w_step) < wmax)
1418 *w += w_step;
1419 if (*h < height && (*h + h_step) < hmax)
1420 *h += h_step;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001421}
1422
1423static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
1424 struct s5p_jpeg_ctx *ctx, int q_type)
1425{
1426 struct v4l2_pix_format *pix = &f->fmt.pix;
1427
1428 if (pix->field == V4L2_FIELD_ANY)
1429 pix->field = V4L2_FIELD_NONE;
1430 else if (pix->field != V4L2_FIELD_NONE)
1431 return -EINVAL;
1432
1433 /* V4L2 specification suggests the driver corrects the format struct
1434 * if any of the dimensions is unsupported */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001435 if (q_type == FMT_TYPE_OUTPUT)
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001436 jpeg_bound_align_image(ctx, &pix->width, S5P_JPEG_MIN_WIDTH,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001437 S5P_JPEG_MAX_WIDTH, 0,
1438 &pix->height, S5P_JPEG_MIN_HEIGHT,
1439 S5P_JPEG_MAX_HEIGHT, 0);
1440 else
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001441 jpeg_bound_align_image(ctx, &pix->width, S5P_JPEG_MIN_WIDTH,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001442 S5P_JPEG_MAX_WIDTH, fmt->h_align,
1443 &pix->height, S5P_JPEG_MIN_HEIGHT,
1444 S5P_JPEG_MAX_HEIGHT, fmt->v_align);
1445
1446 if (fmt->fourcc == V4L2_PIX_FMT_JPEG) {
1447 if (pix->sizeimage <= 0)
1448 pix->sizeimage = PAGE_SIZE;
1449 pix->bytesperline = 0;
1450 } else {
1451 u32 bpl = pix->bytesperline;
1452
1453 if (fmt->colplanes > 1 && bpl < pix->width)
1454 bpl = pix->width; /* planar */
1455
1456 if (fmt->colplanes == 1 && /* packed */
Jacek Anaszewskicc690902013-11-25 06:58:10 -03001457 (bpl << 3) / fmt->depth < pix->width)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001458 bpl = (pix->width * fmt->depth) >> 3;
1459
1460 pix->bytesperline = bpl;
1461 pix->sizeimage = (pix->width * pix->height * fmt->depth) >> 3;
1462 }
1463
1464 return 0;
1465}
1466
1467static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
1468 struct v4l2_format *f)
1469{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001470 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001471 struct v4l2_pix_format *pix = &f->fmt.pix;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001472 struct s5p_jpeg_fmt *fmt;
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001473 int ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001474
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001475 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
1476 FMT_TYPE_CAPTURE);
1477 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001478 v4l2_err(&ctx->jpeg->v4l2_dev,
1479 "Fourcc format (0x%08x) invalid.\n",
1480 f->fmt.pix.pixelformat);
1481 return -EINVAL;
1482 }
1483
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001484 if (!ctx->jpeg->variant->hw_ex4_compat || ctx->mode != S5P_JPEG_DECODE)
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001485 goto exit;
1486
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001487 /*
1488 * The exynos4x12 device requires resulting YUV image
1489 * subsampling not to be lower than the input jpeg subsampling.
1490 * If this requirement is not met then downgrade the requested
1491 * capture format to the one with subsampling equal to the input jpeg.
1492 */
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001493 if ((fmt->flags & SJPEG_FMT_NON_RGB) &&
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001494 (fmt->subsampling < ctx->subsampling)) {
1495 ret = s5p_jpeg_adjust_fourcc_to_subsampling(ctx->subsampling,
1496 fmt->fourcc,
1497 &pix->pixelformat,
1498 ctx);
1499 if (ret < 0)
1500 pix->pixelformat = V4L2_PIX_FMT_GREY;
1501
1502 fmt = s5p_jpeg_find_format(ctx, pix->pixelformat,
1503 FMT_TYPE_CAPTURE);
1504 }
1505
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001506 /*
1507 * Decompression of a JPEG file with 4:2:0 subsampling and odd
1508 * width to the YUV 4:2:0 compliant formats produces a raw image
1509 * with broken luma component. Adjust capture format to RGB565
1510 * in such a case.
1511 */
1512 if (ctx->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_420 &&
1513 (ctx->out_q.w & 1) &&
1514 (pix->pixelformat == V4L2_PIX_FMT_NV12 ||
1515 pix->pixelformat == V4L2_PIX_FMT_NV21 ||
1516 pix->pixelformat == V4L2_PIX_FMT_YUV420)) {
1517 pix->pixelformat = V4L2_PIX_FMT_RGB565;
1518 fmt = s5p_jpeg_find_format(ctx, pix->pixelformat,
1519 FMT_TYPE_CAPTURE);
1520 }
1521
1522exit:
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001523 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001524}
1525
1526static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
1527 struct v4l2_format *f)
1528{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001529 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001530 struct s5p_jpeg_fmt *fmt;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001531
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001532 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
1533 FMT_TYPE_OUTPUT);
1534 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001535 v4l2_err(&ctx->jpeg->v4l2_dev,
1536 "Fourcc format (0x%08x) invalid.\n",
1537 f->fmt.pix.pixelformat);
1538 return -EINVAL;
1539 }
1540
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001541 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001542}
1543
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001544static int exynos4_jpeg_get_output_buffer_size(struct s5p_jpeg_ctx *ctx,
1545 struct v4l2_format *f,
1546 int fmt_depth)
1547{
1548 struct v4l2_pix_format *pix = &f->fmt.pix;
1549 u32 pix_fmt = f->fmt.pix.pixelformat;
1550 int w = pix->width, h = pix->height, wh_align;
1551
1552 if (pix_fmt == V4L2_PIX_FMT_RGB32 ||
1553 pix_fmt == V4L2_PIX_FMT_NV24 ||
1554 pix_fmt == V4L2_PIX_FMT_NV42 ||
1555 pix_fmt == V4L2_PIX_FMT_NV12 ||
1556 pix_fmt == V4L2_PIX_FMT_NV21 ||
1557 pix_fmt == V4L2_PIX_FMT_YUV420)
1558 wh_align = 4;
1559 else
1560 wh_align = 1;
1561
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001562 jpeg_bound_align_image(ctx, &w, S5P_JPEG_MIN_WIDTH,
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001563 S5P_JPEG_MAX_WIDTH, wh_align,
1564 &h, S5P_JPEG_MIN_HEIGHT,
1565 S5P_JPEG_MAX_HEIGHT, wh_align);
1566
1567 return w * h * fmt_depth >> 3;
1568}
1569
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001570static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx,
1571 struct v4l2_rect *r);
1572
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001573static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
1574{
1575 struct vb2_queue *vq;
1576 struct s5p_jpeg_q_data *q_data = NULL;
1577 struct v4l2_pix_format *pix = &f->fmt.pix;
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001578 struct v4l2_ctrl *ctrl_subs;
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001579 struct v4l2_rect scale_rect;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001580 unsigned int f_type;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001581
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001582 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001583 if (!vq)
1584 return -EINVAL;
1585
1586 q_data = get_q_data(ct, f->type);
1587 BUG_ON(q_data == NULL);
1588
1589 if (vb2_is_busy(vq)) {
1590 v4l2_err(&ct->jpeg->v4l2_dev, "%s queue busy\n", __func__);
1591 return -EBUSY;
1592 }
1593
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001594 f_type = V4L2_TYPE_IS_OUTPUT(f->type) ?
1595 FMT_TYPE_OUTPUT : FMT_TYPE_CAPTURE;
1596
1597 q_data->fmt = s5p_jpeg_find_format(ct, pix->pixelformat, f_type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001598 q_data->w = pix->width;
1599 q_data->h = pix->height;
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001600 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
1601 /*
1602 * During encoding Exynos4x12 SoCs access wider memory area
1603 * than it results from Image_x and Image_y values written to
1604 * the JPEG_IMAGE_SIZE register. In order to avoid sysmmu
1605 * page fault calculate proper buffer size in such a case.
1606 */
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001607 if (ct->jpeg->variant->hw_ex4_compat &&
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001608 f_type == FMT_TYPE_OUTPUT && ct->mode == S5P_JPEG_ENCODE)
1609 q_data->size = exynos4_jpeg_get_output_buffer_size(ct,
1610 f,
1611 q_data->fmt->depth);
1612 else
1613 q_data->size = q_data->w * q_data->h *
1614 q_data->fmt->depth >> 3;
1615 } else {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001616 q_data->size = pix->sizeimage;
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001617 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001618
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001619 if (f_type == FMT_TYPE_OUTPUT) {
1620 ctrl_subs = v4l2_ctrl_find(&ct->ctrl_handler,
1621 V4L2_CID_JPEG_CHROMA_SUBSAMPLING);
1622 if (ctrl_subs)
1623 v4l2_ctrl_s_ctrl(ctrl_subs, q_data->fmt->subsampling);
Jacek Anaszewskidfd96902014-07-11 12:19:46 -03001624 ct->crop_altered = false;
1625 }
1626
1627 /*
1628 * For decoding init crop_rect with capture buffer dimmensions which
1629 * contain aligned dimensions of the input JPEG image and do it only
1630 * if crop rectangle hasn't been altered by the user space e.g. with
1631 * S_SELECTION ioctl. For encoding assign output buffer dimensions.
1632 */
1633 if (!ct->crop_altered &&
1634 ((ct->mode == S5P_JPEG_DECODE && f_type == FMT_TYPE_CAPTURE) ||
1635 (ct->mode == S5P_JPEG_ENCODE && f_type == FMT_TYPE_OUTPUT))) {
1636 ct->crop_rect.width = pix->width;
1637 ct->crop_rect.height = pix->height;
1638 }
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001639
1640 /*
1641 * Prevent downscaling to YUV420 format by more than 2
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001642 * for Exynos3250/compatible SoC as it produces broken raw image
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001643 * in such cases.
1644 */
1645 if (ct->mode == S5P_JPEG_DECODE &&
1646 f_type == FMT_TYPE_CAPTURE &&
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001647 ct->jpeg->variant->hw3250_compat &&
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001648 pix->pixelformat == V4L2_PIX_FMT_YUV420 &&
1649 ct->scale_factor > 2) {
1650 scale_rect.width = ct->out_q.w / 2;
1651 scale_rect.height = ct->out_q.h / 2;
1652 exynos3250_jpeg_try_downscale(ct, &scale_rect);
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001653 }
1654
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001655 return 0;
1656}
1657
1658static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
1659 struct v4l2_format *f)
1660{
1661 int ret;
1662
1663 ret = s5p_jpeg_try_fmt_vid_cap(file, priv, f);
1664 if (ret)
1665 return ret;
1666
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001667 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001668}
1669
1670static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
1671 struct v4l2_format *f)
1672{
1673 int ret;
1674
1675 ret = s5p_jpeg_try_fmt_vid_out(file, priv, f);
1676 if (ret)
1677 return ret;
1678
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001679 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001680}
1681
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001682static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx,
1683 struct v4l2_rect *r)
1684{
1685 int w_ratio, h_ratio, scale_factor, cur_ratio, i;
1686
1687 w_ratio = ctx->out_q.w / r->width;
1688 h_ratio = ctx->out_q.h / r->height;
1689
1690 scale_factor = w_ratio > h_ratio ? w_ratio : h_ratio;
1691 scale_factor = clamp_val(scale_factor, 1, 8);
1692
1693 /* Align scale ratio to the nearest power of 2 */
1694 for (i = 0; i <= 3; ++i) {
1695 cur_ratio = 1 << i;
1696 if (scale_factor <= cur_ratio) {
1697 ctx->scale_factor = cur_ratio;
1698 break;
1699 }
1700 }
1701
1702 r->width = round_down(ctx->out_q.w / ctx->scale_factor, 2);
1703 r->height = round_down(ctx->out_q.h / ctx->scale_factor, 2);
1704
1705 ctx->crop_rect.width = r->width;
1706 ctx->crop_rect.height = r->height;
1707 ctx->crop_rect.left = 0;
1708 ctx->crop_rect.top = 0;
1709
1710 ctx->crop_altered = true;
1711
1712 return 0;
1713}
1714
1715/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */
1716static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
1717{
1718 if (a->left < b->left || a->top < b->top)
1719 return 0;
1720 if (a->left + a->width > b->left + b->width)
1721 return 0;
1722 if (a->top + a->height > b->top + b->height)
1723 return 0;
1724
1725 return 1;
1726}
1727
1728static int exynos3250_jpeg_try_crop(struct s5p_jpeg_ctx *ctx,
1729 struct v4l2_rect *r)
1730{
1731 struct v4l2_rect base_rect;
1732 int w_step, h_step;
1733
1734 switch (ctx->cap_q.fmt->fourcc) {
1735 case V4L2_PIX_FMT_NV12:
1736 case V4L2_PIX_FMT_NV21:
1737 w_step = 1;
1738 h_step = 2;
1739 break;
1740 case V4L2_PIX_FMT_YUV420:
1741 w_step = 2;
1742 h_step = 2;
1743 break;
1744 default:
1745 w_step = 1;
1746 h_step = 1;
1747 break;
1748 }
1749
1750 base_rect.top = 0;
1751 base_rect.left = 0;
1752 base_rect.width = ctx->out_q.w;
1753 base_rect.height = ctx->out_q.h;
1754
1755 r->width = round_down(r->width, w_step);
1756 r->height = round_down(r->height, h_step);
1757 r->left = round_down(r->left, 2);
1758 r->top = round_down(r->top, 2);
1759
1760 if (!enclosed_rectangle(r, &base_rect))
1761 return -EINVAL;
1762
1763 ctx->crop_rect.left = r->left;
1764 ctx->crop_rect.top = r->top;
1765 ctx->crop_rect.width = r->width;
1766 ctx->crop_rect.height = r->height;
1767
1768 ctx->crop_altered = true;
1769
1770 return 0;
1771}
1772
1773/*
1774 * V4L2 controls
1775 */
1776
Sachin Kamat9f3bd322012-05-10 03:38:40 -03001777static int s5p_jpeg_g_selection(struct file *file, void *priv,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001778 struct v4l2_selection *s)
1779{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001780 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001781
1782 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
Jacek Anaszewski38a6ef32014-04-10 04:32:15 -03001783 s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001784 return -EINVAL;
1785
1786 /* For JPEG blob active == default == bounds */
1787 switch (s->target) {
Sylwester Nawrockic1334822012-05-20 11:17:12 -03001788 case V4L2_SEL_TGT_CROP:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001789 case V4L2_SEL_TGT_CROP_BOUNDS:
1790 case V4L2_SEL_TGT_CROP_DEFAULT:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001791 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
1792 s->r.width = ctx->out_q.w;
1793 s->r.height = ctx->out_q.h;
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001794 s->r.left = 0;
1795 s->r.top = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001796 break;
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001797 case V4L2_SEL_TGT_COMPOSE:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001798 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
1799 case V4L2_SEL_TGT_COMPOSE_PADDED:
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001800 s->r.width = ctx->crop_rect.width;
1801 s->r.height = ctx->crop_rect.height;
1802 s->r.left = ctx->crop_rect.left;
1803 s->r.top = ctx->crop_rect.top;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001804 break;
1805 default:
1806 return -EINVAL;
1807 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001808 return 0;
1809}
1810
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001811/*
1812 * V4L2 controls
1813 */
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001814static int s5p_jpeg_s_selection(struct file *file, void *fh,
1815 struct v4l2_selection *s)
1816{
1817 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
1818 struct v4l2_rect *rect = &s->r;
1819 int ret = -EINVAL;
1820
1821 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1822 return -EINVAL;
1823
1824 if (s->target == V4L2_SEL_TGT_COMPOSE) {
1825 if (ctx->mode != S5P_JPEG_DECODE)
1826 return -EINVAL;
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001827 if (ctx->jpeg->variant->hw3250_compat)
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001828 ret = exynos3250_jpeg_try_downscale(ctx, rect);
1829 } else if (s->target == V4L2_SEL_TGT_CROP) {
1830 if (ctx->mode != S5P_JPEG_ENCODE)
1831 return -EINVAL;
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001832 if (ctx->jpeg->variant->hw3250_compat)
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001833 ret = exynos3250_jpeg_try_crop(ctx, rect);
1834 }
1835
1836 return ret;
1837}
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001838
1839static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001840{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001841 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1842 struct s5p_jpeg *jpeg = ctx->jpeg;
1843 unsigned long flags;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001844
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001845 switch (ctrl->id) {
1846 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1847 spin_lock_irqsave(&jpeg->slock, flags);
Jacek Anaszewski303b0a92013-12-18 11:14:00 -03001848 ctrl->val = s5p_jpeg_to_user_subsampling(ctx);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001849 spin_unlock_irqrestore(&jpeg->slock, flags);
1850 break;
1851 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001852
1853 return 0;
1854}
1855
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001856static int s5p_jpeg_adjust_subs_ctrl(struct s5p_jpeg_ctx *ctx, int *ctrl_val)
1857{
1858 switch (ctx->jpeg->variant->version) {
1859 case SJPEG_S5P:
1860 return 0;
1861 case SJPEG_EXYNOS3250:
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001862 case SJPEG_EXYNOS5420:
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001863 /*
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001864 * The exynos3250/compatible device can produce JPEG image only
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001865 * of 4:4:4 subsampling when given RGB32 source image.
1866 */
1867 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB32)
1868 *ctrl_val = 0;
1869 break;
1870 case SJPEG_EXYNOS4:
1871 /*
1872 * The exynos4x12 device requires input raw image fourcc
1873 * to be V4L2_PIX_FMT_GREY if gray jpeg format
1874 * is to be set.
1875 */
1876 if (ctx->out_q.fmt->fourcc != V4L2_PIX_FMT_GREY &&
1877 *ctrl_val == V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY)
1878 return -EINVAL;
1879 break;
1880 }
1881
1882 /*
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001883 * The exynos4x12 and exynos3250/compatible devices require resulting
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001884 * jpeg subsampling not to be lower than the input raw image
1885 * subsampling.
1886 */
1887 if (ctx->out_q.fmt->subsampling > *ctrl_val)
1888 *ctrl_val = ctx->out_q.fmt->subsampling;
1889
1890 return 0;
1891}
1892
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001893static int s5p_jpeg_try_ctrl(struct v4l2_ctrl *ctrl)
1894{
1895 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1896 unsigned long flags;
1897 int ret = 0;
1898
1899 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1900
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001901 if (ctrl->id == V4L2_CID_JPEG_CHROMA_SUBSAMPLING)
1902 ret = s5p_jpeg_adjust_subs_ctrl(ctx, &ctrl->val);
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001903
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001904 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1905 return ret;
1906}
1907
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001908static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001909{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001910 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1911 unsigned long flags;
1912
1913 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1914
1915 switch (ctrl->id) {
1916 case V4L2_CID_JPEG_COMPRESSION_QUALITY:
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001917 ctx->compr_quality = ctrl->val;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001918 break;
1919 case V4L2_CID_JPEG_RESTART_INTERVAL:
1920 ctx->restart_interval = ctrl->val;
1921 break;
1922 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1923 ctx->subsampling = ctrl->val;
1924 break;
1925 }
1926
1927 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1928 return 0;
1929}
1930
1931static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
1932 .g_volatile_ctrl = s5p_jpeg_g_volatile_ctrl,
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001933 .try_ctrl = s5p_jpeg_try_ctrl,
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001934 .s_ctrl = s5p_jpeg_s_ctrl,
1935};
1936
1937static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
1938{
1939 unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */
1940 struct v4l2_ctrl *ctrl;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001941 int ret;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001942
1943 v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
1944
1945 if (ctx->mode == S5P_JPEG_ENCODE) {
1946 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1947 V4L2_CID_JPEG_COMPRESSION_QUALITY,
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001948 0, 3, 1, S5P_JPEG_COMPR_QUAL_WORST);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001949
1950 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1951 V4L2_CID_JPEG_RESTART_INTERVAL,
1952 0, 3, 0xffff, 0);
Jacek Anaszewskifdf9e2b2013-11-21 13:33:41 -03001953 if (ctx->jpeg->variant->version == SJPEG_S5P)
1954 mask = ~0x06; /* 422, 420 */
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001955 }
1956
1957 ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1958 V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
1959 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask,
1960 V4L2_JPEG_CHROMA_SUBSAMPLING_422);
1961
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001962 if (ctx->ctrl_handler.error) {
1963 ret = ctx->ctrl_handler.error;
1964 goto error_free;
1965 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001966
1967 if (ctx->mode == S5P_JPEG_DECODE)
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001968 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
1969 V4L2_CTRL_FLAG_READ_ONLY;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001970
1971 ret = v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
1972 if (ret < 0)
1973 goto error_free;
1974
1975 return ret;
1976
1977error_free:
1978 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
1979 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001980}
1981
1982static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
1983 .vidioc_querycap = s5p_jpeg_querycap,
1984
1985 .vidioc_enum_fmt_vid_cap = s5p_jpeg_enum_fmt_vid_cap,
1986 .vidioc_enum_fmt_vid_out = s5p_jpeg_enum_fmt_vid_out,
1987
1988 .vidioc_g_fmt_vid_cap = s5p_jpeg_g_fmt,
1989 .vidioc_g_fmt_vid_out = s5p_jpeg_g_fmt,
1990
1991 .vidioc_try_fmt_vid_cap = s5p_jpeg_try_fmt_vid_cap,
1992 .vidioc_try_fmt_vid_out = s5p_jpeg_try_fmt_vid_out,
1993
1994 .vidioc_s_fmt_vid_cap = s5p_jpeg_s_fmt_vid_cap,
1995 .vidioc_s_fmt_vid_out = s5p_jpeg_s_fmt_vid_out,
1996
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001997 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
1998 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
1999 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
2000 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002001
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002002 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
2003 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002004
2005 .vidioc_g_selection = s5p_jpeg_g_selection,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002006 .vidioc_s_selection = s5p_jpeg_s_selection,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002007};
2008
2009/*
2010 * ============================================================================
2011 * mem2mem callbacks
2012 * ============================================================================
2013 */
2014
2015static void s5p_jpeg_device_run(void *priv)
2016{
2017 struct s5p_jpeg_ctx *ctx = priv;
2018 struct s5p_jpeg *jpeg = ctx->jpeg;
2019 struct vb2_buffer *src_buf, *dst_buf;
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002020 unsigned long src_addr, dst_addr, flags;
2021
2022 spin_lock_irqsave(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002023
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002024 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2025 dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002026 src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
2027 dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
2028
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002029 s5p_jpeg_reset(jpeg->regs);
2030 s5p_jpeg_poweron(jpeg->regs);
2031 s5p_jpeg_proc_mode(jpeg->regs, ctx->mode);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002032 if (ctx->mode == S5P_JPEG_ENCODE) {
2033 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002034 s5p_jpeg_input_raw_mode(jpeg->regs,
2035 S5P_JPEG_RAW_IN_565);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002036 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002037 s5p_jpeg_input_raw_mode(jpeg->regs,
2038 S5P_JPEG_RAW_IN_422);
2039 s5p_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
2040 s5p_jpeg_dri(jpeg->regs, ctx->restart_interval);
2041 s5p_jpeg_x(jpeg->regs, ctx->out_q.w);
2042 s5p_jpeg_y(jpeg->regs, ctx->out_q.h);
2043 s5p_jpeg_imgadr(jpeg->regs, src_addr);
2044 s5p_jpeg_jpgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002045
2046 /* ultimately comes from sizeimage from userspace */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002047 s5p_jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002048
2049 /* JPEG RGB to YCbCr conversion matrix */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002050 s5p_jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11);
2051 s5p_jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12);
2052 s5p_jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13);
2053 s5p_jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21);
2054 s5p_jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22);
2055 s5p_jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23);
2056 s5p_jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31);
2057 s5p_jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32);
2058 s5p_jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002059
2060 /*
2061 * JPEG IP allows storing 4 quantization tables
2062 * We fill table 0 for luma and table 1 for chroma
2063 */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03002064 s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
2065 s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002066 /* use table 0 for Y */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002067 s5p_jpeg_qtbl(jpeg->regs, 1, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002068 /* use table 1 for Cb and Cr*/
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002069 s5p_jpeg_qtbl(jpeg->regs, 2, 1);
2070 s5p_jpeg_qtbl(jpeg->regs, 3, 1);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002071
2072 /* Y, Cb, Cr use Huffman table 0 */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002073 s5p_jpeg_htbl_ac(jpeg->regs, 1);
2074 s5p_jpeg_htbl_dc(jpeg->regs, 1);
2075 s5p_jpeg_htbl_ac(jpeg->regs, 2);
2076 s5p_jpeg_htbl_dc(jpeg->regs, 2);
2077 s5p_jpeg_htbl_ac(jpeg->regs, 3);
2078 s5p_jpeg_htbl_dc(jpeg->regs, 3);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03002079 } else { /* S5P_JPEG_DECODE */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002080 s5p_jpeg_rst_int_enable(jpeg->regs, true);
2081 s5p_jpeg_data_num_int_enable(jpeg->regs, true);
2082 s5p_jpeg_final_mcu_num_int_enable(jpeg->regs, true);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03002083 if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002084 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03002085 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002086 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420);
2087 s5p_jpeg_jpgadr(jpeg->regs, src_addr);
2088 s5p_jpeg_imgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002089 }
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002090
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002091 s5p_jpeg_start(jpeg->regs);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002092
2093 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002094}
2095
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002096static void exynos4_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
2097{
2098 struct s5p_jpeg *jpeg = ctx->jpeg;
2099 struct s5p_jpeg_fmt *fmt;
2100 struct vb2_buffer *vb;
Jacek Anaszewski12b05562015-03-05 10:56:25 -03002101 struct s5p_jpeg_addr jpeg_addr = {};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002102 u32 pix_size, padding_bytes = 0;
2103
Tony K Nadackalcb0c3f52014-12-17 04:21:21 -03002104 jpeg_addr.cb = 0;
2105 jpeg_addr.cr = 0;
2106
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002107 pix_size = ctx->cap_q.w * ctx->cap_q.h;
2108
2109 if (ctx->mode == S5P_JPEG_ENCODE) {
2110 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2111 fmt = ctx->out_q.fmt;
2112 if (ctx->out_q.w % 2 && fmt->h_align > 0)
2113 padding_bytes = ctx->out_q.h;
2114 } else {
2115 fmt = ctx->cap_q.fmt;
2116 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
2117 }
2118
2119 jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
2120
2121 if (fmt->colplanes == 2) {
2122 jpeg_addr.cb = jpeg_addr.y + pix_size - padding_bytes;
2123 } else if (fmt->colplanes == 3) {
2124 jpeg_addr.cb = jpeg_addr.y + pix_size;
2125 if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
2126 jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
2127 else
2128 jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
2129 }
2130
2131 exynos4_jpeg_set_frame_buf_address(jpeg->regs, &jpeg_addr);
2132}
2133
2134static void exynos4_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
2135{
2136 struct s5p_jpeg *jpeg = ctx->jpeg;
2137 struct vb2_buffer *vb;
2138 unsigned int jpeg_addr = 0;
2139
2140 if (ctx->mode == S5P_JPEG_ENCODE)
2141 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
2142 else
2143 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2144
2145 jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002146 if (jpeg->variant->version == SJPEG_EXYNOS5433 &&
2147 ctx->mode == S5P_JPEG_DECODE)
2148 jpeg_addr += ctx->out_q.sos;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002149 exynos4_jpeg_set_stream_buf_address(jpeg->regs, jpeg_addr);
2150}
2151
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002152static inline void exynos4_jpeg_set_img_fmt(void __iomem *base,
2153 unsigned int img_fmt)
2154{
2155 __exynos4_jpeg_set_img_fmt(base, img_fmt, SJPEG_EXYNOS4);
2156}
2157
2158static inline void exynos5433_jpeg_set_img_fmt(void __iomem *base,
2159 unsigned int img_fmt)
2160{
2161 __exynos4_jpeg_set_img_fmt(base, img_fmt, SJPEG_EXYNOS5433);
2162}
2163
2164static inline void exynos4_jpeg_set_enc_out_fmt(void __iomem *base,
2165 unsigned int out_fmt)
2166{
2167 __exynos4_jpeg_set_enc_out_fmt(base, out_fmt, SJPEG_EXYNOS4);
2168}
2169
2170static inline void exynos5433_jpeg_set_enc_out_fmt(void __iomem *base,
2171 unsigned int out_fmt)
2172{
2173 __exynos4_jpeg_set_enc_out_fmt(base, out_fmt, SJPEG_EXYNOS5433);
2174}
2175
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002176static void exynos4_jpeg_device_run(void *priv)
2177{
2178 struct s5p_jpeg_ctx *ctx = priv;
2179 struct s5p_jpeg *jpeg = ctx->jpeg;
2180 unsigned int bitstream_size;
2181 unsigned long flags;
2182
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002183 spin_lock_irqsave(&jpeg->slock, flags);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002184
2185 if (ctx->mode == S5P_JPEG_ENCODE) {
2186 exynos4_jpeg_sw_reset(jpeg->regs);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002187 exynos4_jpeg_set_interrupt(jpeg->regs, jpeg->variant->version);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002188 exynos4_jpeg_set_huf_table_enable(jpeg->regs, 1);
2189
2190 exynos4_jpeg_set_huff_tbl(jpeg->regs);
2191
2192 /*
2193 * JPEG IP allows storing 4 quantization tables
2194 * We fill table 0 for luma and table 1 for chroma
2195 */
2196 exynos4_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
2197 exynos4_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
2198
2199 exynos4_jpeg_set_encode_tbl_select(jpeg->regs,
2200 ctx->compr_quality);
2201 exynos4_jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w,
2202 ctx->cap_q.h);
2203
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002204 if (ctx->jpeg->variant->version == SJPEG_EXYNOS4) {
2205 exynos4_jpeg_set_enc_out_fmt(jpeg->regs,
2206 ctx->subsampling);
2207 exynos4_jpeg_set_img_fmt(jpeg->regs,
2208 ctx->out_q.fmt->fourcc);
2209 } else {
2210 exynos5433_jpeg_set_enc_out_fmt(jpeg->regs,
2211 ctx->subsampling);
2212 exynos5433_jpeg_set_img_fmt(jpeg->regs,
2213 ctx->out_q.fmt->fourcc);
2214 }
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002215 exynos4_jpeg_set_img_addr(ctx);
2216 exynos4_jpeg_set_jpeg_addr(ctx);
2217 exynos4_jpeg_set_encode_hoff_cnt(jpeg->regs,
2218 ctx->out_q.fmt->fourcc);
2219 } else {
2220 exynos4_jpeg_sw_reset(jpeg->regs);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002221 exynos4_jpeg_set_interrupt(jpeg->regs,
2222 jpeg->variant->version);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002223 exynos4_jpeg_set_img_addr(ctx);
2224 exynos4_jpeg_set_jpeg_addr(ctx);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002225
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002226 if (jpeg->variant->version == SJPEG_EXYNOS5433) {
2227 exynos4_jpeg_parse_huff_tbl(ctx);
2228 exynos4_jpeg_parse_decode_h_tbl(ctx);
2229
2230 exynos4_jpeg_parse_q_tbl(ctx);
2231 exynos4_jpeg_parse_decode_q_tbl(ctx);
2232
2233 exynos4_jpeg_set_huf_table_enable(jpeg->regs, 1);
2234
2235 exynos4_jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w,
2236 ctx->cap_q.h);
2237 exynos5433_jpeg_set_enc_out_fmt(jpeg->regs,
2238 ctx->subsampling);
2239 exynos5433_jpeg_set_img_fmt(jpeg->regs,
2240 ctx->cap_q.fmt->fourcc);
2241 bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 16);
2242 } else {
2243 exynos4_jpeg_set_img_fmt(jpeg->regs,
2244 ctx->cap_q.fmt->fourcc);
2245 bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 32);
2246 }
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002247
2248 exynos4_jpeg_set_dec_bitstream_size(jpeg->regs, bitstream_size);
2249 }
2250
2251 exynos4_jpeg_set_enc_dec_mode(jpeg->regs, ctx->mode);
2252
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002253 spin_unlock_irqrestore(&jpeg->slock, flags);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002254}
2255
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002256static void exynos3250_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
2257{
2258 struct s5p_jpeg *jpeg = ctx->jpeg;
2259 struct s5p_jpeg_fmt *fmt;
2260 struct vb2_buffer *vb;
Jacek Anaszewski12b05562015-03-05 10:56:25 -03002261 struct s5p_jpeg_addr jpeg_addr = {};
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002262 u32 pix_size;
2263
2264 pix_size = ctx->cap_q.w * ctx->cap_q.h;
2265
2266 if (ctx->mode == S5P_JPEG_ENCODE) {
2267 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2268 fmt = ctx->out_q.fmt;
2269 } else {
2270 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
2271 fmt = ctx->cap_q.fmt;
2272 }
2273
2274 jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
2275
2276 if (fmt->colplanes == 2) {
2277 jpeg_addr.cb = jpeg_addr.y + pix_size;
2278 } else if (fmt->colplanes == 3) {
2279 jpeg_addr.cb = jpeg_addr.y + pix_size;
2280 if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
2281 jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
2282 else
2283 jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
2284 }
2285
2286 exynos3250_jpeg_imgadr(jpeg->regs, &jpeg_addr);
2287}
2288
2289static void exynos3250_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
2290{
2291 struct s5p_jpeg *jpeg = ctx->jpeg;
2292 struct vb2_buffer *vb;
2293 unsigned int jpeg_addr = 0;
2294
2295 if (ctx->mode == S5P_JPEG_ENCODE)
2296 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
2297 else
2298 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2299
2300 jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
2301 exynos3250_jpeg_jpgadr(jpeg->regs, jpeg_addr);
2302}
2303
2304static void exynos3250_jpeg_device_run(void *priv)
2305{
2306 struct s5p_jpeg_ctx *ctx = priv;
2307 struct s5p_jpeg *jpeg = ctx->jpeg;
2308 unsigned long flags;
2309
2310 spin_lock_irqsave(&ctx->jpeg->slock, flags);
2311
2312 exynos3250_jpeg_reset(jpeg->regs);
2313 exynos3250_jpeg_set_dma_num(jpeg->regs);
2314 exynos3250_jpeg_poweron(jpeg->regs);
2315 exynos3250_jpeg_clk_set(jpeg->regs);
2316 exynos3250_jpeg_proc_mode(jpeg->regs, ctx->mode);
2317
2318 if (ctx->mode == S5P_JPEG_ENCODE) {
2319 exynos3250_jpeg_input_raw_fmt(jpeg->regs,
2320 ctx->out_q.fmt->fourcc);
2321 exynos3250_jpeg_dri(jpeg->regs, ctx->restart_interval);
2322
2323 /*
2324 * JPEG IP allows storing 4 quantization tables
2325 * We fill table 0 for luma and table 1 for chroma
2326 */
2327 s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
2328 s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
2329 /* use table 0 for Y */
2330 exynos3250_jpeg_qtbl(jpeg->regs, 1, 0);
2331 /* use table 1 for Cb and Cr*/
2332 exynos3250_jpeg_qtbl(jpeg->regs, 2, 1);
2333 exynos3250_jpeg_qtbl(jpeg->regs, 3, 1);
2334
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03002335 /*
2336 * Some SoCs require setting Huffman tables before each run
2337 */
2338 if (jpeg->variant->htbl_reinit) {
2339 s5p_jpeg_set_hdctbl(jpeg->regs);
2340 s5p_jpeg_set_hdctblg(jpeg->regs);
2341 s5p_jpeg_set_hactbl(jpeg->regs);
2342 s5p_jpeg_set_hactblg(jpeg->regs);
2343 }
2344
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002345 /* Y, Cb, Cr use Huffman table 0 */
2346 exynos3250_jpeg_htbl_ac(jpeg->regs, 1);
2347 exynos3250_jpeg_htbl_dc(jpeg->regs, 1);
2348 exynos3250_jpeg_htbl_ac(jpeg->regs, 2);
2349 exynos3250_jpeg_htbl_dc(jpeg->regs, 2);
2350 exynos3250_jpeg_htbl_ac(jpeg->regs, 3);
2351 exynos3250_jpeg_htbl_dc(jpeg->regs, 3);
2352
2353 exynos3250_jpeg_set_x(jpeg->regs, ctx->crop_rect.width);
2354 exynos3250_jpeg_set_y(jpeg->regs, ctx->crop_rect.height);
2355 exynos3250_jpeg_stride(jpeg->regs, ctx->out_q.fmt->fourcc,
2356 ctx->out_q.w);
2357 exynos3250_jpeg_offset(jpeg->regs, ctx->crop_rect.left,
2358 ctx->crop_rect.top);
2359 exynos3250_jpeg_set_img_addr(ctx);
2360 exynos3250_jpeg_set_jpeg_addr(ctx);
2361 exynos3250_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
2362
2363 /* ultimately comes from sizeimage from userspace */
2364 exynos3250_jpeg_enc_stream_bound(jpeg->regs, ctx->cap_q.size);
2365
2366 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565 ||
2367 ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565X ||
2368 ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB32)
2369 exynos3250_jpeg_set_y16(jpeg->regs, true);
2370 } else {
2371 exynos3250_jpeg_set_img_addr(ctx);
2372 exynos3250_jpeg_set_jpeg_addr(ctx);
2373 exynos3250_jpeg_stride(jpeg->regs, ctx->cap_q.fmt->fourcc,
2374 ctx->cap_q.w);
2375 exynos3250_jpeg_offset(jpeg->regs, 0, 0);
2376 exynos3250_jpeg_dec_scaling_ratio(jpeg->regs,
2377 ctx->scale_factor);
2378 exynos3250_jpeg_dec_stream_size(jpeg->regs, ctx->out_q.size);
2379 exynos3250_jpeg_output_raw_fmt(jpeg->regs,
2380 ctx->cap_q.fmt->fourcc);
2381 }
2382
2383 exynos3250_jpeg_interrupts_enable(jpeg->regs);
2384
2385 /* JPEG RGB to YCbCr conversion matrix */
2386 exynos3250_jpeg_coef(jpeg->regs, ctx->mode);
2387
2388 exynos3250_jpeg_set_timer(jpeg->regs, EXYNOS3250_IRQ_TIMEOUT);
2389 jpeg->irq_status = 0;
2390 exynos3250_jpeg_start(jpeg->regs);
2391
2392 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
2393}
2394
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002395static int s5p_jpeg_job_ready(void *priv)
2396{
2397 struct s5p_jpeg_ctx *ctx = priv;
2398
2399 if (ctx->mode == S5P_JPEG_DECODE)
2400 return ctx->hdr_parsed;
2401 return 1;
2402}
2403
2404static void s5p_jpeg_job_abort(void *priv)
2405{
2406}
2407
2408static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = {
2409 .device_run = s5p_jpeg_device_run,
2410 .job_ready = s5p_jpeg_job_ready,
2411 .job_abort = s5p_jpeg_job_abort,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002412};
2413
2414static struct v4l2_m2m_ops exynos3250_jpeg_m2m_ops = {
2415 .device_run = exynos3250_jpeg_device_run,
2416 .job_ready = s5p_jpeg_job_ready,
2417 .job_abort = s5p_jpeg_job_abort,
2418};
2419
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03002420static struct v4l2_m2m_ops exynos4_jpeg_m2m_ops = {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002421 .device_run = exynos4_jpeg_device_run,
2422 .job_ready = s5p_jpeg_job_ready,
2423 .job_abort = s5p_jpeg_job_abort,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002424};
2425
2426/*
2427 * ============================================================================
2428 * Queue operations
2429 * ============================================================================
2430 */
2431
Marek Szyprowski719c1742012-01-13 05:12:38 -03002432static int s5p_jpeg_queue_setup(struct vb2_queue *vq,
Marek Szyprowski719c1742012-01-13 05:12:38 -03002433 unsigned int *nbuffers, unsigned int *nplanes,
2434 unsigned int sizes[], void *alloc_ctxs[])
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002435{
2436 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
2437 struct s5p_jpeg_q_data *q_data = NULL;
2438 unsigned int size, count = *nbuffers;
2439
2440 q_data = get_q_data(ctx, vq->type);
2441 BUG_ON(q_data == NULL);
2442
2443 size = q_data->size;
2444
2445 /*
2446 * header is parsed during decoding and parsed information stored
2447 * in the context so we do not allow another buffer to overwrite it
2448 */
2449 if (ctx->mode == S5P_JPEG_DECODE)
2450 count = 1;
2451
2452 *nbuffers = count;
2453 *nplanes = 1;
2454 sizes[0] = size;
2455 alloc_ctxs[0] = ctx->jpeg->alloc_ctx;
2456
2457 return 0;
2458}
2459
2460static int s5p_jpeg_buf_prepare(struct vb2_buffer *vb)
2461{
2462 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
2463 struct s5p_jpeg_q_data *q_data = NULL;
2464
2465 q_data = get_q_data(ctx, vb->vb2_queue->type);
2466 BUG_ON(q_data == NULL);
2467
2468 if (vb2_plane_size(vb, 0) < q_data->size) {
2469 pr_err("%s data will not fit into plane (%lu < %lu)\n",
2470 __func__, vb2_plane_size(vb, 0),
2471 (long)q_data->size);
2472 return -EINVAL;
2473 }
2474
2475 vb2_set_plane_payload(vb, 0, q_data->size);
2476
2477 return 0;
2478}
2479
2480static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
2481{
Junghak Sung2d700712015-09-22 10:30:30 -03002482 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002483 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
2484
2485 if (ctx->mode == S5P_JPEG_DECODE &&
2486 vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
2487 struct s5p_jpeg_q_data tmp, *q_data;
2488 ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp,
2489 (unsigned long)vb2_plane_vaddr(vb, 0),
2490 min((unsigned long)ctx->out_q.size,
Jacek Anaszewskif8433962013-11-21 13:33:09 -03002491 vb2_get_plane_payload(vb, 0)), ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002492 if (!ctx->hdr_parsed) {
2493 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
2494 return;
2495 }
2496
2497 q_data = &ctx->out_q;
2498 q_data->w = tmp.w;
2499 q_data->h = tmp.h;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002500 q_data->sos = tmp.sos;
2501 memcpy(q_data->dht.marker, tmp.dht.marker,
2502 sizeof(tmp.dht.marker));
2503 memcpy(q_data->dht.len, tmp.dht.len, sizeof(tmp.dht.len));
2504 q_data->dht.n = tmp.dht.n;
2505 memcpy(q_data->dqt.marker, tmp.dqt.marker,
2506 sizeof(tmp.dqt.marker));
2507 memcpy(q_data->dqt.len, tmp.dqt.len, sizeof(tmp.dqt.len));
2508 q_data->dqt.n = tmp.dqt.n;
2509 q_data->sof = tmp.sof;
2510 q_data->sof_len = tmp.sof_len;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002511
2512 q_data = &ctx->cap_q;
2513 q_data->w = tmp.w;
2514 q_data->h = tmp.h;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002515 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002516
Junghak Sung2d700712015-09-22 10:30:30 -03002517 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002518}
2519
2520static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
2521{
2522 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
2523 int ret;
2524
2525 ret = pm_runtime_get_sync(ctx->jpeg->dev);
2526
2527 return ret > 0 ? 0 : ret;
2528}
2529
Hans Verkuile37559b2014-04-17 02:47:21 -03002530static void s5p_jpeg_stop_streaming(struct vb2_queue *q)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002531{
2532 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
2533
2534 pm_runtime_put(ctx->jpeg->dev);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002535}
2536
2537static struct vb2_ops s5p_jpeg_qops = {
2538 .queue_setup = s5p_jpeg_queue_setup,
2539 .buf_prepare = s5p_jpeg_buf_prepare,
2540 .buf_queue = s5p_jpeg_buf_queue,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002541 .wait_prepare = vb2_ops_wait_prepare,
2542 .wait_finish = vb2_ops_wait_finish,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002543 .start_streaming = s5p_jpeg_start_streaming,
2544 .stop_streaming = s5p_jpeg_stop_streaming,
2545};
2546
2547static int queue_init(void *priv, struct vb2_queue *src_vq,
2548 struct vb2_queue *dst_vq)
2549{
2550 struct s5p_jpeg_ctx *ctx = priv;
2551 int ret;
2552
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002553 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
2554 src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
2555 src_vq->drv_priv = ctx;
2556 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
2557 src_vq->ops = &s5p_jpeg_qops;
2558 src_vq->mem_ops = &vb2_dma_contig_memops;
Sakari Ailusade48682014-02-25 19:12:19 -03002559 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002560 src_vq->lock = &ctx->jpeg->lock;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002561
2562 ret = vb2_queue_init(src_vq);
2563 if (ret)
2564 return ret;
2565
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002566 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2567 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
2568 dst_vq->drv_priv = ctx;
2569 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
2570 dst_vq->ops = &s5p_jpeg_qops;
2571 dst_vq->mem_ops = &vb2_dma_contig_memops;
Sakari Ailusade48682014-02-25 19:12:19 -03002572 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002573 dst_vq->lock = &ctx->jpeg->lock;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002574
2575 return vb2_queue_init(dst_vq);
2576}
2577
2578/*
2579 * ============================================================================
2580 * ISR
2581 * ============================================================================
2582 */
2583
2584static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
2585{
2586 struct s5p_jpeg *jpeg = dev_id;
2587 struct s5p_jpeg_ctx *curr_ctx;
Junghak Sung2d700712015-09-22 10:30:30 -03002588 struct vb2_v4l2_buffer *src_buf, *dst_buf;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002589 unsigned long payload_size = 0;
2590 enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
2591 bool enc_jpeg_too_large = false;
2592 bool timer_elapsed = false;
2593 bool op_completed = false;
2594
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002595 spin_lock(&jpeg->slock);
2596
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002597 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2598
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002599 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2600 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002601
2602 if (curr_ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002603 enc_jpeg_too_large = s5p_jpeg_enc_stream_stat(jpeg->regs);
2604 timer_elapsed = s5p_jpeg_timer_stat(jpeg->regs);
2605 op_completed = s5p_jpeg_result_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002606 if (curr_ctx->mode == S5P_JPEG_DECODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002607 op_completed = op_completed &&
2608 s5p_jpeg_stream_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002609
2610 if (enc_jpeg_too_large) {
2611 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002612 s5p_jpeg_clear_enc_stream_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002613 } else if (timer_elapsed) {
2614 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002615 s5p_jpeg_clear_timer_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002616 } else if (!op_completed) {
2617 state = VB2_BUF_STATE_ERROR;
2618 } else {
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002619 payload_size = s5p_jpeg_compressed_size(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002620 }
2621
Junghak Sung2d700712015-09-22 10:30:30 -03002622 dst_buf->timecode = src_buf->timecode;
Junghak Sungd6dd6452015-11-03 08:16:37 -02002623 dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
Junghak Sung2d700712015-09-22 10:30:30 -03002624 dst_buf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
2625 dst_buf->flags |=
2626 src_buf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
Kamil Debskiaca326a2013-04-24 10:08:02 -03002627
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002628 v4l2_m2m_buf_done(src_buf, state);
2629 if (curr_ctx->mode == S5P_JPEG_ENCODE)
Junghak Sung2d700712015-09-22 10:30:30 -03002630 vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload_size);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002631 v4l2_m2m_buf_done(dst_buf, state);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002632 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002633
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002634 curr_ctx->subsampling = s5p_jpeg_get_subsampling_mode(jpeg->regs);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002635 spin_unlock(&jpeg->slock);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03002636
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002637 s5p_jpeg_clear_int(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002638
2639 return IRQ_HANDLED;
2640}
2641
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002642static irqreturn_t exynos4_jpeg_irq(int irq, void *priv)
2643{
2644 unsigned int int_status;
Junghak Sung2d700712015-09-22 10:30:30 -03002645 struct vb2_v4l2_buffer *src_vb, *dst_vb;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002646 struct s5p_jpeg *jpeg = priv;
2647 struct s5p_jpeg_ctx *curr_ctx;
2648 unsigned long payload_size = 0;
2649
2650 spin_lock(&jpeg->slock);
2651
2652 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2653
2654 src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2655 dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
2656
2657 int_status = exynos4_jpeg_get_int_status(jpeg->regs);
2658
2659 if (int_status) {
2660 switch (int_status & 0x1f) {
2661 case 0x1:
2662 jpeg->irq_ret = ERR_PROT;
2663 break;
2664 case 0x2:
2665 jpeg->irq_ret = OK_ENC_OR_DEC;
2666 break;
2667 case 0x4:
2668 jpeg->irq_ret = ERR_DEC_INVALID_FORMAT;
2669 break;
2670 case 0x8:
2671 jpeg->irq_ret = ERR_MULTI_SCAN;
2672 break;
2673 case 0x10:
2674 jpeg->irq_ret = ERR_FRAME;
2675 break;
2676 default:
2677 jpeg->irq_ret = ERR_UNKNOWN;
2678 break;
2679 }
2680 } else {
2681 jpeg->irq_ret = ERR_UNKNOWN;
2682 }
2683
2684 if (jpeg->irq_ret == OK_ENC_OR_DEC) {
2685 if (curr_ctx->mode == S5P_JPEG_ENCODE) {
2686 payload_size = exynos4_jpeg_get_stream_size(jpeg->regs);
Junghak Sung2d700712015-09-22 10:30:30 -03002687 vb2_set_plane_payload(&dst_vb->vb2_buf,
2688 0, payload_size);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002689 }
2690 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
2691 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
2692 } else {
2693 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
2694 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
2695 }
2696
2697 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002698 if (jpeg->variant->version == SJPEG_EXYNOS4)
2699 curr_ctx->subsampling = exynos4_jpeg_get_frame_fmt(jpeg->regs);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002700
2701 spin_unlock(&jpeg->slock);
2702 return IRQ_HANDLED;
2703}
2704
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002705static irqreturn_t exynos3250_jpeg_irq(int irq, void *dev_id)
2706{
2707 struct s5p_jpeg *jpeg = dev_id;
2708 struct s5p_jpeg_ctx *curr_ctx;
Junghak Sung2d700712015-09-22 10:30:30 -03002709 struct vb2_v4l2_buffer *src_buf, *dst_buf;
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002710 unsigned long payload_size = 0;
2711 enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
2712 bool interrupt_timeout = false;
2713 u32 irq_status;
2714
2715 spin_lock(&jpeg->slock);
2716
2717 irq_status = exynos3250_jpeg_get_timer_status(jpeg->regs);
2718 if (irq_status & EXYNOS3250_TIMER_INT_STAT) {
2719 exynos3250_jpeg_clear_timer_status(jpeg->regs);
2720 interrupt_timeout = true;
2721 dev_err(jpeg->dev, "Interrupt timeout occurred.\n");
2722 }
2723
2724 irq_status = exynos3250_jpeg_get_int_status(jpeg->regs);
2725 exynos3250_jpeg_clear_int_status(jpeg->regs, irq_status);
2726
2727 jpeg->irq_status |= irq_status;
2728
2729 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2730
2731 if (!curr_ctx)
2732 goto exit_unlock;
2733
2734 if ((irq_status & EXYNOS3250_HEADER_STAT) &&
2735 (curr_ctx->mode == S5P_JPEG_DECODE)) {
2736 exynos3250_jpeg_rstart(jpeg->regs);
2737 goto exit_unlock;
2738 }
2739
2740 if (jpeg->irq_status & (EXYNOS3250_JPEG_DONE |
2741 EXYNOS3250_WDMA_DONE |
2742 EXYNOS3250_RDMA_DONE |
2743 EXYNOS3250_RESULT_STAT))
2744 payload_size = exynos3250_jpeg_compressed_size(jpeg->regs);
2745 else if (interrupt_timeout)
2746 state = VB2_BUF_STATE_ERROR;
2747 else
2748 goto exit_unlock;
2749
2750 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2751 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
2752
Junghak Sung2d700712015-09-22 10:30:30 -03002753 dst_buf->timecode = src_buf->timecode;
Junghak Sungd6dd6452015-11-03 08:16:37 -02002754 dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002755
2756 v4l2_m2m_buf_done(src_buf, state);
2757 if (curr_ctx->mode == S5P_JPEG_ENCODE)
Junghak Sung2d700712015-09-22 10:30:30 -03002758 vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload_size);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002759 v4l2_m2m_buf_done(dst_buf, state);
2760 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
2761
2762 curr_ctx->subsampling =
2763 exynos3250_jpeg_get_subsampling_mode(jpeg->regs);
2764exit_unlock:
2765 spin_unlock(&jpeg->slock);
2766 return IRQ_HANDLED;
2767}
2768
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03002769static void *jpeg_get_drv_data(struct device *dev);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002770
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002771/*
2772 * ============================================================================
2773 * Driver basic infrastructure
2774 * ============================================================================
2775 */
2776
2777static int s5p_jpeg_probe(struct platform_device *pdev)
2778{
2779 struct s5p_jpeg *jpeg;
2780 struct resource *res;
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002781 int i, ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002782
2783 /* JPEG IP abstraction struct */
Sachin Kamat5b58b952012-05-14 06:33:34 -03002784 jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002785 if (!jpeg)
2786 return -ENOMEM;
2787
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03002788 jpeg->variant = jpeg_get_drv_data(&pdev->dev);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002789
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002790 mutex_init(&jpeg->lock);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002791 spin_lock_init(&jpeg->slock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002792 jpeg->dev = &pdev->dev;
2793
2794 /* memory-mapped registers */
2795 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002796
Thierry Redingf23999e2013-01-21 06:09:07 -03002797 jpeg->regs = devm_ioremap_resource(&pdev->dev, res);
2798 if (IS_ERR(jpeg->regs))
2799 return PTR_ERR(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002800
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002801 /* interrupt service routine registration */
2802 jpeg->irq = ret = platform_get_irq(pdev, 0);
2803 if (ret < 0) {
2804 dev_err(&pdev->dev, "cannot find IRQ\n");
Sachin Kamat5b58b952012-05-14 06:33:34 -03002805 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002806 }
2807
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002808 ret = devm_request_irq(&pdev->dev, jpeg->irq, jpeg->variant->jpeg_irq,
2809 0, dev_name(&pdev->dev), jpeg);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002810 if (ret) {
2811 dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
Sachin Kamat5b58b952012-05-14 06:33:34 -03002812 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002813 }
2814
2815 /* clocks */
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002816 for (i = 0; i < jpeg->variant->num_clocks; i++) {
2817 jpeg->clocks[i] = devm_clk_get(&pdev->dev,
2818 jpeg->variant->clk_names[i]);
2819 if (IS_ERR(jpeg->clocks[i])) {
2820 dev_err(&pdev->dev, "failed to get clock: %s\n",
2821 jpeg->variant->clk_names[i]);
2822 return PTR_ERR(jpeg->clocks[i]);
2823 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002824 }
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002825
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002826 /* v4l2 device */
2827 ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
2828 if (ret) {
2829 dev_err(&pdev->dev, "Failed to register v4l2 device\n");
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002830 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002831 }
2832
2833 /* mem2mem device */
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03002834 jpeg->m2m_dev = v4l2_m2m_init(jpeg->variant->m2m_ops);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002835 if (IS_ERR(jpeg->m2m_dev)) {
2836 v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
2837 ret = PTR_ERR(jpeg->m2m_dev);
2838 goto device_register_rollback;
2839 }
2840
2841 jpeg->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
2842 if (IS_ERR(jpeg->alloc_ctx)) {
2843 v4l2_err(&jpeg->v4l2_dev, "Failed to init memory allocator\n");
2844 ret = PTR_ERR(jpeg->alloc_ctx);
2845 goto m2m_init_rollback;
2846 }
2847
2848 /* JPEG encoder /dev/videoX node */
2849 jpeg->vfd_encoder = video_device_alloc();
2850 if (!jpeg->vfd_encoder) {
2851 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
2852 ret = -ENOMEM;
2853 goto vb2_allocator_rollback;
2854 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03002855 snprintf(jpeg->vfd_encoder->name, sizeof(jpeg->vfd_encoder->name),
2856 "%s-enc", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002857 jpeg->vfd_encoder->fops = &s5p_jpeg_fops;
2858 jpeg->vfd_encoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
2859 jpeg->vfd_encoder->minor = -1;
2860 jpeg->vfd_encoder->release = video_device_release;
2861 jpeg->vfd_encoder->lock = &jpeg->lock;
2862 jpeg->vfd_encoder->v4l2_dev = &jpeg->v4l2_dev;
Hans Verkuil954f3402012-09-05 06:05:50 -03002863 jpeg->vfd_encoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002864
2865 ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
2866 if (ret) {
2867 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
Andrzej Pietrasiewicz7a1d4e72015-07-03 07:04:38 -03002868 video_device_release(jpeg->vfd_encoder);
2869 goto vb2_allocator_rollback;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002870 }
2871
2872 video_set_drvdata(jpeg->vfd_encoder, jpeg);
2873 v4l2_info(&jpeg->v4l2_dev,
2874 "encoder device registered as /dev/video%d\n",
2875 jpeg->vfd_encoder->num);
2876
2877 /* JPEG decoder /dev/videoX node */
2878 jpeg->vfd_decoder = video_device_alloc();
2879 if (!jpeg->vfd_decoder) {
2880 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
2881 ret = -ENOMEM;
2882 goto enc_vdev_register_rollback;
2883 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03002884 snprintf(jpeg->vfd_decoder->name, sizeof(jpeg->vfd_decoder->name),
2885 "%s-dec", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002886 jpeg->vfd_decoder->fops = &s5p_jpeg_fops;
2887 jpeg->vfd_decoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
2888 jpeg->vfd_decoder->minor = -1;
2889 jpeg->vfd_decoder->release = video_device_release;
2890 jpeg->vfd_decoder->lock = &jpeg->lock;
2891 jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev;
Jacek Anaszewski7f7d8fe2013-09-11 06:17:45 -03002892 jpeg->vfd_decoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002893
2894 ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
2895 if (ret) {
2896 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
Andrzej Pietrasiewicz7a1d4e72015-07-03 07:04:38 -03002897 video_device_release(jpeg->vfd_decoder);
2898 goto enc_vdev_register_rollback;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002899 }
2900
2901 video_set_drvdata(jpeg->vfd_decoder, jpeg);
2902 v4l2_info(&jpeg->v4l2_dev,
2903 "decoder device registered as /dev/video%d\n",
2904 jpeg->vfd_decoder->num);
2905
2906 /* final statements & power management */
2907 platform_set_drvdata(pdev, jpeg);
2908
2909 pm_runtime_enable(&pdev->dev);
2910
2911 v4l2_info(&jpeg->v4l2_dev, "Samsung S5P JPEG codec\n");
2912
2913 return 0;
2914
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002915enc_vdev_register_rollback:
2916 video_unregister_device(jpeg->vfd_encoder);
2917
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002918vb2_allocator_rollback:
2919 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
2920
2921m2m_init_rollback:
2922 v4l2_m2m_release(jpeg->m2m_dev);
2923
2924device_register_rollback:
2925 v4l2_device_unregister(&jpeg->v4l2_dev);
2926
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002927 return ret;
2928}
2929
2930static int s5p_jpeg_remove(struct platform_device *pdev)
2931{
2932 struct s5p_jpeg *jpeg = platform_get_drvdata(pdev);
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002933 int i;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002934
2935 pm_runtime_disable(jpeg->dev);
2936
2937 video_unregister_device(jpeg->vfd_decoder);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002938 video_unregister_device(jpeg->vfd_encoder);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002939 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
2940 v4l2_m2m_release(jpeg->m2m_dev);
2941 v4l2_device_unregister(&jpeg->v4l2_dev);
2942
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002943 if (!pm_runtime_status_suspended(&pdev->dev)) {
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002944 for (i = jpeg->variant->num_clocks - 1; i >= 0; i--)
2945 clk_disable_unprepare(jpeg->clocks[i]);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002946 }
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002947
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002948 return 0;
2949}
2950
Rafael J. Wysockie243c7c2014-12-04 01:10:10 +01002951#ifdef CONFIG_PM
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002952static int s5p_jpeg_runtime_suspend(struct device *dev)
2953{
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002954 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002955 int i;
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002956
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002957 for (i = jpeg->variant->num_clocks - 1; i >= 0; i--)
2958 clk_disable_unprepare(jpeg->clocks[i]);
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002959
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002960 return 0;
2961}
2962
2963static int s5p_jpeg_runtime_resume(struct device *dev)
2964{
2965 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002966 unsigned long flags;
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002967 int i, ret;
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002968
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002969 for (i = 0; i < jpeg->variant->num_clocks; i++) {
2970 ret = clk_prepare_enable(jpeg->clocks[i]);
2971 if (ret) {
2972 while (--i > 0)
2973 clk_disable_unprepare(jpeg->clocks[i]);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002974 return ret;
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002975 }
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002976 }
2977
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002978 spin_lock_irqsave(&jpeg->slock, flags);
2979
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002980 /*
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002981 * JPEG IP allows storing two Huffman tables for each component.
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002982 * We fill table 0 for each component and do this here only
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03002983 * for S5PC210 and Exynos3250 SoCs. Exynos4x12 and Exynos542x SoC
2984 * require programming their Huffman tables each time the encoding
2985 * process is initialized, and thus it is accomplished in the
2986 * device_run callback of m2m_ops.
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002987 */
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03002988 if (!jpeg->variant->htbl_reinit) {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002989 s5p_jpeg_set_hdctbl(jpeg->regs);
2990 s5p_jpeg_set_hdctblg(jpeg->regs);
2991 s5p_jpeg_set_hactbl(jpeg->regs);
2992 s5p_jpeg_set_hactblg(jpeg->regs);
2993 }
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03002994
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002995 spin_unlock_irqrestore(&jpeg->slock, flags);
2996
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002997 return 0;
2998}
Rafael J. Wysockie243c7c2014-12-04 01:10:10 +01002999#endif /* CONFIG_PM */
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003000
Thierry Redingde3767a2014-10-14 07:10:40 -03003001#ifdef CONFIG_PM_SLEEP
Jacek Anaszewskif1347132013-11-25 06:58:13 -03003002static int s5p_jpeg_suspend(struct device *dev)
3003{
3004 if (pm_runtime_suspended(dev))
3005 return 0;
3006
3007 return s5p_jpeg_runtime_suspend(dev);
3008}
3009
3010static int s5p_jpeg_resume(struct device *dev)
3011{
3012 if (pm_runtime_suspended(dev))
3013 return 0;
3014
3015 return s5p_jpeg_runtime_resume(dev);
3016}
Thierry Redingde3767a2014-10-14 07:10:40 -03003017#endif
Jacek Anaszewskif1347132013-11-25 06:58:13 -03003018
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003019static const struct dev_pm_ops s5p_jpeg_pm_ops = {
Jacek Anaszewskif1347132013-11-25 06:58:13 -03003020 SET_SYSTEM_SLEEP_PM_OPS(s5p_jpeg_suspend, s5p_jpeg_resume)
3021 SET_RUNTIME_PM_OPS(s5p_jpeg_runtime_suspend, s5p_jpeg_runtime_resume, NULL)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003022};
3023
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003024static struct s5p_jpeg_variant s5p_jpeg_drvdata = {
3025 .version = SJPEG_S5P,
3026 .jpeg_irq = s5p_jpeg_irq,
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03003027 .m2m_ops = &s5p_jpeg_m2m_ops,
Jacek Anaszewskib2451682014-04-10 04:32:11 -03003028 .fmt_ver_flag = SJPEG_FMT_FLAG_S5P,
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03003029 .clk_names = {"jpeg"},
3030 .num_clocks = 1,
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03003031};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003032
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003033static struct s5p_jpeg_variant exynos3250_jpeg_drvdata = {
3034 .version = SJPEG_EXYNOS3250,
3035 .jpeg_irq = exynos3250_jpeg_irq,
3036 .m2m_ops = &exynos3250_jpeg_m2m_ops,
3037 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS3250,
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03003038 .hw3250_compat = 1,
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03003039 .clk_names = {"jpeg", "sclk"},
3040 .num_clocks = 2,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003041};
3042
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003043static struct s5p_jpeg_variant exynos4_jpeg_drvdata = {
3044 .version = SJPEG_EXYNOS4,
3045 .jpeg_irq = exynos4_jpeg_irq,
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03003046 .m2m_ops = &exynos4_jpeg_m2m_ops,
Jacek Anaszewskib2451682014-04-10 04:32:11 -03003047 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS4,
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03003048 .htbl_reinit = 1,
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03003049 .clk_names = {"jpeg"},
3050 .num_clocks = 1,
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03003051 .hw_ex4_compat = 1,
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03003052};
3053
3054static struct s5p_jpeg_variant exynos5420_jpeg_drvdata = {
3055 .version = SJPEG_EXYNOS5420,
3056 .jpeg_irq = exynos3250_jpeg_irq, /* intentionally 3250 */
3057 .m2m_ops = &exynos3250_jpeg_m2m_ops, /* intentionally 3250 */
3058 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS3250, /* intentionally 3250 */
3059 .hw3250_compat = 1,
3060 .htbl_reinit = 1,
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03003061 .clk_names = {"jpeg"},
3062 .num_clocks = 1,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003063};
3064
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03003065static struct s5p_jpeg_variant exynos5433_jpeg_drvdata = {
3066 .version = SJPEG_EXYNOS5433,
3067 .jpeg_irq = exynos4_jpeg_irq,
3068 .m2m_ops = &exynos4_jpeg_m2m_ops,
3069 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS4,
3070 .htbl_reinit = 1,
3071 .clk_names = {"pclk", "aclk", "aclk_xiu", "sclk"},
3072 .num_clocks = 4,
3073 .hw_ex4_compat = 1,
3074};
3075
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003076static const struct of_device_id samsung_jpeg_match[] = {
3077 {
3078 .compatible = "samsung,s5pv210-jpeg",
3079 .data = &s5p_jpeg_drvdata,
3080 }, {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003081 .compatible = "samsung,exynos3250-jpeg",
3082 .data = &exynos3250_jpeg_drvdata,
3083 }, {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003084 .compatible = "samsung,exynos4210-jpeg",
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003085 .data = &exynos4_jpeg_drvdata,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003086 }, {
3087 .compatible = "samsung,exynos4212-jpeg",
3088 .data = &exynos4_jpeg_drvdata,
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03003089 }, {
3090 .compatible = "samsung,exynos5420-jpeg",
3091 .data = &exynos5420_jpeg_drvdata,
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03003092 }, {
3093 .compatible = "samsung,exynos5433-jpeg",
3094 .data = &exynos5433_jpeg_drvdata,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003095 },
3096 {},
3097};
3098
3099MODULE_DEVICE_TABLE(of, samsung_jpeg_match);
3100
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03003101static void *jpeg_get_drv_data(struct device *dev)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003102{
3103 struct s5p_jpeg_variant *driver_data = NULL;
3104 const struct of_device_id *match;
3105
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03003106 if (!IS_ENABLED(CONFIG_OF) || !dev->of_node)
3107 return &s5p_jpeg_drvdata;
3108
3109 match = of_match_node(samsung_jpeg_match, dev->of_node);
3110
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003111 if (match)
3112 driver_data = (struct s5p_jpeg_variant *)match->data;
3113
3114 return driver_data;
3115}
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03003116
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003117static struct platform_driver s5p_jpeg_driver = {
3118 .probe = s5p_jpeg_probe,
3119 .remove = s5p_jpeg_remove,
3120 .driver = {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003121 .of_match_table = of_match_ptr(samsung_jpeg_match),
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003122 .name = S5P_JPEG_M2M_NAME,
3123 .pm = &s5p_jpeg_pm_ops,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003124 },
3125};
3126
Sachin Kamat87e94292012-07-03 05:54:33 -03003127module_platform_driver(s5p_jpeg_driver);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003128
3129MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003130MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003131MODULE_DESCRIPTION("Samsung JPEG codec driver");
3132MODULE_LICENSE("GPL");