blob: fbadbb04f2e9ab62479f3253624c3cba8c5ea562 [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
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300361static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c)
362{
363 return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler);
364}
365
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300366static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh)
367{
368 return container_of(fh, struct s5p_jpeg_ctx, fh);
369}
370
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300371static inline void s5p_jpeg_set_qtbl(void __iomem *regs,
372 const unsigned char *qtbl,
373 unsigned long tab, int len)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300374{
375 int i;
376
377 for (i = 0; i < len; i++)
378 writel((unsigned int)qtbl[i], regs + tab + (i * 0x04));
379}
380
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300381static inline void s5p_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300382{
383 /* this driver fills quantisation table 0 with data for luma */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300384 s5p_jpeg_set_qtbl(regs, qtbl_luminance[quality],
385 S5P_JPG_QTBL_CONTENT(0),
386 ARRAY_SIZE(qtbl_luminance[quality]));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300387}
388
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300389static inline void s5p_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300390{
391 /* this driver fills quantisation table 1 with data for chroma */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300392 s5p_jpeg_set_qtbl(regs, qtbl_chrominance[quality],
393 S5P_JPG_QTBL_CONTENT(1),
394 ARRAY_SIZE(qtbl_chrominance[quality]));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300395}
396
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300397static inline void s5p_jpeg_set_htbl(void __iomem *regs,
398 const unsigned char *htbl,
399 unsigned long tab, int len)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300400{
401 int i;
402
403 for (i = 0; i < len; i++)
404 writel((unsigned int)htbl[i], regs + tab + (i * 0x04));
405}
406
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300407static inline void s5p_jpeg_set_hdctbl(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300408{
409 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300410 s5p_jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0),
411 ARRAY_SIZE(hdctbl0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300412}
413
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300414static inline void s5p_jpeg_set_hdctblg(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300415{
416 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300417 s5p_jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0),
418 ARRAY_SIZE(hdctblg0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300419}
420
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300421static inline void s5p_jpeg_set_hactbl(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300422{
423 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300424 s5p_jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0),
425 ARRAY_SIZE(hactbl0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300426}
427
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300428static inline void s5p_jpeg_set_hactblg(void __iomem *regs)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300429{
430 /* this driver fills table 0 for this component */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -0300431 s5p_jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0),
432 ARRAY_SIZE(hactblg0));
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300433}
434
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300435static inline void exynos4_jpeg_set_tbl(void __iomem *regs,
436 const unsigned char *tbl,
437 unsigned long tab, int len)
438{
439 int i;
440 unsigned int dword;
441
442 for (i = 0; i < len; i += 4) {
443 dword = tbl[i] |
444 (tbl[i + 1] << 8) |
445 (tbl[i + 2] << 16) |
446 (tbl[i + 3] << 24);
447 writel(dword, regs + tab + i);
448 }
449}
450
451static inline void exynos4_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
452{
453 /* this driver fills quantisation table 0 with data for luma */
454 exynos4_jpeg_set_tbl(regs, qtbl_luminance[quality],
455 EXYNOS4_QTBL_CONTENT(0),
456 ARRAY_SIZE(qtbl_luminance[quality]));
457}
458
459static inline void exynos4_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
460{
461 /* this driver fills quantisation table 1 with data for chroma */
462 exynos4_jpeg_set_tbl(regs, qtbl_chrominance[quality],
463 EXYNOS4_QTBL_CONTENT(1),
464 ARRAY_SIZE(qtbl_chrominance[quality]));
465}
466
467void exynos4_jpeg_set_huff_tbl(void __iomem *base)
468{
469 exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCLL,
470 ARRAY_SIZE(hdctbl0));
471 exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCCL,
472 ARRAY_SIZE(hdctbl0));
473 exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCLV,
474 ARRAY_SIZE(hdctblg0));
475 exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCCV,
476 ARRAY_SIZE(hdctblg0));
477 exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACLL,
478 ARRAY_SIZE(hactbl0));
479 exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACCL,
480 ARRAY_SIZE(hactbl0));
481 exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACLV,
482 ARRAY_SIZE(hactblg0));
483 exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACCV,
484 ARRAY_SIZE(hactblg0));
485}
486
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300487/*
488 * ============================================================================
489 * Device file operations
490 * ============================================================================
491 */
492
493static int queue_init(void *priv, struct vb2_queue *src_vq,
494 struct vb2_queue *dst_vq);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300495static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
496 __u32 pixelformat, unsigned int fmt_type);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300497static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300498
499static int s5p_jpeg_open(struct file *file)
500{
501 struct s5p_jpeg *jpeg = video_drvdata(file);
502 struct video_device *vfd = video_devdata(file);
503 struct s5p_jpeg_ctx *ctx;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300504 struct s5p_jpeg_fmt *out_fmt, *cap_fmt;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300505 int ret = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300506
Sachin Kamatb5146c92012-08-16 08:52:58 -0300507 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300508 if (!ctx)
509 return -ENOMEM;
510
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300511 if (mutex_lock_interruptible(&jpeg->lock)) {
512 ret = -ERESTARTSYS;
513 goto free;
514 }
515
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300516 v4l2_fh_init(&ctx->fh, vfd);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300517 /* Use separate control handler per file handle */
518 ctx->fh.ctrl_handler = &ctx->ctrl_handler;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300519 file->private_data = &ctx->fh;
520 v4l2_fh_add(&ctx->fh);
521
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300522 ctx->jpeg = jpeg;
523 if (vfd == jpeg->vfd_encoder) {
524 ctx->mode = S5P_JPEG_ENCODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300525 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB565,
526 FMT_TYPE_OUTPUT);
527 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
528 FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300529 } else {
530 ctx->mode = S5P_JPEG_DECODE;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300531 out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
532 FMT_TYPE_OUTPUT);
533 cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_YUYV,
534 FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300535 }
536
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300537 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
538 if (IS_ERR(ctx->fh.m2m_ctx)) {
539 ret = PTR_ERR(ctx->fh.m2m_ctx);
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300540 goto error;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300541 }
542
543 ctx->out_q.fmt = out_fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300544 ctx->cap_q.fmt = cap_fmt;
545
546 ret = s5p_jpeg_controls_create(ctx);
547 if (ret < 0)
548 goto error;
549
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300550 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300551 return 0;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300552
553error:
554 v4l2_fh_del(&ctx->fh);
555 v4l2_fh_exit(&ctx->fh);
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300556 mutex_unlock(&jpeg->lock);
557free:
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300558 kfree(ctx);
559 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300560}
561
562static int s5p_jpeg_release(struct file *file)
563{
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300564 struct s5p_jpeg *jpeg = video_drvdata(file);
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300565 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300566
Hans Verkuilb0d5cd62012-06-24 06:54:18 -0300567 mutex_lock(&jpeg->lock);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300568 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -0300569 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300570 v4l2_fh_del(&ctx->fh);
571 v4l2_fh_exit(&ctx->fh);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300572 kfree(ctx);
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300573 mutex_unlock(&jpeg->lock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300574
575 return 0;
576}
577
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300578static const struct v4l2_file_operations s5p_jpeg_fops = {
579 .owner = THIS_MODULE,
580 .open = s5p_jpeg_open,
581 .release = s5p_jpeg_release,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300582 .poll = v4l2_m2m_fop_poll,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300583 .unlocked_ioctl = video_ioctl2,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300584 .mmap = v4l2_m2m_fop_mmap,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300585};
586
587/*
588 * ============================================================================
589 * video ioctl operations
590 * ============================================================================
591 */
592
593static int get_byte(struct s5p_jpeg_buffer *buf)
594{
595 if (buf->curr >= buf->size)
596 return -1;
597
598 return ((unsigned char *)buf->data)[buf->curr++];
599}
600
601static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word)
602{
603 unsigned int temp;
604 int byte;
605
606 byte = get_byte(buf);
607 if (byte == -1)
608 return -1;
609 temp = byte << 8;
610 byte = get_byte(buf);
611 if (byte == -1)
612 return -1;
613 *word = (unsigned int)byte | temp;
614 return 0;
615}
616
617static void skip(struct s5p_jpeg_buffer *buf, long len)
618{
619 if (len <= 0)
620 return;
621
622 while (len--)
623 get_byte(buf);
624}
625
626static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
627 unsigned long buffer, unsigned long size)
628{
629 int c, components, notfound;
630 unsigned int height, width, word;
631 long length;
632 struct s5p_jpeg_buffer jpeg_buffer;
633
634 jpeg_buffer.size = size;
635 jpeg_buffer.data = buffer;
636 jpeg_buffer.curr = 0;
637
638 notfound = 1;
639 while (notfound) {
640 c = get_byte(&jpeg_buffer);
641 if (c == -1)
642 break;
643 if (c != 0xff)
644 continue;
645 do
646 c = get_byte(&jpeg_buffer);
647 while (c == 0xff);
648 if (c == -1)
649 break;
650 if (c == 0)
651 continue;
652 length = 0;
653 switch (c) {
654 /* SOF0: baseline JPEG */
655 case SOF0:
656 if (get_word_be(&jpeg_buffer, &word))
657 break;
658 if (get_byte(&jpeg_buffer) == -1)
659 break;
660 if (get_word_be(&jpeg_buffer, &height))
661 break;
662 if (get_word_be(&jpeg_buffer, &width))
663 break;
664 components = get_byte(&jpeg_buffer);
665 if (components == -1)
666 break;
667 notfound = 0;
668
669 skip(&jpeg_buffer, components * 3);
670 break;
671
672 /* skip payload-less markers */
673 case RST ... RST + 7:
674 case SOI:
675 case EOI:
676 case TEM:
677 break;
678
679 /* skip uninteresting payload markers */
680 default:
681 if (get_word_be(&jpeg_buffer, &word))
682 break;
683 length = (long)word - 2;
684 skip(&jpeg_buffer, length);
685 break;
686 }
687 }
688 result->w = width;
689 result->h = height;
690 result->size = components;
691 return !notfound;
692}
693
694static int s5p_jpeg_querycap(struct file *file, void *priv,
695 struct v4l2_capability *cap)
696{
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300697 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300698
699 if (ctx->mode == S5P_JPEG_ENCODE) {
700 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder",
701 sizeof(cap->driver));
702 strlcpy(cap->card, S5P_JPEG_M2M_NAME " encoder",
703 sizeof(cap->card));
704 } else {
705 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " decoder",
706 sizeof(cap->driver));
707 strlcpy(cap->card, S5P_JPEG_M2M_NAME " decoder",
708 sizeof(cap->card));
709 }
710 cap->bus_info[0] = 0;
Sylwester Nawrockif0476a82012-07-26 09:30:00 -0300711 /*
712 * This is only a mem-to-mem video device. The capture and output
713 * device capability flags are left only for backward compatibility
714 * and are scheduled for removal.
715 */
716 cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M |
717 V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300718 return 0;
719}
720
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300721static int enum_fmt(struct s5p_jpeg_fmt *sjpeg_formats, int n,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300722 struct v4l2_fmtdesc *f, u32 type)
723{
724 int i, num = 0;
725
726 for (i = 0; i < n; ++i) {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300727 if (sjpeg_formats[i].flags & type) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300728 /* index-th format of type type found ? */
729 if (num == f->index)
730 break;
731 /* Correct type but haven't reached our index yet,
732 * just increment per-type index */
733 ++num;
734 }
735 }
736
737 /* Format not found */
738 if (i >= n)
739 return -EINVAL;
740
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300741 strlcpy(f->description, sjpeg_formats[i].name, sizeof(f->description));
742 f->pixelformat = sjpeg_formats[i].fourcc;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300743
744 return 0;
745}
746
747static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
748 struct v4l2_fmtdesc *f)
749{
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300750 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300751
752 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300753 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
754 SJPEG_FMT_FLAG_ENC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300755
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300756 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
757 SJPEG_FMT_FLAG_DEC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300758}
759
760static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
761 struct v4l2_fmtdesc *f)
762{
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300763 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300764
765 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300766 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
767 SJPEG_FMT_FLAG_ENC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300768
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300769 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
770 SJPEG_FMT_FLAG_DEC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300771}
772
773static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx,
774 enum v4l2_buf_type type)
775{
776 if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
777 return &ctx->out_q;
778 if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
779 return &ctx->cap_q;
780
781 return NULL;
782}
783
784static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
785{
786 struct vb2_queue *vq;
787 struct s5p_jpeg_q_data *q_data = NULL;
788 struct v4l2_pix_format *pix = &f->fmt.pix;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300789 struct s5p_jpeg_ctx *ct = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300790
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300791 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300792 if (!vq)
793 return -EINVAL;
794
795 if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
796 ct->mode == S5P_JPEG_DECODE && !ct->hdr_parsed)
797 return -EINVAL;
798 q_data = get_q_data(ct, f->type);
799 BUG_ON(q_data == NULL);
800
801 pix->width = q_data->w;
802 pix->height = q_data->h;
803 pix->field = V4L2_FIELD_NONE;
804 pix->pixelformat = q_data->fmt->fourcc;
805 pix->bytesperline = 0;
806 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
807 u32 bpl = q_data->w;
808 if (q_data->fmt->colplanes == 1)
809 bpl = (bpl * q_data->fmt->depth) >> 3;
810 pix->bytesperline = bpl;
811 }
812 pix->sizeimage = q_data->size;
813
814 return 0;
815}
816
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300817static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
818 u32 pixelformat, unsigned int fmt_type)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300819{
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300820 unsigned int k, fmt_flag, ver_flag;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300821
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300822 if (ctx->mode == S5P_JPEG_ENCODE)
823 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
824 SJPEG_FMT_FLAG_ENC_OUTPUT :
825 SJPEG_FMT_FLAG_ENC_CAPTURE;
826 else
827 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
828 SJPEG_FMT_FLAG_DEC_OUTPUT :
829 SJPEG_FMT_FLAG_DEC_CAPTURE;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300830
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300831 if (ctx->jpeg->variant->version == SJPEG_S5P)
832 ver_flag = SJPEG_FMT_FLAG_S5P;
833 else
834 ver_flag = SJPEG_FMT_FLAG_EXYNOS4;
835
836 for (k = 0; k < ARRAY_SIZE(sjpeg_formats); k++) {
837 struct s5p_jpeg_fmt *fmt = &sjpeg_formats[k];
838 if (fmt->fourcc == pixelformat &&
839 fmt->flags & fmt_flag &&
840 fmt->flags & ver_flag) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300841 return fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300842 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300843 }
844
845 return NULL;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300846}
847
848static void jpeg_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
849 unsigned int walign,
850 u32 *h, unsigned int hmin, unsigned int hmax,
851 unsigned int halign)
852{
853 int width, height, w_step, h_step;
854
855 width = *w;
856 height = *h;
857
858 w_step = 1 << walign;
859 h_step = 1 << halign;
860 v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
861
862 if (*w < width && (*w + w_step) < wmax)
863 *w += w_step;
864 if (*h < height && (*h + h_step) < hmax)
865 *h += h_step;
866
867}
868
869static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
870 struct s5p_jpeg_ctx *ctx, int q_type)
871{
872 struct v4l2_pix_format *pix = &f->fmt.pix;
873
874 if (pix->field == V4L2_FIELD_ANY)
875 pix->field = V4L2_FIELD_NONE;
876 else if (pix->field != V4L2_FIELD_NONE)
877 return -EINVAL;
878
879 /* V4L2 specification suggests the driver corrects the format struct
880 * if any of the dimensions is unsupported */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300881 if (q_type == FMT_TYPE_OUTPUT)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300882 jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
883 S5P_JPEG_MAX_WIDTH, 0,
884 &pix->height, S5P_JPEG_MIN_HEIGHT,
885 S5P_JPEG_MAX_HEIGHT, 0);
886 else
887 jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
888 S5P_JPEG_MAX_WIDTH, fmt->h_align,
889 &pix->height, S5P_JPEG_MIN_HEIGHT,
890 S5P_JPEG_MAX_HEIGHT, fmt->v_align);
891
892 if (fmt->fourcc == V4L2_PIX_FMT_JPEG) {
893 if (pix->sizeimage <= 0)
894 pix->sizeimage = PAGE_SIZE;
895 pix->bytesperline = 0;
896 } else {
897 u32 bpl = pix->bytesperline;
898
899 if (fmt->colplanes > 1 && bpl < pix->width)
900 bpl = pix->width; /* planar */
901
902 if (fmt->colplanes == 1 && /* packed */
Jacek Anaszewskicc690902013-11-25 06:58:10 -0300903 (bpl << 3) / fmt->depth < pix->width)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300904 bpl = (pix->width * fmt->depth) >> 3;
905
906 pix->bytesperline = bpl;
907 pix->sizeimage = (pix->width * pix->height * fmt->depth) >> 3;
908 }
909
910 return 0;
911}
912
913static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
914 struct v4l2_format *f)
915{
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300916 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300917 struct s5p_jpeg_fmt *fmt;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300918
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300919 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
920 FMT_TYPE_CAPTURE);
921 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300922 v4l2_err(&ctx->jpeg->v4l2_dev,
923 "Fourcc format (0x%08x) invalid.\n",
924 f->fmt.pix.pixelformat);
925 return -EINVAL;
926 }
927
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300928 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300929}
930
931static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
932 struct v4l2_format *f)
933{
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300934 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300935 struct s5p_jpeg_fmt *fmt;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300936
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300937 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
938 FMT_TYPE_OUTPUT);
939 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300940 v4l2_err(&ctx->jpeg->v4l2_dev,
941 "Fourcc format (0x%08x) invalid.\n",
942 f->fmt.pix.pixelformat);
943 return -EINVAL;
944 }
945
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300946 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300947}
948
949static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
950{
951 struct vb2_queue *vq;
952 struct s5p_jpeg_q_data *q_data = NULL;
953 struct v4l2_pix_format *pix = &f->fmt.pix;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300954 unsigned int f_type;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300955
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300956 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300957 if (!vq)
958 return -EINVAL;
959
960 q_data = get_q_data(ct, f->type);
961 BUG_ON(q_data == NULL);
962
963 if (vb2_is_busy(vq)) {
964 v4l2_err(&ct->jpeg->v4l2_dev, "%s queue busy\n", __func__);
965 return -EBUSY;
966 }
967
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300968 f_type = V4L2_TYPE_IS_OUTPUT(f->type) ?
969 FMT_TYPE_OUTPUT : FMT_TYPE_CAPTURE;
970
971 q_data->fmt = s5p_jpeg_find_format(ct, pix->pixelformat, f_type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300972 q_data->w = pix->width;
973 q_data->h = pix->height;
974 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG)
975 q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3;
976 else
977 q_data->size = pix->sizeimage;
978
979 return 0;
980}
981
982static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
983 struct v4l2_format *f)
984{
985 int ret;
986
987 ret = s5p_jpeg_try_fmt_vid_cap(file, priv, f);
988 if (ret)
989 return ret;
990
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300991 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300992}
993
994static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
995 struct v4l2_format *f)
996{
997 int ret;
998
999 ret = s5p_jpeg_try_fmt_vid_out(file, priv, f);
1000 if (ret)
1001 return ret;
1002
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001003 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001004}
1005
Sachin Kamat9f3bd322012-05-10 03:38:40 -03001006static int s5p_jpeg_g_selection(struct file *file, void *priv,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001007 struct v4l2_selection *s)
1008{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001009 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001010
1011 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001012 s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
1013 ctx->jpeg->variant->version != SJPEG_S5P)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001014 return -EINVAL;
1015
1016 /* For JPEG blob active == default == bounds */
1017 switch (s->target) {
Sylwester Nawrockic1334822012-05-20 11:17:12 -03001018 case V4L2_SEL_TGT_CROP:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001019 case V4L2_SEL_TGT_CROP_BOUNDS:
1020 case V4L2_SEL_TGT_CROP_DEFAULT:
Sylwester Nawrockic1334822012-05-20 11:17:12 -03001021 case V4L2_SEL_TGT_COMPOSE:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001022 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
1023 s->r.width = ctx->out_q.w;
1024 s->r.height = ctx->out_q.h;
1025 break;
1026 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
1027 case V4L2_SEL_TGT_COMPOSE_PADDED:
1028 s->r.width = ctx->cap_q.w;
1029 s->r.height = ctx->cap_q.h;
1030 break;
1031 default:
1032 return -EINVAL;
1033 }
1034 s->r.left = 0;
1035 s->r.top = 0;
1036 return 0;
1037}
1038
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001039/*
1040 * V4L2 controls
1041 */
1042
1043static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001044{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001045 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1046 struct s5p_jpeg *jpeg = ctx->jpeg;
1047 unsigned long flags;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001048
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001049 switch (ctrl->id) {
1050 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1051 spin_lock_irqsave(&jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001052
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001053 WARN_ON(ctx->subsampling > S5P_SUBSAMPLING_MODE_GRAY);
1054 if (ctx->subsampling > 2)
1055 ctrl->val = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
1056 else
1057 ctrl->val = ctx->subsampling;
1058 spin_unlock_irqrestore(&jpeg->slock, flags);
1059 break;
1060 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001061
1062 return 0;
1063}
1064
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001065static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001066{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001067 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1068 unsigned long flags;
1069
1070 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1071
1072 switch (ctrl->id) {
1073 case V4L2_CID_JPEG_COMPRESSION_QUALITY:
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001074 ctx->compr_quality = ctrl->val;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001075 break;
1076 case V4L2_CID_JPEG_RESTART_INTERVAL:
1077 ctx->restart_interval = ctrl->val;
1078 break;
1079 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1080 ctx->subsampling = ctrl->val;
1081 break;
1082 }
1083
1084 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1085 return 0;
1086}
1087
1088static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
1089 .g_volatile_ctrl = s5p_jpeg_g_volatile_ctrl,
1090 .s_ctrl = s5p_jpeg_s_ctrl,
1091};
1092
1093static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
1094{
1095 unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */
1096 struct v4l2_ctrl *ctrl;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001097 int ret;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001098
1099 v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
1100
1101 if (ctx->mode == S5P_JPEG_ENCODE) {
1102 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1103 V4L2_CID_JPEG_COMPRESSION_QUALITY,
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001104 0, 3, 1, S5P_JPEG_COMPR_QUAL_WORST);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001105
1106 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1107 V4L2_CID_JPEG_RESTART_INTERVAL,
1108 0, 3, 0xffff, 0);
1109 mask = ~0x06; /* 422, 420 */
1110 }
1111
1112 ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1113 V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
1114 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask,
1115 V4L2_JPEG_CHROMA_SUBSAMPLING_422);
1116
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001117 if (ctx->ctrl_handler.error) {
1118 ret = ctx->ctrl_handler.error;
1119 goto error_free;
1120 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001121
1122 if (ctx->mode == S5P_JPEG_DECODE)
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001123 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
1124 V4L2_CTRL_FLAG_READ_ONLY;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001125
1126 ret = v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
1127 if (ret < 0)
1128 goto error_free;
1129
1130 return ret;
1131
1132error_free:
1133 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
1134 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001135}
1136
1137static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
1138 .vidioc_querycap = s5p_jpeg_querycap,
1139
1140 .vidioc_enum_fmt_vid_cap = s5p_jpeg_enum_fmt_vid_cap,
1141 .vidioc_enum_fmt_vid_out = s5p_jpeg_enum_fmt_vid_out,
1142
1143 .vidioc_g_fmt_vid_cap = s5p_jpeg_g_fmt,
1144 .vidioc_g_fmt_vid_out = s5p_jpeg_g_fmt,
1145
1146 .vidioc_try_fmt_vid_cap = s5p_jpeg_try_fmt_vid_cap,
1147 .vidioc_try_fmt_vid_out = s5p_jpeg_try_fmt_vid_out,
1148
1149 .vidioc_s_fmt_vid_cap = s5p_jpeg_s_fmt_vid_cap,
1150 .vidioc_s_fmt_vid_out = s5p_jpeg_s_fmt_vid_out,
1151
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001152 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
1153 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
1154 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
1155 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001156
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001157 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
1158 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001159
1160 .vidioc_g_selection = s5p_jpeg_g_selection,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001161};
1162
1163/*
1164 * ============================================================================
1165 * mem2mem callbacks
1166 * ============================================================================
1167 */
1168
1169static void s5p_jpeg_device_run(void *priv)
1170{
1171 struct s5p_jpeg_ctx *ctx = priv;
1172 struct s5p_jpeg *jpeg = ctx->jpeg;
1173 struct vb2_buffer *src_buf, *dst_buf;
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001174 unsigned long src_addr, dst_addr, flags;
1175
1176 spin_lock_irqsave(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001177
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001178 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1179 dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001180 src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
1181 dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
1182
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001183 s5p_jpeg_reset(jpeg->regs);
1184 s5p_jpeg_poweron(jpeg->regs);
1185 s5p_jpeg_proc_mode(jpeg->regs, ctx->mode);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001186 if (ctx->mode == S5P_JPEG_ENCODE) {
1187 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001188 s5p_jpeg_input_raw_mode(jpeg->regs,
1189 S5P_JPEG_RAW_IN_565);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001190 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001191 s5p_jpeg_input_raw_mode(jpeg->regs,
1192 S5P_JPEG_RAW_IN_422);
1193 s5p_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
1194 s5p_jpeg_dri(jpeg->regs, ctx->restart_interval);
1195 s5p_jpeg_x(jpeg->regs, ctx->out_q.w);
1196 s5p_jpeg_y(jpeg->regs, ctx->out_q.h);
1197 s5p_jpeg_imgadr(jpeg->regs, src_addr);
1198 s5p_jpeg_jpgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001199
1200 /* ultimately comes from sizeimage from userspace */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001201 s5p_jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001202
1203 /* JPEG RGB to YCbCr conversion matrix */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001204 s5p_jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11);
1205 s5p_jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12);
1206 s5p_jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13);
1207 s5p_jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21);
1208 s5p_jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22);
1209 s5p_jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23);
1210 s5p_jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31);
1211 s5p_jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32);
1212 s5p_jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001213
1214 /*
1215 * JPEG IP allows storing 4 quantization tables
1216 * We fill table 0 for luma and table 1 for chroma
1217 */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03001218 s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
1219 s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001220 /* use table 0 for Y */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001221 s5p_jpeg_qtbl(jpeg->regs, 1, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001222 /* use table 1 for Cb and Cr*/
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001223 s5p_jpeg_qtbl(jpeg->regs, 2, 1);
1224 s5p_jpeg_qtbl(jpeg->regs, 3, 1);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001225
1226 /* Y, Cb, Cr use Huffman table 0 */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001227 s5p_jpeg_htbl_ac(jpeg->regs, 1);
1228 s5p_jpeg_htbl_dc(jpeg->regs, 1);
1229 s5p_jpeg_htbl_ac(jpeg->regs, 2);
1230 s5p_jpeg_htbl_dc(jpeg->regs, 2);
1231 s5p_jpeg_htbl_ac(jpeg->regs, 3);
1232 s5p_jpeg_htbl_dc(jpeg->regs, 3);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001233 } else { /* S5P_JPEG_DECODE */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001234 s5p_jpeg_rst_int_enable(jpeg->regs, true);
1235 s5p_jpeg_data_num_int_enable(jpeg->regs, true);
1236 s5p_jpeg_final_mcu_num_int_enable(jpeg->regs, true);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001237 if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001238 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001239 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001240 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420);
1241 s5p_jpeg_jpgadr(jpeg->regs, src_addr);
1242 s5p_jpeg_imgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001243 }
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001244
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001245 s5p_jpeg_start(jpeg->regs);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001246
1247 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001248}
1249
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001250static void exynos4_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
1251{
1252 struct s5p_jpeg *jpeg = ctx->jpeg;
1253 struct s5p_jpeg_fmt *fmt;
1254 struct vb2_buffer *vb;
1255 struct s5p_jpeg_addr jpeg_addr;
1256 u32 pix_size, padding_bytes = 0;
1257
1258 pix_size = ctx->cap_q.w * ctx->cap_q.h;
1259
1260 if (ctx->mode == S5P_JPEG_ENCODE) {
1261 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1262 fmt = ctx->out_q.fmt;
1263 if (ctx->out_q.w % 2 && fmt->h_align > 0)
1264 padding_bytes = ctx->out_q.h;
1265 } else {
1266 fmt = ctx->cap_q.fmt;
1267 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1268 }
1269
1270 jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
1271
1272 if (fmt->colplanes == 2) {
1273 jpeg_addr.cb = jpeg_addr.y + pix_size - padding_bytes;
1274 } else if (fmt->colplanes == 3) {
1275 jpeg_addr.cb = jpeg_addr.y + pix_size;
1276 if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
1277 jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
1278 else
1279 jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
1280 }
1281
1282 exynos4_jpeg_set_frame_buf_address(jpeg->regs, &jpeg_addr);
1283}
1284
1285static void exynos4_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
1286{
1287 struct s5p_jpeg *jpeg = ctx->jpeg;
1288 struct vb2_buffer *vb;
1289 unsigned int jpeg_addr = 0;
1290
1291 if (ctx->mode == S5P_JPEG_ENCODE)
1292 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1293 else
1294 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1295
1296 jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
1297 exynos4_jpeg_set_stream_buf_address(jpeg->regs, jpeg_addr);
1298}
1299
1300static void exynos4_jpeg_device_run(void *priv)
1301{
1302 struct s5p_jpeg_ctx *ctx = priv;
1303 struct s5p_jpeg *jpeg = ctx->jpeg;
1304 unsigned int bitstream_size;
1305 unsigned long flags;
1306
1307 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1308
1309 if (ctx->mode == S5P_JPEG_ENCODE) {
1310 exynos4_jpeg_sw_reset(jpeg->regs);
1311 exynos4_jpeg_set_interrupt(jpeg->regs);
1312 exynos4_jpeg_set_huf_table_enable(jpeg->regs, 1);
1313
1314 exynos4_jpeg_set_huff_tbl(jpeg->regs);
1315
1316 /*
1317 * JPEG IP allows storing 4 quantization tables
1318 * We fill table 0 for luma and table 1 for chroma
1319 */
1320 exynos4_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
1321 exynos4_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
1322
1323 exynos4_jpeg_set_encode_tbl_select(jpeg->regs,
1324 ctx->compr_quality);
1325 exynos4_jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w,
1326 ctx->cap_q.h);
1327
1328 exynos4_jpeg_set_enc_out_fmt(jpeg->regs, ctx->subsampling);
1329 exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->out_q.fmt->fourcc);
1330 exynos4_jpeg_set_img_addr(ctx);
1331 exynos4_jpeg_set_jpeg_addr(ctx);
1332 exynos4_jpeg_set_encode_hoff_cnt(jpeg->regs,
1333 ctx->out_q.fmt->fourcc);
1334 } else {
1335 exynos4_jpeg_sw_reset(jpeg->regs);
1336 exynos4_jpeg_set_interrupt(jpeg->regs);
1337 exynos4_jpeg_set_img_addr(ctx);
1338 exynos4_jpeg_set_jpeg_addr(ctx);
1339 exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->cap_q.fmt->fourcc);
1340
1341 bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 32);
1342
1343 exynos4_jpeg_set_dec_bitstream_size(jpeg->regs, bitstream_size);
1344 }
1345
1346 exynos4_jpeg_set_enc_dec_mode(jpeg->regs, ctx->mode);
1347
1348 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1349}
1350
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001351static int s5p_jpeg_job_ready(void *priv)
1352{
1353 struct s5p_jpeg_ctx *ctx = priv;
1354
1355 if (ctx->mode == S5P_JPEG_DECODE)
1356 return ctx->hdr_parsed;
1357 return 1;
1358}
1359
1360static void s5p_jpeg_job_abort(void *priv)
1361{
1362}
1363
1364static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = {
1365 .device_run = s5p_jpeg_device_run,
1366 .job_ready = s5p_jpeg_job_ready,
1367 .job_abort = s5p_jpeg_job_abort,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001368}
1369;
1370static struct v4l2_m2m_ops exynos_jpeg_m2m_ops = {
1371 .device_run = exynos4_jpeg_device_run,
1372 .job_ready = s5p_jpeg_job_ready,
1373 .job_abort = s5p_jpeg_job_abort,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001374};
1375
1376/*
1377 * ============================================================================
1378 * Queue operations
1379 * ============================================================================
1380 */
1381
Marek Szyprowski719c1742012-01-13 05:12:38 -03001382static int s5p_jpeg_queue_setup(struct vb2_queue *vq,
1383 const struct v4l2_format *fmt,
1384 unsigned int *nbuffers, unsigned int *nplanes,
1385 unsigned int sizes[], void *alloc_ctxs[])
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001386{
1387 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
1388 struct s5p_jpeg_q_data *q_data = NULL;
1389 unsigned int size, count = *nbuffers;
1390
1391 q_data = get_q_data(ctx, vq->type);
1392 BUG_ON(q_data == NULL);
1393
1394 size = q_data->size;
1395
1396 /*
1397 * header is parsed during decoding and parsed information stored
1398 * in the context so we do not allow another buffer to overwrite it
1399 */
1400 if (ctx->mode == S5P_JPEG_DECODE)
1401 count = 1;
1402
1403 *nbuffers = count;
1404 *nplanes = 1;
1405 sizes[0] = size;
1406 alloc_ctxs[0] = ctx->jpeg->alloc_ctx;
1407
1408 return 0;
1409}
1410
1411static int s5p_jpeg_buf_prepare(struct vb2_buffer *vb)
1412{
1413 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1414 struct s5p_jpeg_q_data *q_data = NULL;
1415
1416 q_data = get_q_data(ctx, vb->vb2_queue->type);
1417 BUG_ON(q_data == NULL);
1418
1419 if (vb2_plane_size(vb, 0) < q_data->size) {
1420 pr_err("%s data will not fit into plane (%lu < %lu)\n",
1421 __func__, vb2_plane_size(vb, 0),
1422 (long)q_data->size);
1423 return -EINVAL;
1424 }
1425
1426 vb2_set_plane_payload(vb, 0, q_data->size);
1427
1428 return 0;
1429}
1430
1431static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
1432{
1433 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1434
1435 if (ctx->mode == S5P_JPEG_DECODE &&
1436 vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
1437 struct s5p_jpeg_q_data tmp, *q_data;
1438 ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp,
1439 (unsigned long)vb2_plane_vaddr(vb, 0),
1440 min((unsigned long)ctx->out_q.size,
1441 vb2_get_plane_payload(vb, 0)));
1442 if (!ctx->hdr_parsed) {
1443 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
1444 return;
1445 }
1446
1447 q_data = &ctx->out_q;
1448 q_data->w = tmp.w;
1449 q_data->h = tmp.h;
1450
1451 q_data = &ctx->cap_q;
1452 q_data->w = tmp.w;
1453 q_data->h = tmp.h;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001454 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001455
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001456 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001457}
1458
1459static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
1460{
1461 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
1462 int ret;
1463
1464 ret = pm_runtime_get_sync(ctx->jpeg->dev);
1465
1466 return ret > 0 ? 0 : ret;
1467}
1468
1469static int s5p_jpeg_stop_streaming(struct vb2_queue *q)
1470{
1471 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
1472
1473 pm_runtime_put(ctx->jpeg->dev);
1474
1475 return 0;
1476}
1477
1478static struct vb2_ops s5p_jpeg_qops = {
1479 .queue_setup = s5p_jpeg_queue_setup,
1480 .buf_prepare = s5p_jpeg_buf_prepare,
1481 .buf_queue = s5p_jpeg_buf_queue,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001482 .wait_prepare = vb2_ops_wait_prepare,
1483 .wait_finish = vb2_ops_wait_finish,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001484 .start_streaming = s5p_jpeg_start_streaming,
1485 .stop_streaming = s5p_jpeg_stop_streaming,
1486};
1487
1488static int queue_init(void *priv, struct vb2_queue *src_vq,
1489 struct vb2_queue *dst_vq)
1490{
1491 struct s5p_jpeg_ctx *ctx = priv;
1492 int ret;
1493
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001494 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1495 src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
1496 src_vq->drv_priv = ctx;
1497 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1498 src_vq->ops = &s5p_jpeg_qops;
1499 src_vq->mem_ops = &vb2_dma_contig_memops;
Kamil Debskiaca326a2013-04-24 10:08:02 -03001500 src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001501 src_vq->lock = &ctx->jpeg->lock;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001502
1503 ret = vb2_queue_init(src_vq);
1504 if (ret)
1505 return ret;
1506
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001507 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1508 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
1509 dst_vq->drv_priv = ctx;
1510 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1511 dst_vq->ops = &s5p_jpeg_qops;
1512 dst_vq->mem_ops = &vb2_dma_contig_memops;
Kamil Debskiaca326a2013-04-24 10:08:02 -03001513 dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001514 dst_vq->lock = &ctx->jpeg->lock;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001515
1516 return vb2_queue_init(dst_vq);
1517}
1518
1519/*
1520 * ============================================================================
1521 * ISR
1522 * ============================================================================
1523 */
1524
1525static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
1526{
1527 struct s5p_jpeg *jpeg = dev_id;
1528 struct s5p_jpeg_ctx *curr_ctx;
1529 struct vb2_buffer *src_buf, *dst_buf;
1530 unsigned long payload_size = 0;
1531 enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
1532 bool enc_jpeg_too_large = false;
1533 bool timer_elapsed = false;
1534 bool op_completed = false;
1535
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001536 spin_lock(&jpeg->slock);
1537
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001538 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
1539
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001540 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
1541 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001542
1543 if (curr_ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001544 enc_jpeg_too_large = s5p_jpeg_enc_stream_stat(jpeg->regs);
1545 timer_elapsed = s5p_jpeg_timer_stat(jpeg->regs);
1546 op_completed = s5p_jpeg_result_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001547 if (curr_ctx->mode == S5P_JPEG_DECODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001548 op_completed = op_completed &&
1549 s5p_jpeg_stream_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001550
1551 if (enc_jpeg_too_large) {
1552 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001553 s5p_jpeg_clear_enc_stream_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001554 } else if (timer_elapsed) {
1555 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001556 s5p_jpeg_clear_timer_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001557 } else if (!op_completed) {
1558 state = VB2_BUF_STATE_ERROR;
1559 } else {
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001560 payload_size = s5p_jpeg_compressed_size(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001561 }
1562
Kamil Debskiaca326a2013-04-24 10:08:02 -03001563 dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
1564 dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
1565
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001566 v4l2_m2m_buf_done(src_buf, state);
1567 if (curr_ctx->mode == S5P_JPEG_ENCODE)
1568 vb2_set_plane_payload(dst_buf, 0, payload_size);
1569 v4l2_m2m_buf_done(dst_buf, state);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001570 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001571
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001572 curr_ctx->subsampling = s5p_jpeg_get_subsampling_mode(jpeg->regs);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001573 spin_unlock(&jpeg->slock);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001574
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001575 s5p_jpeg_clear_int(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001576
1577 return IRQ_HANDLED;
1578}
1579
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001580static irqreturn_t exynos4_jpeg_irq(int irq, void *priv)
1581{
1582 unsigned int int_status;
1583 struct vb2_buffer *src_vb, *dst_vb;
1584 struct s5p_jpeg *jpeg = priv;
1585 struct s5p_jpeg_ctx *curr_ctx;
1586 unsigned long payload_size = 0;
1587
1588 spin_lock(&jpeg->slock);
1589
1590 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
1591
1592 src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
1593 dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
1594
1595 int_status = exynos4_jpeg_get_int_status(jpeg->regs);
1596
1597 if (int_status) {
1598 switch (int_status & 0x1f) {
1599 case 0x1:
1600 jpeg->irq_ret = ERR_PROT;
1601 break;
1602 case 0x2:
1603 jpeg->irq_ret = OK_ENC_OR_DEC;
1604 break;
1605 case 0x4:
1606 jpeg->irq_ret = ERR_DEC_INVALID_FORMAT;
1607 break;
1608 case 0x8:
1609 jpeg->irq_ret = ERR_MULTI_SCAN;
1610 break;
1611 case 0x10:
1612 jpeg->irq_ret = ERR_FRAME;
1613 break;
1614 default:
1615 jpeg->irq_ret = ERR_UNKNOWN;
1616 break;
1617 }
1618 } else {
1619 jpeg->irq_ret = ERR_UNKNOWN;
1620 }
1621
1622 if (jpeg->irq_ret == OK_ENC_OR_DEC) {
1623 if (curr_ctx->mode == S5P_JPEG_ENCODE) {
1624 payload_size = exynos4_jpeg_get_stream_size(jpeg->regs);
1625 vb2_set_plane_payload(dst_vb, 0, payload_size);
1626 }
1627 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
1628 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
1629 } else {
1630 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
1631 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
1632 }
1633
1634 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
1635 curr_ctx->subsampling = exynos4_jpeg_get_frame_fmt(jpeg->regs);
1636
1637 spin_unlock(&jpeg->slock);
1638 return IRQ_HANDLED;
1639}
1640
1641static void *jpeg_get_drv_data(struct platform_device *pdev);
1642
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001643/*
1644 * ============================================================================
1645 * Driver basic infrastructure
1646 * ============================================================================
1647 */
1648
1649static int s5p_jpeg_probe(struct platform_device *pdev)
1650{
1651 struct s5p_jpeg *jpeg;
1652 struct resource *res;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001653 struct v4l2_m2m_ops *samsung_jpeg_m2m_ops;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001654 int ret;
1655
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001656 if (!pdev->dev.of_node)
1657 return -ENODEV;
1658
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001659 /* JPEG IP abstraction struct */
Sachin Kamat5b58b952012-05-14 06:33:34 -03001660 jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001661 if (!jpeg)
1662 return -ENOMEM;
1663
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001664 jpeg->variant = jpeg_get_drv_data(pdev);
1665
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001666 mutex_init(&jpeg->lock);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001667 spin_lock_init(&jpeg->slock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001668 jpeg->dev = &pdev->dev;
1669
1670 /* memory-mapped registers */
1671 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001672
Thierry Redingf23999e2013-01-21 06:09:07 -03001673 jpeg->regs = devm_ioremap_resource(&pdev->dev, res);
1674 if (IS_ERR(jpeg->regs))
1675 return PTR_ERR(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001676
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001677 /* interrupt service routine registration */
1678 jpeg->irq = ret = platform_get_irq(pdev, 0);
1679 if (ret < 0) {
1680 dev_err(&pdev->dev, "cannot find IRQ\n");
Sachin Kamat5b58b952012-05-14 06:33:34 -03001681 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001682 }
1683
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001684 ret = devm_request_irq(&pdev->dev, jpeg->irq, jpeg->variant->jpeg_irq,
1685 0, dev_name(&pdev->dev), jpeg);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001686 if (ret) {
1687 dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
Sachin Kamat5b58b952012-05-14 06:33:34 -03001688 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001689 }
1690
1691 /* clocks */
1692 jpeg->clk = clk_get(&pdev->dev, "jpeg");
1693 if (IS_ERR(jpeg->clk)) {
1694 dev_err(&pdev->dev, "cannot get clock\n");
1695 ret = PTR_ERR(jpeg->clk);
Sachin Kamat5b58b952012-05-14 06:33:34 -03001696 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001697 }
1698 dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001699
1700 /* v4l2 device */
1701 ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
1702 if (ret) {
1703 dev_err(&pdev->dev, "Failed to register v4l2 device\n");
1704 goto clk_get_rollback;
1705 }
1706
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001707 if (jpeg->variant->version == SJPEG_S5P)
1708 samsung_jpeg_m2m_ops = &s5p_jpeg_m2m_ops;
1709 else
1710 samsung_jpeg_m2m_ops = &exynos_jpeg_m2m_ops;
1711
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001712 /* mem2mem device */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001713 jpeg->m2m_dev = v4l2_m2m_init(samsung_jpeg_m2m_ops);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001714 if (IS_ERR(jpeg->m2m_dev)) {
1715 v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
1716 ret = PTR_ERR(jpeg->m2m_dev);
1717 goto device_register_rollback;
1718 }
1719
1720 jpeg->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
1721 if (IS_ERR(jpeg->alloc_ctx)) {
1722 v4l2_err(&jpeg->v4l2_dev, "Failed to init memory allocator\n");
1723 ret = PTR_ERR(jpeg->alloc_ctx);
1724 goto m2m_init_rollback;
1725 }
1726
1727 /* JPEG encoder /dev/videoX node */
1728 jpeg->vfd_encoder = video_device_alloc();
1729 if (!jpeg->vfd_encoder) {
1730 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
1731 ret = -ENOMEM;
1732 goto vb2_allocator_rollback;
1733 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03001734 snprintf(jpeg->vfd_encoder->name, sizeof(jpeg->vfd_encoder->name),
1735 "%s-enc", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001736 jpeg->vfd_encoder->fops = &s5p_jpeg_fops;
1737 jpeg->vfd_encoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
1738 jpeg->vfd_encoder->minor = -1;
1739 jpeg->vfd_encoder->release = video_device_release;
1740 jpeg->vfd_encoder->lock = &jpeg->lock;
1741 jpeg->vfd_encoder->v4l2_dev = &jpeg->v4l2_dev;
Hans Verkuil954f3402012-09-05 06:05:50 -03001742 jpeg->vfd_encoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001743
1744 ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
1745 if (ret) {
1746 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
1747 goto enc_vdev_alloc_rollback;
1748 }
1749
1750 video_set_drvdata(jpeg->vfd_encoder, jpeg);
1751 v4l2_info(&jpeg->v4l2_dev,
1752 "encoder device registered as /dev/video%d\n",
1753 jpeg->vfd_encoder->num);
1754
1755 /* JPEG decoder /dev/videoX node */
1756 jpeg->vfd_decoder = video_device_alloc();
1757 if (!jpeg->vfd_decoder) {
1758 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
1759 ret = -ENOMEM;
1760 goto enc_vdev_register_rollback;
1761 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03001762 snprintf(jpeg->vfd_decoder->name, sizeof(jpeg->vfd_decoder->name),
1763 "%s-dec", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001764 jpeg->vfd_decoder->fops = &s5p_jpeg_fops;
1765 jpeg->vfd_decoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
1766 jpeg->vfd_decoder->minor = -1;
1767 jpeg->vfd_decoder->release = video_device_release;
1768 jpeg->vfd_decoder->lock = &jpeg->lock;
1769 jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev;
Jacek Anaszewski7f7d8fe2013-09-11 06:17:45 -03001770 jpeg->vfd_decoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001771
1772 ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
1773 if (ret) {
1774 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
1775 goto dec_vdev_alloc_rollback;
1776 }
1777
1778 video_set_drvdata(jpeg->vfd_decoder, jpeg);
1779 v4l2_info(&jpeg->v4l2_dev,
1780 "decoder device registered as /dev/video%d\n",
1781 jpeg->vfd_decoder->num);
1782
1783 /* final statements & power management */
1784 platform_set_drvdata(pdev, jpeg);
1785
1786 pm_runtime_enable(&pdev->dev);
1787
1788 v4l2_info(&jpeg->v4l2_dev, "Samsung S5P JPEG codec\n");
1789
1790 return 0;
1791
1792dec_vdev_alloc_rollback:
1793 video_device_release(jpeg->vfd_decoder);
1794
1795enc_vdev_register_rollback:
1796 video_unregister_device(jpeg->vfd_encoder);
1797
1798enc_vdev_alloc_rollback:
1799 video_device_release(jpeg->vfd_encoder);
1800
1801vb2_allocator_rollback:
1802 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
1803
1804m2m_init_rollback:
1805 v4l2_m2m_release(jpeg->m2m_dev);
1806
1807device_register_rollback:
1808 v4l2_device_unregister(&jpeg->v4l2_dev);
1809
1810clk_get_rollback:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001811 clk_put(jpeg->clk);
1812
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001813 return ret;
1814}
1815
1816static int s5p_jpeg_remove(struct platform_device *pdev)
1817{
1818 struct s5p_jpeg *jpeg = platform_get_drvdata(pdev);
1819
1820 pm_runtime_disable(jpeg->dev);
1821
1822 video_unregister_device(jpeg->vfd_decoder);
1823 video_device_release(jpeg->vfd_decoder);
1824 video_unregister_device(jpeg->vfd_encoder);
1825 video_device_release(jpeg->vfd_encoder);
1826 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
1827 v4l2_m2m_release(jpeg->m2m_dev);
1828 v4l2_device_unregister(&jpeg->v4l2_dev);
1829
Jacek Anaszewskif1347132013-11-25 06:58:13 -03001830 if (!pm_runtime_status_suspended(&pdev->dev))
1831 clk_disable_unprepare(jpeg->clk);
1832
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001833 clk_put(jpeg->clk);
1834
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001835 return 0;
1836}
1837
1838static int s5p_jpeg_runtime_suspend(struct device *dev)
1839{
Jacek Anaszewskif1347132013-11-25 06:58:13 -03001840 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
1841
1842 clk_disable_unprepare(jpeg->clk);
1843
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001844 return 0;
1845}
1846
1847static int s5p_jpeg_runtime_resume(struct device *dev)
1848{
1849 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001850 unsigned long flags;
Jacek Anaszewskif1347132013-11-25 06:58:13 -03001851 int ret;
1852
1853 ret = clk_prepare_enable(jpeg->clk);
1854 if (ret < 0)
1855 return ret;
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03001856
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001857 spin_lock_irqsave(&jpeg->slock, flags);
1858
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001859 /*
1860 * JPEG IP allows storing two Huffman tables for each component
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001861 * We fill table 0 for each component and do this here only
1862 * for S5PC210 device as Exynos4x12 requires programming its
1863 * Huffman tables each time the encoding process is initialized.
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001864 */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001865 if (jpeg->variant->version == SJPEG_S5P) {
1866 s5p_jpeg_set_hdctbl(jpeg->regs);
1867 s5p_jpeg_set_hdctblg(jpeg->regs);
1868 s5p_jpeg_set_hactbl(jpeg->regs);
1869 s5p_jpeg_set_hactblg(jpeg->regs);
1870 }
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03001871
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001872 spin_unlock_irqrestore(&jpeg->slock, flags);
1873
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001874 return 0;
1875}
1876
Jacek Anaszewskif1347132013-11-25 06:58:13 -03001877static int s5p_jpeg_suspend(struct device *dev)
1878{
1879 if (pm_runtime_suspended(dev))
1880 return 0;
1881
1882 return s5p_jpeg_runtime_suspend(dev);
1883}
1884
1885static int s5p_jpeg_resume(struct device *dev)
1886{
1887 if (pm_runtime_suspended(dev))
1888 return 0;
1889
1890 return s5p_jpeg_runtime_resume(dev);
1891}
1892
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001893static const struct dev_pm_ops s5p_jpeg_pm_ops = {
Jacek Anaszewskif1347132013-11-25 06:58:13 -03001894 SET_SYSTEM_SLEEP_PM_OPS(s5p_jpeg_suspend, s5p_jpeg_resume)
1895 SET_RUNTIME_PM_OPS(s5p_jpeg_runtime_suspend, s5p_jpeg_runtime_resume, NULL)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001896};
1897
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03001898#ifdef CONFIG_OF
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001899static struct s5p_jpeg_variant s5p_jpeg_drvdata = {
1900 .version = SJPEG_S5P,
1901 .jpeg_irq = s5p_jpeg_irq,
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03001902};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001903
1904static struct s5p_jpeg_variant exynos4_jpeg_drvdata = {
1905 .version = SJPEG_EXYNOS4,
1906 .jpeg_irq = exynos4_jpeg_irq,
1907};
1908
1909static const struct of_device_id samsung_jpeg_match[] = {
1910 {
1911 .compatible = "samsung,s5pv210-jpeg",
1912 .data = &s5p_jpeg_drvdata,
1913 }, {
1914 .compatible = "samsung,exynos4210-jpeg",
1915 .data = &s5p_jpeg_drvdata,
1916 }, {
1917 .compatible = "samsung,exynos4212-jpeg",
1918 .data = &exynos4_jpeg_drvdata,
1919 },
1920 {},
1921};
1922
1923MODULE_DEVICE_TABLE(of, samsung_jpeg_match);
1924
1925static void *jpeg_get_drv_data(struct platform_device *pdev)
1926{
1927 struct s5p_jpeg_variant *driver_data = NULL;
1928 const struct of_device_id *match;
1929
1930 match = of_match_node(of_match_ptr(samsung_jpeg_match),
1931 pdev->dev.of_node);
1932 if (match)
1933 driver_data = (struct s5p_jpeg_variant *)match->data;
1934
1935 return driver_data;
1936}
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03001937#endif
1938
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001939static struct platform_driver s5p_jpeg_driver = {
1940 .probe = s5p_jpeg_probe,
1941 .remove = s5p_jpeg_remove,
1942 .driver = {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001943 .of_match_table = of_match_ptr(samsung_jpeg_match),
1944 .owner = THIS_MODULE,
1945 .name = S5P_JPEG_M2M_NAME,
1946 .pm = &s5p_jpeg_pm_ops,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001947 },
1948};
1949
Sachin Kamat87e94292012-07-03 05:54:33 -03001950module_platform_driver(s5p_jpeg_driver);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001951
1952MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001953MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001954MODULE_DESCRIPTION("Samsung JPEG codec driver");
1955MODULE_LICENSE("GPL");