blob: 18e754d319cf9f8a2946d6c82cc855caecd3f3fe [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;
889 unsigned int word;
890 int c, x, components;
891
892 jpeg_buffer.size = ctx->out_q.sof_len;
893 jpeg_buffer.data =
894 (unsigned long)vb2_plane_vaddr(vb, 0) + ctx->out_q.sof;
895 jpeg_buffer.curr = 0;
896
897 word = 0;
898
899 skip(&jpeg_buffer, 5); /* P, Y, X */
900 components = get_byte(&jpeg_buffer);
901 if (components == -1)
902 return;
903
904 exynos4_jpeg_set_dec_components(jpeg->regs, components);
905
906 while (components--) {
907 c = get_byte(&jpeg_buffer);
908 if (c == -1)
909 return;
910 skip(&jpeg_buffer, 1);
911 x = get_byte(&jpeg_buffer);
912 if (x == -1)
913 return;
914 exynos4_jpeg_select_dec_q_tbl(jpeg->regs, c, x);
915 }
916}
917
918static void exynos4_jpeg_parse_q_tbl(struct s5p_jpeg_ctx *ctx)
919{
920 struct s5p_jpeg *jpeg = ctx->jpeg;
921 struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
922 struct s5p_jpeg_buffer jpeg_buffer;
923 unsigned int word;
924 int c, i, j;
925
926 for (j = 0; j < ctx->out_q.dqt.n; ++j) {
927 jpeg_buffer.size = ctx->out_q.dqt.len[j];
928 jpeg_buffer.data = (unsigned long)vb2_plane_vaddr(vb, 0) +
929 ctx->out_q.dqt.marker[j];
930 jpeg_buffer.curr = 0;
931
932 word = 0;
933 while (jpeg_buffer.size - jpeg_buffer.curr >= 65) {
934 char id;
935
936 c = get_byte(&jpeg_buffer);
937 if (c == -1)
938 return;
939 id = c & 0xf;
940 /* nonzero means extended mode - not supported */
941 if ((c >> 4) & 0xf)
942 return;
943 for (i = 0; i < 64; ++i) {
944 c = get_byte(&jpeg_buffer);
945 if (c == -1)
946 return;
947 word |= c << ((i % 4) * 8);
948 if ((i + 1) % 4 == 0) {
949 writel(word, jpeg->regs +
950 EXYNOS4_QTBL_CONTENT(id) + (i / 4) * 4);
951 word = 0;
952 }
953 }
954 word = 0;
955 }
956 }
957}
958
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300959/*
960 * ============================================================================
961 * Device file operations
962 * ============================================================================
963 */
964
965static int queue_init(void *priv, struct vb2_queue *src_vq,
966 struct vb2_queue *dst_vq);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300967static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
968 __u32 pixelformat, unsigned int fmt_type);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300969static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300970
971static int s5p_jpeg_open(struct file *file)
972{
973 struct s5p_jpeg *jpeg = video_drvdata(file);
974 struct video_device *vfd = video_devdata(file);
975 struct s5p_jpeg_ctx *ctx;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300976 struct s5p_jpeg_fmt *out_fmt, *cap_fmt;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300977 int ret = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300978
Sachin Kamatb5146c92012-08-16 08:52:58 -0300979 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300980 if (!ctx)
981 return -ENOMEM;
982
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300983 if (mutex_lock_interruptible(&jpeg->lock)) {
984 ret = -ERESTARTSYS;
985 goto free;
986 }
987
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300988 v4l2_fh_init(&ctx->fh, vfd);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300989 /* Use separate control handler per file handle */
990 ctx->fh.ctrl_handler = &ctx->ctrl_handler;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300991 file->private_data = &ctx->fh;
992 v4l2_fh_add(&ctx->fh);
993
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300994 ctx->jpeg = jpeg;
995 if (vfd == jpeg->vfd_encoder) {
996 ctx->mode = S5P_JPEG_ENCODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300997 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB565,
998 FMT_TYPE_OUTPUT);
999 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
1000 FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001001 } else {
1002 ctx->mode = S5P_JPEG_DECODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001003 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
1004 FMT_TYPE_OUTPUT);
1005 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_YUYV,
1006 FMT_TYPE_CAPTURE);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001007 ctx->scale_factor = EXYNOS3250_DEC_SCALE_FACTOR_8_8;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001008 }
1009
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001010 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
1011 if (IS_ERR(ctx->fh.m2m_ctx)) {
1012 ret = PTR_ERR(ctx->fh.m2m_ctx);
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001013 goto error;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001014 }
1015
1016 ctx->out_q.fmt = out_fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001017 ctx->cap_q.fmt = cap_fmt;
1018
1019 ret = s5p_jpeg_controls_create(ctx);
1020 if (ret < 0)
1021 goto error;
1022
Hans Verkuilb0d5cd62012-06-24 06:54:18 -03001023 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001024 return 0;
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001025
1026error:
1027 v4l2_fh_del(&ctx->fh);
1028 v4l2_fh_exit(&ctx->fh);
Hans Verkuilb0d5cd62012-06-24 06:54:18 -03001029 mutex_unlock(&jpeg->lock);
1030free:
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001031 kfree(ctx);
1032 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001033}
1034
1035static int s5p_jpeg_release(struct file *file)
1036{
Hans Verkuilb0d5cd62012-06-24 06:54:18 -03001037 struct s5p_jpeg *jpeg = video_drvdata(file);
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001038 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001039
Hans Verkuilb0d5cd62012-06-24 06:54:18 -03001040 mutex_lock(&jpeg->lock);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001041 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001042 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001043 v4l2_fh_del(&ctx->fh);
1044 v4l2_fh_exit(&ctx->fh);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001045 kfree(ctx);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001046 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001047
1048 return 0;
1049}
1050
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001051static const struct v4l2_file_operations s5p_jpeg_fops = {
1052 .owner = THIS_MODULE,
1053 .open = s5p_jpeg_open,
1054 .release = s5p_jpeg_release,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001055 .poll = v4l2_m2m_fop_poll,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001056 .unlocked_ioctl = video_ioctl2,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001057 .mmap = v4l2_m2m_fop_mmap,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001058};
1059
1060/*
1061 * ============================================================================
1062 * video ioctl operations
1063 * ============================================================================
1064 */
1065
1066static int get_byte(struct s5p_jpeg_buffer *buf)
1067{
1068 if (buf->curr >= buf->size)
1069 return -1;
1070
1071 return ((unsigned char *)buf->data)[buf->curr++];
1072}
1073
1074static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word)
1075{
1076 unsigned int temp;
1077 int byte;
1078
1079 byte = get_byte(buf);
1080 if (byte == -1)
1081 return -1;
1082 temp = byte << 8;
1083 byte = get_byte(buf);
1084 if (byte == -1)
1085 return -1;
1086 *word = (unsigned int)byte | temp;
1087 return 0;
1088}
1089
1090static void skip(struct s5p_jpeg_buffer *buf, long len)
1091{
1092 if (len <= 0)
1093 return;
1094
1095 while (len--)
1096 get_byte(buf);
1097}
1098
1099static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001100 unsigned long buffer, unsigned long size,
1101 struct s5p_jpeg_ctx *ctx)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001102{
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001103 int c, components = 0, notfound, n_dht = 0, n_dqt = 0;
1104 unsigned int height, width, word, subsampling = 0, sos = 0, sof = 0,
1105 sof_len = 0;
1106 unsigned int dht[S5P_JPEG_MAX_MARKER], dht_len[S5P_JPEG_MAX_MARKER],
1107 dqt[S5P_JPEG_MAX_MARKER], dqt_len[S5P_JPEG_MAX_MARKER];
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001108 long length;
1109 struct s5p_jpeg_buffer jpeg_buffer;
1110
1111 jpeg_buffer.size = size;
1112 jpeg_buffer.data = buffer;
1113 jpeg_buffer.curr = 0;
1114
1115 notfound = 1;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001116 while (notfound || !sos) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001117 c = get_byte(&jpeg_buffer);
1118 if (c == -1)
Jacek Anaszewskia35f6002014-07-11 12:19:43 -03001119 return false;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001120 if (c != 0xff)
1121 continue;
1122 do
1123 c = get_byte(&jpeg_buffer);
1124 while (c == 0xff);
1125 if (c == -1)
Jacek Anaszewskia35f6002014-07-11 12:19:43 -03001126 return false;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001127 if (c == 0)
1128 continue;
1129 length = 0;
1130 switch (c) {
1131 /* SOF0: baseline JPEG */
1132 case SOF0:
1133 if (get_word_be(&jpeg_buffer, &word))
1134 break;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001135 length = (long)word - 2;
1136 if (!length)
1137 return false;
1138 sof = jpeg_buffer.curr; /* after 0xffc0 */
1139 sof_len = length;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001140 if (get_byte(&jpeg_buffer) == -1)
1141 break;
1142 if (get_word_be(&jpeg_buffer, &height))
1143 break;
1144 if (get_word_be(&jpeg_buffer, &width))
1145 break;
1146 components = get_byte(&jpeg_buffer);
1147 if (components == -1)
1148 break;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001149
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001150 if (components == 1) {
1151 subsampling = 0x33;
1152 } else {
1153 skip(&jpeg_buffer, 1);
1154 subsampling = get_byte(&jpeg_buffer);
1155 skip(&jpeg_buffer, 1);
1156 }
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001157 if (components > 3)
1158 return false;
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001159 skip(&jpeg_buffer, components * 2);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001160 notfound = 0;
1161 break;
1162
1163 case DQT:
1164 if (get_word_be(&jpeg_buffer, &word))
1165 break;
1166 length = (long)word - 2;
1167 if (!length)
1168 return false;
1169 if (n_dqt >= S5P_JPEG_MAX_MARKER)
1170 return false;
1171 dqt[n_dqt] = jpeg_buffer.curr; /* after 0xffdb */
1172 dqt_len[n_dqt++] = length;
1173 skip(&jpeg_buffer, length);
1174 break;
1175
1176 case DHT:
1177 if (get_word_be(&jpeg_buffer, &word))
1178 break;
1179 length = (long)word - 2;
1180 if (!length)
1181 return false;
1182 if (n_dht >= S5P_JPEG_MAX_MARKER)
1183 return false;
1184 dht[n_dht] = jpeg_buffer.curr; /* after 0xffc4 */
1185 dht_len[n_dht++] = length;
1186 skip(&jpeg_buffer, length);
1187 break;
1188
1189 case SOS:
1190 sos = jpeg_buffer.curr - 2; /* 0xffda */
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001191 break;
1192
1193 /* skip payload-less markers */
1194 case RST ... RST + 7:
1195 case SOI:
1196 case EOI:
1197 case TEM:
1198 break;
1199
1200 /* skip uninteresting payload markers */
1201 default:
1202 if (get_word_be(&jpeg_buffer, &word))
1203 break;
1204 length = (long)word - 2;
1205 skip(&jpeg_buffer, length);
1206 break;
1207 }
1208 }
1209 result->w = width;
1210 result->h = height;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001211 result->sos = sos;
1212 result->dht.n = n_dht;
1213 while (n_dht--) {
1214 result->dht.marker[n_dht] = dht[n_dht];
1215 result->dht.len[n_dht] = dht_len[n_dht];
1216 }
1217 result->dqt.n = n_dqt;
1218 while (n_dqt--) {
1219 result->dqt.marker[n_dqt] = dqt[n_dqt];
1220 result->dqt.len[n_dqt] = dqt_len[n_dqt];
1221 }
1222 result->sof = sof;
1223 result->sof_len = sof_len;
1224 result->size = result->components = components;
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001225
1226 switch (subsampling) {
1227 case 0x11:
1228 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444;
1229 break;
1230 case 0x21:
1231 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422;
1232 break;
1233 case 0x22:
1234 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420;
1235 break;
1236 case 0x33:
1237 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
1238 break;
1239 default:
1240 return false;
1241 }
1242
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001243 return !notfound && sos;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001244}
1245
1246static int s5p_jpeg_querycap(struct file *file, void *priv,
1247 struct v4l2_capability *cap)
1248{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001249 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001250
1251 if (ctx->mode == S5P_JPEG_ENCODE) {
1252 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder",
1253 sizeof(cap->driver));
1254 strlcpy(cap->card, S5P_JPEG_M2M_NAME " encoder",
1255 sizeof(cap->card));
1256 } else {
1257 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " decoder",
1258 sizeof(cap->driver));
1259 strlcpy(cap->card, S5P_JPEG_M2M_NAME " decoder",
1260 sizeof(cap->card));
1261 }
1262 cap->bus_info[0] = 0;
Hans Verkuil8c17e5e2014-11-24 06:37:26 -03001263 cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M;
1264 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001265 return 0;
1266}
1267
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001268static int enum_fmt(struct s5p_jpeg_fmt *sjpeg_formats, int n,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001269 struct v4l2_fmtdesc *f, u32 type)
1270{
1271 int i, num = 0;
1272
1273 for (i = 0; i < n; ++i) {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001274 if (sjpeg_formats[i].flags & type) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001275 /* index-th format of type type found ? */
1276 if (num == f->index)
1277 break;
1278 /* Correct type but haven't reached our index yet,
1279 * just increment per-type index */
1280 ++num;
1281 }
1282 }
1283
1284 /* Format not found */
1285 if (i >= n)
1286 return -EINVAL;
1287
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001288 strlcpy(f->description, sjpeg_formats[i].name, sizeof(f->description));
1289 f->pixelformat = sjpeg_formats[i].fourcc;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001290
1291 return 0;
1292}
1293
1294static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
1295 struct v4l2_fmtdesc *f)
1296{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001297 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001298
1299 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001300 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1301 SJPEG_FMT_FLAG_ENC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001302
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001303 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1304 SJPEG_FMT_FLAG_DEC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001305}
1306
1307static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
1308 struct v4l2_fmtdesc *f)
1309{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001310 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001311
1312 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001313 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1314 SJPEG_FMT_FLAG_ENC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001315
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001316 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
1317 SJPEG_FMT_FLAG_DEC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001318}
1319
1320static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx,
1321 enum v4l2_buf_type type)
1322{
1323 if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1324 return &ctx->out_q;
1325 if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1326 return &ctx->cap_q;
1327
1328 return NULL;
1329}
1330
1331static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
1332{
1333 struct vb2_queue *vq;
1334 struct s5p_jpeg_q_data *q_data = NULL;
1335 struct v4l2_pix_format *pix = &f->fmt.pix;
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001336 struct s5p_jpeg_ctx *ct = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001337
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001338 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001339 if (!vq)
1340 return -EINVAL;
1341
1342 if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
1343 ct->mode == S5P_JPEG_DECODE && !ct->hdr_parsed)
1344 return -EINVAL;
1345 q_data = get_q_data(ct, f->type);
1346 BUG_ON(q_data == NULL);
1347
1348 pix->width = q_data->w;
1349 pix->height = q_data->h;
1350 pix->field = V4L2_FIELD_NONE;
1351 pix->pixelformat = q_data->fmt->fourcc;
1352 pix->bytesperline = 0;
1353 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
1354 u32 bpl = q_data->w;
1355 if (q_data->fmt->colplanes == 1)
1356 bpl = (bpl * q_data->fmt->depth) >> 3;
1357 pix->bytesperline = bpl;
1358 }
1359 pix->sizeimage = q_data->size;
1360
1361 return 0;
1362}
1363
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001364static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
1365 u32 pixelformat, unsigned int fmt_type)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001366{
Jacek Anaszewskib2451682014-04-10 04:32:11 -03001367 unsigned int k, fmt_flag;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001368
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001369 if (ctx->mode == S5P_JPEG_ENCODE)
1370 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
1371 SJPEG_FMT_FLAG_ENC_OUTPUT :
1372 SJPEG_FMT_FLAG_ENC_CAPTURE;
1373 else
1374 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
1375 SJPEG_FMT_FLAG_DEC_OUTPUT :
1376 SJPEG_FMT_FLAG_DEC_CAPTURE;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001377
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001378 for (k = 0; k < ARRAY_SIZE(sjpeg_formats); k++) {
1379 struct s5p_jpeg_fmt *fmt = &sjpeg_formats[k];
1380 if (fmt->fourcc == pixelformat &&
1381 fmt->flags & fmt_flag &&
Jacek Anaszewskib2451682014-04-10 04:32:11 -03001382 fmt->flags & ctx->jpeg->variant->fmt_ver_flag) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001383 return fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001384 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001385 }
1386
1387 return NULL;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001388}
1389
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001390static void jpeg_bound_align_image(struct s5p_jpeg_ctx *ctx,
1391 u32 *w, unsigned int wmin, unsigned int wmax,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001392 unsigned int walign,
1393 u32 *h, unsigned int hmin, unsigned int hmax,
1394 unsigned int halign)
1395{
1396 int width, height, w_step, h_step;
1397
1398 width = *w;
1399 height = *h;
1400
1401 w_step = 1 << walign;
1402 h_step = 1 << halign;
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001403
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001404 if (ctx->jpeg->variant->hw3250_compat) {
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001405 /*
1406 * Rightmost and bottommost pixels are cropped by the
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001407 * Exynos3250/compatible JPEG IP for RGB formats, for the
1408 * specific width and height values respectively. This
1409 * assignment will result in v4l_bound_align_image returning
1410 * dimensions reduced by 1 for the aforementioned cases.
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001411 */
1412 if (w_step == 4 && ((width & 3) == 1)) {
1413 wmax = width;
1414 hmax = height;
1415 }
1416 }
1417
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001418 v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
1419
1420 if (*w < width && (*w + w_step) < wmax)
1421 *w += w_step;
1422 if (*h < height && (*h + h_step) < hmax)
1423 *h += h_step;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001424}
1425
1426static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
1427 struct s5p_jpeg_ctx *ctx, int q_type)
1428{
1429 struct v4l2_pix_format *pix = &f->fmt.pix;
1430
1431 if (pix->field == V4L2_FIELD_ANY)
1432 pix->field = V4L2_FIELD_NONE;
1433 else if (pix->field != V4L2_FIELD_NONE)
1434 return -EINVAL;
1435
1436 /* V4L2 specification suggests the driver corrects the format struct
1437 * if any of the dimensions is unsupported */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001438 if (q_type == FMT_TYPE_OUTPUT)
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001439 jpeg_bound_align_image(ctx, &pix->width, S5P_JPEG_MIN_WIDTH,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001440 S5P_JPEG_MAX_WIDTH, 0,
1441 &pix->height, S5P_JPEG_MIN_HEIGHT,
1442 S5P_JPEG_MAX_HEIGHT, 0);
1443 else
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001444 jpeg_bound_align_image(ctx, &pix->width, S5P_JPEG_MIN_WIDTH,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001445 S5P_JPEG_MAX_WIDTH, fmt->h_align,
1446 &pix->height, S5P_JPEG_MIN_HEIGHT,
1447 S5P_JPEG_MAX_HEIGHT, fmt->v_align);
1448
1449 if (fmt->fourcc == V4L2_PIX_FMT_JPEG) {
1450 if (pix->sizeimage <= 0)
1451 pix->sizeimage = PAGE_SIZE;
1452 pix->bytesperline = 0;
1453 } else {
1454 u32 bpl = pix->bytesperline;
1455
1456 if (fmt->colplanes > 1 && bpl < pix->width)
1457 bpl = pix->width; /* planar */
1458
1459 if (fmt->colplanes == 1 && /* packed */
Jacek Anaszewskicc690902013-11-25 06:58:10 -03001460 (bpl << 3) / fmt->depth < pix->width)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001461 bpl = (pix->width * fmt->depth) >> 3;
1462
1463 pix->bytesperline = bpl;
1464 pix->sizeimage = (pix->width * pix->height * fmt->depth) >> 3;
1465 }
1466
1467 return 0;
1468}
1469
1470static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
1471 struct v4l2_format *f)
1472{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001473 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001474 struct v4l2_pix_format *pix = &f->fmt.pix;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001475 struct s5p_jpeg_fmt *fmt;
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001476 int ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001477
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001478 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
1479 FMT_TYPE_CAPTURE);
1480 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001481 v4l2_err(&ctx->jpeg->v4l2_dev,
1482 "Fourcc format (0x%08x) invalid.\n",
1483 f->fmt.pix.pixelformat);
1484 return -EINVAL;
1485 }
1486
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001487 if (!ctx->jpeg->variant->hw_ex4_compat || ctx->mode != S5P_JPEG_DECODE)
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001488 goto exit;
1489
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001490 /*
1491 * The exynos4x12 device requires resulting YUV image
1492 * subsampling not to be lower than the input jpeg subsampling.
1493 * If this requirement is not met then downgrade the requested
1494 * capture format to the one with subsampling equal to the input jpeg.
1495 */
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001496 if ((fmt->flags & SJPEG_FMT_NON_RGB) &&
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001497 (fmt->subsampling < ctx->subsampling)) {
1498 ret = s5p_jpeg_adjust_fourcc_to_subsampling(ctx->subsampling,
1499 fmt->fourcc,
1500 &pix->pixelformat,
1501 ctx);
1502 if (ret < 0)
1503 pix->pixelformat = V4L2_PIX_FMT_GREY;
1504
1505 fmt = s5p_jpeg_find_format(ctx, pix->pixelformat,
1506 FMT_TYPE_CAPTURE);
1507 }
1508
Jacek Anaszewski2caeeb02014-04-10 04:32:17 -03001509 /*
1510 * Decompression of a JPEG file with 4:2:0 subsampling and odd
1511 * width to the YUV 4:2:0 compliant formats produces a raw image
1512 * with broken luma component. Adjust capture format to RGB565
1513 * in such a case.
1514 */
1515 if (ctx->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_420 &&
1516 (ctx->out_q.w & 1) &&
1517 (pix->pixelformat == V4L2_PIX_FMT_NV12 ||
1518 pix->pixelformat == V4L2_PIX_FMT_NV21 ||
1519 pix->pixelformat == V4L2_PIX_FMT_YUV420)) {
1520 pix->pixelformat = V4L2_PIX_FMT_RGB565;
1521 fmt = s5p_jpeg_find_format(ctx, pix->pixelformat,
1522 FMT_TYPE_CAPTURE);
1523 }
1524
1525exit:
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001526 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001527}
1528
1529static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
1530 struct v4l2_format *f)
1531{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001532 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001533 struct s5p_jpeg_fmt *fmt;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001534
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001535 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
1536 FMT_TYPE_OUTPUT);
1537 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001538 v4l2_err(&ctx->jpeg->v4l2_dev,
1539 "Fourcc format (0x%08x) invalid.\n",
1540 f->fmt.pix.pixelformat);
1541 return -EINVAL;
1542 }
1543
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001544 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001545}
1546
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001547static int exynos4_jpeg_get_output_buffer_size(struct s5p_jpeg_ctx *ctx,
1548 struct v4l2_format *f,
1549 int fmt_depth)
1550{
1551 struct v4l2_pix_format *pix = &f->fmt.pix;
1552 u32 pix_fmt = f->fmt.pix.pixelformat;
1553 int w = pix->width, h = pix->height, wh_align;
1554
1555 if (pix_fmt == V4L2_PIX_FMT_RGB32 ||
1556 pix_fmt == V4L2_PIX_FMT_NV24 ||
1557 pix_fmt == V4L2_PIX_FMT_NV42 ||
1558 pix_fmt == V4L2_PIX_FMT_NV12 ||
1559 pix_fmt == V4L2_PIX_FMT_NV21 ||
1560 pix_fmt == V4L2_PIX_FMT_YUV420)
1561 wh_align = 4;
1562 else
1563 wh_align = 1;
1564
Jacek Anaszewskie9e7dfe2014-07-11 12:19:44 -03001565 jpeg_bound_align_image(ctx, &w, S5P_JPEG_MIN_WIDTH,
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001566 S5P_JPEG_MAX_WIDTH, wh_align,
1567 &h, S5P_JPEG_MIN_HEIGHT,
1568 S5P_JPEG_MAX_HEIGHT, wh_align);
1569
1570 return w * h * fmt_depth >> 3;
1571}
1572
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001573static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx,
1574 struct v4l2_rect *r);
1575
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001576static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
1577{
1578 struct vb2_queue *vq;
1579 struct s5p_jpeg_q_data *q_data = NULL;
1580 struct v4l2_pix_format *pix = &f->fmt.pix;
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001581 struct v4l2_ctrl *ctrl_subs;
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001582 struct v4l2_rect scale_rect;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001583 unsigned int f_type;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001584
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001585 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001586 if (!vq)
1587 return -EINVAL;
1588
1589 q_data = get_q_data(ct, f->type);
1590 BUG_ON(q_data == NULL);
1591
1592 if (vb2_is_busy(vq)) {
1593 v4l2_err(&ct->jpeg->v4l2_dev, "%s queue busy\n", __func__);
1594 return -EBUSY;
1595 }
1596
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001597 f_type = V4L2_TYPE_IS_OUTPUT(f->type) ?
1598 FMT_TYPE_OUTPUT : FMT_TYPE_CAPTURE;
1599
1600 q_data->fmt = s5p_jpeg_find_format(ct, pix->pixelformat, f_type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001601 q_data->w = pix->width;
1602 q_data->h = pix->height;
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001603 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
1604 /*
1605 * During encoding Exynos4x12 SoCs access wider memory area
1606 * than it results from Image_x and Image_y values written to
1607 * the JPEG_IMAGE_SIZE register. In order to avoid sysmmu
1608 * page fault calculate proper buffer size in such a case.
1609 */
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03001610 if (ct->jpeg->variant->hw_ex4_compat &&
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001611 f_type == FMT_TYPE_OUTPUT && ct->mode == S5P_JPEG_ENCODE)
1612 q_data->size = exynos4_jpeg_get_output_buffer_size(ct,
1613 f,
1614 q_data->fmt->depth);
1615 else
1616 q_data->size = q_data->w * q_data->h *
1617 q_data->fmt->depth >> 3;
1618 } else {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001619 q_data->size = pix->sizeimage;
Jacek Anaszewskib2254d62014-04-10 04:32:16 -03001620 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001621
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001622 if (f_type == FMT_TYPE_OUTPUT) {
1623 ctrl_subs = v4l2_ctrl_find(&ct->ctrl_handler,
1624 V4L2_CID_JPEG_CHROMA_SUBSAMPLING);
1625 if (ctrl_subs)
1626 v4l2_ctrl_s_ctrl(ctrl_subs, q_data->fmt->subsampling);
Jacek Anaszewskidfd96902014-07-11 12:19:46 -03001627 ct->crop_altered = false;
1628 }
1629
1630 /*
1631 * For decoding init crop_rect with capture buffer dimmensions which
1632 * contain aligned dimensions of the input JPEG image and do it only
1633 * if crop rectangle hasn't been altered by the user space e.g. with
1634 * S_SELECTION ioctl. For encoding assign output buffer dimensions.
1635 */
1636 if (!ct->crop_altered &&
1637 ((ct->mode == S5P_JPEG_DECODE && f_type == FMT_TYPE_CAPTURE) ||
1638 (ct->mode == S5P_JPEG_ENCODE && f_type == FMT_TYPE_OUTPUT))) {
1639 ct->crop_rect.width = pix->width;
1640 ct->crop_rect.height = pix->height;
1641 }
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001642
1643 /*
1644 * Prevent downscaling to YUV420 format by more than 2
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001645 * for Exynos3250/compatible SoC as it produces broken raw image
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001646 * in such cases.
1647 */
1648 if (ct->mode == S5P_JPEG_DECODE &&
1649 f_type == FMT_TYPE_CAPTURE &&
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001650 ct->jpeg->variant->hw3250_compat &&
Jacek Anaszewski5a716712014-07-11 12:19:47 -03001651 pix->pixelformat == V4L2_PIX_FMT_YUV420 &&
1652 ct->scale_factor > 2) {
1653 scale_rect.width = ct->out_q.w / 2;
1654 scale_rect.height = ct->out_q.h / 2;
1655 exynos3250_jpeg_try_downscale(ct, &scale_rect);
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001656 }
1657
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001658 return 0;
1659}
1660
1661static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
1662 struct v4l2_format *f)
1663{
1664 int ret;
1665
1666 ret = s5p_jpeg_try_fmt_vid_cap(file, priv, f);
1667 if (ret)
1668 return ret;
1669
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001670 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001671}
1672
1673static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
1674 struct v4l2_format *f)
1675{
1676 int ret;
1677
1678 ret = s5p_jpeg_try_fmt_vid_out(file, priv, f);
1679 if (ret)
1680 return ret;
1681
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001682 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001683}
1684
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001685static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx,
1686 struct v4l2_rect *r)
1687{
1688 int w_ratio, h_ratio, scale_factor, cur_ratio, i;
1689
1690 w_ratio = ctx->out_q.w / r->width;
1691 h_ratio = ctx->out_q.h / r->height;
1692
1693 scale_factor = w_ratio > h_ratio ? w_ratio : h_ratio;
1694 scale_factor = clamp_val(scale_factor, 1, 8);
1695
1696 /* Align scale ratio to the nearest power of 2 */
1697 for (i = 0; i <= 3; ++i) {
1698 cur_ratio = 1 << i;
1699 if (scale_factor <= cur_ratio) {
1700 ctx->scale_factor = cur_ratio;
1701 break;
1702 }
1703 }
1704
1705 r->width = round_down(ctx->out_q.w / ctx->scale_factor, 2);
1706 r->height = round_down(ctx->out_q.h / ctx->scale_factor, 2);
1707
1708 ctx->crop_rect.width = r->width;
1709 ctx->crop_rect.height = r->height;
1710 ctx->crop_rect.left = 0;
1711 ctx->crop_rect.top = 0;
1712
1713 ctx->crop_altered = true;
1714
1715 return 0;
1716}
1717
1718/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */
1719static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
1720{
1721 if (a->left < b->left || a->top < b->top)
1722 return 0;
1723 if (a->left + a->width > b->left + b->width)
1724 return 0;
1725 if (a->top + a->height > b->top + b->height)
1726 return 0;
1727
1728 return 1;
1729}
1730
1731static int exynos3250_jpeg_try_crop(struct s5p_jpeg_ctx *ctx,
1732 struct v4l2_rect *r)
1733{
1734 struct v4l2_rect base_rect;
1735 int w_step, h_step;
1736
1737 switch (ctx->cap_q.fmt->fourcc) {
1738 case V4L2_PIX_FMT_NV12:
1739 case V4L2_PIX_FMT_NV21:
1740 w_step = 1;
1741 h_step = 2;
1742 break;
1743 case V4L2_PIX_FMT_YUV420:
1744 w_step = 2;
1745 h_step = 2;
1746 break;
1747 default:
1748 w_step = 1;
1749 h_step = 1;
1750 break;
1751 }
1752
1753 base_rect.top = 0;
1754 base_rect.left = 0;
1755 base_rect.width = ctx->out_q.w;
1756 base_rect.height = ctx->out_q.h;
1757
1758 r->width = round_down(r->width, w_step);
1759 r->height = round_down(r->height, h_step);
1760 r->left = round_down(r->left, 2);
1761 r->top = round_down(r->top, 2);
1762
1763 if (!enclosed_rectangle(r, &base_rect))
1764 return -EINVAL;
1765
1766 ctx->crop_rect.left = r->left;
1767 ctx->crop_rect.top = r->top;
1768 ctx->crop_rect.width = r->width;
1769 ctx->crop_rect.height = r->height;
1770
1771 ctx->crop_altered = true;
1772
1773 return 0;
1774}
1775
1776/*
1777 * V4L2 controls
1778 */
1779
Sachin Kamat9f3bd322012-05-10 03:38:40 -03001780static int s5p_jpeg_g_selection(struct file *file, void *priv,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001781 struct v4l2_selection *s)
1782{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001783 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001784
1785 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
Jacek Anaszewski38a6ef32014-04-10 04:32:15 -03001786 s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001787 return -EINVAL;
1788
1789 /* For JPEG blob active == default == bounds */
1790 switch (s->target) {
Sylwester Nawrockic1334822012-05-20 11:17:12 -03001791 case V4L2_SEL_TGT_CROP:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001792 case V4L2_SEL_TGT_CROP_BOUNDS:
1793 case V4L2_SEL_TGT_CROP_DEFAULT:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001794 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
1795 s->r.width = ctx->out_q.w;
1796 s->r.height = ctx->out_q.h;
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001797 s->r.left = 0;
1798 s->r.top = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001799 break;
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001800 case V4L2_SEL_TGT_COMPOSE:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001801 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
1802 case V4L2_SEL_TGT_COMPOSE_PADDED:
Jacek Anaszewskifac4d962014-07-11 12:19:45 -03001803 s->r.width = ctx->crop_rect.width;
1804 s->r.height = ctx->crop_rect.height;
1805 s->r.left = ctx->crop_rect.left;
1806 s->r.top = ctx->crop_rect.top;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001807 break;
1808 default:
1809 return -EINVAL;
1810 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001811 return 0;
1812}
1813
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001814/*
1815 * V4L2 controls
1816 */
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001817static int s5p_jpeg_s_selection(struct file *file, void *fh,
1818 struct v4l2_selection *s)
1819{
1820 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
1821 struct v4l2_rect *rect = &s->r;
1822 int ret = -EINVAL;
1823
1824 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1825 return -EINVAL;
1826
1827 if (s->target == V4L2_SEL_TGT_COMPOSE) {
1828 if (ctx->mode != S5P_JPEG_DECODE)
1829 return -EINVAL;
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001830 if (ctx->jpeg->variant->hw3250_compat)
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001831 ret = exynos3250_jpeg_try_downscale(ctx, rect);
1832 } else if (s->target == V4L2_SEL_TGT_CROP) {
1833 if (ctx->mode != S5P_JPEG_ENCODE)
1834 return -EINVAL;
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001835 if (ctx->jpeg->variant->hw3250_compat)
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03001836 ret = exynos3250_jpeg_try_crop(ctx, rect);
1837 }
1838
1839 return ret;
1840}
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001841
1842static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001843{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001844 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1845 struct s5p_jpeg *jpeg = ctx->jpeg;
1846 unsigned long flags;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001847
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001848 switch (ctrl->id) {
1849 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1850 spin_lock_irqsave(&jpeg->slock, flags);
Jacek Anaszewski303b0a92013-12-18 11:14:00 -03001851 ctrl->val = s5p_jpeg_to_user_subsampling(ctx);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001852 spin_unlock_irqrestore(&jpeg->slock, flags);
1853 break;
1854 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001855
1856 return 0;
1857}
1858
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001859static int s5p_jpeg_adjust_subs_ctrl(struct s5p_jpeg_ctx *ctx, int *ctrl_val)
1860{
1861 switch (ctx->jpeg->variant->version) {
1862 case SJPEG_S5P:
1863 return 0;
1864 case SJPEG_EXYNOS3250:
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001865 case SJPEG_EXYNOS5420:
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001866 /*
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001867 * The exynos3250/compatible device can produce JPEG image only
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001868 * of 4:4:4 subsampling when given RGB32 source image.
1869 */
1870 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB32)
1871 *ctrl_val = 0;
1872 break;
1873 case SJPEG_EXYNOS4:
1874 /*
1875 * The exynos4x12 device requires input raw image fourcc
1876 * to be V4L2_PIX_FMT_GREY if gray jpeg format
1877 * is to be set.
1878 */
1879 if (ctx->out_q.fmt->fourcc != V4L2_PIX_FMT_GREY &&
1880 *ctrl_val == V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY)
1881 return -EINVAL;
1882 break;
1883 }
1884
1885 /*
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03001886 * The exynos4x12 and exynos3250/compatible devices require resulting
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001887 * jpeg subsampling not to be lower than the input raw image
1888 * subsampling.
1889 */
1890 if (ctx->out_q.fmt->subsampling > *ctrl_val)
1891 *ctrl_val = ctx->out_q.fmt->subsampling;
1892
1893 return 0;
1894}
1895
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001896static int s5p_jpeg_try_ctrl(struct v4l2_ctrl *ctrl)
1897{
1898 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1899 unsigned long flags;
1900 int ret = 0;
1901
1902 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1903
Jacek Anaszewski39c344c2014-07-11 12:19:48 -03001904 if (ctrl->id == V4L2_CID_JPEG_CHROMA_SUBSAMPLING)
1905 ret = s5p_jpeg_adjust_subs_ctrl(ctx, &ctrl->val);
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001906
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001907 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1908 return ret;
1909}
1910
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001911static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001912{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001913 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1914 unsigned long flags;
1915
1916 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1917
1918 switch (ctrl->id) {
1919 case V4L2_CID_JPEG_COMPRESSION_QUALITY:
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001920 ctx->compr_quality = ctrl->val;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001921 break;
1922 case V4L2_CID_JPEG_RESTART_INTERVAL:
1923 ctx->restart_interval = ctrl->val;
1924 break;
1925 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1926 ctx->subsampling = ctrl->val;
1927 break;
1928 }
1929
1930 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1931 return 0;
1932}
1933
1934static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
1935 .g_volatile_ctrl = s5p_jpeg_g_volatile_ctrl,
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001936 .try_ctrl = s5p_jpeg_try_ctrl,
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001937 .s_ctrl = s5p_jpeg_s_ctrl,
1938};
1939
1940static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
1941{
1942 unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */
1943 struct v4l2_ctrl *ctrl;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001944 int ret;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001945
1946 v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
1947
1948 if (ctx->mode == S5P_JPEG_ENCODE) {
1949 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1950 V4L2_CID_JPEG_COMPRESSION_QUALITY,
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001951 0, 3, 1, S5P_JPEG_COMPR_QUAL_WORST);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001952
1953 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1954 V4L2_CID_JPEG_RESTART_INTERVAL,
1955 0, 3, 0xffff, 0);
Jacek Anaszewskifdf9e2b2013-11-21 13:33:41 -03001956 if (ctx->jpeg->variant->version == SJPEG_S5P)
1957 mask = ~0x06; /* 422, 420 */
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001958 }
1959
1960 ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1961 V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
1962 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask,
1963 V4L2_JPEG_CHROMA_SUBSAMPLING_422);
1964
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001965 if (ctx->ctrl_handler.error) {
1966 ret = ctx->ctrl_handler.error;
1967 goto error_free;
1968 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001969
1970 if (ctx->mode == S5P_JPEG_DECODE)
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001971 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
1972 V4L2_CTRL_FLAG_READ_ONLY;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001973
1974 ret = v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
1975 if (ret < 0)
1976 goto error_free;
1977
1978 return ret;
1979
1980error_free:
1981 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
1982 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001983}
1984
1985static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
1986 .vidioc_querycap = s5p_jpeg_querycap,
1987
1988 .vidioc_enum_fmt_vid_cap = s5p_jpeg_enum_fmt_vid_cap,
1989 .vidioc_enum_fmt_vid_out = s5p_jpeg_enum_fmt_vid_out,
1990
1991 .vidioc_g_fmt_vid_cap = s5p_jpeg_g_fmt,
1992 .vidioc_g_fmt_vid_out = s5p_jpeg_g_fmt,
1993
1994 .vidioc_try_fmt_vid_cap = s5p_jpeg_try_fmt_vid_cap,
1995 .vidioc_try_fmt_vid_out = s5p_jpeg_try_fmt_vid_out,
1996
1997 .vidioc_s_fmt_vid_cap = s5p_jpeg_s_fmt_vid_cap,
1998 .vidioc_s_fmt_vid_out = s5p_jpeg_s_fmt_vid_out,
1999
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002000 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
2001 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
2002 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
2003 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002004
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002005 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
2006 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002007
2008 .vidioc_g_selection = s5p_jpeg_g_selection,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002009 .vidioc_s_selection = s5p_jpeg_s_selection,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002010};
2011
2012/*
2013 * ============================================================================
2014 * mem2mem callbacks
2015 * ============================================================================
2016 */
2017
2018static void s5p_jpeg_device_run(void *priv)
2019{
2020 struct s5p_jpeg_ctx *ctx = priv;
2021 struct s5p_jpeg *jpeg = ctx->jpeg;
2022 struct vb2_buffer *src_buf, *dst_buf;
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002023 unsigned long src_addr, dst_addr, flags;
2024
2025 spin_lock_irqsave(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002026
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002027 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2028 dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002029 src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
2030 dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
2031
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002032 s5p_jpeg_reset(jpeg->regs);
2033 s5p_jpeg_poweron(jpeg->regs);
2034 s5p_jpeg_proc_mode(jpeg->regs, ctx->mode);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002035 if (ctx->mode == S5P_JPEG_ENCODE) {
2036 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002037 s5p_jpeg_input_raw_mode(jpeg->regs,
2038 S5P_JPEG_RAW_IN_565);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002039 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002040 s5p_jpeg_input_raw_mode(jpeg->regs,
2041 S5P_JPEG_RAW_IN_422);
2042 s5p_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
2043 s5p_jpeg_dri(jpeg->regs, ctx->restart_interval);
2044 s5p_jpeg_x(jpeg->regs, ctx->out_q.w);
2045 s5p_jpeg_y(jpeg->regs, ctx->out_q.h);
2046 s5p_jpeg_imgadr(jpeg->regs, src_addr);
2047 s5p_jpeg_jpgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002048
2049 /* ultimately comes from sizeimage from userspace */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002050 s5p_jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002051
2052 /* JPEG RGB to YCbCr conversion matrix */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002053 s5p_jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11);
2054 s5p_jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12);
2055 s5p_jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13);
2056 s5p_jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21);
2057 s5p_jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22);
2058 s5p_jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23);
2059 s5p_jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31);
2060 s5p_jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32);
2061 s5p_jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002062
2063 /*
2064 * JPEG IP allows storing 4 quantization tables
2065 * We fill table 0 for luma and table 1 for chroma
2066 */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03002067 s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
2068 s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002069 /* use table 0 for Y */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002070 s5p_jpeg_qtbl(jpeg->regs, 1, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002071 /* use table 1 for Cb and Cr*/
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002072 s5p_jpeg_qtbl(jpeg->regs, 2, 1);
2073 s5p_jpeg_qtbl(jpeg->regs, 3, 1);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002074
2075 /* Y, Cb, Cr use Huffman table 0 */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002076 s5p_jpeg_htbl_ac(jpeg->regs, 1);
2077 s5p_jpeg_htbl_dc(jpeg->regs, 1);
2078 s5p_jpeg_htbl_ac(jpeg->regs, 2);
2079 s5p_jpeg_htbl_dc(jpeg->regs, 2);
2080 s5p_jpeg_htbl_ac(jpeg->regs, 3);
2081 s5p_jpeg_htbl_dc(jpeg->regs, 3);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03002082 } else { /* S5P_JPEG_DECODE */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002083 s5p_jpeg_rst_int_enable(jpeg->regs, true);
2084 s5p_jpeg_data_num_int_enable(jpeg->regs, true);
2085 s5p_jpeg_final_mcu_num_int_enable(jpeg->regs, true);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03002086 if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002087 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03002088 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002089 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420);
2090 s5p_jpeg_jpgadr(jpeg->regs, src_addr);
2091 s5p_jpeg_imgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002092 }
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002093
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002094 s5p_jpeg_start(jpeg->regs);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002095
2096 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002097}
2098
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002099static void exynos4_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
2100{
2101 struct s5p_jpeg *jpeg = ctx->jpeg;
2102 struct s5p_jpeg_fmt *fmt;
2103 struct vb2_buffer *vb;
Jacek Anaszewski12b05562015-03-05 10:56:25 -03002104 struct s5p_jpeg_addr jpeg_addr = {};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002105 u32 pix_size, padding_bytes = 0;
2106
Tony K Nadackalcb0c3f52014-12-17 04:21:21 -03002107 jpeg_addr.cb = 0;
2108 jpeg_addr.cr = 0;
2109
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002110 pix_size = ctx->cap_q.w * ctx->cap_q.h;
2111
2112 if (ctx->mode == S5P_JPEG_ENCODE) {
2113 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2114 fmt = ctx->out_q.fmt;
2115 if (ctx->out_q.w % 2 && fmt->h_align > 0)
2116 padding_bytes = ctx->out_q.h;
2117 } else {
2118 fmt = ctx->cap_q.fmt;
2119 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
2120 }
2121
2122 jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
2123
2124 if (fmt->colplanes == 2) {
2125 jpeg_addr.cb = jpeg_addr.y + pix_size - padding_bytes;
2126 } else if (fmt->colplanes == 3) {
2127 jpeg_addr.cb = jpeg_addr.y + pix_size;
2128 if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
2129 jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
2130 else
2131 jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
2132 }
2133
2134 exynos4_jpeg_set_frame_buf_address(jpeg->regs, &jpeg_addr);
2135}
2136
2137static void exynos4_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
2138{
2139 struct s5p_jpeg *jpeg = ctx->jpeg;
2140 struct vb2_buffer *vb;
2141 unsigned int jpeg_addr = 0;
2142
2143 if (ctx->mode == S5P_JPEG_ENCODE)
2144 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
2145 else
2146 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2147
2148 jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002149 if (jpeg->variant->version == SJPEG_EXYNOS5433 &&
2150 ctx->mode == S5P_JPEG_DECODE)
2151 jpeg_addr += ctx->out_q.sos;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002152 exynos4_jpeg_set_stream_buf_address(jpeg->regs, jpeg_addr);
2153}
2154
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002155static inline void exynos4_jpeg_set_img_fmt(void __iomem *base,
2156 unsigned int img_fmt)
2157{
2158 __exynos4_jpeg_set_img_fmt(base, img_fmt, SJPEG_EXYNOS4);
2159}
2160
2161static inline void exynos5433_jpeg_set_img_fmt(void __iomem *base,
2162 unsigned int img_fmt)
2163{
2164 __exynos4_jpeg_set_img_fmt(base, img_fmt, SJPEG_EXYNOS5433);
2165}
2166
2167static inline void exynos4_jpeg_set_enc_out_fmt(void __iomem *base,
2168 unsigned int out_fmt)
2169{
2170 __exynos4_jpeg_set_enc_out_fmt(base, out_fmt, SJPEG_EXYNOS4);
2171}
2172
2173static inline void exynos5433_jpeg_set_enc_out_fmt(void __iomem *base,
2174 unsigned int out_fmt)
2175{
2176 __exynos4_jpeg_set_enc_out_fmt(base, out_fmt, SJPEG_EXYNOS5433);
2177}
2178
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002179static void exynos4_jpeg_device_run(void *priv)
2180{
2181 struct s5p_jpeg_ctx *ctx = priv;
2182 struct s5p_jpeg *jpeg = ctx->jpeg;
2183 unsigned int bitstream_size;
2184 unsigned long flags;
2185
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002186 spin_lock_irqsave(&jpeg->slock, flags);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002187
2188 if (ctx->mode == S5P_JPEG_ENCODE) {
2189 exynos4_jpeg_sw_reset(jpeg->regs);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002190 exynos4_jpeg_set_interrupt(jpeg->regs, jpeg->variant->version);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002191 exynos4_jpeg_set_huf_table_enable(jpeg->regs, 1);
2192
2193 exynos4_jpeg_set_huff_tbl(jpeg->regs);
2194
2195 /*
2196 * JPEG IP allows storing 4 quantization tables
2197 * We fill table 0 for luma and table 1 for chroma
2198 */
2199 exynos4_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
2200 exynos4_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
2201
2202 exynos4_jpeg_set_encode_tbl_select(jpeg->regs,
2203 ctx->compr_quality);
2204 exynos4_jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w,
2205 ctx->cap_q.h);
2206
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002207 if (ctx->jpeg->variant->version == SJPEG_EXYNOS4) {
2208 exynos4_jpeg_set_enc_out_fmt(jpeg->regs,
2209 ctx->subsampling);
2210 exynos4_jpeg_set_img_fmt(jpeg->regs,
2211 ctx->out_q.fmt->fourcc);
2212 } else {
2213 exynos5433_jpeg_set_enc_out_fmt(jpeg->regs,
2214 ctx->subsampling);
2215 exynos5433_jpeg_set_img_fmt(jpeg->regs,
2216 ctx->out_q.fmt->fourcc);
2217 }
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002218 exynos4_jpeg_set_img_addr(ctx);
2219 exynos4_jpeg_set_jpeg_addr(ctx);
2220 exynos4_jpeg_set_encode_hoff_cnt(jpeg->regs,
2221 ctx->out_q.fmt->fourcc);
2222 } else {
2223 exynos4_jpeg_sw_reset(jpeg->regs);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002224 exynos4_jpeg_set_interrupt(jpeg->regs,
2225 jpeg->variant->version);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002226 exynos4_jpeg_set_img_addr(ctx);
2227 exynos4_jpeg_set_jpeg_addr(ctx);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002228
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002229 if (jpeg->variant->version == SJPEG_EXYNOS5433) {
2230 exynos4_jpeg_parse_huff_tbl(ctx);
2231 exynos4_jpeg_parse_decode_h_tbl(ctx);
2232
2233 exynos4_jpeg_parse_q_tbl(ctx);
2234 exynos4_jpeg_parse_decode_q_tbl(ctx);
2235
2236 exynos4_jpeg_set_huf_table_enable(jpeg->regs, 1);
2237
2238 exynos4_jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w,
2239 ctx->cap_q.h);
2240 exynos5433_jpeg_set_enc_out_fmt(jpeg->regs,
2241 ctx->subsampling);
2242 exynos5433_jpeg_set_img_fmt(jpeg->regs,
2243 ctx->cap_q.fmt->fourcc);
2244 bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 16);
2245 } else {
2246 exynos4_jpeg_set_img_fmt(jpeg->regs,
2247 ctx->cap_q.fmt->fourcc);
2248 bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 32);
2249 }
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002250
2251 exynos4_jpeg_set_dec_bitstream_size(jpeg->regs, bitstream_size);
2252 }
2253
2254 exynos4_jpeg_set_enc_dec_mode(jpeg->regs, ctx->mode);
2255
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002256 spin_unlock_irqrestore(&jpeg->slock, flags);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002257}
2258
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002259static void exynos3250_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
2260{
2261 struct s5p_jpeg *jpeg = ctx->jpeg;
2262 struct s5p_jpeg_fmt *fmt;
2263 struct vb2_buffer *vb;
Jacek Anaszewski12b05562015-03-05 10:56:25 -03002264 struct s5p_jpeg_addr jpeg_addr = {};
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002265 u32 pix_size;
2266
2267 pix_size = ctx->cap_q.w * ctx->cap_q.h;
2268
2269 if (ctx->mode == S5P_JPEG_ENCODE) {
2270 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2271 fmt = ctx->out_q.fmt;
2272 } else {
2273 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
2274 fmt = ctx->cap_q.fmt;
2275 }
2276
2277 jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
2278
2279 if (fmt->colplanes == 2) {
2280 jpeg_addr.cb = jpeg_addr.y + pix_size;
2281 } else if (fmt->colplanes == 3) {
2282 jpeg_addr.cb = jpeg_addr.y + pix_size;
2283 if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
2284 jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
2285 else
2286 jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
2287 }
2288
2289 exynos3250_jpeg_imgadr(jpeg->regs, &jpeg_addr);
2290}
2291
2292static void exynos3250_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
2293{
2294 struct s5p_jpeg *jpeg = ctx->jpeg;
2295 struct vb2_buffer *vb;
2296 unsigned int jpeg_addr = 0;
2297
2298 if (ctx->mode == S5P_JPEG_ENCODE)
2299 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
2300 else
2301 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
2302
2303 jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
2304 exynos3250_jpeg_jpgadr(jpeg->regs, jpeg_addr);
2305}
2306
2307static void exynos3250_jpeg_device_run(void *priv)
2308{
2309 struct s5p_jpeg_ctx *ctx = priv;
2310 struct s5p_jpeg *jpeg = ctx->jpeg;
2311 unsigned long flags;
2312
2313 spin_lock_irqsave(&ctx->jpeg->slock, flags);
2314
2315 exynos3250_jpeg_reset(jpeg->regs);
2316 exynos3250_jpeg_set_dma_num(jpeg->regs);
2317 exynos3250_jpeg_poweron(jpeg->regs);
2318 exynos3250_jpeg_clk_set(jpeg->regs);
2319 exynos3250_jpeg_proc_mode(jpeg->regs, ctx->mode);
2320
2321 if (ctx->mode == S5P_JPEG_ENCODE) {
2322 exynos3250_jpeg_input_raw_fmt(jpeg->regs,
2323 ctx->out_q.fmt->fourcc);
2324 exynos3250_jpeg_dri(jpeg->regs, ctx->restart_interval);
2325
2326 /*
2327 * JPEG IP allows storing 4 quantization tables
2328 * We fill table 0 for luma and table 1 for chroma
2329 */
2330 s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
2331 s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
2332 /* use table 0 for Y */
2333 exynos3250_jpeg_qtbl(jpeg->regs, 1, 0);
2334 /* use table 1 for Cb and Cr*/
2335 exynos3250_jpeg_qtbl(jpeg->regs, 2, 1);
2336 exynos3250_jpeg_qtbl(jpeg->regs, 3, 1);
2337
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03002338 /*
2339 * Some SoCs require setting Huffman tables before each run
2340 */
2341 if (jpeg->variant->htbl_reinit) {
2342 s5p_jpeg_set_hdctbl(jpeg->regs);
2343 s5p_jpeg_set_hdctblg(jpeg->regs);
2344 s5p_jpeg_set_hactbl(jpeg->regs);
2345 s5p_jpeg_set_hactblg(jpeg->regs);
2346 }
2347
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002348 /* Y, Cb, Cr use Huffman table 0 */
2349 exynos3250_jpeg_htbl_ac(jpeg->regs, 1);
2350 exynos3250_jpeg_htbl_dc(jpeg->regs, 1);
2351 exynos3250_jpeg_htbl_ac(jpeg->regs, 2);
2352 exynos3250_jpeg_htbl_dc(jpeg->regs, 2);
2353 exynos3250_jpeg_htbl_ac(jpeg->regs, 3);
2354 exynos3250_jpeg_htbl_dc(jpeg->regs, 3);
2355
2356 exynos3250_jpeg_set_x(jpeg->regs, ctx->crop_rect.width);
2357 exynos3250_jpeg_set_y(jpeg->regs, ctx->crop_rect.height);
2358 exynos3250_jpeg_stride(jpeg->regs, ctx->out_q.fmt->fourcc,
2359 ctx->out_q.w);
2360 exynos3250_jpeg_offset(jpeg->regs, ctx->crop_rect.left,
2361 ctx->crop_rect.top);
2362 exynos3250_jpeg_set_img_addr(ctx);
2363 exynos3250_jpeg_set_jpeg_addr(ctx);
2364 exynos3250_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
2365
2366 /* ultimately comes from sizeimage from userspace */
2367 exynos3250_jpeg_enc_stream_bound(jpeg->regs, ctx->cap_q.size);
2368
2369 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565 ||
2370 ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565X ||
2371 ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB32)
2372 exynos3250_jpeg_set_y16(jpeg->regs, true);
2373 } else {
2374 exynos3250_jpeg_set_img_addr(ctx);
2375 exynos3250_jpeg_set_jpeg_addr(ctx);
2376 exynos3250_jpeg_stride(jpeg->regs, ctx->cap_q.fmt->fourcc,
2377 ctx->cap_q.w);
2378 exynos3250_jpeg_offset(jpeg->regs, 0, 0);
2379 exynos3250_jpeg_dec_scaling_ratio(jpeg->regs,
2380 ctx->scale_factor);
2381 exynos3250_jpeg_dec_stream_size(jpeg->regs, ctx->out_q.size);
2382 exynos3250_jpeg_output_raw_fmt(jpeg->regs,
2383 ctx->cap_q.fmt->fourcc);
2384 }
2385
2386 exynos3250_jpeg_interrupts_enable(jpeg->regs);
2387
2388 /* JPEG RGB to YCbCr conversion matrix */
2389 exynos3250_jpeg_coef(jpeg->regs, ctx->mode);
2390
2391 exynos3250_jpeg_set_timer(jpeg->regs, EXYNOS3250_IRQ_TIMEOUT);
2392 jpeg->irq_status = 0;
2393 exynos3250_jpeg_start(jpeg->regs);
2394
2395 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
2396}
2397
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002398static int s5p_jpeg_job_ready(void *priv)
2399{
2400 struct s5p_jpeg_ctx *ctx = priv;
2401
2402 if (ctx->mode == S5P_JPEG_DECODE)
2403 return ctx->hdr_parsed;
2404 return 1;
2405}
2406
2407static void s5p_jpeg_job_abort(void *priv)
2408{
2409}
2410
2411static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = {
2412 .device_run = s5p_jpeg_device_run,
2413 .job_ready = s5p_jpeg_job_ready,
2414 .job_abort = s5p_jpeg_job_abort,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002415};
2416
2417static struct v4l2_m2m_ops exynos3250_jpeg_m2m_ops = {
2418 .device_run = exynos3250_jpeg_device_run,
2419 .job_ready = s5p_jpeg_job_ready,
2420 .job_abort = s5p_jpeg_job_abort,
2421};
2422
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03002423static struct v4l2_m2m_ops exynos4_jpeg_m2m_ops = {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002424 .device_run = exynos4_jpeg_device_run,
2425 .job_ready = s5p_jpeg_job_ready,
2426 .job_abort = s5p_jpeg_job_abort,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002427};
2428
2429/*
2430 * ============================================================================
2431 * Queue operations
2432 * ============================================================================
2433 */
2434
Marek Szyprowski719c1742012-01-13 05:12:38 -03002435static int s5p_jpeg_queue_setup(struct vb2_queue *vq,
2436 const struct v4l2_format *fmt,
2437 unsigned int *nbuffers, unsigned int *nplanes,
2438 unsigned int sizes[], void *alloc_ctxs[])
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002439{
2440 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
2441 struct s5p_jpeg_q_data *q_data = NULL;
2442 unsigned int size, count = *nbuffers;
2443
2444 q_data = get_q_data(ctx, vq->type);
2445 BUG_ON(q_data == NULL);
2446
2447 size = q_data->size;
2448
2449 /*
2450 * header is parsed during decoding and parsed information stored
2451 * in the context so we do not allow another buffer to overwrite it
2452 */
2453 if (ctx->mode == S5P_JPEG_DECODE)
2454 count = 1;
2455
2456 *nbuffers = count;
2457 *nplanes = 1;
2458 sizes[0] = size;
2459 alloc_ctxs[0] = ctx->jpeg->alloc_ctx;
2460
2461 return 0;
2462}
2463
2464static int s5p_jpeg_buf_prepare(struct vb2_buffer *vb)
2465{
2466 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
2467 struct s5p_jpeg_q_data *q_data = NULL;
2468
2469 q_data = get_q_data(ctx, vb->vb2_queue->type);
2470 BUG_ON(q_data == NULL);
2471
2472 if (vb2_plane_size(vb, 0) < q_data->size) {
2473 pr_err("%s data will not fit into plane (%lu < %lu)\n",
2474 __func__, vb2_plane_size(vb, 0),
2475 (long)q_data->size);
2476 return -EINVAL;
2477 }
2478
2479 vb2_set_plane_payload(vb, 0, q_data->size);
2480
2481 return 0;
2482}
2483
2484static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
2485{
2486 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
2487
2488 if (ctx->mode == S5P_JPEG_DECODE &&
2489 vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
2490 struct s5p_jpeg_q_data tmp, *q_data;
2491 ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp,
2492 (unsigned long)vb2_plane_vaddr(vb, 0),
2493 min((unsigned long)ctx->out_q.size,
Jacek Anaszewskif8433962013-11-21 13:33:09 -03002494 vb2_get_plane_payload(vb, 0)), ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002495 if (!ctx->hdr_parsed) {
2496 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
2497 return;
2498 }
2499
2500 q_data = &ctx->out_q;
2501 q_data->w = tmp.w;
2502 q_data->h = tmp.h;
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002503 q_data->sos = tmp.sos;
2504 memcpy(q_data->dht.marker, tmp.dht.marker,
2505 sizeof(tmp.dht.marker));
2506 memcpy(q_data->dht.len, tmp.dht.len, sizeof(tmp.dht.len));
2507 q_data->dht.n = tmp.dht.n;
2508 memcpy(q_data->dqt.marker, tmp.dqt.marker,
2509 sizeof(tmp.dqt.marker));
2510 memcpy(q_data->dqt.len, tmp.dqt.len, sizeof(tmp.dqt.len));
2511 q_data->dqt.n = tmp.dqt.n;
2512 q_data->sof = tmp.sof;
2513 q_data->sof_len = tmp.sof_len;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002514
2515 q_data = &ctx->cap_q;
2516 q_data->w = tmp.w;
2517 q_data->h = tmp.h;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002518 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002519
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002520 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002521}
2522
2523static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
2524{
2525 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
2526 int ret;
2527
2528 ret = pm_runtime_get_sync(ctx->jpeg->dev);
2529
2530 return ret > 0 ? 0 : ret;
2531}
2532
Hans Verkuile37559b2014-04-17 02:47:21 -03002533static void s5p_jpeg_stop_streaming(struct vb2_queue *q)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002534{
2535 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
2536
2537 pm_runtime_put(ctx->jpeg->dev);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002538}
2539
2540static struct vb2_ops s5p_jpeg_qops = {
2541 .queue_setup = s5p_jpeg_queue_setup,
2542 .buf_prepare = s5p_jpeg_buf_prepare,
2543 .buf_queue = s5p_jpeg_buf_queue,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002544 .wait_prepare = vb2_ops_wait_prepare,
2545 .wait_finish = vb2_ops_wait_finish,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002546 .start_streaming = s5p_jpeg_start_streaming,
2547 .stop_streaming = s5p_jpeg_stop_streaming,
2548};
2549
2550static int queue_init(void *priv, struct vb2_queue *src_vq,
2551 struct vb2_queue *dst_vq)
2552{
2553 struct s5p_jpeg_ctx *ctx = priv;
2554 int ret;
2555
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002556 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
2557 src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
2558 src_vq->drv_priv = ctx;
2559 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
2560 src_vq->ops = &s5p_jpeg_qops;
2561 src_vq->mem_ops = &vb2_dma_contig_memops;
Sakari Ailusade48682014-02-25 19:12:19 -03002562 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002563 src_vq->lock = &ctx->jpeg->lock;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002564
2565 ret = vb2_queue_init(src_vq);
2566 if (ret)
2567 return ret;
2568
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002569 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2570 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
2571 dst_vq->drv_priv = ctx;
2572 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
2573 dst_vq->ops = &s5p_jpeg_qops;
2574 dst_vq->mem_ops = &vb2_dma_contig_memops;
Sakari Ailusade48682014-02-25 19:12:19 -03002575 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002576 dst_vq->lock = &ctx->jpeg->lock;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002577
2578 return vb2_queue_init(dst_vq);
2579}
2580
2581/*
2582 * ============================================================================
2583 * ISR
2584 * ============================================================================
2585 */
2586
2587static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
2588{
2589 struct s5p_jpeg *jpeg = dev_id;
2590 struct s5p_jpeg_ctx *curr_ctx;
2591 struct vb2_buffer *src_buf, *dst_buf;
2592 unsigned long payload_size = 0;
2593 enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
2594 bool enc_jpeg_too_large = false;
2595 bool timer_elapsed = false;
2596 bool op_completed = false;
2597
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002598 spin_lock(&jpeg->slock);
2599
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002600 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2601
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002602 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2603 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002604
2605 if (curr_ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002606 enc_jpeg_too_large = s5p_jpeg_enc_stream_stat(jpeg->regs);
2607 timer_elapsed = s5p_jpeg_timer_stat(jpeg->regs);
2608 op_completed = s5p_jpeg_result_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002609 if (curr_ctx->mode == S5P_JPEG_DECODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002610 op_completed = op_completed &&
2611 s5p_jpeg_stream_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002612
2613 if (enc_jpeg_too_large) {
2614 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002615 s5p_jpeg_clear_enc_stream_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002616 } else if (timer_elapsed) {
2617 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002618 s5p_jpeg_clear_timer_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002619 } else if (!op_completed) {
2620 state = VB2_BUF_STATE_ERROR;
2621 } else {
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002622 payload_size = s5p_jpeg_compressed_size(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002623 }
2624
Kamil Debskiaca326a2013-04-24 10:08:02 -03002625 dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
2626 dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
Sakari Ailus309f4d62014-02-08 14:21:35 -03002627 dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
2628 dst_buf->v4l2_buf.flags |=
2629 src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
Kamil Debskiaca326a2013-04-24 10:08:02 -03002630
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002631 v4l2_m2m_buf_done(src_buf, state);
2632 if (curr_ctx->mode == S5P_JPEG_ENCODE)
2633 vb2_set_plane_payload(dst_buf, 0, payload_size);
2634 v4l2_m2m_buf_done(dst_buf, state);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03002635 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002636
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002637 curr_ctx->subsampling = s5p_jpeg_get_subsampling_mode(jpeg->regs);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002638 spin_unlock(&jpeg->slock);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03002639
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03002640 s5p_jpeg_clear_int(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002641
2642 return IRQ_HANDLED;
2643}
2644
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002645static irqreturn_t exynos4_jpeg_irq(int irq, void *priv)
2646{
2647 unsigned int int_status;
2648 struct vb2_buffer *src_vb, *dst_vb;
2649 struct s5p_jpeg *jpeg = priv;
2650 struct s5p_jpeg_ctx *curr_ctx;
2651 unsigned long payload_size = 0;
2652
2653 spin_lock(&jpeg->slock);
2654
2655 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2656
2657 src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2658 dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
2659
2660 int_status = exynos4_jpeg_get_int_status(jpeg->regs);
2661
2662 if (int_status) {
2663 switch (int_status & 0x1f) {
2664 case 0x1:
2665 jpeg->irq_ret = ERR_PROT;
2666 break;
2667 case 0x2:
2668 jpeg->irq_ret = OK_ENC_OR_DEC;
2669 break;
2670 case 0x4:
2671 jpeg->irq_ret = ERR_DEC_INVALID_FORMAT;
2672 break;
2673 case 0x8:
2674 jpeg->irq_ret = ERR_MULTI_SCAN;
2675 break;
2676 case 0x10:
2677 jpeg->irq_ret = ERR_FRAME;
2678 break;
2679 default:
2680 jpeg->irq_ret = ERR_UNKNOWN;
2681 break;
2682 }
2683 } else {
2684 jpeg->irq_ret = ERR_UNKNOWN;
2685 }
2686
2687 if (jpeg->irq_ret == OK_ENC_OR_DEC) {
2688 if (curr_ctx->mode == S5P_JPEG_ENCODE) {
2689 payload_size = exynos4_jpeg_get_stream_size(jpeg->regs);
2690 vb2_set_plane_payload(dst_vb, 0, payload_size);
2691 }
2692 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
2693 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
2694 } else {
2695 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
2696 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
2697 }
2698
2699 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03002700 if (jpeg->variant->version == SJPEG_EXYNOS4)
2701 curr_ctx->subsampling = exynos4_jpeg_get_frame_fmt(jpeg->regs);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002702
2703 spin_unlock(&jpeg->slock);
2704 return IRQ_HANDLED;
2705}
2706
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002707static irqreturn_t exynos3250_jpeg_irq(int irq, void *dev_id)
2708{
2709 struct s5p_jpeg *jpeg = dev_id;
2710 struct s5p_jpeg_ctx *curr_ctx;
2711 struct vb2_buffer *src_buf, *dst_buf;
2712 unsigned long payload_size = 0;
2713 enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
2714 bool interrupt_timeout = false;
2715 u32 irq_status;
2716
2717 spin_lock(&jpeg->slock);
2718
2719 irq_status = exynos3250_jpeg_get_timer_status(jpeg->regs);
2720 if (irq_status & EXYNOS3250_TIMER_INT_STAT) {
2721 exynos3250_jpeg_clear_timer_status(jpeg->regs);
2722 interrupt_timeout = true;
2723 dev_err(jpeg->dev, "Interrupt timeout occurred.\n");
2724 }
2725
2726 irq_status = exynos3250_jpeg_get_int_status(jpeg->regs);
2727 exynos3250_jpeg_clear_int_status(jpeg->regs, irq_status);
2728
2729 jpeg->irq_status |= irq_status;
2730
2731 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
2732
2733 if (!curr_ctx)
2734 goto exit_unlock;
2735
2736 if ((irq_status & EXYNOS3250_HEADER_STAT) &&
2737 (curr_ctx->mode == S5P_JPEG_DECODE)) {
2738 exynos3250_jpeg_rstart(jpeg->regs);
2739 goto exit_unlock;
2740 }
2741
2742 if (jpeg->irq_status & (EXYNOS3250_JPEG_DONE |
2743 EXYNOS3250_WDMA_DONE |
2744 EXYNOS3250_RDMA_DONE |
2745 EXYNOS3250_RESULT_STAT))
2746 payload_size = exynos3250_jpeg_compressed_size(jpeg->regs);
2747 else if (interrupt_timeout)
2748 state = VB2_BUF_STATE_ERROR;
2749 else
2750 goto exit_unlock;
2751
2752 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
2753 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
2754
2755 dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
2756 dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
2757
2758 v4l2_m2m_buf_done(src_buf, state);
2759 if (curr_ctx->mode == S5P_JPEG_ENCODE)
2760 vb2_set_plane_payload(dst_buf, 0, payload_size);
2761 v4l2_m2m_buf_done(dst_buf, state);
2762 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
2763
2764 curr_ctx->subsampling =
2765 exynos3250_jpeg_get_subsampling_mode(jpeg->regs);
2766exit_unlock:
2767 spin_unlock(&jpeg->slock);
2768 return IRQ_HANDLED;
2769}
2770
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03002771static void *jpeg_get_drv_data(struct device *dev);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002772
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002773/*
2774 * ============================================================================
2775 * Driver basic infrastructure
2776 * ============================================================================
2777 */
2778
2779static int s5p_jpeg_probe(struct platform_device *pdev)
2780{
2781 struct s5p_jpeg *jpeg;
2782 struct resource *res;
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002783 int i, ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002784
2785 /* JPEG IP abstraction struct */
Sachin Kamat5b58b952012-05-14 06:33:34 -03002786 jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002787 if (!jpeg)
2788 return -ENOMEM;
2789
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03002790 jpeg->variant = jpeg_get_drv_data(&pdev->dev);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002791
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002792 mutex_init(&jpeg->lock);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03002793 spin_lock_init(&jpeg->slock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002794 jpeg->dev = &pdev->dev;
2795
2796 /* memory-mapped registers */
2797 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002798
Thierry Redingf23999e2013-01-21 06:09:07 -03002799 jpeg->regs = devm_ioremap_resource(&pdev->dev, res);
2800 if (IS_ERR(jpeg->regs))
2801 return PTR_ERR(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002802
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002803 /* interrupt service routine registration */
2804 jpeg->irq = ret = platform_get_irq(pdev, 0);
2805 if (ret < 0) {
2806 dev_err(&pdev->dev, "cannot find IRQ\n");
Sachin Kamat5b58b952012-05-14 06:33:34 -03002807 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002808 }
2809
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002810 ret = devm_request_irq(&pdev->dev, jpeg->irq, jpeg->variant->jpeg_irq,
2811 0, dev_name(&pdev->dev), jpeg);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002812 if (ret) {
2813 dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
Sachin Kamat5b58b952012-05-14 06:33:34 -03002814 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002815 }
2816
2817 /* clocks */
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002818 for (i = 0; i < jpeg->variant->num_clocks; i++) {
2819 jpeg->clocks[i] = devm_clk_get(&pdev->dev,
2820 jpeg->variant->clk_names[i]);
2821 if (IS_ERR(jpeg->clocks[i])) {
2822 dev_err(&pdev->dev, "failed to get clock: %s\n",
2823 jpeg->variant->clk_names[i]);
2824 return PTR_ERR(jpeg->clocks[i]);
2825 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002826 }
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002827
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002828 /* v4l2 device */
2829 ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
2830 if (ret) {
2831 dev_err(&pdev->dev, "Failed to register v4l2 device\n");
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002832 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002833 }
2834
2835 /* mem2mem device */
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03002836 jpeg->m2m_dev = v4l2_m2m_init(jpeg->variant->m2m_ops);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002837 if (IS_ERR(jpeg->m2m_dev)) {
2838 v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
2839 ret = PTR_ERR(jpeg->m2m_dev);
2840 goto device_register_rollback;
2841 }
2842
2843 jpeg->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
2844 if (IS_ERR(jpeg->alloc_ctx)) {
2845 v4l2_err(&jpeg->v4l2_dev, "Failed to init memory allocator\n");
2846 ret = PTR_ERR(jpeg->alloc_ctx);
2847 goto m2m_init_rollback;
2848 }
2849
2850 /* JPEG encoder /dev/videoX node */
2851 jpeg->vfd_encoder = video_device_alloc();
2852 if (!jpeg->vfd_encoder) {
2853 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
2854 ret = -ENOMEM;
2855 goto vb2_allocator_rollback;
2856 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03002857 snprintf(jpeg->vfd_encoder->name, sizeof(jpeg->vfd_encoder->name),
2858 "%s-enc", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002859 jpeg->vfd_encoder->fops = &s5p_jpeg_fops;
2860 jpeg->vfd_encoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
2861 jpeg->vfd_encoder->minor = -1;
2862 jpeg->vfd_encoder->release = video_device_release;
2863 jpeg->vfd_encoder->lock = &jpeg->lock;
2864 jpeg->vfd_encoder->v4l2_dev = &jpeg->v4l2_dev;
Hans Verkuil954f3402012-09-05 06:05:50 -03002865 jpeg->vfd_encoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002866
2867 ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
2868 if (ret) {
2869 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
Andrzej Pietrasiewicz7a1d4e72015-07-03 07:04:38 -03002870 video_device_release(jpeg->vfd_encoder);
2871 goto vb2_allocator_rollback;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002872 }
2873
2874 video_set_drvdata(jpeg->vfd_encoder, jpeg);
2875 v4l2_info(&jpeg->v4l2_dev,
2876 "encoder device registered as /dev/video%d\n",
2877 jpeg->vfd_encoder->num);
2878
2879 /* JPEG decoder /dev/videoX node */
2880 jpeg->vfd_decoder = video_device_alloc();
2881 if (!jpeg->vfd_decoder) {
2882 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
2883 ret = -ENOMEM;
2884 goto enc_vdev_register_rollback;
2885 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03002886 snprintf(jpeg->vfd_decoder->name, sizeof(jpeg->vfd_decoder->name),
2887 "%s-dec", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002888 jpeg->vfd_decoder->fops = &s5p_jpeg_fops;
2889 jpeg->vfd_decoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
2890 jpeg->vfd_decoder->minor = -1;
2891 jpeg->vfd_decoder->release = video_device_release;
2892 jpeg->vfd_decoder->lock = &jpeg->lock;
2893 jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev;
Jacek Anaszewski7f7d8fe2013-09-11 06:17:45 -03002894 jpeg->vfd_decoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002895
2896 ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
2897 if (ret) {
2898 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
Andrzej Pietrasiewicz7a1d4e72015-07-03 07:04:38 -03002899 video_device_release(jpeg->vfd_decoder);
2900 goto enc_vdev_register_rollback;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002901 }
2902
2903 video_set_drvdata(jpeg->vfd_decoder, jpeg);
2904 v4l2_info(&jpeg->v4l2_dev,
2905 "decoder device registered as /dev/video%d\n",
2906 jpeg->vfd_decoder->num);
2907
2908 /* final statements & power management */
2909 platform_set_drvdata(pdev, jpeg);
2910
2911 pm_runtime_enable(&pdev->dev);
2912
2913 v4l2_info(&jpeg->v4l2_dev, "Samsung S5P JPEG codec\n");
2914
2915 return 0;
2916
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002917enc_vdev_register_rollback:
2918 video_unregister_device(jpeg->vfd_encoder);
2919
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002920vb2_allocator_rollback:
2921 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
2922
2923m2m_init_rollback:
2924 v4l2_m2m_release(jpeg->m2m_dev);
2925
2926device_register_rollback:
2927 v4l2_device_unregister(&jpeg->v4l2_dev);
2928
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002929 return ret;
2930}
2931
2932static int s5p_jpeg_remove(struct platform_device *pdev)
2933{
2934 struct s5p_jpeg *jpeg = platform_get_drvdata(pdev);
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002935 int i;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002936
2937 pm_runtime_disable(jpeg->dev);
2938
2939 video_unregister_device(jpeg->vfd_decoder);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002940 video_unregister_device(jpeg->vfd_encoder);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002941 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
2942 v4l2_m2m_release(jpeg->m2m_dev);
2943 v4l2_device_unregister(&jpeg->v4l2_dev);
2944
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002945 if (!pm_runtime_status_suspended(&pdev->dev)) {
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002946 for (i = jpeg->variant->num_clocks - 1; i >= 0; i--)
2947 clk_disable_unprepare(jpeg->clocks[i]);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002948 }
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002949
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002950 return 0;
2951}
2952
Rafael J. Wysockie243c7c2014-12-04 01:10:10 +01002953#ifdef CONFIG_PM
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002954static int s5p_jpeg_runtime_suspend(struct device *dev)
2955{
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002956 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002957 int i;
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002958
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002959 for (i = jpeg->variant->num_clocks - 1; i >= 0; i--)
2960 clk_disable_unprepare(jpeg->clocks[i]);
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002961
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002962 return 0;
2963}
2964
2965static int s5p_jpeg_runtime_resume(struct device *dev)
2966{
2967 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002968 unsigned long flags;
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002969 int i, ret;
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002970
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002971 for (i = 0; i < jpeg->variant->num_clocks; i++) {
2972 ret = clk_prepare_enable(jpeg->clocks[i]);
2973 if (ret) {
2974 while (--i > 0)
2975 clk_disable_unprepare(jpeg->clocks[i]);
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002976 return ret;
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03002977 }
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002978 }
2979
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002980 spin_lock_irqsave(&jpeg->slock, flags);
2981
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002982 /*
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03002983 * JPEG IP allows storing two Huffman tables for each component.
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002984 * We fill table 0 for each component and do this here only
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03002985 * for S5PC210 and Exynos3250 SoCs. Exynos4x12 and Exynos542x SoC
2986 * require programming their Huffman tables each time the encoding
2987 * process is initialized, and thus it is accomplished in the
2988 * device_run callback of m2m_ops.
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002989 */
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03002990 if (!jpeg->variant->htbl_reinit) {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002991 s5p_jpeg_set_hdctbl(jpeg->regs);
2992 s5p_jpeg_set_hdctblg(jpeg->regs);
2993 s5p_jpeg_set_hactbl(jpeg->regs);
2994 s5p_jpeg_set_hactblg(jpeg->regs);
2995 }
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03002996
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002997 spin_unlock_irqrestore(&jpeg->slock, flags);
2998
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002999 return 0;
3000}
Rafael J. Wysockie243c7c2014-12-04 01:10:10 +01003001#endif /* CONFIG_PM */
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003002
Thierry Redingde3767a2014-10-14 07:10:40 -03003003#ifdef CONFIG_PM_SLEEP
Jacek Anaszewskif1347132013-11-25 06:58:13 -03003004static int s5p_jpeg_suspend(struct device *dev)
3005{
3006 if (pm_runtime_suspended(dev))
3007 return 0;
3008
3009 return s5p_jpeg_runtime_suspend(dev);
3010}
3011
3012static int s5p_jpeg_resume(struct device *dev)
3013{
3014 if (pm_runtime_suspended(dev))
3015 return 0;
3016
3017 return s5p_jpeg_runtime_resume(dev);
3018}
Thierry Redingde3767a2014-10-14 07:10:40 -03003019#endif
Jacek Anaszewskif1347132013-11-25 06:58:13 -03003020
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003021static const struct dev_pm_ops s5p_jpeg_pm_ops = {
Jacek Anaszewskif1347132013-11-25 06:58:13 -03003022 SET_SYSTEM_SLEEP_PM_OPS(s5p_jpeg_suspend, s5p_jpeg_resume)
3023 SET_RUNTIME_PM_OPS(s5p_jpeg_runtime_suspend, s5p_jpeg_runtime_resume, NULL)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003024};
3025
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003026static struct s5p_jpeg_variant s5p_jpeg_drvdata = {
3027 .version = SJPEG_S5P,
3028 .jpeg_irq = s5p_jpeg_irq,
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03003029 .m2m_ops = &s5p_jpeg_m2m_ops,
Jacek Anaszewskib2451682014-04-10 04:32:11 -03003030 .fmt_ver_flag = SJPEG_FMT_FLAG_S5P,
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03003031 .clk_names = {"jpeg"},
3032 .num_clocks = 1,
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03003033};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003034
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003035static struct s5p_jpeg_variant exynos3250_jpeg_drvdata = {
3036 .version = SJPEG_EXYNOS3250,
3037 .jpeg_irq = exynos3250_jpeg_irq,
3038 .m2m_ops = &exynos3250_jpeg_m2m_ops,
3039 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS3250,
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03003040 .hw3250_compat = 1,
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03003041 .clk_names = {"jpeg", "sclk"},
3042 .num_clocks = 2,
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003043};
3044
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003045static struct s5p_jpeg_variant exynos4_jpeg_drvdata = {
3046 .version = SJPEG_EXYNOS4,
3047 .jpeg_irq = exynos4_jpeg_irq,
Jacek Anaszewskibf689bb2014-04-10 04:32:13 -03003048 .m2m_ops = &exynos4_jpeg_m2m_ops,
Jacek Anaszewskib2451682014-04-10 04:32:11 -03003049 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS4,
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03003050 .htbl_reinit = 1,
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03003051 .clk_names = {"jpeg"},
3052 .num_clocks = 1,
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03003053 .hw_ex4_compat = 1,
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03003054};
3055
3056static struct s5p_jpeg_variant exynos5420_jpeg_drvdata = {
3057 .version = SJPEG_EXYNOS5420,
3058 .jpeg_irq = exynos3250_jpeg_irq, /* intentionally 3250 */
3059 .m2m_ops = &exynos3250_jpeg_m2m_ops, /* intentionally 3250 */
3060 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS3250, /* intentionally 3250 */
3061 .hw3250_compat = 1,
3062 .htbl_reinit = 1,
Marek Szyprowskib95a24d2015-09-18 11:20:57 -03003063 .clk_names = {"jpeg"},
3064 .num_clocks = 1,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003065};
3066
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03003067static struct s5p_jpeg_variant exynos5433_jpeg_drvdata = {
3068 .version = SJPEG_EXYNOS5433,
3069 .jpeg_irq = exynos4_jpeg_irq,
3070 .m2m_ops = &exynos4_jpeg_m2m_ops,
3071 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS4,
3072 .htbl_reinit = 1,
3073 .clk_names = {"pclk", "aclk", "aclk_xiu", "sclk"},
3074 .num_clocks = 4,
3075 .hw_ex4_compat = 1,
3076};
3077
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003078static const struct of_device_id samsung_jpeg_match[] = {
3079 {
3080 .compatible = "samsung,s5pv210-jpeg",
3081 .data = &s5p_jpeg_drvdata,
3082 }, {
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003083 .compatible = "samsung,exynos3250-jpeg",
3084 .data = &exynos3250_jpeg_drvdata,
3085 }, {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003086 .compatible = "samsung,exynos4210-jpeg",
Jacek Anaszewski3246fda2014-07-11 12:19:42 -03003087 .data = &exynos4_jpeg_drvdata,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003088 }, {
3089 .compatible = "samsung,exynos4212-jpeg",
3090 .data = &exynos4_jpeg_drvdata,
Andrzej Pietrasiewicz7c15fd42015-03-09 09:32:46 -03003091 }, {
3092 .compatible = "samsung,exynos5420-jpeg",
3093 .data = &exynos5420_jpeg_drvdata,
Andrzej Pietrasiewicz6c96dbb2015-09-18 11:20:58 -03003094 }, {
3095 .compatible = "samsung,exynos5433-jpeg",
3096 .data = &exynos5433_jpeg_drvdata,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003097 },
3098 {},
3099};
3100
3101MODULE_DEVICE_TABLE(of, samsung_jpeg_match);
3102
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03003103static void *jpeg_get_drv_data(struct device *dev)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003104{
3105 struct s5p_jpeg_variant *driver_data = NULL;
3106 const struct of_device_id *match;
3107
Jacek Anaszewski79a38a82014-04-10 04:32:14 -03003108 if (!IS_ENABLED(CONFIG_OF) || !dev->of_node)
3109 return &s5p_jpeg_drvdata;
3110
3111 match = of_match_node(samsung_jpeg_match, dev->of_node);
3112
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003113 if (match)
3114 driver_data = (struct s5p_jpeg_variant *)match->data;
3115
3116 return driver_data;
3117}
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03003118
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003119static struct platform_driver s5p_jpeg_driver = {
3120 .probe = s5p_jpeg_probe,
3121 .remove = s5p_jpeg_remove,
3122 .driver = {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003123 .of_match_table = of_match_ptr(samsung_jpeg_match),
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003124 .name = S5P_JPEG_M2M_NAME,
3125 .pm = &s5p_jpeg_pm_ops,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003126 },
3127};
3128
Sachin Kamat87e94292012-07-03 05:54:33 -03003129module_platform_driver(s5p_jpeg_driver);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003130
3131MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03003132MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03003133MODULE_DESCRIPTION("Samsung JPEG codec driver");
3134MODULE_LICENSE("GPL");