blob: 8202fed79345b199e415f5420d2e54d90d511b62 [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,
Jacek Anaszewskia62cffe2014-01-16 08:26:33 -0300178 .depth = 12,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300179 .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,
Jacek Anaszewskia62cffe2014-01-16 08:26:33 -0300191 .depth = 12,
192 .colplanes = 2,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300193 .h_align = 4,
Jacek Anaszewskia62cffe2014-01-16 08:26:33 -0300194 .v_align = 4,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300195 .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
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300454static int exynos4x12_decoded_subsampling[] = {
455 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
456 V4L2_JPEG_CHROMA_SUBSAMPLING_444,
457 V4L2_JPEG_CHROMA_SUBSAMPLING_422,
458 V4L2_JPEG_CHROMA_SUBSAMPLING_420,
459};
460
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300461static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c)
462{
463 return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler);
464}
465
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300466static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh)
467{
468 return container_of(fh, struct s5p_jpeg_ctx, fh);
469}
470
Jacek Anaszewski303b0a92013-12-18 11:14:00 -0300471static int s5p_jpeg_to_user_subsampling(struct s5p_jpeg_ctx *ctx)
472{
473 WARN_ON(ctx->subsampling > 3);
474
475 if (ctx->jpeg->variant->version == SJPEG_S5P) {
476 if (ctx->subsampling > 2)
477 return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
478 return ctx->subsampling;
479 } else {
480 if (ctx->subsampling > 2)
481 return V4L2_JPEG_CHROMA_SUBSAMPLING_420;
482 return exynos4x12_decoded_subsampling[ctx->subsampling];
483 }
484}
485
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300486static inline void s5p_jpeg_set_qtbl(void __iomem *regs,
487 const unsigned char *qtbl,
488 unsigned long tab, int len)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300489{
490 int i;
491
492 for (i = 0; i < len; i++)
493 writel((unsigned int)qtbl[i], regs + tab + (i * 0x04));
494}
495
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300496static inline void s5p_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300497{
498 /* this driver fills quantisation table 0 with data for luma */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300499 s5p_jpeg_set_qtbl(regs, qtbl_luminance[quality],
500 S5P_JPG_QTBL_CONTENT(0),
501 ARRAY_SIZE(qtbl_luminance[quality]));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300502}
503
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300504static inline void s5p_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300505{
506 /* this driver fills quantisation table 1 with data for chroma */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300507 s5p_jpeg_set_qtbl(regs, qtbl_chrominance[quality],
508 S5P_JPG_QTBL_CONTENT(1),
509 ARRAY_SIZE(qtbl_chrominance[quality]));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300510}
511
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300512static inline void s5p_jpeg_set_htbl(void __iomem *regs,
513 const unsigned char *htbl,
514 unsigned long tab, int len)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300515{
516 int i;
517
518 for (i = 0; i < len; i++)
519 writel((unsigned int)htbl[i], regs + tab + (i * 0x04));
520}
521
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300522static inline void s5p_jpeg_set_hdctbl(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300523{
524 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300525 s5p_jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0),
526 ARRAY_SIZE(hdctbl0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300527}
528
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300529static inline void s5p_jpeg_set_hdctblg(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300530{
531 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300532 s5p_jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0),
533 ARRAY_SIZE(hdctblg0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300534}
535
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300536static inline void s5p_jpeg_set_hactbl(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300537{
538 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300539 s5p_jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0),
540 ARRAY_SIZE(hactbl0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300541}
542
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300543static inline void s5p_jpeg_set_hactblg(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300544{
545 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300546 s5p_jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0),
547 ARRAY_SIZE(hactblg0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300548}
549
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300550static inline void exynos4_jpeg_set_tbl(void __iomem *regs,
551 const unsigned char *tbl,
552 unsigned long tab, int len)
553{
554 int i;
555 unsigned int dword;
556
557 for (i = 0; i < len; i += 4) {
558 dword = tbl[i] |
559 (tbl[i + 1] << 8) |
560 (tbl[i + 2] << 16) |
561 (tbl[i + 3] << 24);
562 writel(dword, regs + tab + i);
563 }
564}
565
566static inline void exynos4_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
567{
568 /* this driver fills quantisation table 0 with data for luma */
569 exynos4_jpeg_set_tbl(regs, qtbl_luminance[quality],
570 EXYNOS4_QTBL_CONTENT(0),
571 ARRAY_SIZE(qtbl_luminance[quality]));
572}
573
574static inline void exynos4_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
575{
576 /* this driver fills quantisation table 1 with data for chroma */
577 exynos4_jpeg_set_tbl(regs, qtbl_chrominance[quality],
578 EXYNOS4_QTBL_CONTENT(1),
579 ARRAY_SIZE(qtbl_chrominance[quality]));
580}
581
582void exynos4_jpeg_set_huff_tbl(void __iomem *base)
583{
584 exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCLL,
585 ARRAY_SIZE(hdctbl0));
586 exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCCL,
587 ARRAY_SIZE(hdctbl0));
588 exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCLV,
589 ARRAY_SIZE(hdctblg0));
590 exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCCV,
591 ARRAY_SIZE(hdctblg0));
592 exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACLL,
593 ARRAY_SIZE(hactbl0));
594 exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACCL,
595 ARRAY_SIZE(hactbl0));
596 exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACLV,
597 ARRAY_SIZE(hactblg0));
598 exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACCV,
599 ARRAY_SIZE(hactblg0));
600}
601
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300602/*
603 * ============================================================================
604 * Device file operations
605 * ============================================================================
606 */
607
608static int queue_init(void *priv, struct vb2_queue *src_vq,
609 struct vb2_queue *dst_vq);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300610static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
611 __u32 pixelformat, unsigned int fmt_type);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300612static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300613
614static int s5p_jpeg_open(struct file *file)
615{
616 struct s5p_jpeg *jpeg = video_drvdata(file);
617 struct video_device *vfd = video_devdata(file);
618 struct s5p_jpeg_ctx *ctx;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300619 struct s5p_jpeg_fmt *out_fmt, *cap_fmt;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300620 int ret = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300621
Sachin Kamatb5146c92012-08-16 08:52:58 -0300622 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300623 if (!ctx)
624 return -ENOMEM;
625
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300626 if (mutex_lock_interruptible(&jpeg->lock)) {
627 ret = -ERESTARTSYS;
628 goto free;
629 }
630
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300631 v4l2_fh_init(&ctx->fh, vfd);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300632 /* Use separate control handler per file handle */
633 ctx->fh.ctrl_handler = &ctx->ctrl_handler;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300634 file->private_data = &ctx->fh;
635 v4l2_fh_add(&ctx->fh);
636
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300637 ctx->jpeg = jpeg;
638 if (vfd == jpeg->vfd_encoder) {
639 ctx->mode = S5P_JPEG_ENCODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300640 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB565,
641 FMT_TYPE_OUTPUT);
642 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
643 FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300644 } else {
645 ctx->mode = S5P_JPEG_DECODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300646 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
647 FMT_TYPE_OUTPUT);
648 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_YUYV,
649 FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300650 }
651
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300652 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
653 if (IS_ERR(ctx->fh.m2m_ctx)) {
654 ret = PTR_ERR(ctx->fh.m2m_ctx);
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300655 goto error;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300656 }
657
658 ctx->out_q.fmt = out_fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300659 ctx->cap_q.fmt = cap_fmt;
660
661 ret = s5p_jpeg_controls_create(ctx);
662 if (ret < 0)
663 goto error;
664
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300665 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300666 return 0;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300667
668error:
669 v4l2_fh_del(&ctx->fh);
670 v4l2_fh_exit(&ctx->fh);
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300671 mutex_unlock(&jpeg->lock);
672free:
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300673 kfree(ctx);
674 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300675}
676
677static int s5p_jpeg_release(struct file *file)
678{
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300679 struct s5p_jpeg *jpeg = video_drvdata(file);
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300680 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300681
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300682 mutex_lock(&jpeg->lock);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300683 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300684 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300685 v4l2_fh_del(&ctx->fh);
686 v4l2_fh_exit(&ctx->fh);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300687 kfree(ctx);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300688 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300689
690 return 0;
691}
692
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300693static const struct v4l2_file_operations s5p_jpeg_fops = {
694 .owner = THIS_MODULE,
695 .open = s5p_jpeg_open,
696 .release = s5p_jpeg_release,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300697 .poll = v4l2_m2m_fop_poll,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300698 .unlocked_ioctl = video_ioctl2,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300699 .mmap = v4l2_m2m_fop_mmap,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300700};
701
702/*
703 * ============================================================================
704 * video ioctl operations
705 * ============================================================================
706 */
707
708static int get_byte(struct s5p_jpeg_buffer *buf)
709{
710 if (buf->curr >= buf->size)
711 return -1;
712
713 return ((unsigned char *)buf->data)[buf->curr++];
714}
715
716static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word)
717{
718 unsigned int temp;
719 int byte;
720
721 byte = get_byte(buf);
722 if (byte == -1)
723 return -1;
724 temp = byte << 8;
725 byte = get_byte(buf);
726 if (byte == -1)
727 return -1;
728 *word = (unsigned int)byte | temp;
729 return 0;
730}
731
732static void skip(struct s5p_jpeg_buffer *buf, long len)
733{
734 if (len <= 0)
735 return;
736
737 while (len--)
738 get_byte(buf);
739}
740
741static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300742 unsigned long buffer, unsigned long size,
743 struct s5p_jpeg_ctx *ctx)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300744{
745 int c, components, notfound;
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300746 unsigned int height, width, word, subsampling = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300747 long length;
748 struct s5p_jpeg_buffer jpeg_buffer;
749
750 jpeg_buffer.size = size;
751 jpeg_buffer.data = buffer;
752 jpeg_buffer.curr = 0;
753
754 notfound = 1;
755 while (notfound) {
756 c = get_byte(&jpeg_buffer);
757 if (c == -1)
758 break;
759 if (c != 0xff)
760 continue;
761 do
762 c = get_byte(&jpeg_buffer);
763 while (c == 0xff);
764 if (c == -1)
765 break;
766 if (c == 0)
767 continue;
768 length = 0;
769 switch (c) {
770 /* SOF0: baseline JPEG */
771 case SOF0:
772 if (get_word_be(&jpeg_buffer, &word))
773 break;
774 if (get_byte(&jpeg_buffer) == -1)
775 break;
776 if (get_word_be(&jpeg_buffer, &height))
777 break;
778 if (get_word_be(&jpeg_buffer, &width))
779 break;
780 components = get_byte(&jpeg_buffer);
781 if (components == -1)
782 break;
783 notfound = 0;
784
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300785 if (components == 1) {
786 subsampling = 0x33;
787 } else {
788 skip(&jpeg_buffer, 1);
789 subsampling = get_byte(&jpeg_buffer);
790 skip(&jpeg_buffer, 1);
791 }
792
793 skip(&jpeg_buffer, components * 2);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300794 break;
795
796 /* skip payload-less markers */
797 case RST ... RST + 7:
798 case SOI:
799 case EOI:
800 case TEM:
801 break;
802
803 /* skip uninteresting payload markers */
804 default:
805 if (get_word_be(&jpeg_buffer, &word))
806 break;
807 length = (long)word - 2;
808 skip(&jpeg_buffer, length);
809 break;
810 }
811 }
812 result->w = width;
813 result->h = height;
814 result->size = components;
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300815
816 switch (subsampling) {
817 case 0x11:
818 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444;
819 break;
820 case 0x21:
821 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422;
822 break;
823 case 0x22:
824 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420;
825 break;
826 case 0x33:
827 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
828 break;
829 default:
830 return false;
831 }
832
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300833 return !notfound;
834}
835
836static int s5p_jpeg_querycap(struct file *file, void *priv,
837 struct v4l2_capability *cap)
838{
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300839 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300840
841 if (ctx->mode == S5P_JPEG_ENCODE) {
842 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder",
843 sizeof(cap->driver));
844 strlcpy(cap->card, S5P_JPEG_M2M_NAME " encoder",
845 sizeof(cap->card));
846 } else {
847 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " decoder",
848 sizeof(cap->driver));
849 strlcpy(cap->card, S5P_JPEG_M2M_NAME " decoder",
850 sizeof(cap->card));
851 }
852 cap->bus_info[0] = 0;
Sylwester Nawrockif0476a82012-07-26 09:30:00 -0300853 /*
854 * This is only a mem-to-mem video device. The capture and output
855 * device capability flags are left only for backward compatibility
856 * and are scheduled for removal.
857 */
858 cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M |
859 V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300860 return 0;
861}
862
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300863static int enum_fmt(struct s5p_jpeg_fmt *sjpeg_formats, int n,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300864 struct v4l2_fmtdesc *f, u32 type)
865{
866 int i, num = 0;
867
868 for (i = 0; i < n; ++i) {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300869 if (sjpeg_formats[i].flags & type) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300870 /* index-th format of type type found ? */
871 if (num == f->index)
872 break;
873 /* Correct type but haven't reached our index yet,
874 * just increment per-type index */
875 ++num;
876 }
877 }
878
879 /* Format not found */
880 if (i >= n)
881 return -EINVAL;
882
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300883 strlcpy(f->description, sjpeg_formats[i].name, sizeof(f->description));
884 f->pixelformat = sjpeg_formats[i].fourcc;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300885
886 return 0;
887}
888
889static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
890 struct v4l2_fmtdesc *f)
891{
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300892 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300893
894 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300895 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
896 SJPEG_FMT_FLAG_ENC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300897
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300898 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
899 SJPEG_FMT_FLAG_DEC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300900}
901
902static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
903 struct v4l2_fmtdesc *f)
904{
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300905 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300906
907 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300908 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
909 SJPEG_FMT_FLAG_ENC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300910
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300911 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
912 SJPEG_FMT_FLAG_DEC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300913}
914
915static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx,
916 enum v4l2_buf_type type)
917{
918 if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
919 return &ctx->out_q;
920 if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
921 return &ctx->cap_q;
922
923 return NULL;
924}
925
926static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
927{
928 struct vb2_queue *vq;
929 struct s5p_jpeg_q_data *q_data = NULL;
930 struct v4l2_pix_format *pix = &f->fmt.pix;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300931 struct s5p_jpeg_ctx *ct = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300932
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300933 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300934 if (!vq)
935 return -EINVAL;
936
937 if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
938 ct->mode == S5P_JPEG_DECODE && !ct->hdr_parsed)
939 return -EINVAL;
940 q_data = get_q_data(ct, f->type);
941 BUG_ON(q_data == NULL);
942
943 pix->width = q_data->w;
944 pix->height = q_data->h;
945 pix->field = V4L2_FIELD_NONE;
946 pix->pixelformat = q_data->fmt->fourcc;
947 pix->bytesperline = 0;
948 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
949 u32 bpl = q_data->w;
950 if (q_data->fmt->colplanes == 1)
951 bpl = (bpl * q_data->fmt->depth) >> 3;
952 pix->bytesperline = bpl;
953 }
954 pix->sizeimage = q_data->size;
955
956 return 0;
957}
958
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300959static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
960 u32 pixelformat, unsigned int fmt_type)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300961{
Jacek Anaszewskib2451682014-04-10 04:32:11 -0300962 unsigned int k, fmt_flag;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300963
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300964 if (ctx->mode == S5P_JPEG_ENCODE)
965 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
966 SJPEG_FMT_FLAG_ENC_OUTPUT :
967 SJPEG_FMT_FLAG_ENC_CAPTURE;
968 else
969 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
970 SJPEG_FMT_FLAG_DEC_OUTPUT :
971 SJPEG_FMT_FLAG_DEC_CAPTURE;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300972
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300973 for (k = 0; k < ARRAY_SIZE(sjpeg_formats); k++) {
974 struct s5p_jpeg_fmt *fmt = &sjpeg_formats[k];
975 if (fmt->fourcc == pixelformat &&
976 fmt->flags & fmt_flag &&
Jacek Anaszewskib2451682014-04-10 04:32:11 -0300977 fmt->flags & ctx->jpeg->variant->fmt_ver_flag) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300978 return fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300979 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300980 }
981
982 return NULL;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300983}
984
985static void jpeg_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
986 unsigned int walign,
987 u32 *h, unsigned int hmin, unsigned int hmax,
988 unsigned int halign)
989{
990 int width, height, w_step, h_step;
991
992 width = *w;
993 height = *h;
994
995 w_step = 1 << walign;
996 h_step = 1 << halign;
997 v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
998
999 if (*w < width && (*w + w_step) < wmax)
1000 *w += w_step;
1001 if (*h < height && (*h + h_step) < hmax)
1002 *h += h_step;
1003
1004}
1005
1006static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
1007 struct s5p_jpeg_ctx *ctx, int q_type)
1008{
1009 struct v4l2_pix_format *pix = &f->fmt.pix;
1010
1011 if (pix->field == V4L2_FIELD_ANY)
1012 pix->field = V4L2_FIELD_NONE;
1013 else if (pix->field != V4L2_FIELD_NONE)
1014 return -EINVAL;
1015
1016 /* V4L2 specification suggests the driver corrects the format struct
1017 * if any of the dimensions is unsupported */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001018 if (q_type == FMT_TYPE_OUTPUT)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001019 jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
1020 S5P_JPEG_MAX_WIDTH, 0,
1021 &pix->height, S5P_JPEG_MIN_HEIGHT,
1022 S5P_JPEG_MAX_HEIGHT, 0);
1023 else
1024 jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
1025 S5P_JPEG_MAX_WIDTH, fmt->h_align,
1026 &pix->height, S5P_JPEG_MIN_HEIGHT,
1027 S5P_JPEG_MAX_HEIGHT, fmt->v_align);
1028
1029 if (fmt->fourcc == V4L2_PIX_FMT_JPEG) {
1030 if (pix->sizeimage <= 0)
1031 pix->sizeimage = PAGE_SIZE;
1032 pix->bytesperline = 0;
1033 } else {
1034 u32 bpl = pix->bytesperline;
1035
1036 if (fmt->colplanes > 1 && bpl < pix->width)
1037 bpl = pix->width; /* planar */
1038
1039 if (fmt->colplanes == 1 && /* packed */
Jacek Anaszewskicc690902013-11-25 06:58:10 -03001040 (bpl << 3) / fmt->depth < pix->width)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001041 bpl = (pix->width * fmt->depth) >> 3;
1042
1043 pix->bytesperline = bpl;
1044 pix->sizeimage = (pix->width * pix->height * fmt->depth) >> 3;
1045 }
1046
1047 return 0;
1048}
1049
1050static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
1051 struct v4l2_format *f)
1052{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001053 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001054 struct v4l2_pix_format *pix = &f->fmt.pix;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001055 struct s5p_jpeg_fmt *fmt;
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001056 int ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001057
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001058 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
1059 FMT_TYPE_CAPTURE);
1060 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001061 v4l2_err(&ctx->jpeg->v4l2_dev,
1062 "Fourcc format (0x%08x) invalid.\n",
1063 f->fmt.pix.pixelformat);
1064 return -EINVAL;
1065 }
1066
Jacek Anaszewski337777a2013-11-22 06:13:34 -03001067 /*
1068 * The exynos4x12 device requires resulting YUV image
1069 * subsampling not to be lower than the input jpeg subsampling.
1070 * If this requirement is not met then downgrade the requested
1071 * capture format to the one with subsampling equal to the input jpeg.
1072 */
1073 if ((ctx->jpeg->variant->version != SJPEG_S5P) &&
1074 (ctx->mode == S5P_JPEG_DECODE) &&
1075 (fmt->flags & SJPEG_FMT_NON_RGB) &&
1076 (fmt->subsampling < ctx->subsampling)) {
1077 ret = s5p_jpeg_adjust_fourcc_to_subsampling(ctx->subsampling,
1078 fmt->fourcc,
1079 &pix->pixelformat,
1080 ctx);
1081 if (ret < 0)
1082 pix->pixelformat = V4L2_PIX_FMT_GREY;
1083
1084 fmt = s5p_jpeg_find_format(ctx, pix->pixelformat,
1085 FMT_TYPE_CAPTURE);
1086 }
1087
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001088 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001089}
1090
1091static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
1092 struct v4l2_format *f)
1093{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001094 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001095 struct s5p_jpeg_fmt *fmt;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001096
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001097 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
1098 FMT_TYPE_OUTPUT);
1099 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001100 v4l2_err(&ctx->jpeg->v4l2_dev,
1101 "Fourcc format (0x%08x) invalid.\n",
1102 f->fmt.pix.pixelformat);
1103 return -EINVAL;
1104 }
1105
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001106 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001107}
1108
1109static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
1110{
1111 struct vb2_queue *vq;
1112 struct s5p_jpeg_q_data *q_data = NULL;
1113 struct v4l2_pix_format *pix = &f->fmt.pix;
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001114 struct v4l2_ctrl *ctrl_subs;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001115 unsigned int f_type;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001116
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001117 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001118 if (!vq)
1119 return -EINVAL;
1120
1121 q_data = get_q_data(ct, f->type);
1122 BUG_ON(q_data == NULL);
1123
1124 if (vb2_is_busy(vq)) {
1125 v4l2_err(&ct->jpeg->v4l2_dev, "%s queue busy\n", __func__);
1126 return -EBUSY;
1127 }
1128
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001129 f_type = V4L2_TYPE_IS_OUTPUT(f->type) ?
1130 FMT_TYPE_OUTPUT : FMT_TYPE_CAPTURE;
1131
1132 q_data->fmt = s5p_jpeg_find_format(ct, pix->pixelformat, f_type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001133 q_data->w = pix->width;
1134 q_data->h = pix->height;
1135 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG)
1136 q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3;
1137 else
1138 q_data->size = pix->sizeimage;
1139
Jacek Anaszewski4a30d302013-11-21 13:33:52 -03001140 if (f_type == FMT_TYPE_OUTPUT) {
1141 ctrl_subs = v4l2_ctrl_find(&ct->ctrl_handler,
1142 V4L2_CID_JPEG_CHROMA_SUBSAMPLING);
1143 if (ctrl_subs)
1144 v4l2_ctrl_s_ctrl(ctrl_subs, q_data->fmt->subsampling);
1145 }
1146
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001147 return 0;
1148}
1149
1150static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
1151 struct v4l2_format *f)
1152{
1153 int ret;
1154
1155 ret = s5p_jpeg_try_fmt_vid_cap(file, priv, f);
1156 if (ret)
1157 return ret;
1158
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001159 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001160}
1161
1162static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
1163 struct v4l2_format *f)
1164{
1165 int ret;
1166
1167 ret = s5p_jpeg_try_fmt_vid_out(file, priv, f);
1168 if (ret)
1169 return ret;
1170
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001171 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001172}
1173
Sachin Kamat9f3bd322012-05-10 03:38:40 -03001174static int s5p_jpeg_g_selection(struct file *file, void *priv,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001175 struct v4l2_selection *s)
1176{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001177 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001178
1179 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001180 s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
1181 ctx->jpeg->variant->version != SJPEG_S5P)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001182 return -EINVAL;
1183
1184 /* For JPEG blob active == default == bounds */
1185 switch (s->target) {
Sylwester Nawrockic1334822012-05-20 11:17:12 -03001186 case V4L2_SEL_TGT_CROP:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001187 case V4L2_SEL_TGT_CROP_BOUNDS:
1188 case V4L2_SEL_TGT_CROP_DEFAULT:
Sylwester Nawrockic1334822012-05-20 11:17:12 -03001189 case V4L2_SEL_TGT_COMPOSE:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001190 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
1191 s->r.width = ctx->out_q.w;
1192 s->r.height = ctx->out_q.h;
1193 break;
1194 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
1195 case V4L2_SEL_TGT_COMPOSE_PADDED:
1196 s->r.width = ctx->cap_q.w;
1197 s->r.height = ctx->cap_q.h;
1198 break;
1199 default:
1200 return -EINVAL;
1201 }
1202 s->r.left = 0;
1203 s->r.top = 0;
1204 return 0;
1205}
1206
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001207/*
1208 * V4L2 controls
1209 */
1210
1211static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001212{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001213 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1214 struct s5p_jpeg *jpeg = ctx->jpeg;
1215 unsigned long flags;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001216
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001217 switch (ctrl->id) {
1218 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1219 spin_lock_irqsave(&jpeg->slock, flags);
Jacek Anaszewski303b0a92013-12-18 11:14:00 -03001220 ctrl->val = s5p_jpeg_to_user_subsampling(ctx);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001221 spin_unlock_irqrestore(&jpeg->slock, flags);
1222 break;
1223 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001224
1225 return 0;
1226}
1227
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001228static int s5p_jpeg_try_ctrl(struct v4l2_ctrl *ctrl)
1229{
1230 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1231 unsigned long flags;
1232 int ret = 0;
1233
1234 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1235
1236 if (ctrl->id == V4L2_CID_JPEG_CHROMA_SUBSAMPLING) {
1237 if (ctx->jpeg->variant->version == SJPEG_S5P)
1238 goto error_free;
1239 /*
1240 * The exynos4x12 device requires input raw image fourcc
1241 * to be V4L2_PIX_FMT_GREY if gray jpeg format
1242 * is to be set.
1243 */
1244 if (ctx->out_q.fmt->fourcc != V4L2_PIX_FMT_GREY &&
1245 ctrl->val == V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY) {
1246 ret = -EINVAL;
1247 goto error_free;
1248 }
1249 /*
1250 * The exynos4x12 device requires resulting jpeg subsampling
1251 * not to be lower than the input raw image subsampling.
1252 */
1253 if (ctx->out_q.fmt->subsampling > ctrl->val)
1254 ctrl->val = ctx->out_q.fmt->subsampling;
1255 }
1256
1257error_free:
1258 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1259 return ret;
1260}
1261
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001262static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001263{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001264 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1265 unsigned long flags;
1266
1267 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1268
1269 switch (ctrl->id) {
1270 case V4L2_CID_JPEG_COMPRESSION_QUALITY:
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001271 ctx->compr_quality = ctrl->val;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001272 break;
1273 case V4L2_CID_JPEG_RESTART_INTERVAL:
1274 ctx->restart_interval = ctrl->val;
1275 break;
1276 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1277 ctx->subsampling = ctrl->val;
1278 break;
1279 }
1280
1281 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1282 return 0;
1283}
1284
1285static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
1286 .g_volatile_ctrl = s5p_jpeg_g_volatile_ctrl,
Jacek Anaszewski11fbea32013-11-21 13:34:01 -03001287 .try_ctrl = s5p_jpeg_try_ctrl,
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001288 .s_ctrl = s5p_jpeg_s_ctrl,
1289};
1290
1291static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
1292{
1293 unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */
1294 struct v4l2_ctrl *ctrl;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001295 int ret;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001296
1297 v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
1298
1299 if (ctx->mode == S5P_JPEG_ENCODE) {
1300 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1301 V4L2_CID_JPEG_COMPRESSION_QUALITY,
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001302 0, 3, 1, S5P_JPEG_COMPR_QUAL_WORST);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001303
1304 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1305 V4L2_CID_JPEG_RESTART_INTERVAL,
1306 0, 3, 0xffff, 0);
Jacek Anaszewskifdf9e2b2013-11-21 13:33:41 -03001307 if (ctx->jpeg->variant->version == SJPEG_S5P)
1308 mask = ~0x06; /* 422, 420 */
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001309 }
1310
1311 ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1312 V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
1313 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask,
1314 V4L2_JPEG_CHROMA_SUBSAMPLING_422);
1315
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001316 if (ctx->ctrl_handler.error) {
1317 ret = ctx->ctrl_handler.error;
1318 goto error_free;
1319 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001320
1321 if (ctx->mode == S5P_JPEG_DECODE)
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001322 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
1323 V4L2_CTRL_FLAG_READ_ONLY;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001324
1325 ret = v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
1326 if (ret < 0)
1327 goto error_free;
1328
1329 return ret;
1330
1331error_free:
1332 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
1333 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001334}
1335
1336static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
1337 .vidioc_querycap = s5p_jpeg_querycap,
1338
1339 .vidioc_enum_fmt_vid_cap = s5p_jpeg_enum_fmt_vid_cap,
1340 .vidioc_enum_fmt_vid_out = s5p_jpeg_enum_fmt_vid_out,
1341
1342 .vidioc_g_fmt_vid_cap = s5p_jpeg_g_fmt,
1343 .vidioc_g_fmt_vid_out = s5p_jpeg_g_fmt,
1344
1345 .vidioc_try_fmt_vid_cap = s5p_jpeg_try_fmt_vid_cap,
1346 .vidioc_try_fmt_vid_out = s5p_jpeg_try_fmt_vid_out,
1347
1348 .vidioc_s_fmt_vid_cap = s5p_jpeg_s_fmt_vid_cap,
1349 .vidioc_s_fmt_vid_out = s5p_jpeg_s_fmt_vid_out,
1350
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001351 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
1352 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
1353 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
1354 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001355
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001356 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
1357 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001358
1359 .vidioc_g_selection = s5p_jpeg_g_selection,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001360};
1361
1362/*
1363 * ============================================================================
1364 * mem2mem callbacks
1365 * ============================================================================
1366 */
1367
1368static void s5p_jpeg_device_run(void *priv)
1369{
1370 struct s5p_jpeg_ctx *ctx = priv;
1371 struct s5p_jpeg *jpeg = ctx->jpeg;
1372 struct vb2_buffer *src_buf, *dst_buf;
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001373 unsigned long src_addr, dst_addr, flags;
1374
1375 spin_lock_irqsave(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001376
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001377 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1378 dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001379 src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
1380 dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
1381
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001382 s5p_jpeg_reset(jpeg->regs);
1383 s5p_jpeg_poweron(jpeg->regs);
1384 s5p_jpeg_proc_mode(jpeg->regs, ctx->mode);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001385 if (ctx->mode == S5P_JPEG_ENCODE) {
1386 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001387 s5p_jpeg_input_raw_mode(jpeg->regs,
1388 S5P_JPEG_RAW_IN_565);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001389 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001390 s5p_jpeg_input_raw_mode(jpeg->regs,
1391 S5P_JPEG_RAW_IN_422);
1392 s5p_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
1393 s5p_jpeg_dri(jpeg->regs, ctx->restart_interval);
1394 s5p_jpeg_x(jpeg->regs, ctx->out_q.w);
1395 s5p_jpeg_y(jpeg->regs, ctx->out_q.h);
1396 s5p_jpeg_imgadr(jpeg->regs, src_addr);
1397 s5p_jpeg_jpgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001398
1399 /* ultimately comes from sizeimage from userspace */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001400 s5p_jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001401
1402 /* JPEG RGB to YCbCr conversion matrix */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001403 s5p_jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11);
1404 s5p_jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12);
1405 s5p_jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13);
1406 s5p_jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21);
1407 s5p_jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22);
1408 s5p_jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23);
1409 s5p_jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31);
1410 s5p_jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32);
1411 s5p_jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001412
1413 /*
1414 * JPEG IP allows storing 4 quantization tables
1415 * We fill table 0 for luma and table 1 for chroma
1416 */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03001417 s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
1418 s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001419 /* use table 0 for Y */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001420 s5p_jpeg_qtbl(jpeg->regs, 1, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001421 /* use table 1 for Cb and Cr*/
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001422 s5p_jpeg_qtbl(jpeg->regs, 2, 1);
1423 s5p_jpeg_qtbl(jpeg->regs, 3, 1);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001424
1425 /* Y, Cb, Cr use Huffman table 0 */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001426 s5p_jpeg_htbl_ac(jpeg->regs, 1);
1427 s5p_jpeg_htbl_dc(jpeg->regs, 1);
1428 s5p_jpeg_htbl_ac(jpeg->regs, 2);
1429 s5p_jpeg_htbl_dc(jpeg->regs, 2);
1430 s5p_jpeg_htbl_ac(jpeg->regs, 3);
1431 s5p_jpeg_htbl_dc(jpeg->regs, 3);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001432 } else { /* S5P_JPEG_DECODE */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001433 s5p_jpeg_rst_int_enable(jpeg->regs, true);
1434 s5p_jpeg_data_num_int_enable(jpeg->regs, true);
1435 s5p_jpeg_final_mcu_num_int_enable(jpeg->regs, true);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001436 if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001437 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001438 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001439 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420);
1440 s5p_jpeg_jpgadr(jpeg->regs, src_addr);
1441 s5p_jpeg_imgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001442 }
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001443
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001444 s5p_jpeg_start(jpeg->regs);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001445
1446 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001447}
1448
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001449static void exynos4_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
1450{
1451 struct s5p_jpeg *jpeg = ctx->jpeg;
1452 struct s5p_jpeg_fmt *fmt;
1453 struct vb2_buffer *vb;
1454 struct s5p_jpeg_addr jpeg_addr;
1455 u32 pix_size, padding_bytes = 0;
1456
1457 pix_size = ctx->cap_q.w * ctx->cap_q.h;
1458
1459 if (ctx->mode == S5P_JPEG_ENCODE) {
1460 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1461 fmt = ctx->out_q.fmt;
1462 if (ctx->out_q.w % 2 && fmt->h_align > 0)
1463 padding_bytes = ctx->out_q.h;
1464 } else {
1465 fmt = ctx->cap_q.fmt;
1466 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1467 }
1468
1469 jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
1470
1471 if (fmt->colplanes == 2) {
1472 jpeg_addr.cb = jpeg_addr.y + pix_size - padding_bytes;
1473 } else if (fmt->colplanes == 3) {
1474 jpeg_addr.cb = jpeg_addr.y + pix_size;
1475 if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
1476 jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
1477 else
1478 jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
1479 }
1480
1481 exynos4_jpeg_set_frame_buf_address(jpeg->regs, &jpeg_addr);
1482}
1483
1484static void exynos4_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
1485{
1486 struct s5p_jpeg *jpeg = ctx->jpeg;
1487 struct vb2_buffer *vb;
1488 unsigned int jpeg_addr = 0;
1489
1490 if (ctx->mode == S5P_JPEG_ENCODE)
1491 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1492 else
1493 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1494
1495 jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
1496 exynos4_jpeg_set_stream_buf_address(jpeg->regs, jpeg_addr);
1497}
1498
1499static void exynos4_jpeg_device_run(void *priv)
1500{
1501 struct s5p_jpeg_ctx *ctx = priv;
1502 struct s5p_jpeg *jpeg = ctx->jpeg;
1503 unsigned int bitstream_size;
1504 unsigned long flags;
1505
1506 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1507
1508 if (ctx->mode == S5P_JPEG_ENCODE) {
1509 exynos4_jpeg_sw_reset(jpeg->regs);
1510 exynos4_jpeg_set_interrupt(jpeg->regs);
1511 exynos4_jpeg_set_huf_table_enable(jpeg->regs, 1);
1512
1513 exynos4_jpeg_set_huff_tbl(jpeg->regs);
1514
1515 /*
1516 * JPEG IP allows storing 4 quantization tables
1517 * We fill table 0 for luma and table 1 for chroma
1518 */
1519 exynos4_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
1520 exynos4_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
1521
1522 exynos4_jpeg_set_encode_tbl_select(jpeg->regs,
1523 ctx->compr_quality);
1524 exynos4_jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w,
1525 ctx->cap_q.h);
1526
1527 exynos4_jpeg_set_enc_out_fmt(jpeg->regs, ctx->subsampling);
1528 exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->out_q.fmt->fourcc);
1529 exynos4_jpeg_set_img_addr(ctx);
1530 exynos4_jpeg_set_jpeg_addr(ctx);
1531 exynos4_jpeg_set_encode_hoff_cnt(jpeg->regs,
1532 ctx->out_q.fmt->fourcc);
1533 } else {
1534 exynos4_jpeg_sw_reset(jpeg->regs);
1535 exynos4_jpeg_set_interrupt(jpeg->regs);
1536 exynos4_jpeg_set_img_addr(ctx);
1537 exynos4_jpeg_set_jpeg_addr(ctx);
1538 exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->cap_q.fmt->fourcc);
1539
1540 bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 32);
1541
1542 exynos4_jpeg_set_dec_bitstream_size(jpeg->regs, bitstream_size);
1543 }
1544
1545 exynos4_jpeg_set_enc_dec_mode(jpeg->regs, ctx->mode);
1546
1547 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1548}
1549
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001550static int s5p_jpeg_job_ready(void *priv)
1551{
1552 struct s5p_jpeg_ctx *ctx = priv;
1553
1554 if (ctx->mode == S5P_JPEG_DECODE)
1555 return ctx->hdr_parsed;
1556 return 1;
1557}
1558
1559static void s5p_jpeg_job_abort(void *priv)
1560{
1561}
1562
1563static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = {
1564 .device_run = s5p_jpeg_device_run,
1565 .job_ready = s5p_jpeg_job_ready,
1566 .job_abort = s5p_jpeg_job_abort,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001567}
1568;
1569static struct v4l2_m2m_ops exynos_jpeg_m2m_ops = {
1570 .device_run = exynos4_jpeg_device_run,
1571 .job_ready = s5p_jpeg_job_ready,
1572 .job_abort = s5p_jpeg_job_abort,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001573};
1574
1575/*
1576 * ============================================================================
1577 * Queue operations
1578 * ============================================================================
1579 */
1580
Marek Szyprowski719c1742012-01-13 05:12:38 -03001581static int s5p_jpeg_queue_setup(struct vb2_queue *vq,
1582 const struct v4l2_format *fmt,
1583 unsigned int *nbuffers, unsigned int *nplanes,
1584 unsigned int sizes[], void *alloc_ctxs[])
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001585{
1586 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
1587 struct s5p_jpeg_q_data *q_data = NULL;
1588 unsigned int size, count = *nbuffers;
1589
1590 q_data = get_q_data(ctx, vq->type);
1591 BUG_ON(q_data == NULL);
1592
1593 size = q_data->size;
1594
1595 /*
1596 * header is parsed during decoding and parsed information stored
1597 * in the context so we do not allow another buffer to overwrite it
1598 */
1599 if (ctx->mode == S5P_JPEG_DECODE)
1600 count = 1;
1601
1602 *nbuffers = count;
1603 *nplanes = 1;
1604 sizes[0] = size;
1605 alloc_ctxs[0] = ctx->jpeg->alloc_ctx;
1606
1607 return 0;
1608}
1609
1610static int s5p_jpeg_buf_prepare(struct vb2_buffer *vb)
1611{
1612 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1613 struct s5p_jpeg_q_data *q_data = NULL;
1614
1615 q_data = get_q_data(ctx, vb->vb2_queue->type);
1616 BUG_ON(q_data == NULL);
1617
1618 if (vb2_plane_size(vb, 0) < q_data->size) {
1619 pr_err("%s data will not fit into plane (%lu < %lu)\n",
1620 __func__, vb2_plane_size(vb, 0),
1621 (long)q_data->size);
1622 return -EINVAL;
1623 }
1624
1625 vb2_set_plane_payload(vb, 0, q_data->size);
1626
1627 return 0;
1628}
1629
1630static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
1631{
1632 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1633
1634 if (ctx->mode == S5P_JPEG_DECODE &&
1635 vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
1636 struct s5p_jpeg_q_data tmp, *q_data;
1637 ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp,
1638 (unsigned long)vb2_plane_vaddr(vb, 0),
1639 min((unsigned long)ctx->out_q.size,
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001640 vb2_get_plane_payload(vb, 0)), ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001641 if (!ctx->hdr_parsed) {
1642 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
1643 return;
1644 }
1645
1646 q_data = &ctx->out_q;
1647 q_data->w = tmp.w;
1648 q_data->h = tmp.h;
1649
1650 q_data = &ctx->cap_q;
1651 q_data->w = tmp.w;
1652 q_data->h = tmp.h;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001653 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001654
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001655 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001656}
1657
1658static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
1659{
1660 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
1661 int ret;
1662
1663 ret = pm_runtime_get_sync(ctx->jpeg->dev);
1664
1665 return ret > 0 ? 0 : ret;
1666}
1667
Hans Verkuile37559b2014-04-17 02:47:21 -03001668static void s5p_jpeg_stop_streaming(struct vb2_queue *q)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001669{
1670 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
1671
1672 pm_runtime_put(ctx->jpeg->dev);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001673}
1674
1675static struct vb2_ops s5p_jpeg_qops = {
1676 .queue_setup = s5p_jpeg_queue_setup,
1677 .buf_prepare = s5p_jpeg_buf_prepare,
1678 .buf_queue = s5p_jpeg_buf_queue,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001679 .wait_prepare = vb2_ops_wait_prepare,
1680 .wait_finish = vb2_ops_wait_finish,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001681 .start_streaming = s5p_jpeg_start_streaming,
1682 .stop_streaming = s5p_jpeg_stop_streaming,
1683};
1684
1685static int queue_init(void *priv, struct vb2_queue *src_vq,
1686 struct vb2_queue *dst_vq)
1687{
1688 struct s5p_jpeg_ctx *ctx = priv;
1689 int ret;
1690
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001691 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1692 src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
1693 src_vq->drv_priv = ctx;
1694 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1695 src_vq->ops = &s5p_jpeg_qops;
1696 src_vq->mem_ops = &vb2_dma_contig_memops;
Sakari Ailusade48682014-02-25 19:12:19 -03001697 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001698 src_vq->lock = &ctx->jpeg->lock;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001699
1700 ret = vb2_queue_init(src_vq);
1701 if (ret)
1702 return ret;
1703
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001704 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1705 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
1706 dst_vq->drv_priv = ctx;
1707 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1708 dst_vq->ops = &s5p_jpeg_qops;
1709 dst_vq->mem_ops = &vb2_dma_contig_memops;
Sakari Ailusade48682014-02-25 19:12:19 -03001710 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001711 dst_vq->lock = &ctx->jpeg->lock;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001712
1713 return vb2_queue_init(dst_vq);
1714}
1715
1716/*
1717 * ============================================================================
1718 * ISR
1719 * ============================================================================
1720 */
1721
1722static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
1723{
1724 struct s5p_jpeg *jpeg = dev_id;
1725 struct s5p_jpeg_ctx *curr_ctx;
1726 struct vb2_buffer *src_buf, *dst_buf;
1727 unsigned long payload_size = 0;
1728 enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
1729 bool enc_jpeg_too_large = false;
1730 bool timer_elapsed = false;
1731 bool op_completed = false;
1732
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001733 spin_lock(&jpeg->slock);
1734
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001735 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
1736
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001737 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
1738 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001739
1740 if (curr_ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001741 enc_jpeg_too_large = s5p_jpeg_enc_stream_stat(jpeg->regs);
1742 timer_elapsed = s5p_jpeg_timer_stat(jpeg->regs);
1743 op_completed = s5p_jpeg_result_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001744 if (curr_ctx->mode == S5P_JPEG_DECODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001745 op_completed = op_completed &&
1746 s5p_jpeg_stream_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001747
1748 if (enc_jpeg_too_large) {
1749 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001750 s5p_jpeg_clear_enc_stream_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001751 } else if (timer_elapsed) {
1752 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001753 s5p_jpeg_clear_timer_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001754 } else if (!op_completed) {
1755 state = VB2_BUF_STATE_ERROR;
1756 } else {
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001757 payload_size = s5p_jpeg_compressed_size(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001758 }
1759
Kamil Debskiaca326a2013-04-24 10:08:02 -03001760 dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
1761 dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
Sakari Ailus309f4d62014-02-08 14:21:35 -03001762 dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
1763 dst_buf->v4l2_buf.flags |=
1764 src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
Kamil Debskiaca326a2013-04-24 10:08:02 -03001765
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001766 v4l2_m2m_buf_done(src_buf, state);
1767 if (curr_ctx->mode == S5P_JPEG_ENCODE)
1768 vb2_set_plane_payload(dst_buf, 0, payload_size);
1769 v4l2_m2m_buf_done(dst_buf, state);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001770 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001771
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001772 curr_ctx->subsampling = s5p_jpeg_get_subsampling_mode(jpeg->regs);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001773 spin_unlock(&jpeg->slock);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001774
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001775 s5p_jpeg_clear_int(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001776
1777 return IRQ_HANDLED;
1778}
1779
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001780static irqreturn_t exynos4_jpeg_irq(int irq, void *priv)
1781{
1782 unsigned int int_status;
1783 struct vb2_buffer *src_vb, *dst_vb;
1784 struct s5p_jpeg *jpeg = priv;
1785 struct s5p_jpeg_ctx *curr_ctx;
1786 unsigned long payload_size = 0;
1787
1788 spin_lock(&jpeg->slock);
1789
1790 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
1791
1792 src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
1793 dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
1794
1795 int_status = exynos4_jpeg_get_int_status(jpeg->regs);
1796
1797 if (int_status) {
1798 switch (int_status & 0x1f) {
1799 case 0x1:
1800 jpeg->irq_ret = ERR_PROT;
1801 break;
1802 case 0x2:
1803 jpeg->irq_ret = OK_ENC_OR_DEC;
1804 break;
1805 case 0x4:
1806 jpeg->irq_ret = ERR_DEC_INVALID_FORMAT;
1807 break;
1808 case 0x8:
1809 jpeg->irq_ret = ERR_MULTI_SCAN;
1810 break;
1811 case 0x10:
1812 jpeg->irq_ret = ERR_FRAME;
1813 break;
1814 default:
1815 jpeg->irq_ret = ERR_UNKNOWN;
1816 break;
1817 }
1818 } else {
1819 jpeg->irq_ret = ERR_UNKNOWN;
1820 }
1821
1822 if (jpeg->irq_ret == OK_ENC_OR_DEC) {
1823 if (curr_ctx->mode == S5P_JPEG_ENCODE) {
1824 payload_size = exynos4_jpeg_get_stream_size(jpeg->regs);
1825 vb2_set_plane_payload(dst_vb, 0, payload_size);
1826 }
1827 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
1828 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
1829 } else {
1830 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
1831 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
1832 }
1833
1834 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
1835 curr_ctx->subsampling = exynos4_jpeg_get_frame_fmt(jpeg->regs);
1836
1837 spin_unlock(&jpeg->slock);
1838 return IRQ_HANDLED;
1839}
1840
1841static void *jpeg_get_drv_data(struct platform_device *pdev);
1842
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001843/*
1844 * ============================================================================
1845 * Driver basic infrastructure
1846 * ============================================================================
1847 */
1848
1849static int s5p_jpeg_probe(struct platform_device *pdev)
1850{
1851 struct s5p_jpeg *jpeg;
1852 struct resource *res;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001853 struct v4l2_m2m_ops *samsung_jpeg_m2m_ops;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001854 int ret;
1855
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001856 if (!pdev->dev.of_node)
1857 return -ENODEV;
1858
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001859 /* JPEG IP abstraction struct */
Sachin Kamat5b58b952012-05-14 06:33:34 -03001860 jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001861 if (!jpeg)
1862 return -ENOMEM;
1863
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001864 jpeg->variant = jpeg_get_drv_data(pdev);
1865
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001866 mutex_init(&jpeg->lock);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001867 spin_lock_init(&jpeg->slock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001868 jpeg->dev = &pdev->dev;
1869
1870 /* memory-mapped registers */
1871 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001872
Thierry Redingf23999e2013-01-21 06:09:07 -03001873 jpeg->regs = devm_ioremap_resource(&pdev->dev, res);
1874 if (IS_ERR(jpeg->regs))
1875 return PTR_ERR(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001876
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001877 /* interrupt service routine registration */
1878 jpeg->irq = ret = platform_get_irq(pdev, 0);
1879 if (ret < 0) {
1880 dev_err(&pdev->dev, "cannot find IRQ\n");
Sachin Kamat5b58b952012-05-14 06:33:34 -03001881 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001882 }
1883
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001884 ret = devm_request_irq(&pdev->dev, jpeg->irq, jpeg->variant->jpeg_irq,
1885 0, dev_name(&pdev->dev), jpeg);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001886 if (ret) {
1887 dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
Sachin Kamat5b58b952012-05-14 06:33:34 -03001888 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001889 }
1890
1891 /* clocks */
1892 jpeg->clk = clk_get(&pdev->dev, "jpeg");
1893 if (IS_ERR(jpeg->clk)) {
1894 dev_err(&pdev->dev, "cannot get clock\n");
1895 ret = PTR_ERR(jpeg->clk);
Sachin Kamat5b58b952012-05-14 06:33:34 -03001896 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001897 }
1898 dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001899
1900 /* v4l2 device */
1901 ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
1902 if (ret) {
1903 dev_err(&pdev->dev, "Failed to register v4l2 device\n");
1904 goto clk_get_rollback;
1905 }
1906
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001907 if (jpeg->variant->version == SJPEG_S5P)
1908 samsung_jpeg_m2m_ops = &s5p_jpeg_m2m_ops;
1909 else
1910 samsung_jpeg_m2m_ops = &exynos_jpeg_m2m_ops;
1911
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001912 /* mem2mem device */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001913 jpeg->m2m_dev = v4l2_m2m_init(samsung_jpeg_m2m_ops);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001914 if (IS_ERR(jpeg->m2m_dev)) {
1915 v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
1916 ret = PTR_ERR(jpeg->m2m_dev);
1917 goto device_register_rollback;
1918 }
1919
1920 jpeg->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
1921 if (IS_ERR(jpeg->alloc_ctx)) {
1922 v4l2_err(&jpeg->v4l2_dev, "Failed to init memory allocator\n");
1923 ret = PTR_ERR(jpeg->alloc_ctx);
1924 goto m2m_init_rollback;
1925 }
1926
1927 /* JPEG encoder /dev/videoX node */
1928 jpeg->vfd_encoder = video_device_alloc();
1929 if (!jpeg->vfd_encoder) {
1930 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
1931 ret = -ENOMEM;
1932 goto vb2_allocator_rollback;
1933 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03001934 snprintf(jpeg->vfd_encoder->name, sizeof(jpeg->vfd_encoder->name),
1935 "%s-enc", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001936 jpeg->vfd_encoder->fops = &s5p_jpeg_fops;
1937 jpeg->vfd_encoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
1938 jpeg->vfd_encoder->minor = -1;
1939 jpeg->vfd_encoder->release = video_device_release;
1940 jpeg->vfd_encoder->lock = &jpeg->lock;
1941 jpeg->vfd_encoder->v4l2_dev = &jpeg->v4l2_dev;
Hans Verkuil954f3402012-09-05 06:05:50 -03001942 jpeg->vfd_encoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001943
1944 ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
1945 if (ret) {
1946 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
1947 goto enc_vdev_alloc_rollback;
1948 }
1949
1950 video_set_drvdata(jpeg->vfd_encoder, jpeg);
1951 v4l2_info(&jpeg->v4l2_dev,
1952 "encoder device registered as /dev/video%d\n",
1953 jpeg->vfd_encoder->num);
1954
1955 /* JPEG decoder /dev/videoX node */
1956 jpeg->vfd_decoder = video_device_alloc();
1957 if (!jpeg->vfd_decoder) {
1958 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
1959 ret = -ENOMEM;
1960 goto enc_vdev_register_rollback;
1961 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03001962 snprintf(jpeg->vfd_decoder->name, sizeof(jpeg->vfd_decoder->name),
1963 "%s-dec", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001964 jpeg->vfd_decoder->fops = &s5p_jpeg_fops;
1965 jpeg->vfd_decoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
1966 jpeg->vfd_decoder->minor = -1;
1967 jpeg->vfd_decoder->release = video_device_release;
1968 jpeg->vfd_decoder->lock = &jpeg->lock;
1969 jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev;
Jacek Anaszewski7f7d8fe2013-09-11 06:17:45 -03001970 jpeg->vfd_decoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001971
1972 ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
1973 if (ret) {
1974 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
1975 goto dec_vdev_alloc_rollback;
1976 }
1977
1978 video_set_drvdata(jpeg->vfd_decoder, jpeg);
1979 v4l2_info(&jpeg->v4l2_dev,
1980 "decoder device registered as /dev/video%d\n",
1981 jpeg->vfd_decoder->num);
1982
1983 /* final statements & power management */
1984 platform_set_drvdata(pdev, jpeg);
1985
1986 pm_runtime_enable(&pdev->dev);
1987
1988 v4l2_info(&jpeg->v4l2_dev, "Samsung S5P JPEG codec\n");
1989
1990 return 0;
1991
1992dec_vdev_alloc_rollback:
1993 video_device_release(jpeg->vfd_decoder);
1994
1995enc_vdev_register_rollback:
1996 video_unregister_device(jpeg->vfd_encoder);
1997
1998enc_vdev_alloc_rollback:
1999 video_device_release(jpeg->vfd_encoder);
2000
2001vb2_allocator_rollback:
2002 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
2003
2004m2m_init_rollback:
2005 v4l2_m2m_release(jpeg->m2m_dev);
2006
2007device_register_rollback:
2008 v4l2_device_unregister(&jpeg->v4l2_dev);
2009
2010clk_get_rollback:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002011 clk_put(jpeg->clk);
2012
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002013 return ret;
2014}
2015
2016static int s5p_jpeg_remove(struct platform_device *pdev)
2017{
2018 struct s5p_jpeg *jpeg = platform_get_drvdata(pdev);
2019
2020 pm_runtime_disable(jpeg->dev);
2021
2022 video_unregister_device(jpeg->vfd_decoder);
2023 video_device_release(jpeg->vfd_decoder);
2024 video_unregister_device(jpeg->vfd_encoder);
2025 video_device_release(jpeg->vfd_encoder);
2026 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
2027 v4l2_m2m_release(jpeg->m2m_dev);
2028 v4l2_device_unregister(&jpeg->v4l2_dev);
2029
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002030 if (!pm_runtime_status_suspended(&pdev->dev))
2031 clk_disable_unprepare(jpeg->clk);
2032
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002033 clk_put(jpeg->clk);
2034
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002035 return 0;
2036}
2037
2038static int s5p_jpeg_runtime_suspend(struct device *dev)
2039{
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002040 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
2041
2042 clk_disable_unprepare(jpeg->clk);
2043
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002044 return 0;
2045}
2046
2047static int s5p_jpeg_runtime_resume(struct device *dev)
2048{
2049 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002050 unsigned long flags;
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002051 int ret;
2052
2053 ret = clk_prepare_enable(jpeg->clk);
2054 if (ret < 0)
2055 return ret;
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03002056
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002057 spin_lock_irqsave(&jpeg->slock, flags);
2058
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002059 /*
2060 * JPEG IP allows storing two Huffman tables for each component
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002061 * We fill table 0 for each component and do this here only
2062 * for S5PC210 device as Exynos4x12 requires programming its
2063 * Huffman tables each time the encoding process is initialized.
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002064 */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002065 if (jpeg->variant->version == SJPEG_S5P) {
2066 s5p_jpeg_set_hdctbl(jpeg->regs);
2067 s5p_jpeg_set_hdctblg(jpeg->regs);
2068 s5p_jpeg_set_hactbl(jpeg->regs);
2069 s5p_jpeg_set_hactblg(jpeg->regs);
2070 }
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03002071
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002072 spin_unlock_irqrestore(&jpeg->slock, flags);
2073
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002074 return 0;
2075}
2076
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002077static int s5p_jpeg_suspend(struct device *dev)
2078{
2079 if (pm_runtime_suspended(dev))
2080 return 0;
2081
2082 return s5p_jpeg_runtime_suspend(dev);
2083}
2084
2085static int s5p_jpeg_resume(struct device *dev)
2086{
2087 if (pm_runtime_suspended(dev))
2088 return 0;
2089
2090 return s5p_jpeg_runtime_resume(dev);
2091}
2092
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002093static const struct dev_pm_ops s5p_jpeg_pm_ops = {
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002094 SET_SYSTEM_SLEEP_PM_OPS(s5p_jpeg_suspend, s5p_jpeg_resume)
2095 SET_RUNTIME_PM_OPS(s5p_jpeg_runtime_suspend, s5p_jpeg_runtime_resume, NULL)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002096};
2097
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03002098#ifdef CONFIG_OF
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002099static struct s5p_jpeg_variant s5p_jpeg_drvdata = {
2100 .version = SJPEG_S5P,
2101 .jpeg_irq = s5p_jpeg_irq,
Jacek Anaszewskib2451682014-04-10 04:32:11 -03002102 .fmt_ver_flag = SJPEG_FMT_FLAG_S5P,
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03002103};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002104
2105static struct s5p_jpeg_variant exynos4_jpeg_drvdata = {
2106 .version = SJPEG_EXYNOS4,
2107 .jpeg_irq = exynos4_jpeg_irq,
Jacek Anaszewskib2451682014-04-10 04:32:11 -03002108 .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS4,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002109};
2110
2111static const struct of_device_id samsung_jpeg_match[] = {
2112 {
2113 .compatible = "samsung,s5pv210-jpeg",
2114 .data = &s5p_jpeg_drvdata,
2115 }, {
2116 .compatible = "samsung,exynos4210-jpeg",
2117 .data = &s5p_jpeg_drvdata,
2118 }, {
2119 .compatible = "samsung,exynos4212-jpeg",
2120 .data = &exynos4_jpeg_drvdata,
2121 },
2122 {},
2123};
2124
2125MODULE_DEVICE_TABLE(of, samsung_jpeg_match);
2126
2127static void *jpeg_get_drv_data(struct platform_device *pdev)
2128{
2129 struct s5p_jpeg_variant *driver_data = NULL;
2130 const struct of_device_id *match;
2131
2132 match = of_match_node(of_match_ptr(samsung_jpeg_match),
2133 pdev->dev.of_node);
2134 if (match)
2135 driver_data = (struct s5p_jpeg_variant *)match->data;
2136
2137 return driver_data;
2138}
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03002139#endif
2140
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002141static struct platform_driver s5p_jpeg_driver = {
2142 .probe = s5p_jpeg_probe,
2143 .remove = s5p_jpeg_remove,
2144 .driver = {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002145 .of_match_table = of_match_ptr(samsung_jpeg_match),
2146 .owner = THIS_MODULE,
2147 .name = S5P_JPEG_M2M_NAME,
2148 .pm = &s5p_jpeg_pm_ops,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002149 },
2150};
2151
Sachin Kamat87e94292012-07-03 05:54:33 -03002152module_platform_driver(s5p_jpeg_driver);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002153
2154MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002155MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002156MODULE_DESCRIPTION("Samsung JPEG codec driver");
2157MODULE_LICENSE("GPL");