blob: 0ae3d2cdef03ce4596136b837f27fbb9d59ebed6 [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,
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300627 unsigned long buffer, unsigned long size,
628 struct s5p_jpeg_ctx *ctx)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300629{
630 int c, components, notfound;
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300631 unsigned int height, width, word, subsampling = 0;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300632 long length;
633 struct s5p_jpeg_buffer jpeg_buffer;
634
635 jpeg_buffer.size = size;
636 jpeg_buffer.data = buffer;
637 jpeg_buffer.curr = 0;
638
639 notfound = 1;
640 while (notfound) {
641 c = get_byte(&jpeg_buffer);
642 if (c == -1)
643 break;
644 if (c != 0xff)
645 continue;
646 do
647 c = get_byte(&jpeg_buffer);
648 while (c == 0xff);
649 if (c == -1)
650 break;
651 if (c == 0)
652 continue;
653 length = 0;
654 switch (c) {
655 /* SOF0: baseline JPEG */
656 case SOF0:
657 if (get_word_be(&jpeg_buffer, &word))
658 break;
659 if (get_byte(&jpeg_buffer) == -1)
660 break;
661 if (get_word_be(&jpeg_buffer, &height))
662 break;
663 if (get_word_be(&jpeg_buffer, &width))
664 break;
665 components = get_byte(&jpeg_buffer);
666 if (components == -1)
667 break;
668 notfound = 0;
669
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300670 if (components == 1) {
671 subsampling = 0x33;
672 } else {
673 skip(&jpeg_buffer, 1);
674 subsampling = get_byte(&jpeg_buffer);
675 skip(&jpeg_buffer, 1);
676 }
677
678 skip(&jpeg_buffer, components * 2);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300679 break;
680
681 /* skip payload-less markers */
682 case RST ... RST + 7:
683 case SOI:
684 case EOI:
685 case TEM:
686 break;
687
688 /* skip uninteresting payload markers */
689 default:
690 if (get_word_be(&jpeg_buffer, &word))
691 break;
692 length = (long)word - 2;
693 skip(&jpeg_buffer, length);
694 break;
695 }
696 }
697 result->w = width;
698 result->h = height;
699 result->size = components;
Jacek Anaszewskif8433962013-11-21 13:33:09 -0300700
701 switch (subsampling) {
702 case 0x11:
703 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444;
704 break;
705 case 0x21:
706 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422;
707 break;
708 case 0x22:
709 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420;
710 break;
711 case 0x33:
712 ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
713 break;
714 default:
715 return false;
716 }
717
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300718 return !notfound;
719}
720
721static int s5p_jpeg_querycap(struct file *file, void *priv,
722 struct v4l2_capability *cap)
723{
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300724 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300725
726 if (ctx->mode == S5P_JPEG_ENCODE) {
727 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder",
728 sizeof(cap->driver));
729 strlcpy(cap->card, S5P_JPEG_M2M_NAME " encoder",
730 sizeof(cap->card));
731 } else {
732 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " decoder",
733 sizeof(cap->driver));
734 strlcpy(cap->card, S5P_JPEG_M2M_NAME " decoder",
735 sizeof(cap->card));
736 }
737 cap->bus_info[0] = 0;
Sylwester Nawrockif0476a82012-07-26 09:30:00 -0300738 /*
739 * This is only a mem-to-mem video device. The capture and output
740 * device capability flags are left only for backward compatibility
741 * and are scheduled for removal.
742 */
743 cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M |
744 V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300745 return 0;
746}
747
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300748static int enum_fmt(struct s5p_jpeg_fmt *sjpeg_formats, int n,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300749 struct v4l2_fmtdesc *f, u32 type)
750{
751 int i, num = 0;
752
753 for (i = 0; i < n; ++i) {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300754 if (sjpeg_formats[i].flags & type) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300755 /* index-th format of type type found ? */
756 if (num == f->index)
757 break;
758 /* Correct type but haven't reached our index yet,
759 * just increment per-type index */
760 ++num;
761 }
762 }
763
764 /* Format not found */
765 if (i >= n)
766 return -EINVAL;
767
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300768 strlcpy(f->description, sjpeg_formats[i].name, sizeof(f->description));
769 f->pixelformat = sjpeg_formats[i].fourcc;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300770
771 return 0;
772}
773
774static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
775 struct v4l2_fmtdesc *f)
776{
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300777 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300778
779 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300780 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
781 SJPEG_FMT_FLAG_ENC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300782
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300783 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
784 SJPEG_FMT_FLAG_DEC_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300785}
786
787static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
788 struct v4l2_fmtdesc *f)
789{
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300790 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300791
792 if (ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300793 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
794 SJPEG_FMT_FLAG_ENC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300795
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300796 return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
797 SJPEG_FMT_FLAG_DEC_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300798}
799
800static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx,
801 enum v4l2_buf_type type)
802{
803 if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
804 return &ctx->out_q;
805 if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
806 return &ctx->cap_q;
807
808 return NULL;
809}
810
811static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
812{
813 struct vb2_queue *vq;
814 struct s5p_jpeg_q_data *q_data = NULL;
815 struct v4l2_pix_format *pix = &f->fmt.pix;
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300816 struct s5p_jpeg_ctx *ct = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300817
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300818 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300819 if (!vq)
820 return -EINVAL;
821
822 if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
823 ct->mode == S5P_JPEG_DECODE && !ct->hdr_parsed)
824 return -EINVAL;
825 q_data = get_q_data(ct, f->type);
826 BUG_ON(q_data == NULL);
827
828 pix->width = q_data->w;
829 pix->height = q_data->h;
830 pix->field = V4L2_FIELD_NONE;
831 pix->pixelformat = q_data->fmt->fourcc;
832 pix->bytesperline = 0;
833 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
834 u32 bpl = q_data->w;
835 if (q_data->fmt->colplanes == 1)
836 bpl = (bpl * q_data->fmt->depth) >> 3;
837 pix->bytesperline = bpl;
838 }
839 pix->sizeimage = q_data->size;
840
841 return 0;
842}
843
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300844static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
845 u32 pixelformat, unsigned int fmt_type)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300846{
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300847 unsigned int k, fmt_flag, ver_flag;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300848
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300849 if (ctx->mode == S5P_JPEG_ENCODE)
850 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
851 SJPEG_FMT_FLAG_ENC_OUTPUT :
852 SJPEG_FMT_FLAG_ENC_CAPTURE;
853 else
854 fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
855 SJPEG_FMT_FLAG_DEC_OUTPUT :
856 SJPEG_FMT_FLAG_DEC_CAPTURE;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300857
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300858 if (ctx->jpeg->variant->version == SJPEG_S5P)
859 ver_flag = SJPEG_FMT_FLAG_S5P;
860 else
861 ver_flag = SJPEG_FMT_FLAG_EXYNOS4;
862
863 for (k = 0; k < ARRAY_SIZE(sjpeg_formats); k++) {
864 struct s5p_jpeg_fmt *fmt = &sjpeg_formats[k];
865 if (fmt->fourcc == pixelformat &&
866 fmt->flags & fmt_flag &&
867 fmt->flags & ver_flag) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300868 return fmt;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300869 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300870 }
871
872 return NULL;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300873}
874
875static void jpeg_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
876 unsigned int walign,
877 u32 *h, unsigned int hmin, unsigned int hmax,
878 unsigned int halign)
879{
880 int width, height, w_step, h_step;
881
882 width = *w;
883 height = *h;
884
885 w_step = 1 << walign;
886 h_step = 1 << halign;
887 v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
888
889 if (*w < width && (*w + w_step) < wmax)
890 *w += w_step;
891 if (*h < height && (*h + h_step) < hmax)
892 *h += h_step;
893
894}
895
896static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
897 struct s5p_jpeg_ctx *ctx, int q_type)
898{
899 struct v4l2_pix_format *pix = &f->fmt.pix;
900
901 if (pix->field == V4L2_FIELD_ANY)
902 pix->field = V4L2_FIELD_NONE;
903 else if (pix->field != V4L2_FIELD_NONE)
904 return -EINVAL;
905
906 /* V4L2 specification suggests the driver corrects the format struct
907 * if any of the dimensions is unsupported */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300908 if (q_type == FMT_TYPE_OUTPUT)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300909 jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
910 S5P_JPEG_MAX_WIDTH, 0,
911 &pix->height, S5P_JPEG_MIN_HEIGHT,
912 S5P_JPEG_MAX_HEIGHT, 0);
913 else
914 jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
915 S5P_JPEG_MAX_WIDTH, fmt->h_align,
916 &pix->height, S5P_JPEG_MIN_HEIGHT,
917 S5P_JPEG_MAX_HEIGHT, fmt->v_align);
918
919 if (fmt->fourcc == V4L2_PIX_FMT_JPEG) {
920 if (pix->sizeimage <= 0)
921 pix->sizeimage = PAGE_SIZE;
922 pix->bytesperline = 0;
923 } else {
924 u32 bpl = pix->bytesperline;
925
926 if (fmt->colplanes > 1 && bpl < pix->width)
927 bpl = pix->width; /* planar */
928
929 if (fmt->colplanes == 1 && /* packed */
Jacek Anaszewskicc690902013-11-25 06:58:10 -0300930 (bpl << 3) / fmt->depth < pix->width)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300931 bpl = (pix->width * fmt->depth) >> 3;
932
933 pix->bytesperline = bpl;
934 pix->sizeimage = (pix->width * pix->height * fmt->depth) >> 3;
935 }
936
937 return 0;
938}
939
940static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
941 struct v4l2_format *f)
942{
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300943 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300944 struct s5p_jpeg_fmt *fmt;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300945
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300946 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
947 FMT_TYPE_CAPTURE);
948 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300949 v4l2_err(&ctx->jpeg->v4l2_dev,
950 "Fourcc format (0x%08x) invalid.\n",
951 f->fmt.pix.pixelformat);
952 return -EINVAL;
953 }
954
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300955 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_CAPTURE);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300956}
957
958static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
959 struct v4l2_format *f)
960{
Sylwester Nawrocki275de242012-02-17 11:38:09 -0300961 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300962 struct s5p_jpeg_fmt *fmt;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300963
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300964 fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
965 FMT_TYPE_OUTPUT);
966 if (!fmt) {
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300967 v4l2_err(&ctx->jpeg->v4l2_dev,
968 "Fourcc format (0x%08x) invalid.\n",
969 f->fmt.pix.pixelformat);
970 return -EINVAL;
971 }
972
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300973 return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_OUTPUT);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300974}
975
976static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
977{
978 struct vb2_queue *vq;
979 struct s5p_jpeg_q_data *q_data = NULL;
980 struct v4l2_pix_format *pix = &f->fmt.pix;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300981 unsigned int f_type;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300982
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -0300983 vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300984 if (!vq)
985 return -EINVAL;
986
987 q_data = get_q_data(ct, f->type);
988 BUG_ON(q_data == NULL);
989
990 if (vb2_is_busy(vq)) {
991 v4l2_err(&ct->jpeg->v4l2_dev, "%s queue busy\n", __func__);
992 return -EBUSY;
993 }
994
Jacek Anaszewski80529ae2013-12-18 11:04:44 -0300995 f_type = V4L2_TYPE_IS_OUTPUT(f->type) ?
996 FMT_TYPE_OUTPUT : FMT_TYPE_CAPTURE;
997
998 q_data->fmt = s5p_jpeg_find_format(ct, pix->pixelformat, f_type);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -0300999 q_data->w = pix->width;
1000 q_data->h = pix->height;
1001 if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG)
1002 q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3;
1003 else
1004 q_data->size = pix->sizeimage;
1005
1006 return 0;
1007}
1008
1009static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
1010 struct v4l2_format *f)
1011{
1012 int ret;
1013
1014 ret = s5p_jpeg_try_fmt_vid_cap(file, priv, f);
1015 if (ret)
1016 return ret;
1017
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001018 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001019}
1020
1021static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
1022 struct v4l2_format *f)
1023{
1024 int ret;
1025
1026 ret = s5p_jpeg_try_fmt_vid_out(file, priv, f);
1027 if (ret)
1028 return ret;
1029
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001030 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001031}
1032
Sachin Kamat9f3bd322012-05-10 03:38:40 -03001033static int s5p_jpeg_g_selection(struct file *file, void *priv,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001034 struct v4l2_selection *s)
1035{
Sylwester Nawrocki275de242012-02-17 11:38:09 -03001036 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001037
1038 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001039 s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
1040 ctx->jpeg->variant->version != SJPEG_S5P)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001041 return -EINVAL;
1042
1043 /* For JPEG blob active == default == bounds */
1044 switch (s->target) {
Sylwester Nawrockic1334822012-05-20 11:17:12 -03001045 case V4L2_SEL_TGT_CROP:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001046 case V4L2_SEL_TGT_CROP_BOUNDS:
1047 case V4L2_SEL_TGT_CROP_DEFAULT:
Sylwester Nawrockic1334822012-05-20 11:17:12 -03001048 case V4L2_SEL_TGT_COMPOSE:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001049 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
1050 s->r.width = ctx->out_q.w;
1051 s->r.height = ctx->out_q.h;
1052 break;
1053 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
1054 case V4L2_SEL_TGT_COMPOSE_PADDED:
1055 s->r.width = ctx->cap_q.w;
1056 s->r.height = ctx->cap_q.h;
1057 break;
1058 default:
1059 return -EINVAL;
1060 }
1061 s->r.left = 0;
1062 s->r.top = 0;
1063 return 0;
1064}
1065
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001066/*
1067 * V4L2 controls
1068 */
1069
1070static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001071{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001072 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1073 struct s5p_jpeg *jpeg = ctx->jpeg;
1074 unsigned long flags;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001075
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001076 switch (ctrl->id) {
1077 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1078 spin_lock_irqsave(&jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001079
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001080 WARN_ON(ctx->subsampling > S5P_SUBSAMPLING_MODE_GRAY);
1081 if (ctx->subsampling > 2)
1082 ctrl->val = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
1083 else
1084 ctrl->val = ctx->subsampling;
1085 spin_unlock_irqrestore(&jpeg->slock, flags);
1086 break;
1087 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001088
1089 return 0;
1090}
1091
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001092static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001093{
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001094 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
1095 unsigned long flags;
1096
1097 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1098
1099 switch (ctrl->id) {
1100 case V4L2_CID_JPEG_COMPRESSION_QUALITY:
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001101 ctx->compr_quality = ctrl->val;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001102 break;
1103 case V4L2_CID_JPEG_RESTART_INTERVAL:
1104 ctx->restart_interval = ctrl->val;
1105 break;
1106 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
1107 ctx->subsampling = ctrl->val;
1108 break;
1109 }
1110
1111 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1112 return 0;
1113}
1114
1115static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
1116 .g_volatile_ctrl = s5p_jpeg_g_volatile_ctrl,
1117 .s_ctrl = s5p_jpeg_s_ctrl,
1118};
1119
1120static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
1121{
1122 unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */
1123 struct v4l2_ctrl *ctrl;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001124 int ret;
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001125
1126 v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
1127
1128 if (ctx->mode == S5P_JPEG_ENCODE) {
1129 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1130 V4L2_CID_JPEG_COMPRESSION_QUALITY,
Jacek Anaszewski78e5a3c2013-11-25 06:58:08 -03001131 0, 3, 1, S5P_JPEG_COMPR_QUAL_WORST);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001132
1133 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1134 V4L2_CID_JPEG_RESTART_INTERVAL,
1135 0, 3, 0xffff, 0);
1136 mask = ~0x06; /* 422, 420 */
1137 }
1138
1139 ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
1140 V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
1141 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask,
1142 V4L2_JPEG_CHROMA_SUBSAMPLING_422);
1143
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001144 if (ctx->ctrl_handler.error) {
1145 ret = ctx->ctrl_handler.error;
1146 goto error_free;
1147 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001148
1149 if (ctx->mode == S5P_JPEG_DECODE)
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001150 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
1151 V4L2_CTRL_FLAG_READ_ONLY;
Jacek Anaszewski088f8302013-11-25 06:58:15 -03001152
1153 ret = v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
1154 if (ret < 0)
1155 goto error_free;
1156
1157 return ret;
1158
1159error_free:
1160 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
1161 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001162}
1163
1164static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
1165 .vidioc_querycap = s5p_jpeg_querycap,
1166
1167 .vidioc_enum_fmt_vid_cap = s5p_jpeg_enum_fmt_vid_cap,
1168 .vidioc_enum_fmt_vid_out = s5p_jpeg_enum_fmt_vid_out,
1169
1170 .vidioc_g_fmt_vid_cap = s5p_jpeg_g_fmt,
1171 .vidioc_g_fmt_vid_out = s5p_jpeg_g_fmt,
1172
1173 .vidioc_try_fmt_vid_cap = s5p_jpeg_try_fmt_vid_cap,
1174 .vidioc_try_fmt_vid_out = s5p_jpeg_try_fmt_vid_out,
1175
1176 .vidioc_s_fmt_vid_cap = s5p_jpeg_s_fmt_vid_cap,
1177 .vidioc_s_fmt_vid_out = s5p_jpeg_s_fmt_vid_out,
1178
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001179 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
1180 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
1181 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
1182 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001183
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001184 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
1185 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001186
1187 .vidioc_g_selection = s5p_jpeg_g_selection,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001188};
1189
1190/*
1191 * ============================================================================
1192 * mem2mem callbacks
1193 * ============================================================================
1194 */
1195
1196static void s5p_jpeg_device_run(void *priv)
1197{
1198 struct s5p_jpeg_ctx *ctx = priv;
1199 struct s5p_jpeg *jpeg = ctx->jpeg;
1200 struct vb2_buffer *src_buf, *dst_buf;
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001201 unsigned long src_addr, dst_addr, flags;
1202
1203 spin_lock_irqsave(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001204
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001205 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1206 dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001207 src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
1208 dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
1209
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001210 s5p_jpeg_reset(jpeg->regs);
1211 s5p_jpeg_poweron(jpeg->regs);
1212 s5p_jpeg_proc_mode(jpeg->regs, ctx->mode);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001213 if (ctx->mode == S5P_JPEG_ENCODE) {
1214 if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001215 s5p_jpeg_input_raw_mode(jpeg->regs,
1216 S5P_JPEG_RAW_IN_565);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001217 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001218 s5p_jpeg_input_raw_mode(jpeg->regs,
1219 S5P_JPEG_RAW_IN_422);
1220 s5p_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
1221 s5p_jpeg_dri(jpeg->regs, ctx->restart_interval);
1222 s5p_jpeg_x(jpeg->regs, ctx->out_q.w);
1223 s5p_jpeg_y(jpeg->regs, ctx->out_q.h);
1224 s5p_jpeg_imgadr(jpeg->regs, src_addr);
1225 s5p_jpeg_jpgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001226
1227 /* ultimately comes from sizeimage from userspace */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001228 s5p_jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001229
1230 /* JPEG RGB to YCbCr conversion matrix */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001231 s5p_jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11);
1232 s5p_jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12);
1233 s5p_jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13);
1234 s5p_jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21);
1235 s5p_jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22);
1236 s5p_jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23);
1237 s5p_jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31);
1238 s5p_jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32);
1239 s5p_jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001240
1241 /*
1242 * JPEG IP allows storing 4 quantization tables
1243 * We fill table 0 for luma and table 1 for chroma
1244 */
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03001245 s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
1246 s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001247 /* use table 0 for Y */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001248 s5p_jpeg_qtbl(jpeg->regs, 1, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001249 /* use table 1 for Cb and Cr*/
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001250 s5p_jpeg_qtbl(jpeg->regs, 2, 1);
1251 s5p_jpeg_qtbl(jpeg->regs, 3, 1);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001252
1253 /* Y, Cb, Cr use Huffman table 0 */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001254 s5p_jpeg_htbl_ac(jpeg->regs, 1);
1255 s5p_jpeg_htbl_dc(jpeg->regs, 1);
1256 s5p_jpeg_htbl_ac(jpeg->regs, 2);
1257 s5p_jpeg_htbl_dc(jpeg->regs, 2);
1258 s5p_jpeg_htbl_ac(jpeg->regs, 3);
1259 s5p_jpeg_htbl_dc(jpeg->regs, 3);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001260 } else { /* S5P_JPEG_DECODE */
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001261 s5p_jpeg_rst_int_enable(jpeg->regs, true);
1262 s5p_jpeg_data_num_int_enable(jpeg->regs, true);
1263 s5p_jpeg_final_mcu_num_int_enable(jpeg->regs, true);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001264 if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001265 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001266 else
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001267 s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420);
1268 s5p_jpeg_jpgadr(jpeg->regs, src_addr);
1269 s5p_jpeg_imgadr(jpeg->regs, dst_addr);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001270 }
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001271
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001272 s5p_jpeg_start(jpeg->regs);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001273
1274 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001275}
1276
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001277static void exynos4_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
1278{
1279 struct s5p_jpeg *jpeg = ctx->jpeg;
1280 struct s5p_jpeg_fmt *fmt;
1281 struct vb2_buffer *vb;
1282 struct s5p_jpeg_addr jpeg_addr;
1283 u32 pix_size, padding_bytes = 0;
1284
1285 pix_size = ctx->cap_q.w * ctx->cap_q.h;
1286
1287 if (ctx->mode == S5P_JPEG_ENCODE) {
1288 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1289 fmt = ctx->out_q.fmt;
1290 if (ctx->out_q.w % 2 && fmt->h_align > 0)
1291 padding_bytes = ctx->out_q.h;
1292 } else {
1293 fmt = ctx->cap_q.fmt;
1294 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1295 }
1296
1297 jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
1298
1299 if (fmt->colplanes == 2) {
1300 jpeg_addr.cb = jpeg_addr.y + pix_size - padding_bytes;
1301 } else if (fmt->colplanes == 3) {
1302 jpeg_addr.cb = jpeg_addr.y + pix_size;
1303 if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
1304 jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
1305 else
1306 jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
1307 }
1308
1309 exynos4_jpeg_set_frame_buf_address(jpeg->regs, &jpeg_addr);
1310}
1311
1312static void exynos4_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
1313{
1314 struct s5p_jpeg *jpeg = ctx->jpeg;
1315 struct vb2_buffer *vb;
1316 unsigned int jpeg_addr = 0;
1317
1318 if (ctx->mode == S5P_JPEG_ENCODE)
1319 vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1320 else
1321 vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1322
1323 jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
1324 exynos4_jpeg_set_stream_buf_address(jpeg->regs, jpeg_addr);
1325}
1326
1327static void exynos4_jpeg_device_run(void *priv)
1328{
1329 struct s5p_jpeg_ctx *ctx = priv;
1330 struct s5p_jpeg *jpeg = ctx->jpeg;
1331 unsigned int bitstream_size;
1332 unsigned long flags;
1333
1334 spin_lock_irqsave(&ctx->jpeg->slock, flags);
1335
1336 if (ctx->mode == S5P_JPEG_ENCODE) {
1337 exynos4_jpeg_sw_reset(jpeg->regs);
1338 exynos4_jpeg_set_interrupt(jpeg->regs);
1339 exynos4_jpeg_set_huf_table_enable(jpeg->regs, 1);
1340
1341 exynos4_jpeg_set_huff_tbl(jpeg->regs);
1342
1343 /*
1344 * JPEG IP allows storing 4 quantization tables
1345 * We fill table 0 for luma and table 1 for chroma
1346 */
1347 exynos4_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
1348 exynos4_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
1349
1350 exynos4_jpeg_set_encode_tbl_select(jpeg->regs,
1351 ctx->compr_quality);
1352 exynos4_jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w,
1353 ctx->cap_q.h);
1354
1355 exynos4_jpeg_set_enc_out_fmt(jpeg->regs, ctx->subsampling);
1356 exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->out_q.fmt->fourcc);
1357 exynos4_jpeg_set_img_addr(ctx);
1358 exynos4_jpeg_set_jpeg_addr(ctx);
1359 exynos4_jpeg_set_encode_hoff_cnt(jpeg->regs,
1360 ctx->out_q.fmt->fourcc);
1361 } else {
1362 exynos4_jpeg_sw_reset(jpeg->regs);
1363 exynos4_jpeg_set_interrupt(jpeg->regs);
1364 exynos4_jpeg_set_img_addr(ctx);
1365 exynos4_jpeg_set_jpeg_addr(ctx);
1366 exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->cap_q.fmt->fourcc);
1367
1368 bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 32);
1369
1370 exynos4_jpeg_set_dec_bitstream_size(jpeg->regs, bitstream_size);
1371 }
1372
1373 exynos4_jpeg_set_enc_dec_mode(jpeg->regs, ctx->mode);
1374
1375 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
1376}
1377
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001378static int s5p_jpeg_job_ready(void *priv)
1379{
1380 struct s5p_jpeg_ctx *ctx = priv;
1381
1382 if (ctx->mode == S5P_JPEG_DECODE)
1383 return ctx->hdr_parsed;
1384 return 1;
1385}
1386
1387static void s5p_jpeg_job_abort(void *priv)
1388{
1389}
1390
1391static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = {
1392 .device_run = s5p_jpeg_device_run,
1393 .job_ready = s5p_jpeg_job_ready,
1394 .job_abort = s5p_jpeg_job_abort,
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001395}
1396;
1397static struct v4l2_m2m_ops exynos_jpeg_m2m_ops = {
1398 .device_run = exynos4_jpeg_device_run,
1399 .job_ready = s5p_jpeg_job_ready,
1400 .job_abort = s5p_jpeg_job_abort,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001401};
1402
1403/*
1404 * ============================================================================
1405 * Queue operations
1406 * ============================================================================
1407 */
1408
Marek Szyprowski719c1742012-01-13 05:12:38 -03001409static int s5p_jpeg_queue_setup(struct vb2_queue *vq,
1410 const struct v4l2_format *fmt,
1411 unsigned int *nbuffers, unsigned int *nplanes,
1412 unsigned int sizes[], void *alloc_ctxs[])
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001413{
1414 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
1415 struct s5p_jpeg_q_data *q_data = NULL;
1416 unsigned int size, count = *nbuffers;
1417
1418 q_data = get_q_data(ctx, vq->type);
1419 BUG_ON(q_data == NULL);
1420
1421 size = q_data->size;
1422
1423 /*
1424 * header is parsed during decoding and parsed information stored
1425 * in the context so we do not allow another buffer to overwrite it
1426 */
1427 if (ctx->mode == S5P_JPEG_DECODE)
1428 count = 1;
1429
1430 *nbuffers = count;
1431 *nplanes = 1;
1432 sizes[0] = size;
1433 alloc_ctxs[0] = ctx->jpeg->alloc_ctx;
1434
1435 return 0;
1436}
1437
1438static int s5p_jpeg_buf_prepare(struct vb2_buffer *vb)
1439{
1440 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1441 struct s5p_jpeg_q_data *q_data = NULL;
1442
1443 q_data = get_q_data(ctx, vb->vb2_queue->type);
1444 BUG_ON(q_data == NULL);
1445
1446 if (vb2_plane_size(vb, 0) < q_data->size) {
1447 pr_err("%s data will not fit into plane (%lu < %lu)\n",
1448 __func__, vb2_plane_size(vb, 0),
1449 (long)q_data->size);
1450 return -EINVAL;
1451 }
1452
1453 vb2_set_plane_payload(vb, 0, q_data->size);
1454
1455 return 0;
1456}
1457
1458static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
1459{
1460 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1461
1462 if (ctx->mode == S5P_JPEG_DECODE &&
1463 vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
1464 struct s5p_jpeg_q_data tmp, *q_data;
1465 ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp,
1466 (unsigned long)vb2_plane_vaddr(vb, 0),
1467 min((unsigned long)ctx->out_q.size,
Jacek Anaszewskif8433962013-11-21 13:33:09 -03001468 vb2_get_plane_payload(vb, 0)), ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001469 if (!ctx->hdr_parsed) {
1470 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
1471 return;
1472 }
1473
1474 q_data = &ctx->out_q;
1475 q_data->w = tmp.w;
1476 q_data->h = tmp.h;
1477
1478 q_data = &ctx->cap_q;
1479 q_data->w = tmp.w;
1480 q_data->h = tmp.h;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001481 }
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001482
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001483 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001484}
1485
1486static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
1487{
1488 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
1489 int ret;
1490
1491 ret = pm_runtime_get_sync(ctx->jpeg->dev);
1492
1493 return ret > 0 ? 0 : ret;
1494}
1495
1496static int s5p_jpeg_stop_streaming(struct vb2_queue *q)
1497{
1498 struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
1499
1500 pm_runtime_put(ctx->jpeg->dev);
1501
1502 return 0;
1503}
1504
1505static struct vb2_ops s5p_jpeg_qops = {
1506 .queue_setup = s5p_jpeg_queue_setup,
1507 .buf_prepare = s5p_jpeg_buf_prepare,
1508 .buf_queue = s5p_jpeg_buf_queue,
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001509 .wait_prepare = vb2_ops_wait_prepare,
1510 .wait_finish = vb2_ops_wait_finish,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001511 .start_streaming = s5p_jpeg_start_streaming,
1512 .stop_streaming = s5p_jpeg_stop_streaming,
1513};
1514
1515static int queue_init(void *priv, struct vb2_queue *src_vq,
1516 struct vb2_queue *dst_vq)
1517{
1518 struct s5p_jpeg_ctx *ctx = priv;
1519 int ret;
1520
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001521 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1522 src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
1523 src_vq->drv_priv = ctx;
1524 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1525 src_vq->ops = &s5p_jpeg_qops;
1526 src_vq->mem_ops = &vb2_dma_contig_memops;
Kamil Debskiaca326a2013-04-24 10:08:02 -03001527 src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001528 src_vq->lock = &ctx->jpeg->lock;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001529
1530 ret = vb2_queue_init(src_vq);
1531 if (ret)
1532 return ret;
1533
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001534 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1535 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
1536 dst_vq->drv_priv = ctx;
1537 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1538 dst_vq->ops = &s5p_jpeg_qops;
1539 dst_vq->mem_ops = &vb2_dma_contig_memops;
Kamil Debskiaca326a2013-04-24 10:08:02 -03001540 dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001541 dst_vq->lock = &ctx->jpeg->lock;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001542
1543 return vb2_queue_init(dst_vq);
1544}
1545
1546/*
1547 * ============================================================================
1548 * ISR
1549 * ============================================================================
1550 */
1551
1552static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
1553{
1554 struct s5p_jpeg *jpeg = dev_id;
1555 struct s5p_jpeg_ctx *curr_ctx;
1556 struct vb2_buffer *src_buf, *dst_buf;
1557 unsigned long payload_size = 0;
1558 enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
1559 bool enc_jpeg_too_large = false;
1560 bool timer_elapsed = false;
1561 bool op_completed = false;
1562
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001563 spin_lock(&jpeg->slock);
1564
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001565 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
1566
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001567 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
1568 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001569
1570 if (curr_ctx->mode == S5P_JPEG_ENCODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001571 enc_jpeg_too_large = s5p_jpeg_enc_stream_stat(jpeg->regs);
1572 timer_elapsed = s5p_jpeg_timer_stat(jpeg->regs);
1573 op_completed = s5p_jpeg_result_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001574 if (curr_ctx->mode == S5P_JPEG_DECODE)
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001575 op_completed = op_completed &&
1576 s5p_jpeg_stream_stat_ok(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001577
1578 if (enc_jpeg_too_large) {
1579 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001580 s5p_jpeg_clear_enc_stream_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001581 } else if (timer_elapsed) {
1582 state = VB2_BUF_STATE_ERROR;
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001583 s5p_jpeg_clear_timer_stat(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001584 } else if (!op_completed) {
1585 state = VB2_BUF_STATE_ERROR;
1586 } else {
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001587 payload_size = s5p_jpeg_compressed_size(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001588 }
1589
Kamil Debskiaca326a2013-04-24 10:08:02 -03001590 dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
1591 dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
1592
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001593 v4l2_m2m_buf_done(src_buf, state);
1594 if (curr_ctx->mode == S5P_JPEG_ENCODE)
1595 vb2_set_plane_payload(dst_buf, 0, payload_size);
1596 v4l2_m2m_buf_done(dst_buf, state);
Sylwester Nawrocki718cf4a2013-08-25 17:16:56 -03001597 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001598
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001599 curr_ctx->subsampling = s5p_jpeg_get_subsampling_mode(jpeg->regs);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001600 spin_unlock(&jpeg->slock);
Andrzej Pietrasiewiczfb6f8c02012-02-20 07:32:25 -03001601
Jacek Anaszewski9f7b62d2013-12-18 09:32:50 -03001602 s5p_jpeg_clear_int(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001603
1604 return IRQ_HANDLED;
1605}
1606
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001607static irqreturn_t exynos4_jpeg_irq(int irq, void *priv)
1608{
1609 unsigned int int_status;
1610 struct vb2_buffer *src_vb, *dst_vb;
1611 struct s5p_jpeg *jpeg = priv;
1612 struct s5p_jpeg_ctx *curr_ctx;
1613 unsigned long payload_size = 0;
1614
1615 spin_lock(&jpeg->slock);
1616
1617 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
1618
1619 src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
1620 dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
1621
1622 int_status = exynos4_jpeg_get_int_status(jpeg->regs);
1623
1624 if (int_status) {
1625 switch (int_status & 0x1f) {
1626 case 0x1:
1627 jpeg->irq_ret = ERR_PROT;
1628 break;
1629 case 0x2:
1630 jpeg->irq_ret = OK_ENC_OR_DEC;
1631 break;
1632 case 0x4:
1633 jpeg->irq_ret = ERR_DEC_INVALID_FORMAT;
1634 break;
1635 case 0x8:
1636 jpeg->irq_ret = ERR_MULTI_SCAN;
1637 break;
1638 case 0x10:
1639 jpeg->irq_ret = ERR_FRAME;
1640 break;
1641 default:
1642 jpeg->irq_ret = ERR_UNKNOWN;
1643 break;
1644 }
1645 } else {
1646 jpeg->irq_ret = ERR_UNKNOWN;
1647 }
1648
1649 if (jpeg->irq_ret == OK_ENC_OR_DEC) {
1650 if (curr_ctx->mode == S5P_JPEG_ENCODE) {
1651 payload_size = exynos4_jpeg_get_stream_size(jpeg->regs);
1652 vb2_set_plane_payload(dst_vb, 0, payload_size);
1653 }
1654 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
1655 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
1656 } else {
1657 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
1658 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
1659 }
1660
1661 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
1662 curr_ctx->subsampling = exynos4_jpeg_get_frame_fmt(jpeg->regs);
1663
1664 spin_unlock(&jpeg->slock);
1665 return IRQ_HANDLED;
1666}
1667
1668static void *jpeg_get_drv_data(struct platform_device *pdev);
1669
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001670/*
1671 * ============================================================================
1672 * Driver basic infrastructure
1673 * ============================================================================
1674 */
1675
1676static int s5p_jpeg_probe(struct platform_device *pdev)
1677{
1678 struct s5p_jpeg *jpeg;
1679 struct resource *res;
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001680 struct v4l2_m2m_ops *samsung_jpeg_m2m_ops;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001681 int ret;
1682
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001683 if (!pdev->dev.of_node)
1684 return -ENODEV;
1685
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001686 /* JPEG IP abstraction struct */
Sachin Kamat5b58b952012-05-14 06:33:34 -03001687 jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001688 if (!jpeg)
1689 return -ENOMEM;
1690
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001691 jpeg->variant = jpeg_get_drv_data(pdev);
1692
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001693 mutex_init(&jpeg->lock);
Sylwester Nawrocki15f4bc32012-02-17 11:39:36 -03001694 spin_lock_init(&jpeg->slock);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001695 jpeg->dev = &pdev->dev;
1696
1697 /* memory-mapped registers */
1698 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001699
Thierry Redingf23999e2013-01-21 06:09:07 -03001700 jpeg->regs = devm_ioremap_resource(&pdev->dev, res);
1701 if (IS_ERR(jpeg->regs))
1702 return PTR_ERR(jpeg->regs);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001703
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001704 /* interrupt service routine registration */
1705 jpeg->irq = ret = platform_get_irq(pdev, 0);
1706 if (ret < 0) {
1707 dev_err(&pdev->dev, "cannot find IRQ\n");
Sachin Kamat5b58b952012-05-14 06:33:34 -03001708 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001709 }
1710
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001711 ret = devm_request_irq(&pdev->dev, jpeg->irq, jpeg->variant->jpeg_irq,
1712 0, dev_name(&pdev->dev), jpeg);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001713 if (ret) {
1714 dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
Sachin Kamat5b58b952012-05-14 06:33:34 -03001715 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001716 }
1717
1718 /* clocks */
1719 jpeg->clk = clk_get(&pdev->dev, "jpeg");
1720 if (IS_ERR(jpeg->clk)) {
1721 dev_err(&pdev->dev, "cannot get clock\n");
1722 ret = PTR_ERR(jpeg->clk);
Sachin Kamat5b58b952012-05-14 06:33:34 -03001723 return ret;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001724 }
1725 dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001726
1727 /* v4l2 device */
1728 ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
1729 if (ret) {
1730 dev_err(&pdev->dev, "Failed to register v4l2 device\n");
1731 goto clk_get_rollback;
1732 }
1733
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001734 if (jpeg->variant->version == SJPEG_S5P)
1735 samsung_jpeg_m2m_ops = &s5p_jpeg_m2m_ops;
1736 else
1737 samsung_jpeg_m2m_ops = &exynos_jpeg_m2m_ops;
1738
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001739 /* mem2mem device */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001740 jpeg->m2m_dev = v4l2_m2m_init(samsung_jpeg_m2m_ops);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001741 if (IS_ERR(jpeg->m2m_dev)) {
1742 v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
1743 ret = PTR_ERR(jpeg->m2m_dev);
1744 goto device_register_rollback;
1745 }
1746
1747 jpeg->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
1748 if (IS_ERR(jpeg->alloc_ctx)) {
1749 v4l2_err(&jpeg->v4l2_dev, "Failed to init memory allocator\n");
1750 ret = PTR_ERR(jpeg->alloc_ctx);
1751 goto m2m_init_rollback;
1752 }
1753
1754 /* JPEG encoder /dev/videoX node */
1755 jpeg->vfd_encoder = video_device_alloc();
1756 if (!jpeg->vfd_encoder) {
1757 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
1758 ret = -ENOMEM;
1759 goto vb2_allocator_rollback;
1760 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03001761 snprintf(jpeg->vfd_encoder->name, sizeof(jpeg->vfd_encoder->name),
1762 "%s-enc", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001763 jpeg->vfd_encoder->fops = &s5p_jpeg_fops;
1764 jpeg->vfd_encoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
1765 jpeg->vfd_encoder->minor = -1;
1766 jpeg->vfd_encoder->release = video_device_release;
1767 jpeg->vfd_encoder->lock = &jpeg->lock;
1768 jpeg->vfd_encoder->v4l2_dev = &jpeg->v4l2_dev;
Hans Verkuil954f3402012-09-05 06:05:50 -03001769 jpeg->vfd_encoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001770
1771 ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
1772 if (ret) {
1773 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
1774 goto enc_vdev_alloc_rollback;
1775 }
1776
1777 video_set_drvdata(jpeg->vfd_encoder, jpeg);
1778 v4l2_info(&jpeg->v4l2_dev,
1779 "encoder device registered as /dev/video%d\n",
1780 jpeg->vfd_encoder->num);
1781
1782 /* JPEG decoder /dev/videoX node */
1783 jpeg->vfd_decoder = video_device_alloc();
1784 if (!jpeg->vfd_decoder) {
1785 v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
1786 ret = -ENOMEM;
1787 goto enc_vdev_register_rollback;
1788 }
Seung-Woo Kimbaaf0462013-10-10 04:45:56 -03001789 snprintf(jpeg->vfd_decoder->name, sizeof(jpeg->vfd_decoder->name),
1790 "%s-dec", S5P_JPEG_M2M_NAME);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001791 jpeg->vfd_decoder->fops = &s5p_jpeg_fops;
1792 jpeg->vfd_decoder->ioctl_ops = &s5p_jpeg_ioctl_ops;
1793 jpeg->vfd_decoder->minor = -1;
1794 jpeg->vfd_decoder->release = video_device_release;
1795 jpeg->vfd_decoder->lock = &jpeg->lock;
1796 jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev;
Jacek Anaszewski7f7d8fe2013-09-11 06:17:45 -03001797 jpeg->vfd_decoder->vfl_dir = VFL_DIR_M2M;
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001798
1799 ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
1800 if (ret) {
1801 v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
1802 goto dec_vdev_alloc_rollback;
1803 }
1804
1805 video_set_drvdata(jpeg->vfd_decoder, jpeg);
1806 v4l2_info(&jpeg->v4l2_dev,
1807 "decoder device registered as /dev/video%d\n",
1808 jpeg->vfd_decoder->num);
1809
1810 /* final statements & power management */
1811 platform_set_drvdata(pdev, jpeg);
1812
1813 pm_runtime_enable(&pdev->dev);
1814
1815 v4l2_info(&jpeg->v4l2_dev, "Samsung S5P JPEG codec\n");
1816
1817 return 0;
1818
1819dec_vdev_alloc_rollback:
1820 video_device_release(jpeg->vfd_decoder);
1821
1822enc_vdev_register_rollback:
1823 video_unregister_device(jpeg->vfd_encoder);
1824
1825enc_vdev_alloc_rollback:
1826 video_device_release(jpeg->vfd_encoder);
1827
1828vb2_allocator_rollback:
1829 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
1830
1831m2m_init_rollback:
1832 v4l2_m2m_release(jpeg->m2m_dev);
1833
1834device_register_rollback:
1835 v4l2_device_unregister(&jpeg->v4l2_dev);
1836
1837clk_get_rollback:
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001838 clk_put(jpeg->clk);
1839
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001840 return ret;
1841}
1842
1843static int s5p_jpeg_remove(struct platform_device *pdev)
1844{
1845 struct s5p_jpeg *jpeg = platform_get_drvdata(pdev);
1846
1847 pm_runtime_disable(jpeg->dev);
1848
1849 video_unregister_device(jpeg->vfd_decoder);
1850 video_device_release(jpeg->vfd_decoder);
1851 video_unregister_device(jpeg->vfd_encoder);
1852 video_device_release(jpeg->vfd_encoder);
1853 vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
1854 v4l2_m2m_release(jpeg->m2m_dev);
1855 v4l2_device_unregister(&jpeg->v4l2_dev);
1856
Jacek Anaszewskif1347132013-11-25 06:58:13 -03001857 if (!pm_runtime_status_suspended(&pdev->dev))
1858 clk_disable_unprepare(jpeg->clk);
1859
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001860 clk_put(jpeg->clk);
1861
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001862 return 0;
1863}
1864
1865static int s5p_jpeg_runtime_suspend(struct device *dev)
1866{
Jacek Anaszewskif1347132013-11-25 06:58:13 -03001867 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
1868
1869 clk_disable_unprepare(jpeg->clk);
1870
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001871 return 0;
1872}
1873
1874static int s5p_jpeg_runtime_resume(struct device *dev)
1875{
1876 struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001877 unsigned long flags;
Jacek Anaszewskif1347132013-11-25 06:58:13 -03001878 int ret;
1879
1880 ret = clk_prepare_enable(jpeg->clk);
1881 if (ret < 0)
1882 return ret;
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03001883
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001884 spin_lock_irqsave(&jpeg->slock, flags);
1885
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001886 /*
1887 * JPEG IP allows storing two Huffman tables for each component
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001888 * We fill table 0 for each component and do this here only
1889 * for S5PC210 device as Exynos4x12 requires programming its
1890 * Huffman tables each time the encoding process is initialized.
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001891 */
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001892 if (jpeg->variant->version == SJPEG_S5P) {
1893 s5p_jpeg_set_hdctbl(jpeg->regs);
1894 s5p_jpeg_set_hdctblg(jpeg->regs);
1895 s5p_jpeg_set_hactbl(jpeg->regs);
1896 s5p_jpeg_set_hactblg(jpeg->regs);
1897 }
Jacek Anaszewski31dc0ac2013-11-25 06:58:12 -03001898
Jacek Anaszewskib3c932a2013-11-25 06:58:14 -03001899 spin_unlock_irqrestore(&jpeg->slock, flags);
1900
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001901 return 0;
1902}
1903
Jacek Anaszewskif1347132013-11-25 06:58:13 -03001904static int s5p_jpeg_suspend(struct device *dev)
1905{
1906 if (pm_runtime_suspended(dev))
1907 return 0;
1908
1909 return s5p_jpeg_runtime_suspend(dev);
1910}
1911
1912static int s5p_jpeg_resume(struct device *dev)
1913{
1914 if (pm_runtime_suspended(dev))
1915 return 0;
1916
1917 return s5p_jpeg_runtime_resume(dev);
1918}
1919
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001920static const struct dev_pm_ops s5p_jpeg_pm_ops = {
Jacek Anaszewskif1347132013-11-25 06:58:13 -03001921 SET_SYSTEM_SLEEP_PM_OPS(s5p_jpeg_suspend, s5p_jpeg_resume)
1922 SET_RUNTIME_PM_OPS(s5p_jpeg_runtime_suspend, s5p_jpeg_runtime_resume, NULL)
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001923};
1924
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03001925#ifdef CONFIG_OF
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001926static struct s5p_jpeg_variant s5p_jpeg_drvdata = {
1927 .version = SJPEG_S5P,
1928 .jpeg_irq = s5p_jpeg_irq,
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03001929};
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001930
1931static struct s5p_jpeg_variant exynos4_jpeg_drvdata = {
1932 .version = SJPEG_EXYNOS4,
1933 .jpeg_irq = exynos4_jpeg_irq,
1934};
1935
1936static const struct of_device_id samsung_jpeg_match[] = {
1937 {
1938 .compatible = "samsung,s5pv210-jpeg",
1939 .data = &s5p_jpeg_drvdata,
1940 }, {
1941 .compatible = "samsung,exynos4210-jpeg",
1942 .data = &s5p_jpeg_drvdata,
1943 }, {
1944 .compatible = "samsung,exynos4212-jpeg",
1945 .data = &exynos4_jpeg_drvdata,
1946 },
1947 {},
1948};
1949
1950MODULE_DEVICE_TABLE(of, samsung_jpeg_match);
1951
1952static void *jpeg_get_drv_data(struct platform_device *pdev)
1953{
1954 struct s5p_jpeg_variant *driver_data = NULL;
1955 const struct of_device_id *match;
1956
1957 match = of_match_node(of_match_ptr(samsung_jpeg_match),
1958 pdev->dev.of_node);
1959 if (match)
1960 driver_data = (struct s5p_jpeg_variant *)match->data;
1961
1962 return driver_data;
1963}
Sylwester Nawrockif7074ab2013-08-18 16:14:27 -03001964#endif
1965
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001966static struct platform_driver s5p_jpeg_driver = {
1967 .probe = s5p_jpeg_probe,
1968 .remove = s5p_jpeg_remove,
1969 .driver = {
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001970 .of_match_table = of_match_ptr(samsung_jpeg_match),
1971 .owner = THIS_MODULE,
1972 .name = S5P_JPEG_M2M_NAME,
1973 .pm = &s5p_jpeg_pm_ops,
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001974 },
1975};
1976
Sachin Kamat87e94292012-07-03 05:54:33 -03001977module_platform_driver(s5p_jpeg_driver);
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001978
1979MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
Jacek Anaszewski80529ae2013-12-18 11:04:44 -03001980MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
Andrzej Pietrasiewiczbb677f32011-11-24 11:15:23 -03001981MODULE_DESCRIPTION("Samsung JPEG codec driver");
1982MODULE_LICENSE("GPL");