blob: 3d5d99446d78b8edb780ad49cc1a28a287579016 [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 Anaszewski80529ae2013-12-18 11:04:44 -03001097 unsigned int f_type;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001098
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001099 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001100 if (!vq)
1101 return -EINVAL;
1102
1103 q_data = get_q_data(ct, f->type);
1104 BUG_ON(q_data == NULL);
1105
1106 if (vb2_is_busy(vq)) {
1107 v4l2_err(&ct->jpeg->v4l2_dev, "%s queue busy\n", __func__);
1108 return -EBUSY;
1109 }
1110
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001111 f_type = V4L2_TYPE_IS_OUTPUT(f->type) ?
1112 FMT_TYPE_OUTPUT : FMT_TYPE_CAPTURE;
1113
1114 q_data->fmt = s5p_jpeg_find_format(ct, pix->pixelformat, f_type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001115 q_data->w = pix->width;
1116 q_data->h = pix->height;
1117 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG)
1118 q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3;
1119 else
1120 q_data->size = pix->sizeimage;
1121
1122 return 0;
1123}
1124
1125static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
1126 struct v4l2_format *f)
1127{
1128 int ret;
1129
1130 ret = s5p_jpeg_try_fmt_vid_cap(file, priv, f);
1131 if (ret)
1132 return ret;
1133
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001134 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001135}
1136
1137static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
1138 struct v4l2_format *f)
1139{
1140 int ret;
1141
1142 ret = s5p_jpeg_try_fmt_vid_out(file, priv, f);
1143 if (ret)
1144 return ret;
1145
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001146 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001147}
1148
Sachin Kamat9f3bd322012-05-10 03:38:40 -03001149static int s5p_jpeg_g_selection(struct file *file, void *priv,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001150 struct v4l2_selection *s)
1151{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001152 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001153
1154 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001155 s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
1156 ctx->jpeg->variant->version != SJPEG_S5P)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001157 return -EINVAL;
1158
1159 /* For JPEG blob active == default == bounds */
1160 switch (s->target) {
Sylwester Nawrockic1334822012-05-20 11:17:12 -03001161 case V4L2_SEL_TGT_CROP:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001162 case V4L2_SEL_TGT_CROP_BOUNDS:
1163 case V4L2_SEL_TGT_CROP_DEFAULT:
Sylwester Nawrockic1334822012-05-20 11:17:12 -03001164 case V4L2_SEL_TGT_COMPOSE:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001165 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
1166 s->r.width = ctx->out_q.w;
1167 s->r.height = ctx->out_q.h;
1168 break;
1169 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
1170 case V4L2_SEL_TGT_COMPOSE_PADDED:
1171 s->r.width = ctx->cap_q.w;
1172 s->r.height = ctx->cap_q.h;
1173 break;
1174 default:
1175 return -EINVAL;
1176 }
1177 s->r.left = 0;
1178 s->r.top = 0;
1179 return 0;
1180}
1181
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001182/*
1183 * V4L2 controls
1184 */
1185
1186static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001187{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001188 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1189 struct s5p_jpeg *jpeg = ctx->jpeg;
1190 unsigned long flags;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001191
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001192 switch (ctrl->id) {
1193 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1194 spin_lock_irqsave(&jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001195
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001196 WARN_ON(ctx->subsampling > S5P_SUBSAMPLING_MODE_GRAY);
1197 if (ctx->subsampling > 2)
1198 ctrl->val = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
1199 else
1200 ctrl->val = ctx->subsampling;
1201 spin_unlock_irqrestore(&jpeg->slock, flags);
1202 break;
1203 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001204
1205 return 0;
1206}
1207
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001208static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001209{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001210 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1211 unsigned long flags;
1212
1213 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1214
1215 switch (ctrl->id) {
1216 case V4L2_CID_JPEG_COMPRESSION_QUALITY:
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001217 ctx->compr_quality = ctrl->val;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001218 break;
1219 case V4L2_CID_JPEG_RESTART_INTERVAL:
1220 ctx->restart_interval = ctrl->val;
1221 break;
1222 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1223 ctx->subsampling = ctrl->val;
1224 break;
1225 }
1226
1227 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1228 return 0;
1229}
1230
1231static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
1232 .g_volatile_ctrl = s5p_jpeg_g_volatile_ctrl,
1233 .s_ctrl = s5p_jpeg_s_ctrl,
1234};
1235
1236static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
1237{
1238 unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */
1239 struct v4l2_ctrl *ctrl;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001240 int ret;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001241
1242 v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
1243
1244 if (ctx->mode == S5P_JPEG_ENCODE) {
1245 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1246 V4L2_CID_JPEG_COMPRESSION_QUALITY,
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001247 0, 3, 1, S5P_JPEG_COMPR_QUAL_WORST);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001248
1249 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1250 V4L2_CID_JPEG_RESTART_INTERVAL,
1251 0, 3, 0xffff, 0);
Jacek Anaszewskifdf9e2b2013-11-21 13:33:41 -03001252 if (ctx->jpeg->variant->version == SJPEG_S5P)
1253 mask = ~0x06; /* 422, 420 */
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001254 }
1255
1256 ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1257 V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
1258 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask,
1259 V4L2_JPEG_CHROMA_SUBSAMPLING_422);
1260
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001261 if (ctx->ctrl_handler.error) {
1262 ret = ctx->ctrl_handler.error;
1263 goto error_free;
1264 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001265
1266 if (ctx->mode == S5P_JPEG_DECODE)
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001267 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
1268 V4L2_CTRL_FLAG_READ_ONLY;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001269
1270 ret = v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
1271 if (ret < 0)
1272 goto error_free;
1273
1274 return ret;
1275
1276error_free:
1277 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
1278 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001279}
1280
1281static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
1282 .vidioc_querycap = s5p_jpeg_querycap,
1283
1284 .vidioc_enum_fmt_vid_cap = s5p_jpeg_enum_fmt_vid_cap,
1285 .vidioc_enum_fmt_vid_out = s5p_jpeg_enum_fmt_vid_out,
1286
1287 .vidioc_g_fmt_vid_cap = s5p_jpeg_g_fmt,
1288 .vidioc_g_fmt_vid_out = s5p_jpeg_g_fmt,
1289
1290 .vidioc_try_fmt_vid_cap = s5p_jpeg_try_fmt_vid_cap,
1291 .vidioc_try_fmt_vid_out = s5p_jpeg_try_fmt_vid_out,
1292
1293 .vidioc_s_fmt_vid_cap = s5p_jpeg_s_fmt_vid_cap,
1294 .vidioc_s_fmt_vid_out = s5p_jpeg_s_fmt_vid_out,
1295
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001296 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
1297 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
1298 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
1299 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001300
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001301 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
1302 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001303
1304 .vidioc_g_selection = s5p_jpeg_g_selection,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001305};
1306
1307/*
1308 * ============================================================================
1309 * mem2mem callbacks
1310 * ============================================================================
1311 */
1312
1313static void s5p_jpeg_device_run(void *priv)
1314{
1315 struct s5p_jpeg_ctx *ctx = priv;
1316 struct s5p_jpeg *jpeg = ctx->jpeg;
1317 struct vb2_buffer *src_buf, *dst_buf;
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001318 unsigned long src_addr, dst_addr, flags;
1319
1320 spin_lock_irqsave(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001321
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001322 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1323 dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001324 src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
1325 dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
1326
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001327 s5p_jpeg_reset(jpeg->regs);
1328 s5p_jpeg_poweron(jpeg->regs);
1329 s5p_jpeg_proc_mode(jpeg->regs, ctx->mode);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001330 if (ctx->mode == S5P_JPEG_ENCODE) {
1331 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001332 s5p_jpeg_input_raw_mode(jpeg->regs,
1333 S5P_JPEG_RAW_IN_565);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001334 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001335 s5p_jpeg_input_raw_mode(jpeg->regs,
1336 S5P_JPEG_RAW_IN_422);
1337 s5p_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
1338 s5p_jpeg_dri(jpeg->regs, ctx->restart_interval);
1339 s5p_jpeg_x(jpeg->regs, ctx->out_q.w);
1340 s5p_jpeg_y(jpeg->regs, ctx->out_q.h);
1341 s5p_jpeg_imgadr(jpeg->regs, src_addr);
1342 s5p_jpeg_jpgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001343
1344 /* ultimately comes from sizeimage from userspace */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001345 s5p_jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001346
1347 /* JPEG RGB to YCbCr conversion matrix */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001348 s5p_jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11);
1349 s5p_jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12);
1350 s5p_jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13);
1351 s5p_jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21);
1352 s5p_jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22);
1353 s5p_jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23);
1354 s5p_jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31);
1355 s5p_jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32);
1356 s5p_jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001357
1358 /*
1359 * JPEG IP allows storing 4 quantization tables
1360 * We fill table 0 for luma and table 1 for chroma
1361 */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03001362 s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
1363 s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001364 /* use table 0 for Y */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001365 s5p_jpeg_qtbl(jpeg->regs, 1, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001366 /* use table 1 for Cb and Cr*/
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001367 s5p_jpeg_qtbl(jpeg->regs, 2, 1);
1368 s5p_jpeg_qtbl(jpeg->regs, 3, 1);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001369
1370 /* Y, Cb, Cr use Huffman table 0 */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001371 s5p_jpeg_htbl_ac(jpeg->regs, 1);
1372 s5p_jpeg_htbl_dc(jpeg->regs, 1);
1373 s5p_jpeg_htbl_ac(jpeg->regs, 2);
1374 s5p_jpeg_htbl_dc(jpeg->regs, 2);
1375 s5p_jpeg_htbl_ac(jpeg->regs, 3);
1376 s5p_jpeg_htbl_dc(jpeg->regs, 3);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001377 } else { /* S5P_JPEG_DECODE */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001378 s5p_jpeg_rst_int_enable(jpeg->regs, true);
1379 s5p_jpeg_data_num_int_enable(jpeg->regs, true);
1380 s5p_jpeg_final_mcu_num_int_enable(jpeg->regs, true);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001381 if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001382 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001383 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001384 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420);
1385 s5p_jpeg_jpgadr(jpeg->regs, src_addr);
1386 s5p_jpeg_imgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001387 }
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001388
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001389 s5p_jpeg_start(jpeg->regs);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001390
1391 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001392}
1393
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001394static void exynos4_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
1395{
1396 struct s5p_jpeg *jpeg = ctx->jpeg;
1397 struct s5p_jpeg_fmt *fmt;
1398 struct vb2_buffer *vb;
1399 struct s5p_jpeg_addr jpeg_addr;
1400 u32 pix_size, padding_bytes = 0;
1401
1402 pix_size = ctx->cap_q.w * ctx->cap_q.h;
1403
1404 if (ctx->mode == S5P_JPEG_ENCODE) {
1405 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1406 fmt = ctx->out_q.fmt;
1407 if (ctx->out_q.w % 2 && fmt->h_align > 0)
1408 padding_bytes = ctx->out_q.h;
1409 } else {
1410 fmt = ctx->cap_q.fmt;
1411 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1412 }
1413
1414 jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
1415
1416 if (fmt->colplanes == 2) {
1417 jpeg_addr.cb = jpeg_addr.y + pix_size - padding_bytes;
1418 } else if (fmt->colplanes == 3) {
1419 jpeg_addr.cb = jpeg_addr.y + pix_size;
1420 if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
1421 jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
1422 else
1423 jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
1424 }
1425
1426 exynos4_jpeg_set_frame_buf_address(jpeg->regs, &jpeg_addr);
1427}
1428
1429static void exynos4_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
1430{
1431 struct s5p_jpeg *jpeg = ctx->jpeg;
1432 struct vb2_buffer *vb;
1433 unsigned int jpeg_addr = 0;
1434
1435 if (ctx->mode == S5P_JPEG_ENCODE)
1436 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1437 else
1438 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1439
1440 jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
1441 exynos4_jpeg_set_stream_buf_address(jpeg->regs, jpeg_addr);
1442}
1443
1444static void exynos4_jpeg_device_run(void *priv)
1445{
1446 struct s5p_jpeg_ctx *ctx = priv;
1447 struct s5p_jpeg *jpeg = ctx->jpeg;
1448 unsigned int bitstream_size;
1449 unsigned long flags;
1450
1451 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1452
1453 if (ctx->mode == S5P_JPEG_ENCODE) {
1454 exynos4_jpeg_sw_reset(jpeg->regs);
1455 exynos4_jpeg_set_interrupt(jpeg->regs);
1456 exynos4_jpeg_set_huf_table_enable(jpeg->regs, 1);
1457
1458 exynos4_jpeg_set_huff_tbl(jpeg->regs);
1459
1460 /*
1461 * JPEG IP allows storing 4 quantization tables
1462 * We fill table 0 for luma and table 1 for chroma
1463 */
1464 exynos4_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
1465 exynos4_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
1466
1467 exynos4_jpeg_set_encode_tbl_select(jpeg->regs,
1468 ctx->compr_quality);
1469 exynos4_jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w,
1470 ctx->cap_q.h);
1471
1472 exynos4_jpeg_set_enc_out_fmt(jpeg->regs, ctx->subsampling);
1473 exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->out_q.fmt->fourcc);
1474 exynos4_jpeg_set_img_addr(ctx);
1475 exynos4_jpeg_set_jpeg_addr(ctx);
1476 exynos4_jpeg_set_encode_hoff_cnt(jpeg->regs,
1477 ctx->out_q.fmt->fourcc);
1478 } else {
1479 exynos4_jpeg_sw_reset(jpeg->regs);
1480 exynos4_jpeg_set_interrupt(jpeg->regs);
1481 exynos4_jpeg_set_img_addr(ctx);
1482 exynos4_jpeg_set_jpeg_addr(ctx);
1483 exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->cap_q.fmt->fourcc);
1484
1485 bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 32);
1486
1487 exynos4_jpeg_set_dec_bitstream_size(jpeg->regs, bitstream_size);
1488 }
1489
1490 exynos4_jpeg_set_enc_dec_mode(jpeg->regs, ctx->mode);
1491
1492 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1493}
1494
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001495static int s5p_jpeg_job_ready(void *priv)
1496{
1497 struct s5p_jpeg_ctx *ctx = priv;
1498
1499 if (ctx->mode == S5P_JPEG_DECODE)
1500 return ctx->hdr_parsed;
1501 return 1;
1502}
1503
1504static void s5p_jpeg_job_abort(void *priv)
1505{
1506}
1507
1508static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = {
1509 .device_run = s5p_jpeg_device_run,
1510 .job_ready = s5p_jpeg_job_ready,
1511 .job_abort = s5p_jpeg_job_abort,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001512}
1513;
1514static struct v4l2_m2m_ops exynos_jpeg_m2m_ops = {
1515 .device_run = exynos4_jpeg_device_run,
1516 .job_ready = s5p_jpeg_job_ready,
1517 .job_abort = s5p_jpeg_job_abort,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001518};
1519
1520/*
1521 * ============================================================================
1522 * Queue operations
1523 * ============================================================================
1524 */
1525
Marek Szyprowski719c1742012-01-13 05:12:38 -03001526static int s5p_jpeg_queue_setup(struct vb2_queue *vq,
1527 const struct v4l2_format *fmt,
1528 unsigned int *nbuffers, unsigned int *nplanes,
1529 unsigned int sizes[], void *alloc_ctxs[])
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001530{
1531 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
1532 struct s5p_jpeg_q_data *q_data = NULL;
1533 unsigned int size, count = *nbuffers;
1534
1535 q_data = get_q_data(ctx, vq->type);
1536 BUG_ON(q_data == NULL);
1537
1538 size = q_data->size;
1539
1540 /*
1541 * header is parsed during decoding and parsed information stored
1542 * in the context so we do not allow another buffer to overwrite it
1543 */
1544 if (ctx->mode == S5P_JPEG_DECODE)
1545 count = 1;
1546
1547 *nbuffers = count;
1548 *nplanes = 1;
1549 sizes[0] = size;
1550 alloc_ctxs[0] = ctx->jpeg->alloc_ctx;
1551
1552 return 0;
1553}
1554
1555static int s5p_jpeg_buf_prepare(struct vb2_buffer *vb)
1556{
1557 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1558 struct s5p_jpeg_q_data *q_data = NULL;
1559
1560 q_data = get_q_data(ctx, vb->vb2_queue->type);
1561 BUG_ON(q_data == NULL);
1562
1563 if (vb2_plane_size(vb, 0) < q_data->size) {
1564 pr_err("%s data will not fit into plane (%lu < %lu)\n",
1565 __func__, vb2_plane_size(vb, 0),
1566 (long)q_data->size);
1567 return -EINVAL;
1568 }
1569
1570 vb2_set_plane_payload(vb, 0, q_data->size);
1571
1572 return 0;
1573}
1574
1575static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
1576{
1577 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1578
1579 if (ctx->mode == S5P_JPEG_DECODE &&
1580 vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
1581 struct s5p_jpeg_q_data tmp, *q_data;
1582 ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp,
1583 (unsigned long)vb2_plane_vaddr(vb, 0),
1584 min((unsigned long)ctx->out_q.size,
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001585 vb2_get_plane_payload(vb, 0)), ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001586 if (!ctx->hdr_parsed) {
1587 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
1588 return;
1589 }
1590
1591 q_data = &ctx->out_q;
1592 q_data->w = tmp.w;
1593 q_data->h = tmp.h;
1594
1595 q_data = &ctx->cap_q;
1596 q_data->w = tmp.w;
1597 q_data->h = tmp.h;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001598 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001599
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001600 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001601}
1602
1603static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
1604{
1605 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
1606 int ret;
1607
1608 ret = pm_runtime_get_sync(ctx->jpeg->dev);
1609
1610 return ret > 0 ? 0 : ret;
1611}
1612
1613static int s5p_jpeg_stop_streaming(struct vb2_queue *q)
1614{
1615 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
1616
1617 pm_runtime_put(ctx->jpeg->dev);
1618
1619 return 0;
1620}
1621
1622static struct vb2_ops s5p_jpeg_qops = {
1623 .queue_setup = s5p_jpeg_queue_setup,
1624 .buf_prepare = s5p_jpeg_buf_prepare,
1625 .buf_queue = s5p_jpeg_buf_queue,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001626 .wait_prepare = vb2_ops_wait_prepare,
1627 .wait_finish = vb2_ops_wait_finish,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001628 .start_streaming = s5p_jpeg_start_streaming,
1629 .stop_streaming = s5p_jpeg_stop_streaming,
1630};
1631
1632static int queue_init(void *priv, struct vb2_queue *src_vq,
1633 struct vb2_queue *dst_vq)
1634{
1635 struct s5p_jpeg_ctx *ctx = priv;
1636 int ret;
1637
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001638 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1639 src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
1640 src_vq->drv_priv = ctx;
1641 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1642 src_vq->ops = &s5p_jpeg_qops;
1643 src_vq->mem_ops = &vb2_dma_contig_memops;
Kamil Debskiaca326a2013-04-24 10:08:02 -03001644 src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001645 src_vq->lock = &ctx->jpeg->lock;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001646
1647 ret = vb2_queue_init(src_vq);
1648 if (ret)
1649 return ret;
1650
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001651 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1652 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
1653 dst_vq->drv_priv = ctx;
1654 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1655 dst_vq->ops = &s5p_jpeg_qops;
1656 dst_vq->mem_ops = &vb2_dma_contig_memops;
Kamil Debskiaca326a2013-04-24 10:08:02 -03001657 dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001658 dst_vq->lock = &ctx->jpeg->lock;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001659
1660 return vb2_queue_init(dst_vq);
1661}
1662
1663/*
1664 * ============================================================================
1665 * ISR
1666 * ============================================================================
1667 */
1668
1669static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
1670{
1671 struct s5p_jpeg *jpeg = dev_id;
1672 struct s5p_jpeg_ctx *curr_ctx;
1673 struct vb2_buffer *src_buf, *dst_buf;
1674 unsigned long payload_size = 0;
1675 enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
1676 bool enc_jpeg_too_large = false;
1677 bool timer_elapsed = false;
1678 bool op_completed = false;
1679
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001680 spin_lock(&jpeg->slock);
1681
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001682 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
1683
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001684 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
1685 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001686
1687 if (curr_ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001688 enc_jpeg_too_large = s5p_jpeg_enc_stream_stat(jpeg->regs);
1689 timer_elapsed = s5p_jpeg_timer_stat(jpeg->regs);
1690 op_completed = s5p_jpeg_result_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001691 if (curr_ctx->mode == S5P_JPEG_DECODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001692 op_completed = op_completed &&
1693 s5p_jpeg_stream_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001694
1695 if (enc_jpeg_too_large) {
1696 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001697 s5p_jpeg_clear_enc_stream_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001698 } else if (timer_elapsed) {
1699 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001700 s5p_jpeg_clear_timer_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001701 } else if (!op_completed) {
1702 state = VB2_BUF_STATE_ERROR;
1703 } else {
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001704 payload_size = s5p_jpeg_compressed_size(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001705 }
1706
Kamil Debskiaca326a2013-04-24 10:08:02 -03001707 dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
1708 dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
1709
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001710 v4l2_m2m_buf_done(src_buf, state);
1711 if (curr_ctx->mode == S5P_JPEG_ENCODE)
1712 vb2_set_plane_payload(dst_buf, 0, payload_size);
1713 v4l2_m2m_buf_done(dst_buf, state);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001714 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001715
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001716 curr_ctx->subsampling = s5p_jpeg_get_subsampling_mode(jpeg->regs);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001717 spin_unlock(&jpeg->slock);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001718
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001719 s5p_jpeg_clear_int(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001720
1721 return IRQ_HANDLED;
1722}
1723
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001724static irqreturn_t exynos4_jpeg_irq(int irq, void *priv)
1725{
1726 unsigned int int_status;
1727 struct vb2_buffer *src_vb, *dst_vb;
1728 struct s5p_jpeg *jpeg = priv;
1729 struct s5p_jpeg_ctx *curr_ctx;
1730 unsigned long payload_size = 0;
1731
1732 spin_lock(&jpeg->slock);
1733
1734 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
1735
1736 src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
1737 dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
1738
1739 int_status = exynos4_jpeg_get_int_status(jpeg->regs);
1740
1741 if (int_status) {
1742 switch (int_status & 0x1f) {
1743 case 0x1:
1744 jpeg->irq_ret = ERR_PROT;
1745 break;
1746 case 0x2:
1747 jpeg->irq_ret = OK_ENC_OR_DEC;
1748 break;
1749 case 0x4:
1750 jpeg->irq_ret = ERR_DEC_INVALID_FORMAT;
1751 break;
1752 case 0x8:
1753 jpeg->irq_ret = ERR_MULTI_SCAN;
1754 break;
1755 case 0x10:
1756 jpeg->irq_ret = ERR_FRAME;
1757 break;
1758 default:
1759 jpeg->irq_ret = ERR_UNKNOWN;
1760 break;
1761 }
1762 } else {
1763 jpeg->irq_ret = ERR_UNKNOWN;
1764 }
1765
1766 if (jpeg->irq_ret == OK_ENC_OR_DEC) {
1767 if (curr_ctx->mode == S5P_JPEG_ENCODE) {
1768 payload_size = exynos4_jpeg_get_stream_size(jpeg->regs);
1769 vb2_set_plane_payload(dst_vb, 0, payload_size);
1770 }
1771 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
1772 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
1773 } else {
1774 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
1775 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
1776 }
1777
1778 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
1779 curr_ctx->subsampling = exynos4_jpeg_get_frame_fmt(jpeg->regs);
1780
1781 spin_unlock(&jpeg->slock);
1782 return IRQ_HANDLED;
1783}
1784
1785static void *jpeg_get_drv_data(struct platform_device *pdev);
1786
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001787/*
1788 * ============================================================================
1789 * Driver basic infrastructure
1790 * ============================================================================
1791 */
1792
1793static int s5p_jpeg_probe(struct platform_device *pdev)
1794{
1795 struct s5p_jpeg *jpeg;
1796 struct resource *res;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001797 struct v4l2_m2m_ops *samsung_jpeg_m2m_ops;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001798 int ret;
1799
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001800 if (!pdev->dev.of_node)
1801 return -ENODEV;
1802
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001803 /* JPEG IP abstraction struct */
Sachin Kamat5b58b952012-05-14 06:33:34 -03001804 jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001805 if (!jpeg)
1806 return -ENOMEM;
1807
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001808 jpeg->variant = jpeg_get_drv_data(pdev);
1809
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001810 mutex_init(&jpeg->lock);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001811 spin_lock_init(&jpeg->slock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001812 jpeg->dev = &pdev->dev;
1813
1814 /* memory-mapped registers */
1815 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001816
Thierry Redingf23999e2013-01-21 06:09:07 -03001817 jpeg->regs = devm_ioremap_resource(&pdev->dev, res);
1818 if (IS_ERR(jpeg->regs))
1819 return PTR_ERR(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001820
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001821 /* interrupt service routine registration */
1822 jpeg->irq = ret = platform_get_irq(pdev, 0);
1823 if (ret < 0) {
1824 dev_err(&pdev->dev, "cannot find IRQ\n");
Sachin Kamat5b58b952012-05-14 06:33:34 -03001825 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001826 }
1827
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001828 ret = devm_request_irq(&pdev->dev, jpeg->irq, jpeg->variant->jpeg_irq,
1829 0, dev_name(&pdev->dev), jpeg);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001830 if (ret) {
1831 dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
Sachin Kamat5b58b952012-05-14 06:33:34 -03001832 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001833 }
1834
1835 /* clocks */
1836 jpeg->clk = clk_get(&pdev->dev, "jpeg");
1837 if (IS_ERR(jpeg->clk)) {
1838 dev_err(&pdev->dev, "cannot get clock\n");
1839 ret = PTR_ERR(jpeg->clk);
Sachin Kamat5b58b952012-05-14 06:33:34 -03001840 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001841 }
1842 dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001843
1844 /* v4l2 device */
1845 ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
1846 if (ret) {
1847 dev_err(&pdev->dev, "Failed to register v4l2 device\n");
1848 goto clk_get_rollback;
1849 }
1850
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001851 if (jpeg->variant->version == SJPEG_S5P)
1852 samsung_jpeg_m2m_ops = &s5p_jpeg_m2m_ops;
1853 else
1854 samsung_jpeg_m2m_ops = &exynos_jpeg_m2m_ops;
1855
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001856 /* mem2mem device */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001857 jpeg->m2m_dev = v4l2_m2m_init(samsung_jpeg_m2m_ops);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001858 if (IS_ERR(jpeg->m2m_dev)) {
1859 v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
1860 ret = PTR_ERR(jpeg->m2m_dev);
1861 goto device_register_rollback;
1862 }
1863
1864 jpeg->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
1865 if (IS_ERR(jpeg->alloc_ctx)) {
1866 v4l2_err(&jpeg->v4l2_dev, "Failed to init memory allocator\n");
1867 ret = PTR_ERR(jpeg->alloc_ctx);
1868 goto m2m_init_rollback;
1869 }
1870
1871 /* JPEG encoder /dev/videoX node */
1872 jpeg->vfd_encoder = video_device_alloc();
1873 if (!jpeg->vfd_encoder) {
1874 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
1875 ret = -ENOMEM;
1876 goto vb2_allocator_rollback;
1877 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03001878 snprintf(jpeg->vfd_encoder->name, sizeof(jpeg->vfd_encoder->name),
1879 "%s-enc", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001880 jpeg->vfd_encoder->fops = &s5p_jpeg_fops;
1881 jpeg->vfd_encoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
1882 jpeg->vfd_encoder->minor = -1;
1883 jpeg->vfd_encoder->release = video_device_release;
1884 jpeg->vfd_encoder->lock = &jpeg->lock;
1885 jpeg->vfd_encoder->v4l2_dev = &jpeg->v4l2_dev;
Hans Verkuil954f3402012-09-05 06:05:50 -03001886 jpeg->vfd_encoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001887
1888 ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
1889 if (ret) {
1890 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
1891 goto enc_vdev_alloc_rollback;
1892 }
1893
1894 video_set_drvdata(jpeg->vfd_encoder, jpeg);
1895 v4l2_info(&jpeg->v4l2_dev,
1896 "encoder device registered as /dev/video%d\n",
1897 jpeg->vfd_encoder->num);
1898
1899 /* JPEG decoder /dev/videoX node */
1900 jpeg->vfd_decoder = video_device_alloc();
1901 if (!jpeg->vfd_decoder) {
1902 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
1903 ret = -ENOMEM;
1904 goto enc_vdev_register_rollback;
1905 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03001906 snprintf(jpeg->vfd_decoder->name, sizeof(jpeg->vfd_decoder->name),
1907 "%s-dec", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001908 jpeg->vfd_decoder->fops = &s5p_jpeg_fops;
1909 jpeg->vfd_decoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
1910 jpeg->vfd_decoder->minor = -1;
1911 jpeg->vfd_decoder->release = video_device_release;
1912 jpeg->vfd_decoder->lock = &jpeg->lock;
1913 jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev;
Jacek Anaszewski7f7d8fe2013-09-11 06:17:45 -03001914 jpeg->vfd_decoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001915
1916 ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
1917 if (ret) {
1918 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
1919 goto dec_vdev_alloc_rollback;
1920 }
1921
1922 video_set_drvdata(jpeg->vfd_decoder, jpeg);
1923 v4l2_info(&jpeg->v4l2_dev,
1924 "decoder device registered as /dev/video%d\n",
1925 jpeg->vfd_decoder->num);
1926
1927 /* final statements & power management */
1928 platform_set_drvdata(pdev, jpeg);
1929
1930 pm_runtime_enable(&pdev->dev);
1931
1932 v4l2_info(&jpeg->v4l2_dev, "Samsung S5P JPEG codec\n");
1933
1934 return 0;
1935
1936dec_vdev_alloc_rollback:
1937 video_device_release(jpeg->vfd_decoder);
1938
1939enc_vdev_register_rollback:
1940 video_unregister_device(jpeg->vfd_encoder);
1941
1942enc_vdev_alloc_rollback:
1943 video_device_release(jpeg->vfd_encoder);
1944
1945vb2_allocator_rollback:
1946 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
1947
1948m2m_init_rollback:
1949 v4l2_m2m_release(jpeg->m2m_dev);
1950
1951device_register_rollback:
1952 v4l2_device_unregister(&jpeg->v4l2_dev);
1953
1954clk_get_rollback:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001955 clk_put(jpeg->clk);
1956
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001957 return ret;
1958}
1959
1960static int s5p_jpeg_remove(struct platform_device *pdev)
1961{
1962 struct s5p_jpeg *jpeg = platform_get_drvdata(pdev);
1963
1964 pm_runtime_disable(jpeg->dev);
1965
1966 video_unregister_device(jpeg->vfd_decoder);
1967 video_device_release(jpeg->vfd_decoder);
1968 video_unregister_device(jpeg->vfd_encoder);
1969 video_device_release(jpeg->vfd_encoder);
1970 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
1971 v4l2_m2m_release(jpeg->m2m_dev);
1972 v4l2_device_unregister(&jpeg->v4l2_dev);
1973
Jacek Anaszewskif1347132013-11-25 06:58:13 -03001974 if (!pm_runtime_status_suspended(&pdev->dev))
1975 clk_disable_unprepare(jpeg->clk);
1976
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001977 clk_put(jpeg->clk);
1978
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001979 return 0;
1980}
1981
1982static int s5p_jpeg_runtime_suspend(struct device *dev)
1983{
Jacek Anaszewskif1347132013-11-25 06:58:13 -03001984 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
1985
1986 clk_disable_unprepare(jpeg->clk);
1987
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001988 return 0;
1989}
1990
1991static int s5p_jpeg_runtime_resume(struct device *dev)
1992{
1993 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001994 unsigned long flags;
Jacek Anaszewskif1347132013-11-25 06:58:13 -03001995 int ret;
1996
1997 ret = clk_prepare_enable(jpeg->clk);
1998 if (ret < 0)
1999 return ret;
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03002000
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002001 spin_lock_irqsave(&jpeg->slock, flags);
2002
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002003 /*
2004 * JPEG IP allows storing two Huffman tables for each component
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002005 * We fill table 0 for each component and do this here only
2006 * for S5PC210 device as Exynos4x12 requires programming its
2007 * Huffman tables each time the encoding process is initialized.
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002008 */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002009 if (jpeg->variant->version == SJPEG_S5P) {
2010 s5p_jpeg_set_hdctbl(jpeg->regs);
2011 s5p_jpeg_set_hdctblg(jpeg->regs);
2012 s5p_jpeg_set_hactbl(jpeg->regs);
2013 s5p_jpeg_set_hactblg(jpeg->regs);
2014 }
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03002015
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03002016 spin_unlock_irqrestore(&jpeg->slock, flags);
2017
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002018 return 0;
2019}
2020
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002021static int s5p_jpeg_suspend(struct device *dev)
2022{
2023 if (pm_runtime_suspended(dev))
2024 return 0;
2025
2026 return s5p_jpeg_runtime_suspend(dev);
2027}
2028
2029static int s5p_jpeg_resume(struct device *dev)
2030{
2031 if (pm_runtime_suspended(dev))
2032 return 0;
2033
2034 return s5p_jpeg_runtime_resume(dev);
2035}
2036
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002037static const struct dev_pm_ops s5p_jpeg_pm_ops = {
Jacek Anaszewskif1347132013-11-25 06:58:13 -03002038 SET_SYSTEM_SLEEP_PM_OPS(s5p_jpeg_suspend, s5p_jpeg_resume)
2039 SET_RUNTIME_PM_OPS(s5p_jpeg_runtime_suspend, s5p_jpeg_runtime_resume, NULL)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002040};
2041
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03002042#ifdef CONFIG_OF
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002043static struct s5p_jpeg_variant s5p_jpeg_drvdata = {
2044 .version = SJPEG_S5P,
2045 .jpeg_irq = s5p_jpeg_irq,
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03002046};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002047
2048static struct s5p_jpeg_variant exynos4_jpeg_drvdata = {
2049 .version = SJPEG_EXYNOS4,
2050 .jpeg_irq = exynos4_jpeg_irq,
2051};
2052
2053static const struct of_device_id samsung_jpeg_match[] = {
2054 {
2055 .compatible = "samsung,s5pv210-jpeg",
2056 .data = &s5p_jpeg_drvdata,
2057 }, {
2058 .compatible = "samsung,exynos4210-jpeg",
2059 .data = &s5p_jpeg_drvdata,
2060 }, {
2061 .compatible = "samsung,exynos4212-jpeg",
2062 .data = &exynos4_jpeg_drvdata,
2063 },
2064 {},
2065};
2066
2067MODULE_DEVICE_TABLE(of, samsung_jpeg_match);
2068
2069static void *jpeg_get_drv_data(struct platform_device *pdev)
2070{
2071 struct s5p_jpeg_variant *driver_data = NULL;
2072 const struct of_device_id *match;
2073
2074 match = of_match_node(of_match_ptr(samsung_jpeg_match),
2075 pdev->dev.of_node);
2076 if (match)
2077 driver_data = (struct s5p_jpeg_variant *)match->data;
2078
2079 return driver_data;
2080}
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03002081#endif
2082
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002083static struct platform_driver s5p_jpeg_driver = {
2084 .probe = s5p_jpeg_probe,
2085 .remove = s5p_jpeg_remove,
2086 .driver = {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002087 .of_match_table = of_match_ptr(samsung_jpeg_match),
2088 .owner = THIS_MODULE,
2089 .name = S5P_JPEG_M2M_NAME,
2090 .pm = &s5p_jpeg_pm_ops,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002091 },
2092};
2093
Sachin Kamat87e94292012-07-03 05:54:33 -03002094module_platform_driver(s5p_jpeg_driver);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002095
2096MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03002097MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03002098MODULE_DESCRIPTION("Samsung JPEG codec driver");
2099MODULE_LICENSE("GPL");