blob: ea9cf737201b6524b02697c42237e1fc63084b0c [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 Anaszewski80529ae2013-12-18 11:04:44 -03003 * Copyright (c) 2011-2013 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>
29#include <media/videobuf2-core.h>
30#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"
35#include "jpeg-regs.h"
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030036
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030037static struct s5p_jpeg_fmt sjpeg_formats[] = {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030038 {
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -030039 .name = "JPEG JFIF",
40 .fourcc = V4L2_PIX_FMT_JPEG,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030041 .flags = SJPEG_FMT_FLAG_ENC_CAPTURE |
42 SJPEG_FMT_FLAG_DEC_OUTPUT |
43 SJPEG_FMT_FLAG_S5P |
44 SJPEG_FMT_FLAG_EXYNOS4,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030045 },
46 {
47 .name = "YUV 4:2:2 packed, YCbYCr",
48 .fourcc = V4L2_PIX_FMT_YUYV,
49 .depth = 16,
50 .colplanes = 1,
51 .h_align = 4,
52 .v_align = 3,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030053 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
54 SJPEG_FMT_FLAG_DEC_CAPTURE |
55 SJPEG_FMT_FLAG_S5P |
56 SJPEG_FMT_NON_RGB,
57 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030058 },
59 {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030060 .name = "YUV 4:2:2 packed, YCbYCr",
61 .fourcc = V4L2_PIX_FMT_YUYV,
62 .depth = 16,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -030063 .colplanes = 1,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -030064 .h_align = 1,
65 .v_align = 0,
66 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
67 SJPEG_FMT_FLAG_DEC_CAPTURE |
68 SJPEG_FMT_FLAG_EXYNOS4 |
69 SJPEG_FMT_NON_RGB,
70 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
71 },
72 {
73 .name = "YUV 4:2:2 packed, YCrYCb",
74 .fourcc = V4L2_PIX_FMT_YVYU,
75 .depth = 16,
76 .colplanes = 1,
77 .h_align = 1,
78 .v_align = 0,
79 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
80 SJPEG_FMT_FLAG_DEC_CAPTURE |
81 SJPEG_FMT_FLAG_EXYNOS4 |
82 SJPEG_FMT_NON_RGB,
83 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
84 },
85 {
86 .name = "RGB565",
87 .fourcc = V4L2_PIX_FMT_RGB565,
88 .depth = 16,
89 .colplanes = 1,
90 .h_align = 0,
91 .v_align = 0,
92 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
93 SJPEG_FMT_FLAG_DEC_CAPTURE |
94 SJPEG_FMT_FLAG_EXYNOS4 |
95 SJPEG_FMT_RGB,
96 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
97 },
98 {
99 .name = "RGB565",
100 .fourcc = V4L2_PIX_FMT_RGB565,
101 .depth = 16,
102 .colplanes = 1,
103 .h_align = 0,
104 .v_align = 0,
105 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
106 SJPEG_FMT_FLAG_S5P |
107 SJPEG_FMT_RGB,
108 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
109 },
110 {
111 .name = "ARGB8888, 32 bpp",
112 .fourcc = V4L2_PIX_FMT_RGB32,
113 .depth = 32,
114 .colplanes = 1,
115 .h_align = 0,
116 .v_align = 0,
117 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
118 SJPEG_FMT_FLAG_DEC_CAPTURE |
119 SJPEG_FMT_FLAG_EXYNOS4 |
120 SJPEG_FMT_RGB,
121 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
122 },
123 {
124 .name = "YUV 4:4:4 planar, Y/CbCr",
125 .fourcc = V4L2_PIX_FMT_NV24,
126 .depth = 24,
127 .colplanes = 2,
128 .h_align = 0,
129 .v_align = 0,
130 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
131 SJPEG_FMT_FLAG_DEC_CAPTURE |
132 SJPEG_FMT_FLAG_EXYNOS4 |
133 SJPEG_FMT_NON_RGB,
134 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
135 },
136 {
137 .name = "YUV 4:4:4 planar, Y/CrCb",
138 .fourcc = V4L2_PIX_FMT_NV42,
139 .depth = 24,
140 .colplanes = 2,
141 .h_align = 0,
142 .v_align = 0,
143 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
144 SJPEG_FMT_FLAG_DEC_CAPTURE |
145 SJPEG_FMT_FLAG_EXYNOS4 |
146 SJPEG_FMT_NON_RGB,
147 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
148 },
149 {
150 .name = "YUV 4:2:2 planar, Y/CrCb",
151 .fourcc = V4L2_PIX_FMT_NV61,
152 .depth = 16,
153 .colplanes = 2,
154 .h_align = 1,
155 .v_align = 0,
156 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
157 SJPEG_FMT_FLAG_DEC_CAPTURE |
158 SJPEG_FMT_FLAG_EXYNOS4 |
159 SJPEG_FMT_NON_RGB,
160 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
161 },
162 {
163 .name = "YUV 4:2:2 planar, Y/CbCr",
164 .fourcc = V4L2_PIX_FMT_NV16,
165 .depth = 16,
166 .colplanes = 2,
167 .h_align = 1,
168 .v_align = 0,
169 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
170 SJPEG_FMT_FLAG_DEC_CAPTURE |
171 SJPEG_FMT_FLAG_EXYNOS4 |
172 SJPEG_FMT_NON_RGB,
173 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
174 },
175 {
176 .name = "YUV 4:2:0 planar, Y/CbCr",
177 .fourcc = V4L2_PIX_FMT_NV12,
178 .depth = 16,
179 .colplanes = 2,
180 .h_align = 1,
181 .v_align = 1,
182 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
183 SJPEG_FMT_FLAG_DEC_CAPTURE |
184 SJPEG_FMT_FLAG_EXYNOS4 |
185 SJPEG_FMT_NON_RGB,
186 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
187 },
188 {
189 .name = "YUV 4:2:0 planar, Y/CbCr",
190 .fourcc = V4L2_PIX_FMT_NV12,
191 .depth = 16,
192 .colplanes = 4,
193 .h_align = 4,
194 .v_align = 1,
195 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
196 SJPEG_FMT_FLAG_DEC_CAPTURE |
197 SJPEG_FMT_FLAG_S5P |
198 SJPEG_FMT_NON_RGB,
199 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
200 },
201 {
202 .name = "YUV 4:2:0 planar, Y/CrCb",
203 .fourcc = V4L2_PIX_FMT_NV21,
204 .depth = 12,
205 .colplanes = 2,
206 .h_align = 1,
207 .v_align = 1,
208 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
209 SJPEG_FMT_FLAG_DEC_CAPTURE |
210 SJPEG_FMT_FLAG_EXYNOS4 |
211 SJPEG_FMT_NON_RGB,
212 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
213 },
214 {
215 .name = "YUV 4:2:0 contiguous 3-planar, Y/Cb/Cr",
216 .fourcc = V4L2_PIX_FMT_YUV420,
217 .depth = 12,
218 .colplanes = 3,
219 .h_align = 1,
220 .v_align = 1,
221 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
222 SJPEG_FMT_FLAG_DEC_CAPTURE |
223 SJPEG_FMT_FLAG_EXYNOS4 |
224 SJPEG_FMT_NON_RGB,
225 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
226 },
227 {
228 .name = "Gray",
229 .fourcc = V4L2_PIX_FMT_GREY,
230 .depth = 8,
231 .colplanes = 1,
232 .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
233 SJPEG_FMT_FLAG_DEC_CAPTURE |
234 SJPEG_FMT_FLAG_EXYNOS4 |
235 SJPEG_FMT_NON_RGB,
236 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300237 },
238};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300239#define SJPEG_NUM_FORMATS ARRAY_SIZE(sjpeg_formats)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300240
241static const unsigned char qtbl_luminance[4][64] = {
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300242 {/*level 0 - high compression quality */
243 20, 16, 25, 39, 50, 46, 62, 68,
244 16, 18, 23, 38, 38, 53, 65, 68,
245 25, 23, 31, 38, 53, 65, 68, 68,
246 39, 38, 38, 53, 65, 68, 68, 68,
247 50, 38, 53, 65, 68, 68, 68, 68,
248 46, 53, 65, 68, 68, 68, 68, 68,
249 62, 65, 68, 68, 68, 68, 68, 68,
250 68, 68, 68, 68, 68, 68, 68, 68
251 },
252 {/* level 1 */
253 16, 11, 11, 16, 23, 27, 31, 30,
254 11, 12, 12, 15, 20, 23, 23, 30,
255 11, 12, 13, 16, 23, 26, 35, 47,
256 16, 15, 16, 23, 26, 37, 47, 64,
257 23, 20, 23, 26, 39, 51, 64, 64,
258 27, 23, 26, 37, 51, 64, 64, 64,
259 31, 23, 35, 47, 64, 64, 64, 64,
260 30, 30, 47, 64, 64, 64, 64, 64
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300261 },
262 {/* level 2 */
263 12, 8, 8, 12, 17, 21, 24, 23,
264 8, 9, 9, 11, 15, 19, 18, 23,
265 8, 9, 10, 12, 19, 20, 27, 36,
266 12, 11, 12, 21, 20, 28, 36, 53,
267 17, 15, 19, 20, 30, 39, 51, 59,
268 21, 19, 20, 28, 39, 51, 59, 59,
269 24, 18, 27, 36, 51, 59, 59, 59,
270 23, 23, 36, 53, 59, 59, 59, 59
271 },
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300272 {/* level 3 - low compression quality */
273 8, 6, 6, 8, 12, 14, 16, 17,
274 6, 6, 6, 8, 10, 13, 12, 15,
275 6, 6, 7, 8, 13, 14, 18, 24,
276 8, 8, 8, 14, 13, 19, 24, 35,
277 12, 10, 13, 13, 20, 26, 34, 39,
278 14, 13, 14, 19, 26, 34, 39, 39,
279 16, 12, 18, 24, 34, 39, 39, 39,
280 17, 15, 24, 35, 39, 39, 39, 39
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300281 }
282};
283
284static const unsigned char qtbl_chrominance[4][64] = {
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300285 {/*level 0 - high compression quality */
286 21, 25, 32, 38, 54, 68, 68, 68,
287 25, 28, 24, 38, 54, 68, 68, 68,
288 32, 24, 32, 43, 66, 68, 68, 68,
289 38, 38, 43, 53, 68, 68, 68, 68,
290 54, 54, 66, 68, 68, 68, 68, 68,
291 68, 68, 68, 68, 68, 68, 68, 68,
292 68, 68, 68, 68, 68, 68, 68, 68,
293 68, 68, 68, 68, 68, 68, 68, 68
294 },
295 {/* level 1 */
296 17, 15, 17, 21, 20, 26, 38, 48,
297 15, 19, 18, 17, 20, 26, 35, 43,
298 17, 18, 20, 22, 26, 30, 46, 53,
299 21, 17, 22, 28, 30, 39, 53, 64,
300 20, 20, 26, 30, 39, 48, 64, 64,
301 26, 26, 30, 39, 48, 63, 64, 64,
302 38, 35, 46, 53, 64, 64, 64, 64,
303 48, 43, 53, 64, 64, 64, 64, 64
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300304 },
305 {/* level 2 */
306 13, 11, 13, 16, 20, 20, 29, 37,
307 11, 14, 14, 14, 16, 20, 26, 32,
308 13, 14, 15, 17, 20, 23, 35, 40,
309 16, 14, 17, 21, 23, 30, 40, 50,
310 20, 16, 20, 23, 30, 37, 50, 59,
311 20, 20, 23, 30, 37, 48, 59, 59,
312 29, 26, 35, 40, 50, 59, 59, 59,
313 37, 32, 40, 50, 59, 59, 59, 59
314 },
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -0300315 {/* level 3 - low compression quality */
316 9, 8, 9, 11, 14, 17, 19, 24,
317 8, 10, 9, 11, 14, 13, 17, 22,
318 9, 9, 13, 14, 13, 15, 23, 26,
319 11, 11, 14, 14, 15, 20, 26, 33,
320 14, 14, 13, 15, 20, 24, 33, 39,
321 17, 13, 15, 20, 24, 32, 39, 39,
322 19, 17, 23, 26, 33, 39, 39, 39,
323 24, 22, 26, 33, 39, 39, 39, 39
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300324 }
325};
326
327static const unsigned char hdctbl0[16] = {
328 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
329};
330
331static const unsigned char hdctblg0[12] = {
332 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb
333};
334static const unsigned char hactbl0[16] = {
335 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
336};
337static const unsigned char hactblg0[162] = {
338 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
339 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
340 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
341 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
342 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
343 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
344 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
345 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
346 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
347 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
348 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
349 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
350 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
351 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
352 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
353 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
354 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
355 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
356 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
357 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
358 0xf9, 0xfa
359};
360
Jacek Anaszewski337777a2013-11-22 06:13:34 -0300361/*
362 * Fourcc downgrade schema lookup tables for 422 and 420
363 * chroma subsampling - fourcc on each position maps on the
364 * fourcc from the table fourcc_to_dwngrd_schema_id which allows
365 * to get the most suitable fourcc counterpart for the given
366 * downgraded subsampling property.
367 */
368static const u32 subs422_fourcc_dwngrd_schema[] = {
369 V4L2_PIX_FMT_NV16,
370 V4L2_PIX_FMT_NV61,
371};
372
373static const u32 subs420_fourcc_dwngrd_schema[] = {
374 V4L2_PIX_FMT_NV12,
375 V4L2_PIX_FMT_NV21,
376 V4L2_PIX_FMT_NV12,
377 V4L2_PIX_FMT_NV21,
378 V4L2_PIX_FMT_NV12,
379 V4L2_PIX_FMT_NV21,
380 V4L2_PIX_FMT_GREY,
381 V4L2_PIX_FMT_GREY,
382 V4L2_PIX_FMT_GREY,
383 V4L2_PIX_FMT_GREY,
384};
385
386/*
387 * Lookup table for translation of a fourcc to the position
388 * of its downgraded counterpart in the *fourcc_dwngrd_schema
389 * tables.
390 */
391static const u32 fourcc_to_dwngrd_schema_id[] = {
392 V4L2_PIX_FMT_NV24,
393 V4L2_PIX_FMT_NV42,
394 V4L2_PIX_FMT_NV16,
395 V4L2_PIX_FMT_NV61,
396 V4L2_PIX_FMT_YUYV,
397 V4L2_PIX_FMT_YVYU,
398 V4L2_PIX_FMT_NV12,
399 V4L2_PIX_FMT_NV21,
400 V4L2_PIX_FMT_YUV420,
401 V4L2_PIX_FMT_GREY,
402};
403
404static int s5p_jpeg_get_dwngrd_sch_id_by_fourcc(u32 fourcc)
405{
406 int i;
407 for (i = 0; i < ARRAY_SIZE(fourcc_to_dwngrd_schema_id); ++i) {
408 if (fourcc_to_dwngrd_schema_id[i] == fourcc)
409 return i;
410 }
411
412 return -EINVAL;
413}
414
415static int s5p_jpeg_adjust_fourcc_to_subsampling(
416 enum v4l2_jpeg_chroma_subsampling subs,
417 u32 in_fourcc,
418 u32 *out_fourcc,
419 struct s5p_jpeg_ctx *ctx)
420{
421 int dwngrd_sch_id;
422
423 if (ctx->subsampling != V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY) {
424 dwngrd_sch_id =
425 s5p_jpeg_get_dwngrd_sch_id_by_fourcc(in_fourcc);
426 if (dwngrd_sch_id < 0)
427 return -EINVAL;
428 }
429
430 switch (ctx->subsampling) {
431 case V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY:
432 *out_fourcc = V4L2_PIX_FMT_GREY;
433 break;
434 case V4L2_JPEG_CHROMA_SUBSAMPLING_420:
435 if (dwngrd_sch_id >
436 ARRAY_SIZE(subs420_fourcc_dwngrd_schema) - 1)
437 return -EINVAL;
438 *out_fourcc = subs420_fourcc_dwngrd_schema[dwngrd_sch_id];
439 break;
440 case V4L2_JPEG_CHROMA_SUBSAMPLING_422:
441 if (dwngrd_sch_id >
442 ARRAY_SIZE(subs422_fourcc_dwngrd_schema) - 1)
443 return -EINVAL;
444 *out_fourcc = subs422_fourcc_dwngrd_schema[dwngrd_sch_id];
445 break;
446 default:
447 *out_fourcc = V4L2_PIX_FMT_GREY;
448 break;
449 }
450
451 return 0;
452}
453
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300454static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c)
455{
456 return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler);
457}
458
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300459static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh)
460{
461 return container_of(fh, struct s5p_jpeg_ctx, fh);
462}
463
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300464static inline void s5p_jpeg_set_qtbl(void __iomem *regs,
465 const unsigned char *qtbl,
466 unsigned long tab, int len)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300467{
468 int i;
469
470 for (i = 0; i < len; i++)
471 writel((unsigned int)qtbl[i], regs + tab + (i * 0x04));
472}
473
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300474static inline void s5p_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300475{
476 /* this driver fills quantisation table 0 with data for luma */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300477 s5p_jpeg_set_qtbl(regs, qtbl_luminance[quality],
478 S5P_JPG_QTBL_CONTENT(0),
479 ARRAY_SIZE(qtbl_luminance[quality]));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300480}
481
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300482static inline void s5p_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300483{
484 /* this driver fills quantisation table 1 with data for chroma */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300485 s5p_jpeg_set_qtbl(regs, qtbl_chrominance[quality],
486 S5P_JPG_QTBL_CONTENT(1),
487 ARRAY_SIZE(qtbl_chrominance[quality]));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300488}
489
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300490static inline void s5p_jpeg_set_htbl(void __iomem *regs,
491 const unsigned char *htbl,
492 unsigned long tab, int len)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300493{
494 int i;
495
496 for (i = 0; i < len; i++)
497 writel((unsigned int)htbl[i], regs + tab + (i * 0x04));
498}
499
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300500static inline void s5p_jpeg_set_hdctbl(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300501{
502 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300503 s5p_jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0),
504 ARRAY_SIZE(hdctbl0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300505}
506
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300507static inline void s5p_jpeg_set_hdctblg(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300508{
509 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300510 s5p_jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0),
511 ARRAY_SIZE(hdctblg0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300512}
513
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300514static inline void s5p_jpeg_set_hactbl(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300515{
516 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300517 s5p_jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0),
518 ARRAY_SIZE(hactbl0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300519}
520
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300521static inline void s5p_jpeg_set_hactblg(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300522{
523 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300524 s5p_jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0),
525 ARRAY_SIZE(hactblg0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300526}
527
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300528static inline void exynos4_jpeg_set_tbl(void __iomem *regs,
529 const unsigned char *tbl,
530 unsigned long tab, int len)
531{
532 int i;
533 unsigned int dword;
534
535 for (i = 0; i < len; i += 4) {
536 dword = tbl[i] |
537 (tbl[i + 1] << 8) |
538 (tbl[i + 2] << 16) |
539 (tbl[i + 3] << 24);
540 writel(dword, regs + tab + i);
541 }
542}
543
544static inline void exynos4_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
545{
546 /* this driver fills quantisation table 0 with data for luma */
547 exynos4_jpeg_set_tbl(regs, qtbl_luminance[quality],
548 EXYNOS4_QTBL_CONTENT(0),
549 ARRAY_SIZE(qtbl_luminance[quality]));
550}
551
552static inline void exynos4_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
553{
554 /* this driver fills quantisation table 1 with data for chroma */
555 exynos4_jpeg_set_tbl(regs, qtbl_chrominance[quality],
556 EXYNOS4_QTBL_CONTENT(1),
557 ARRAY_SIZE(qtbl_chrominance[quality]));
558}
559
560void exynos4_jpeg_set_huff_tbl(void __iomem *base)
561{
562 exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCLL,
563 ARRAY_SIZE(hdctbl0));
564 exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCCL,
565 ARRAY_SIZE(hdctbl0));
566 exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCLV,
567 ARRAY_SIZE(hdctblg0));
568 exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCCV,
569 ARRAY_SIZE(hdctblg0));
570 exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACLL,
571 ARRAY_SIZE(hactbl0));
572 exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACCL,
573 ARRAY_SIZE(hactbl0));
574 exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACLV,
575 ARRAY_SIZE(hactblg0));
576 exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACCV,
577 ARRAY_SIZE(hactblg0));
578}
579
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300580/*
581 * ============================================================================
582 * Device file operations
583 * ============================================================================
584 */
585
586static int queue_init(void *priv, struct vb2_queue *src_vq,
587 struct vb2_queue *dst_vq);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300588static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
589 __u32 pixelformat, unsigned int fmt_type);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300590static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300591
592static int s5p_jpeg_open(struct file *file)
593{
594 struct s5p_jpeg *jpeg = video_drvdata(file);
595 struct video_device *vfd = video_devdata(file);
596 struct s5p_jpeg_ctx *ctx;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300597 struct s5p_jpeg_fmt *out_fmt, *cap_fmt;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300598 int ret = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300599
Sachin Kamatb5146c92012-08-16 08:52:58 -0300600 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300601 if (!ctx)
602 return -ENOMEM;
603
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300604 if (mutex_lock_interruptible(&jpeg->lock)) {
605 ret = -ERESTARTSYS;
606 goto free;
607 }
608
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300609 v4l2_fh_init(&ctx->fh, vfd);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300610 /* Use separate control handler per file handle */
611 ctx->fh.ctrl_handler = &ctx->ctrl_handler;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300612 file->private_data = &ctx->fh;
613 v4l2_fh_add(&ctx->fh);
614
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300615 ctx->jpeg = jpeg;
616 if (vfd == jpeg->vfd_encoder) {
617 ctx->mode = S5P_JPEG_ENCODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300618 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB565,
619 FMT_TYPE_OUTPUT);
620 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
621 FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300622 } else {
623 ctx->mode = S5P_JPEG_DECODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300624 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
625 FMT_TYPE_OUTPUT);
626 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_YUYV,
627 FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300628 }
629
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300630 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
631 if (IS_ERR(ctx->fh.m2m_ctx)) {
632 ret = PTR_ERR(ctx->fh.m2m_ctx);
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300633 goto error;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300634 }
635
636 ctx->out_q.fmt = out_fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300637 ctx->cap_q.fmt = cap_fmt;
638
639 ret = s5p_jpeg_controls_create(ctx);
640 if (ret < 0)
641 goto error;
642
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300643 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300644 return 0;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300645
646error:
647 v4l2_fh_del(&ctx->fh);
648 v4l2_fh_exit(&ctx->fh);
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300649 mutex_unlock(&jpeg->lock);
650free:
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300651 kfree(ctx);
652 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300653}
654
655static int s5p_jpeg_release(struct file *file)
656{
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300657 struct s5p_jpeg *jpeg = video_drvdata(file);
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300658 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300659
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300660 mutex_lock(&jpeg->lock);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300661 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300662 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300663 v4l2_fh_del(&ctx->fh);
664 v4l2_fh_exit(&ctx->fh);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300665 kfree(ctx);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300666 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300667
668 return 0;
669}
670
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300671static const struct v4l2_file_operations s5p_jpeg_fops = {
672 .owner = THIS_MODULE,
673 .open = s5p_jpeg_open,
674 .release = s5p_jpeg_release,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300675 .poll = v4l2_m2m_fop_poll,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300676 .unlocked_ioctl = video_ioctl2,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300677 .mmap = v4l2_m2m_fop_mmap,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300678};
679
680/*
681 * ============================================================================
682 * video ioctl operations
683 * ============================================================================
684 */
685
686static int get_byte(struct s5p_jpeg_buffer *buf)
687{
688 if (buf->curr >= buf->size)
689 return -1;
690
691 return ((unsigned char *)buf->data)[buf->curr++];
692}
693
694static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word)
695{
696 unsigned int temp;
697 int byte;
698
699 byte = get_byte(buf);
700 if (byte == -1)
701 return -1;
702 temp = byte << 8;
703 byte = get_byte(buf);
704 if (byte == -1)
705 return -1;
706 *word = (unsigned int)byte | temp;
707 return 0;
708}
709
710static void skip(struct s5p_jpeg_buffer *buf, long len)
711{
712 if (len <= 0)
713 return;
714
715 while (len--)
716 get_byte(buf);
717}
718
719static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300720 unsigned long buffer, unsigned long size,
721 struct s5p_jpeg_ctx *ctx)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300722{
723 int c, components, notfound;
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300724 unsigned int height, width, word, subsampling = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300725 long length;
726 struct s5p_jpeg_buffer jpeg_buffer;
727
728 jpeg_buffer.size = size;
729 jpeg_buffer.data = buffer;
730 jpeg_buffer.curr = 0;
731
732 notfound = 1;
733 while (notfound) {
734 c = get_byte(&jpeg_buffer);
735 if (c == -1)
736 break;
737 if (c != 0xff)
738 continue;
739 do
740 c = get_byte(&jpeg_buffer);
741 while (c == 0xff);
742 if (c == -1)
743 break;
744 if (c == 0)
745 continue;
746 length = 0;
747 switch (c) {
748 /* SOF0: baseline JPEG */
749 case SOF0:
750 if (get_word_be(&jpeg_buffer, &word))
751 break;
752 if (get_byte(&jpeg_buffer) == -1)
753 break;
754 if (get_word_be(&jpeg_buffer, &height))
755 break;
756 if (get_word_be(&jpeg_buffer, &width))
757 break;
758 components = get_byte(&jpeg_buffer);
759 if (components == -1)
760 break;
761 notfound = 0;
762
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300763 if (components == 1) {
764 subsampling = 0x33;
765 } else {
766 skip(&jpeg_buffer, 1);
767 subsampling = get_byte(&jpeg_buffer);
768 skip(&jpeg_buffer, 1);
769 }
770
771 skip(&jpeg_buffer, components * 2);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300772 break;
773
774 /* skip payload-less markers */
775 case RST ... RST + 7:
776 case SOI:
777 case EOI:
778 case TEM:
779 break;
780
781 /* skip uninteresting payload markers */
782 default:
783 if (get_word_be(&jpeg_buffer, &word))
784 break;
785 length = (long)word - 2;
786 skip(&jpeg_buffer, length);
787 break;
788 }
789 }
790 result->w = width;
791 result->h = height;
792 result->size = components;
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300793
794 switch (subsampling) {
795 case 0x11:
796 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444;
797 break;
798 case 0x21:
799 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422;
800 break;
801 case 0x22:
802 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420;
803 break;
804 case 0x33:
805 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
806 break;
807 default:
808 return false;
809 }
810
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300811 return !notfound;
812}
813
814static int s5p_jpeg_querycap(struct file *file, void *priv,
815 struct v4l2_capability *cap)
816{
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300817 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300818
819 if (ctx->mode == S5P_JPEG_ENCODE) {
820 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder",
821 sizeof(cap->driver));
822 strlcpy(cap->card, S5P_JPEG_M2M_NAME " encoder",
823 sizeof(cap->card));
824 } else {
825 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " decoder",
826 sizeof(cap->driver));
827 strlcpy(cap->card, S5P_JPEG_M2M_NAME " decoder",
828 sizeof(cap->card));
829 }
830 cap->bus_info[0] = 0;
Sylwester Nawrockif0476a82012-07-26 09:30:00 -0300831 /*
832 * This is only a mem-to-mem video device. The capture and output
833 * device capability flags are left only for backward compatibility
834 * and are scheduled for removal.
835 */
836 cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M |
837 V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300838 return 0;
839}
840
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300841static int enum_fmt(struct s5p_jpeg_fmt *sjpeg_formats, int n,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300842 struct v4l2_fmtdesc *f, u32 type)
843{
844 int i, num = 0;
845
846 for (i = 0; i < n; ++i) {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300847 if (sjpeg_formats[i].flags & type) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300848 /* index-th format of type type found ? */
849 if (num == f->index)
850 break;
851 /* Correct type but haven't reached our index yet,
852 * just increment per-type index */
853 ++num;
854 }
855 }
856
857 /* Format not found */
858 if (i >= n)
859 return -EINVAL;
860
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300861 strlcpy(f->description, sjpeg_formats[i].name, sizeof(f->description));
862 f->pixelformat = sjpeg_formats[i].fourcc;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300863
864 return 0;
865}
866
867static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
868 struct v4l2_fmtdesc *f)
869{
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300870 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300871
872 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300873 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
874 SJPEG_FMT_FLAG_ENC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300875
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300876 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
877 SJPEG_FMT_FLAG_DEC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300878}
879
880static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
881 struct v4l2_fmtdesc *f)
882{
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300883 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300884
885 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300886 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
887 SJPEG_FMT_FLAG_ENC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300888
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300889 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
890 SJPEG_FMT_FLAG_DEC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300891}
892
893static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx,
894 enum v4l2_buf_type type)
895{
896 if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
897 return &ctx->out_q;
898 if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
899 return &ctx->cap_q;
900
901 return NULL;
902}
903
904static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
905{
906 struct vb2_queue *vq;
907 struct s5p_jpeg_q_data *q_data = NULL;
908 struct v4l2_pix_format *pix = &f->fmt.pix;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300909 struct s5p_jpeg_ctx *ct = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300910
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300911 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300912 if (!vq)
913 return -EINVAL;
914
915 if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
916 ct->mode == S5P_JPEG_DECODE && !ct->hdr_parsed)
917 return -EINVAL;
918 q_data = get_q_data(ct, f->type);
919 BUG_ON(q_data == NULL);
920
921 pix->width = q_data->w;
922 pix->height = q_data->h;
923 pix->field = V4L2_FIELD_NONE;
924 pix->pixelformat = q_data->fmt->fourcc;
925 pix->bytesperline = 0;
926 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
927 u32 bpl = q_data->w;
928 if (q_data->fmt->colplanes == 1)
929 bpl = (bpl * q_data->fmt->depth) >> 3;
930 pix->bytesperline = bpl;
931 }
932 pix->sizeimage = q_data->size;
933
934 return 0;
935}
936
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300937static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
938 u32 pixelformat, unsigned int fmt_type)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300939{
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300940 unsigned int k, fmt_flag, ver_flag;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300941
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300942 if (ctx->mode == S5P_JPEG_ENCODE)
943 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
944 SJPEG_FMT_FLAG_ENC_OUTPUT :
945 SJPEG_FMT_FLAG_ENC_CAPTURE;
946 else
947 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
948 SJPEG_FMT_FLAG_DEC_OUTPUT :
949 SJPEG_FMT_FLAG_DEC_CAPTURE;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300950
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300951 if (ctx->jpeg->variant->version == SJPEG_S5P)
952 ver_flag = SJPEG_FMT_FLAG_S5P;
953 else
954 ver_flag = SJPEG_FMT_FLAG_EXYNOS4;
955
956 for (k = 0; k < ARRAY_SIZE(sjpeg_formats); k++) {
957 struct s5p_jpeg_fmt *fmt = &sjpeg_formats[k];
958 if (fmt->fourcc == pixelformat &&
959 fmt->flags & fmt_flag &&
960 fmt->flags & ver_flag) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300961 return fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300962 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300963 }
964
965 return NULL;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300966}
967
968static void jpeg_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
969 unsigned int walign,
970 u32 *h, unsigned int hmin, unsigned int hmax,
971 unsigned int halign)
972{
973 int width, height, w_step, h_step;
974
975 width = *w;
976 height = *h;
977
978 w_step = 1 << walign;
979 h_step = 1 << halign;
980 v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
981
982 if (*w < width && (*w + w_step) < wmax)
983 *w += w_step;
984 if (*h < height && (*h + h_step) < hmax)
985 *h += h_step;
986
987}
988
989static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
990 struct s5p_jpeg_ctx *ctx, int q_type)
991{
992 struct v4l2_pix_format *pix = &f->fmt.pix;
993
994 if (pix->field == V4L2_FIELD_ANY)
995 pix->field = V4L2_FIELD_NONE;
996 else if (pix->field != V4L2_FIELD_NONE)
997 return -EINVAL;
998
999 /* V4L2 specification suggests the driver corrects the format struct
1000 * if any of the dimensions is unsupported */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001001 if (q_type == FMT_TYPE_OUTPUT)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001002 jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
1003 S5P_JPEG_MAX_WIDTH, 0,
1004 &pix->height, S5P_JPEG_MIN_HEIGHT,
1005 S5P_JPEG_MAX_HEIGHT, 0);
1006 else
1007 jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
1008 S5P_JPEG_MAX_WIDTH, fmt->h_align,
1009 &pix->height, S5P_JPEG_MIN_HEIGHT,
1010 S5P_JPEG_MAX_HEIGHT, fmt->v_align);
1011
1012 if (fmt->fourcc == V4L2_PIX_FMT_JPEG) {
1013 if (pix->sizeimage <= 0)
1014 pix->sizeimage = PAGE_SIZE;
1015 pix->bytesperline = 0;
1016 } else {
1017 u32 bpl = pix->bytesperline;
1018
1019 if (fmt->colplanes > 1 && bpl < pix->width)
1020 bpl = pix->width; /* planar */
1021
1022 if (fmt->colplanes == 1 && /* packed */
Jacek Anaszewskicc690902013-11-25 06:58:10 -03001023 (bpl << 3) / fmt->depth < pix->width)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001024 bpl = (pix->width * fmt->depth) >> 3;
1025
1026 pix->bytesperline = bpl;
1027 pix->sizeimage = (pix->width * pix->height * fmt->depth) >> 3;
1028 }
1029
1030 return 0;
1031}
1032
1033static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
1034 struct v4l2_format *f)
1035{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001036 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001037 struct v4l2_pix_format *pix = &f->fmt.pix;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001038 struct s5p_jpeg_fmt *fmt;
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001039 int ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001040
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001041 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
1042 FMT_TYPE_CAPTURE);
1043 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001044 v4l2_err(&ctx->jpeg->v4l2_dev,
1045 "Fourcc format (0x%08x) invalid.\n",
1046 f->fmt.pix.pixelformat);
1047 return -EINVAL;
1048 }
1049
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001050 /*
1051 * The exynos4x12 device requires resulting YUV image
1052 * subsampling not to be lower than the input jpeg subsampling.
1053 * If this requirement is not met then downgrade the requested
1054 * capture format to the one with subsampling equal to the input jpeg.
1055 */
1056 if ((ctx->jpeg->variant->version != SJPEG_S5P) &&
1057 (ctx->mode == S5P_JPEG_DECODE) &&
1058 (fmt->flags & SJPEG_FMT_NON_RGB) &&
1059 (fmt->subsampling < ctx->subsampling)) {
1060 ret = s5p_jpeg_adjust_fourcc_to_subsampling(ctx->subsampling,
1061 fmt->fourcc,
1062 &pix->pixelformat,
1063 ctx);
1064 if (ret < 0)
1065 pix->pixelformat = V4L2_PIX_FMT_GREY;
1066
1067 fmt = s5p_jpeg_find_format(ctx, pix->pixelformat,
1068 FMT_TYPE_CAPTURE);
1069 }
1070
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001071 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001072}
1073
1074static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
1075 struct v4l2_format *f)
1076{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001077 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001078 struct s5p_jpeg_fmt *fmt;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001079
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001080 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
1081 FMT_TYPE_OUTPUT);
1082 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001083 v4l2_err(&ctx->jpeg->v4l2_dev,
1084 "Fourcc format (0x%08x) invalid.\n",
1085 f->fmt.pix.pixelformat);
1086 return -EINVAL;
1087 }
1088
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001089 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001090}
1091
1092static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
1093{
1094 struct vb2_queue *vq;
1095 struct s5p_jpeg_q_data *q_data = NULL;
1096 struct v4l2_pix_format *pix = &f->fmt.pix;
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001097 struct v4l2_ctrl *ctrl_subs;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001098 unsigned int f_type;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001099
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001100 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001101 if (!vq)
1102 return -EINVAL;
1103
1104 q_data = get_q_data(ct, f->type);
1105 BUG_ON(q_data == NULL);
1106
1107 if (vb2_is_busy(vq)) {
1108 v4l2_err(&ct->jpeg->v4l2_dev, "%s queue busy\n", __func__);
1109 return -EBUSY;
1110 }
1111
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001112 f_type = V4L2_TYPE_IS_OUTPUT(f->type) ?
1113 FMT_TYPE_OUTPUT : FMT_TYPE_CAPTURE;
1114
1115 q_data->fmt = s5p_jpeg_find_format(ct, pix->pixelformat, f_type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001116 q_data->w = pix->width;
1117 q_data->h = pix->height;
1118 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG)
1119 q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3;
1120 else
1121 q_data->size = pix->sizeimage;
1122
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001123 if (f_type == FMT_TYPE_OUTPUT) {
1124 ctrl_subs = v4l2_ctrl_find(&ct->ctrl_handler,
1125 V4L2_CID_JPEG_CHROMA_SUBSAMPLING);
1126 if (ctrl_subs)
1127 v4l2_ctrl_s_ctrl(ctrl_subs, q_data->fmt->subsampling);
1128 }
1129
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001130 return 0;
1131}
1132
1133static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
1134 struct v4l2_format *f)
1135{
1136 int ret;
1137
1138 ret = s5p_jpeg_try_fmt_vid_cap(file, priv, f);
1139 if (ret)
1140 return ret;
1141
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001142 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001143}
1144
1145static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
1146 struct v4l2_format *f)
1147{
1148 int ret;
1149
1150 ret = s5p_jpeg_try_fmt_vid_out(file, priv, f);
1151 if (ret)
1152 return ret;
1153
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001154 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001155}
1156
Sachin Kamat9f3bd322012-05-10 03:38:40 -03001157static int s5p_jpeg_g_selection(struct file *file, void *priv,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001158 struct v4l2_selection *s)
1159{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001160 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001161
1162 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001163 s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
1164 ctx->jpeg->variant->version != SJPEG_S5P)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001165 return -EINVAL;
1166
1167 /* For JPEG blob active == default == bounds */
1168 switch (s->target) {
Sylwester Nawrockic1334822012-05-20 11:17:12 -03001169 case V4L2_SEL_TGT_CROP:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001170 case V4L2_SEL_TGT_CROP_BOUNDS:
1171 case V4L2_SEL_TGT_CROP_DEFAULT:
Sylwester Nawrockic1334822012-05-20 11:17:12 -03001172 case V4L2_SEL_TGT_COMPOSE:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001173 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
1174 s->r.width = ctx->out_q.w;
1175 s->r.height = ctx->out_q.h;
1176 break;
1177 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
1178 case V4L2_SEL_TGT_COMPOSE_PADDED:
1179 s->r.width = ctx->cap_q.w;
1180 s->r.height = ctx->cap_q.h;
1181 break;
1182 default:
1183 return -EINVAL;
1184 }
1185 s->r.left = 0;
1186 s->r.top = 0;
1187 return 0;
1188}
1189
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001190/*
1191 * V4L2 controls
1192 */
1193
1194static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001195{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001196 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1197 struct s5p_jpeg *jpeg = ctx->jpeg;
1198 unsigned long flags;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001199
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001200 switch (ctrl->id) {
1201 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1202 spin_lock_irqsave(&jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001203
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001204 WARN_ON(ctx->subsampling > S5P_SUBSAMPLING_MODE_GRAY);
1205 if (ctx->subsampling > 2)
1206 ctrl->val = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
1207 else
1208 ctrl->val = ctx->subsampling;
1209 spin_unlock_irqrestore(&jpeg->slock, flags);
1210 break;
1211 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001212
1213 return 0;
1214}
1215
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001216static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001217{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001218 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1219 unsigned long flags;
1220
1221 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1222
1223 switch (ctrl->id) {
1224 case V4L2_CID_JPEG_COMPRESSION_QUALITY:
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001225 ctx->compr_quality = ctrl->val;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001226 break;
1227 case V4L2_CID_JPEG_RESTART_INTERVAL:
1228 ctx->restart_interval = ctrl->val;
1229 break;
1230 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1231 ctx->subsampling = ctrl->val;
1232 break;
1233 }
1234
1235 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1236 return 0;
1237}
1238
1239static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
1240 .g_volatile_ctrl = s5p_jpeg_g_volatile_ctrl,
1241 .s_ctrl = s5p_jpeg_s_ctrl,
1242};
1243
1244static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
1245{
1246 unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */
1247 struct v4l2_ctrl *ctrl;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001248 int ret;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001249
1250 v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
1251
1252 if (ctx->mode == S5P_JPEG_ENCODE) {
1253 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1254 V4L2_CID_JPEG_COMPRESSION_QUALITY,
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001255 0, 3, 1, S5P_JPEG_COMPR_QUAL_WORST);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001256
1257 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1258 V4L2_CID_JPEG_RESTART_INTERVAL,
1259 0, 3, 0xffff, 0);
Jacek Anaszewskifdf9e2b2013-11-21 13:33:41 -03001260 if (ctx->jpeg->variant->version == SJPEG_S5P)
1261 mask = ~0x06; /* 422, 420 */
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001262 }
1263
1264 ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1265 V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
1266 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask,
1267 V4L2_JPEG_CHROMA_SUBSAMPLING_422);
1268
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001269 if (ctx->ctrl_handler.error) {
1270 ret = ctx->ctrl_handler.error;
1271 goto error_free;
1272 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001273
1274 if (ctx->mode == S5P_JPEG_DECODE)
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001275 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
1276 V4L2_CTRL_FLAG_READ_ONLY;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001277
1278 ret = v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
1279 if (ret < 0)
1280 goto error_free;
1281
1282 return ret;
1283
1284error_free:
1285 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
1286 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001287}
1288
1289static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
1290 .vidioc_querycap = s5p_jpeg_querycap,
1291
1292 .vidioc_enum_fmt_vid_cap = s5p_jpeg_enum_fmt_vid_cap,
1293 .vidioc_enum_fmt_vid_out = s5p_jpeg_enum_fmt_vid_out,
1294
1295 .vidioc_g_fmt_vid_cap = s5p_jpeg_g_fmt,
1296 .vidioc_g_fmt_vid_out = s5p_jpeg_g_fmt,
1297
1298 .vidioc_try_fmt_vid_cap = s5p_jpeg_try_fmt_vid_cap,
1299 .vidioc_try_fmt_vid_out = s5p_jpeg_try_fmt_vid_out,
1300
1301 .vidioc_s_fmt_vid_cap = s5p_jpeg_s_fmt_vid_cap,
1302 .vidioc_s_fmt_vid_out = s5p_jpeg_s_fmt_vid_out,
1303
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001304 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
1305 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
1306 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
1307 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001308
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001309 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
1310 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001311
1312 .vidioc_g_selection = s5p_jpeg_g_selection,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001313};
1314
1315/*
1316 * ============================================================================
1317 * mem2mem callbacks
1318 * ============================================================================
1319 */
1320
1321static void s5p_jpeg_device_run(void *priv)
1322{
1323 struct s5p_jpeg_ctx *ctx = priv;
1324 struct s5p_jpeg *jpeg = ctx->jpeg;
1325 struct vb2_buffer *src_buf, *dst_buf;
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001326 unsigned long src_addr, dst_addr, flags;
1327
1328 spin_lock_irqsave(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001329
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001330 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1331 dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001332 src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
1333 dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
1334
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001335 s5p_jpeg_reset(jpeg->regs);
1336 s5p_jpeg_poweron(jpeg->regs);
1337 s5p_jpeg_proc_mode(jpeg->regs, ctx->mode);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001338 if (ctx->mode == S5P_JPEG_ENCODE) {
1339 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001340 s5p_jpeg_input_raw_mode(jpeg->regs,
1341 S5P_JPEG_RAW_IN_565);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001342 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001343 s5p_jpeg_input_raw_mode(jpeg->regs,
1344 S5P_JPEG_RAW_IN_422);
1345 s5p_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
1346 s5p_jpeg_dri(jpeg->regs, ctx->restart_interval);
1347 s5p_jpeg_x(jpeg->regs, ctx->out_q.w);
1348 s5p_jpeg_y(jpeg->regs, ctx->out_q.h);
1349 s5p_jpeg_imgadr(jpeg->regs, src_addr);
1350 s5p_jpeg_jpgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001351
1352 /* ultimately comes from sizeimage from userspace */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001353 s5p_jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001354
1355 /* JPEG RGB to YCbCr conversion matrix */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001356 s5p_jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11);
1357 s5p_jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12);
1358 s5p_jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13);
1359 s5p_jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21);
1360 s5p_jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22);
1361 s5p_jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23);
1362 s5p_jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31);
1363 s5p_jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32);
1364 s5p_jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001365
1366 /*
1367 * JPEG IP allows storing 4 quantization tables
1368 * We fill table 0 for luma and table 1 for chroma
1369 */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03001370 s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
1371 s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001372 /* use table 0 for Y */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001373 s5p_jpeg_qtbl(jpeg->regs, 1, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001374 /* use table 1 for Cb and Cr*/
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001375 s5p_jpeg_qtbl(jpeg->regs, 2, 1);
1376 s5p_jpeg_qtbl(jpeg->regs, 3, 1);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001377
1378 /* Y, Cb, Cr use Huffman table 0 */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001379 s5p_jpeg_htbl_ac(jpeg->regs, 1);
1380 s5p_jpeg_htbl_dc(jpeg->regs, 1);
1381 s5p_jpeg_htbl_ac(jpeg->regs, 2);
1382 s5p_jpeg_htbl_dc(jpeg->regs, 2);
1383 s5p_jpeg_htbl_ac(jpeg->regs, 3);
1384 s5p_jpeg_htbl_dc(jpeg->regs, 3);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001385 } else { /* S5P_JPEG_DECODE */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001386 s5p_jpeg_rst_int_enable(jpeg->regs, true);
1387 s5p_jpeg_data_num_int_enable(jpeg->regs, true);
1388 s5p_jpeg_final_mcu_num_int_enable(jpeg->regs, true);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001389 if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001390 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001391 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001392 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420);
1393 s5p_jpeg_jpgadr(jpeg->regs, src_addr);
1394 s5p_jpeg_imgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001395 }
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001396
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001397 s5p_jpeg_start(jpeg->regs);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001398
1399 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001400}
1401
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001402static void exynos4_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
1403{
1404 struct s5p_jpeg *jpeg = ctx->jpeg;
1405 struct s5p_jpeg_fmt *fmt;
1406 struct vb2_buffer *vb;
1407 struct s5p_jpeg_addr jpeg_addr;
1408 u32 pix_size, padding_bytes = 0;
1409
1410 pix_size = ctx->cap_q.w * ctx->cap_q.h;
1411
1412 if (ctx->mode == S5P_JPEG_ENCODE) {
1413 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1414 fmt = ctx->out_q.fmt;
1415 if (ctx->out_q.w % 2 && fmt->h_align > 0)
1416 padding_bytes = ctx->out_q.h;
1417 } else {
1418 fmt = ctx->cap_q.fmt;
1419 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1420 }
1421
1422 jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
1423
1424 if (fmt->colplanes == 2) {
1425 jpeg_addr.cb = jpeg_addr.y + pix_size - padding_bytes;
1426 } else if (fmt->colplanes == 3) {
1427 jpeg_addr.cb = jpeg_addr.y + pix_size;
1428 if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
1429 jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
1430 else
1431 jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
1432 }
1433
1434 exynos4_jpeg_set_frame_buf_address(jpeg->regs, &jpeg_addr);
1435}
1436
1437static void exynos4_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
1438{
1439 struct s5p_jpeg *jpeg = ctx->jpeg;
1440 struct vb2_buffer *vb;
1441 unsigned int jpeg_addr = 0;
1442
1443 if (ctx->mode == S5P_JPEG_ENCODE)
1444 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1445 else
1446 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1447
1448 jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
1449 exynos4_jpeg_set_stream_buf_address(jpeg->regs, jpeg_addr);
1450}
1451
1452static void exynos4_jpeg_device_run(void *priv)
1453{
1454 struct s5p_jpeg_ctx *ctx = priv;
1455 struct s5p_jpeg *jpeg = ctx->jpeg;
1456 unsigned int bitstream_size;
1457 unsigned long flags;
1458
1459 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1460
1461 if (ctx->mode == S5P_JPEG_ENCODE) {
1462 exynos4_jpeg_sw_reset(jpeg->regs);
1463 exynos4_jpeg_set_interrupt(jpeg->regs);
1464 exynos4_jpeg_set_huf_table_enable(jpeg->regs, 1);
1465
1466 exynos4_jpeg_set_huff_tbl(jpeg->regs);
1467
1468 /*
1469 * JPEG IP allows storing 4 quantization tables
1470 * We fill table 0 for luma and table 1 for chroma
1471 */
1472 exynos4_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
1473 exynos4_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
1474
1475 exynos4_jpeg_set_encode_tbl_select(jpeg->regs,
1476 ctx->compr_quality);
1477 exynos4_jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w,
1478 ctx->cap_q.h);
1479
1480 exynos4_jpeg_set_enc_out_fmt(jpeg->regs, ctx->subsampling);
1481 exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->out_q.fmt->fourcc);
1482 exynos4_jpeg_set_img_addr(ctx);
1483 exynos4_jpeg_set_jpeg_addr(ctx);
1484 exynos4_jpeg_set_encode_hoff_cnt(jpeg->regs,
1485 ctx->out_q.fmt->fourcc);
1486 } else {
1487 exynos4_jpeg_sw_reset(jpeg->regs);
1488 exynos4_jpeg_set_interrupt(jpeg->regs);
1489 exynos4_jpeg_set_img_addr(ctx);
1490 exynos4_jpeg_set_jpeg_addr(ctx);
1491 exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->cap_q.fmt->fourcc);
1492
1493 bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 32);
1494
1495 exynos4_jpeg_set_dec_bitstream_size(jpeg->regs, bitstream_size);
1496 }
1497
1498 exynos4_jpeg_set_enc_dec_mode(jpeg->regs, ctx->mode);
1499
1500 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1501}
1502
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001503static int s5p_jpeg_job_ready(void *priv)
1504{
1505 struct s5p_jpeg_ctx *ctx = priv;
1506
1507 if (ctx->mode == S5P_JPEG_DECODE)
1508 return ctx->hdr_parsed;
1509 return 1;
1510}
1511
1512static void s5p_jpeg_job_abort(void *priv)
1513{
1514}
1515
1516static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = {
1517 .device_run = s5p_jpeg_device_run,
1518 .job_ready = s5p_jpeg_job_ready,
1519 .job_abort = s5p_jpeg_job_abort,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001520}
1521;
1522static struct v4l2_m2m_ops exynos_jpeg_m2m_ops = {
1523 .device_run = exynos4_jpeg_device_run,
1524 .job_ready = s5p_jpeg_job_ready,
1525 .job_abort = s5p_jpeg_job_abort,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001526};
1527
1528/*
1529 * ============================================================================
1530 * Queue operations
1531 * ============================================================================
1532 */
1533
Marek Szyprowski719c1742012-01-13 05:12:38 -03001534static int s5p_jpeg_queue_setup(struct vb2_queue *vq,
1535 const struct v4l2_format *fmt,
1536 unsigned int *nbuffers, unsigned int *nplanes,
1537 unsigned int sizes[], void *alloc_ctxs[])
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001538{
1539 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
1540 struct s5p_jpeg_q_data *q_data = NULL;
1541 unsigned int size, count = *nbuffers;
1542
1543 q_data = get_q_data(ctx, vq->type);
1544 BUG_ON(q_data == NULL);
1545
1546 size = q_data->size;
1547
1548 /*
1549 * header is parsed during decoding and parsed information stored
1550 * in the context so we do not allow another buffer to overwrite it
1551 */
1552 if (ctx->mode == S5P_JPEG_DECODE)
1553 count = 1;
1554
1555 *nbuffers = count;
1556 *nplanes = 1;
1557 sizes[0] = size;
1558 alloc_ctxs[0] = ctx->jpeg->alloc_ctx;
1559
1560 return 0;
1561}
1562
1563static int s5p_jpeg_buf_prepare(struct vb2_buffer *vb)
1564{
1565 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1566 struct s5p_jpeg_q_data *q_data = NULL;
1567
1568 q_data = get_q_data(ctx, vb->vb2_queue->type);
1569 BUG_ON(q_data == NULL);
1570
1571 if (vb2_plane_size(vb, 0) < q_data->size) {
1572 pr_err("%s data will not fit into plane (%lu < %lu)\n",
1573 __func__, vb2_plane_size(vb, 0),
1574 (long)q_data->size);
1575 return -EINVAL;
1576 }
1577
1578 vb2_set_plane_payload(vb, 0, q_data->size);
1579
1580 return 0;
1581}
1582
1583static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
1584{
1585 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1586
1587 if (ctx->mode == S5P_JPEG_DECODE &&
1588 vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
1589 struct s5p_jpeg_q_data tmp, *q_data;
1590 ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp,
1591 (unsigned long)vb2_plane_vaddr(vb, 0),
1592 min((unsigned long)ctx->out_q.size,
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001593 vb2_get_plane_payload(vb, 0)), ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001594 if (!ctx->hdr_parsed) {
1595 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
1596 return;
1597 }
1598
1599 q_data = &ctx->out_q;
1600 q_data->w = tmp.w;
1601 q_data->h = tmp.h;
1602
1603 q_data = &ctx->cap_q;
1604 q_data->w = tmp.w;
1605 q_data->h = tmp.h;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001606 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001607
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001608 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001609}
1610
1611static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
1612{
1613 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
1614 int ret;
1615
1616 ret = pm_runtime_get_sync(ctx->jpeg->dev);
1617
1618 return ret > 0 ? 0 : ret;
1619}
1620
1621static int s5p_jpeg_stop_streaming(struct vb2_queue *q)
1622{
1623 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
1624
1625 pm_runtime_put(ctx->jpeg->dev);
1626
1627 return 0;
1628}
1629
1630static struct vb2_ops s5p_jpeg_qops = {
1631 .queue_setup = s5p_jpeg_queue_setup,
1632 .buf_prepare = s5p_jpeg_buf_prepare,
1633 .buf_queue = s5p_jpeg_buf_queue,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001634 .wait_prepare = vb2_ops_wait_prepare,
1635 .wait_finish = vb2_ops_wait_finish,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001636 .start_streaming = s5p_jpeg_start_streaming,
1637 .stop_streaming = s5p_jpeg_stop_streaming,
1638};
1639
1640static int queue_init(void *priv, struct vb2_queue *src_vq,
1641 struct vb2_queue *dst_vq)
1642{
1643 struct s5p_jpeg_ctx *ctx = priv;
1644 int ret;
1645
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001646 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1647 src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
1648 src_vq->drv_priv = ctx;
1649 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1650 src_vq->ops = &s5p_jpeg_qops;
1651 src_vq->mem_ops = &vb2_dma_contig_memops;
Kamil Debskiaca326a2013-04-24 10:08:02 -03001652 src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001653 src_vq->lock = &ctx->jpeg->lock;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001654
1655 ret = vb2_queue_init(src_vq);
1656 if (ret)
1657 return ret;
1658
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001659 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1660 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
1661 dst_vq->drv_priv = ctx;
1662 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1663 dst_vq->ops = &s5p_jpeg_qops;
1664 dst_vq->mem_ops = &vb2_dma_contig_memops;
Kamil Debskiaca326a2013-04-24 10:08:02 -03001665 dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001666 dst_vq->lock = &ctx->jpeg->lock;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001667
1668 return vb2_queue_init(dst_vq);
1669}
1670
1671/*
1672 * ============================================================================
1673 * ISR
1674 * ============================================================================
1675 */
1676
1677static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
1678{
1679 struct s5p_jpeg *jpeg = dev_id;
1680 struct s5p_jpeg_ctx *curr_ctx;
1681 struct vb2_buffer *src_buf, *dst_buf;
1682 unsigned long payload_size = 0;
1683 enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
1684 bool enc_jpeg_too_large = false;
1685 bool timer_elapsed = false;
1686 bool op_completed = false;
1687
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001688 spin_lock(&jpeg->slock);
1689
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001690 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
1691
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001692 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
1693 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001694
1695 if (curr_ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001696 enc_jpeg_too_large = s5p_jpeg_enc_stream_stat(jpeg->regs);
1697 timer_elapsed = s5p_jpeg_timer_stat(jpeg->regs);
1698 op_completed = s5p_jpeg_result_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001699 if (curr_ctx->mode == S5P_JPEG_DECODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001700 op_completed = op_completed &&
1701 s5p_jpeg_stream_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001702
1703 if (enc_jpeg_too_large) {
1704 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001705 s5p_jpeg_clear_enc_stream_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001706 } else if (timer_elapsed) {
1707 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001708 s5p_jpeg_clear_timer_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001709 } else if (!op_completed) {
1710 state = VB2_BUF_STATE_ERROR;
1711 } else {
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001712 payload_size = s5p_jpeg_compressed_size(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001713 }
1714
Kamil Debskiaca326a2013-04-24 10:08:02 -03001715 dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
1716 dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
1717
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001718 v4l2_m2m_buf_done(src_buf, state);
1719 if (curr_ctx->mode == S5P_JPEG_ENCODE)
1720 vb2_set_plane_payload(dst_buf, 0, payload_size);
1721 v4l2_m2m_buf_done(dst_buf, state);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001722 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001723
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001724 curr_ctx->subsampling = s5p_jpeg_get_subsampling_mode(jpeg->regs);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001725 spin_unlock(&jpeg->slock);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001726
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001727 s5p_jpeg_clear_int(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001728
1729 return IRQ_HANDLED;
1730}
1731
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001732static irqreturn_t exynos4_jpeg_irq(int irq, void *priv)
1733{
1734 unsigned int int_status;
1735 struct vb2_buffer *src_vb, *dst_vb;
1736 struct s5p_jpeg *jpeg = priv;
1737 struct s5p_jpeg_ctx *curr_ctx;
1738 unsigned long payload_size = 0;
1739
1740 spin_lock(&jpeg->slock);
1741
1742 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
1743
1744 src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
1745 dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
1746
1747 int_status = exynos4_jpeg_get_int_status(jpeg->regs);
1748
1749 if (int_status) {
1750 switch (int_status & 0x1f) {
1751 case 0x1:
1752 jpeg->irq_ret = ERR_PROT;
1753 break;
1754 case 0x2:
1755 jpeg->irq_ret = OK_ENC_OR_DEC;
1756 break;
1757 case 0x4:
1758 jpeg->irq_ret = ERR_DEC_INVALID_FORMAT;
1759 break;
1760 case 0x8:
1761 jpeg->irq_ret = ERR_MULTI_SCAN;
1762 break;
1763 case 0x10:
1764 jpeg->irq_ret = ERR_FRAME;
1765 break;
1766 default:
1767 jpeg->irq_ret = ERR_UNKNOWN;
1768 break;
1769 }
1770 } else {
1771 jpeg->irq_ret = ERR_UNKNOWN;
1772 }
1773
1774 if (jpeg->irq_ret == OK_ENC_OR_DEC) {
1775 if (curr_ctx->mode == S5P_JPEG_ENCODE) {
1776 payload_size = exynos4_jpeg_get_stream_size(jpeg->regs);
1777 vb2_set_plane_payload(dst_vb, 0, payload_size);
1778 }
1779 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
1780 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
1781 } else {
1782 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
1783 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
1784 }
1785
1786 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
1787 curr_ctx->subsampling = exynos4_jpeg_get_frame_fmt(jpeg->regs);
1788
1789 spin_unlock(&jpeg->slock);
1790 return IRQ_HANDLED;
1791}
1792
1793static void *jpeg_get_drv_data(struct platform_device *pdev);
1794
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001795/*
1796 * ============================================================================
1797 * Driver basic infrastructure
1798 * ============================================================================
1799 */
1800
1801static int s5p_jpeg_probe(struct platform_device *pdev)
1802{
1803 struct s5p_jpeg *jpeg;
1804 struct resource *res;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001805 struct v4l2_m2m_ops *samsung_jpeg_m2m_ops;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001806 int ret;
1807
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001808 if (!pdev->dev.of_node)
1809 return -ENODEV;
1810
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001811 /* JPEG IP abstraction struct */
Sachin Kamat5b58b952012-05-14 06:33:34 -03001812 jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001813 if (!jpeg)
1814 return -ENOMEM;
1815
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001816 jpeg->variant = jpeg_get_drv_data(pdev);
1817
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001818 mutex_init(&jpeg->lock);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001819 spin_lock_init(&jpeg->slock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001820 jpeg->dev = &pdev->dev;
1821
1822 /* memory-mapped registers */
1823 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001824
Thierry Redingf23999e2013-01-21 06:09:07 -03001825 jpeg->regs = devm_ioremap_resource(&pdev->dev, res);
1826 if (IS_ERR(jpeg->regs))
1827 return PTR_ERR(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001828
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001829 /* interrupt service routine registration */
1830 jpeg->irq = ret = platform_get_irq(pdev, 0);
1831 if (ret < 0) {
1832 dev_err(&pdev->dev, "cannot find IRQ\n");
Sachin Kamat5b58b952012-05-14 06:33:34 -03001833 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001834 }
1835
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001836 ret = devm_request_irq(&pdev->dev, jpeg->irq, jpeg->variant->jpeg_irq,
1837 0, dev_name(&pdev->dev), jpeg);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001838 if (ret) {
1839 dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
Sachin Kamat5b58b952012-05-14 06:33:34 -03001840 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001841 }
1842
1843 /* clocks */
1844 jpeg->clk = clk_get(&pdev->dev, "jpeg");
1845 if (IS_ERR(jpeg->clk)) {
1846 dev_err(&pdev->dev, "cannot get clock\n");
1847 ret = PTR_ERR(jpeg->clk);
Sachin Kamat5b58b952012-05-14 06:33:34 -03001848 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001849 }
1850 dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001851
1852 /* v4l2 device */
1853 ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
1854 if (ret) {
1855 dev_err(&pdev->dev, "Failed to register v4l2 device\n");
1856 goto clk_get_rollback;
1857 }
1858
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001859 if (jpeg->variant->version == SJPEG_S5P)
1860 samsung_jpeg_m2m_ops = &s5p_jpeg_m2m_ops;
1861 else
1862 samsung_jpeg_m2m_ops = &exynos_jpeg_m2m_ops;
1863
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001864 /* mem2mem device */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001865 jpeg->m2m_dev = v4l2_m2m_init(samsung_jpeg_m2m_ops);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001866 if (IS_ERR(jpeg->m2m_dev)) {
1867 v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
1868 ret = PTR_ERR(jpeg->m2m_dev);
1869 goto device_register_rollback;
1870 }
1871
1872 jpeg->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
1873 if (IS_ERR(jpeg->alloc_ctx)) {
1874 v4l2_err(&jpeg->v4l2_dev, "Failed to init memory allocator\n");
1875 ret = PTR_ERR(jpeg->alloc_ctx);
1876 goto m2m_init_rollback;
1877 }
1878
1879 /* JPEG encoder /dev/videoX node */
1880 jpeg->vfd_encoder = video_device_alloc();
1881 if (!jpeg->vfd_encoder) {
1882 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
1883 ret = -ENOMEM;
1884 goto vb2_allocator_rollback;
1885 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03001886 snprintf(jpeg->vfd_encoder->name, sizeof(jpeg->vfd_encoder->name),
1887 "%s-enc", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001888 jpeg->vfd_encoder->fops = &s5p_jpeg_fops;
1889 jpeg->vfd_encoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
1890 jpeg->vfd_encoder->minor = -1;
1891 jpeg->vfd_encoder->release = video_device_release;
1892 jpeg->vfd_encoder->lock = &jpeg->lock;
1893 jpeg->vfd_encoder->v4l2_dev = &jpeg->v4l2_dev;
Hans Verkuil954f3402012-09-05 06:05:50 -03001894 jpeg->vfd_encoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001895
1896 ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
1897 if (ret) {
1898 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
1899 goto enc_vdev_alloc_rollback;
1900 }
1901
1902 video_set_drvdata(jpeg->vfd_encoder, jpeg);
1903 v4l2_info(&jpeg->v4l2_dev,
1904 "encoder device registered as /dev/video%d\n",
1905 jpeg->vfd_encoder->num);
1906
1907 /* JPEG decoder /dev/videoX node */
1908 jpeg->vfd_decoder = video_device_alloc();
1909 if (!jpeg->vfd_decoder) {
1910 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
1911 ret = -ENOMEM;
1912 goto enc_vdev_register_rollback;
1913 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03001914 snprintf(jpeg->vfd_decoder->name, sizeof(jpeg->vfd_decoder->name),
1915 "%s-dec", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001916 jpeg->vfd_decoder->fops = &s5p_jpeg_fops;
1917 jpeg->vfd_decoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
1918 jpeg->vfd_decoder->minor = -1;
1919 jpeg->vfd_decoder->release = video_device_release;
1920 jpeg->vfd_decoder->lock = &jpeg->lock;
1921 jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev;
Jacek Anaszewski7f7d8fe2013-09-11 06:17:45 -03001922 jpeg->vfd_decoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001923
1924 ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
1925 if (ret) {
1926 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
1927 goto dec_vdev_alloc_rollback;
1928 }
1929
1930 video_set_drvdata(jpeg->vfd_decoder, jpeg);
1931 v4l2_info(&jpeg->v4l2_dev,
1932 "decoder device registered as /dev/video%d\n",
1933 jpeg->vfd_decoder->num);
1934
1935 /* final statements & power management */
1936 platform_set_drvdata(pdev, jpeg);
1937
1938 pm_runtime_enable(&pdev->dev);
1939
1940 v4l2_info(&jpeg->v4l2_dev, "Samsung S5P JPEG codec\n");
1941
1942 return 0;
1943
1944dec_vdev_alloc_rollback:
1945 video_device_release(jpeg->vfd_decoder);
1946
1947enc_vdev_register_rollback:
1948 video_unregister_device(jpeg->vfd_encoder);
1949
1950enc_vdev_alloc_rollback:
1951 video_device_release(jpeg->vfd_encoder);
1952
1953vb2_allocator_rollback:
1954 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
1955
1956m2m_init_rollback:
1957 v4l2_m2m_release(jpeg->m2m_dev);
1958
1959device_register_rollback:
1960 v4l2_device_unregister(&jpeg->v4l2_dev);
1961
1962clk_get_rollback:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001963 clk_put(jpeg->clk);
1964
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001965 return ret;
1966}
1967
1968static int s5p_jpeg_remove(struct platform_device *pdev)
1969{
1970 struct s5p_jpeg *jpeg = platform_get_drvdata(pdev);
1971
1972 pm_runtime_disable(jpeg->dev);
1973
1974 video_unregister_device(jpeg->vfd_decoder);
1975 video_device_release(jpeg->vfd_decoder);
1976 video_unregister_device(jpeg->vfd_encoder);
1977 video_device_release(jpeg->vfd_encoder);
1978 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
1979 v4l2_m2m_release(jpeg->m2m_dev);
1980 v4l2_device_unregister(&jpeg->v4l2_dev);
1981
Jacek Anaszewskif1347132013-11-25 06:58:13 -03001982 if (!pm_runtime_status_suspended(&pdev->dev))
1983 clk_disable_unprepare(jpeg->clk);
1984
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001985 clk_put(jpeg->clk);
1986
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001987 return 0;
1988}
1989
1990static int s5p_jpeg_runtime_suspend(struct device *dev)
1991{
Jacek Anaszewskif1347132013-11-25 06:58:13 -03001992 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
1993
1994 clk_disable_unprepare(jpeg->clk);
1995
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001996 return 0;
1997}
1998
1999static int s5p_jpeg_runtime_resume(struct device *dev)
2000{
2001 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002002 unsigned long flags;
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002003 int ret;
2004
2005 ret = clk_prepare_enable(jpeg->clk);
2006 if (ret < 0)
2007 return ret;
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03002008
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002009 spin_lock_irqsave(&jpeg->slock, flags);
2010
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002011 /*
2012 * JPEG IP allows storing two Huffman tables for each component
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002013 * We fill table 0 for each component and do this here only
2014 * for S5PC210 device as Exynos4x12 requires programming its
2015 * Huffman tables each time the encoding process is initialized.
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002016 */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002017 if (jpeg->variant->version == SJPEG_S5P) {
2018 s5p_jpeg_set_hdctbl(jpeg->regs);
2019 s5p_jpeg_set_hdctblg(jpeg->regs);
2020 s5p_jpeg_set_hactbl(jpeg->regs);
2021 s5p_jpeg_set_hactblg(jpeg->regs);
2022 }
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03002023
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002024 spin_unlock_irqrestore(&jpeg->slock, flags);
2025
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002026 return 0;
2027}
2028
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002029static int s5p_jpeg_suspend(struct device *dev)
2030{
2031 if (pm_runtime_suspended(dev))
2032 return 0;
2033
2034 return s5p_jpeg_runtime_suspend(dev);
2035}
2036
2037static int s5p_jpeg_resume(struct device *dev)
2038{
2039 if (pm_runtime_suspended(dev))
2040 return 0;
2041
2042 return s5p_jpeg_runtime_resume(dev);
2043}
2044
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002045static const struct dev_pm_ops s5p_jpeg_pm_ops = {
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002046 SET_SYSTEM_SLEEP_PM_OPS(s5p_jpeg_suspend, s5p_jpeg_resume)
2047 SET_RUNTIME_PM_OPS(s5p_jpeg_runtime_suspend, s5p_jpeg_runtime_resume, NULL)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002048};
2049
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03002050#ifdef CONFIG_OF
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002051static struct s5p_jpeg_variant s5p_jpeg_drvdata = {
2052 .version = SJPEG_S5P,
2053 .jpeg_irq = s5p_jpeg_irq,
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03002054};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002055
2056static struct s5p_jpeg_variant exynos4_jpeg_drvdata = {
2057 .version = SJPEG_EXYNOS4,
2058 .jpeg_irq = exynos4_jpeg_irq,
2059};
2060
2061static const struct of_device_id samsung_jpeg_match[] = {
2062 {
2063 .compatible = "samsung,s5pv210-jpeg",
2064 .data = &s5p_jpeg_drvdata,
2065 }, {
2066 .compatible = "samsung,exynos4210-jpeg",
2067 .data = &s5p_jpeg_drvdata,
2068 }, {
2069 .compatible = "samsung,exynos4212-jpeg",
2070 .data = &exynos4_jpeg_drvdata,
2071 },
2072 {},
2073};
2074
2075MODULE_DEVICE_TABLE(of, samsung_jpeg_match);
2076
2077static void *jpeg_get_drv_data(struct platform_device *pdev)
2078{
2079 struct s5p_jpeg_variant *driver_data = NULL;
2080 const struct of_device_id *match;
2081
2082 match = of_match_node(of_match_ptr(samsung_jpeg_match),
2083 pdev->dev.of_node);
2084 if (match)
2085 driver_data = (struct s5p_jpeg_variant *)match->data;
2086
2087 return driver_data;
2088}
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03002089#endif
2090
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002091static struct platform_driver s5p_jpeg_driver = {
2092 .probe = s5p_jpeg_probe,
2093 .remove = s5p_jpeg_remove,
2094 .driver = {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002095 .of_match_table = of_match_ptr(samsung_jpeg_match),
2096 .owner = THIS_MODULE,
2097 .name = S5P_JPEG_M2M_NAME,
2098 .pm = &s5p_jpeg_pm_ops,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002099 },
2100};
2101
Sachin Kamat87e94292012-07-03 05:54:33 -03002102module_platform_driver(s5p_jpeg_driver);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002103
2104MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002105MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002106MODULE_DESCRIPTION("Samsung JPEG codec driver");
2107MODULE_LICENSE("GPL");