Commit | Line | Data |
---|---|---|
af935746 KD |
1 | /* |
2 | * linux/drivers/media/video/s5p-mfc/s5p_mfc_dec.c | |
3 | * | |
4 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. | |
5 | * http://www.samsung.com/ | |
6 | * Kamil Debski, <k.debski@samsung.com> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; either version 2 of the License, or | |
11 | * (at your option) any later version. | |
12 | */ | |
13 | ||
14 | #include <linux/clk.h> | |
15 | #include <linux/interrupt.h> | |
16 | #include <linux/io.h> | |
17 | #include <linux/module.h> | |
18 | #include <linux/platform_device.h> | |
19 | #include <linux/sched.h> | |
20 | #include <linux/slab.h> | |
21 | #include <linux/version.h> | |
22 | #include <linux/videodev2.h> | |
23 | #include <linux/workqueue.h> | |
24 | #include <media/v4l2-ctrls.h> | |
25 | #include <media/videobuf2-core.h> | |
26 | #include "regs-mfc.h" | |
27 | #include "s5p_mfc_common.h" | |
28 | #include "s5p_mfc_debug.h" | |
29 | #include "s5p_mfc_dec.h" | |
30 | #include "s5p_mfc_intr.h" | |
31 | #include "s5p_mfc_opr.h" | |
32 | #include "s5p_mfc_pm.h" | |
33 | #include "s5p_mfc_shm.h" | |
34 | ||
35 | static struct s5p_mfc_fmt formats[] = { | |
36 | { | |
37 | .name = "4:2:0 2 Planes 64x32 Tiles", | |
38 | .fourcc = V4L2_PIX_FMT_NV12MT, | |
39 | .codec_mode = S5P_FIMV_CODEC_NONE, | |
40 | .type = MFC_FMT_RAW, | |
41 | .num_planes = 2, | |
42 | }, | |
43 | { | |
44 | .name = "4:2:0 2 Planes", | |
45 | .fourcc = V4L2_PIX_FMT_NV12M, | |
46 | .codec_mode = S5P_FIMV_CODEC_NONE, | |
47 | .type = MFC_FMT_RAW, | |
48 | .num_planes = 2, | |
49 | }, | |
50 | { | |
51 | .name = "H264 Encoded Stream", | |
52 | .fourcc = V4L2_PIX_FMT_H264, | |
53 | .codec_mode = S5P_FIMV_CODEC_H264_DEC, | |
54 | .type = MFC_FMT_DEC, | |
55 | .num_planes = 1, | |
56 | }, | |
57 | { | |
58 | .name = "H263 Encoded Stream", | |
59 | .fourcc = V4L2_PIX_FMT_H263, | |
60 | .codec_mode = S5P_FIMV_CODEC_H263_DEC, | |
61 | .type = MFC_FMT_DEC, | |
62 | .num_planes = 1, | |
63 | }, | |
64 | { | |
65 | .name = "MPEG1 Encoded Stream", | |
66 | .fourcc = V4L2_PIX_FMT_MPEG1, | |
67 | .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC, | |
68 | .type = MFC_FMT_DEC, | |
69 | .num_planes = 1, | |
70 | }, | |
71 | { | |
72 | .name = "MPEG2 Encoded Stream", | |
73 | .fourcc = V4L2_PIX_FMT_MPEG2, | |
74 | .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC, | |
75 | .type = MFC_FMT_DEC, | |
76 | .num_planes = 1, | |
77 | }, | |
78 | { | |
79 | .name = "MPEG4 Encoded Stream", | |
80 | .fourcc = V4L2_PIX_FMT_MPEG4, | |
81 | .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC, | |
82 | .type = MFC_FMT_DEC, | |
83 | .num_planes = 1, | |
84 | }, | |
85 | { | |
86 | .name = "XviD Encoded Stream", | |
87 | .fourcc = V4L2_PIX_FMT_XVID, | |
88 | .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC, | |
89 | .type = MFC_FMT_DEC, | |
90 | .num_planes = 1, | |
91 | }, | |
92 | { | |
93 | .name = "VC1 Encoded Stream", | |
94 | .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G, | |
95 | .codec_mode = S5P_FIMV_CODEC_VC1_DEC, | |
96 | .type = MFC_FMT_DEC, | |
97 | .num_planes = 1, | |
98 | }, | |
99 | { | |
100 | .name = "VC1 RCV Encoded Stream", | |
101 | .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L, | |
102 | .codec_mode = S5P_FIMV_CODEC_VC1RCV_DEC, | |
103 | .type = MFC_FMT_DEC, | |
104 | .num_planes = 1, | |
105 | }, | |
106 | }; | |
107 | ||
108 | #define NUM_FORMATS ARRAY_SIZE(formats) | |
109 | ||
110 | /* Find selected format description */ | |
111 | static struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t) | |
112 | { | |
113 | unsigned int i; | |
114 | ||
115 | for (i = 0; i < NUM_FORMATS; i++) { | |
116 | if (formats[i].fourcc == f->fmt.pix_mp.pixelformat && | |
117 | formats[i].type == t) | |
118 | return &formats[i]; | |
119 | } | |
120 | return NULL; | |
121 | } | |
122 | ||
123 | static struct mfc_control controls[] = { | |
124 | { | |
125 | .id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY, | |
126 | .type = V4L2_CTRL_TYPE_INTEGER, | |
127 | .name = "H264 Display Delay", | |
128 | .minimum = 0, | |
129 | .maximum = 16383, | |
130 | .step = 1, | |
131 | .default_value = 0, | |
132 | }, | |
133 | { | |
134 | .id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE, | |
135 | .type = V4L2_CTRL_TYPE_BOOLEAN, | |
136 | .name = "H264 Display Delay Enable", | |
137 | .minimum = 0, | |
138 | .maximum = 1, | |
139 | .step = 1, | |
140 | .default_value = 0, | |
141 | }, | |
142 | { | |
143 | .id = V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER, | |
144 | .type = V4L2_CTRL_TYPE_BOOLEAN, | |
145 | .name = "Mpeg4 Loop Filter Enable", | |
146 | .minimum = 0, | |
147 | .maximum = 1, | |
148 | .step = 1, | |
149 | .default_value = 0, | |
150 | }, | |
151 | { | |
152 | .id = V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE, | |
153 | .type = V4L2_CTRL_TYPE_BOOLEAN, | |
154 | .name = "Slice Interface Enable", | |
155 | .minimum = 0, | |
156 | .maximum = 1, | |
157 | .step = 1, | |
158 | .default_value = 0, | |
159 | }, | |
160 | { | |
161 | .id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, | |
162 | .type = V4L2_CTRL_TYPE_INTEGER, | |
163 | .name = "Minimum number of cap bufs", | |
164 | .minimum = 1, | |
165 | .maximum = 32, | |
166 | .step = 1, | |
167 | .default_value = 1, | |
0da0a783 | 168 | .is_volatile = 1, |
af935746 KD |
169 | }, |
170 | }; | |
171 | ||
172 | #define NUM_CTRLS ARRAY_SIZE(controls) | |
173 | ||
174 | /* Check whether a context should be run on hardware */ | |
175 | static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx) | |
176 | { | |
177 | /* Context is to parse header */ | |
178 | if (ctx->src_queue_cnt >= 1 && ctx->state == MFCINST_GOT_INST) | |
179 | return 1; | |
180 | /* Context is to decode a frame */ | |
181 | if (ctx->src_queue_cnt >= 1 && | |
182 | ctx->state == MFCINST_RUNNING && | |
183 | ctx->dst_queue_cnt >= ctx->dpb_count) | |
184 | return 1; | |
185 | /* Context is to return last frame */ | |
186 | if (ctx->state == MFCINST_FINISHING && | |
187 | ctx->dst_queue_cnt >= ctx->dpb_count) | |
188 | return 1; | |
189 | /* Context is to set buffers */ | |
190 | if (ctx->src_queue_cnt >= 1 && | |
191 | ctx->state == MFCINST_HEAD_PARSED && | |
192 | ctx->capture_state == QUEUE_BUFS_MMAPED) | |
193 | return 1; | |
194 | /* Resolution change */ | |
195 | if ((ctx->state == MFCINST_RES_CHANGE_INIT || | |
196 | ctx->state == MFCINST_RES_CHANGE_FLUSH) && | |
197 | ctx->dst_queue_cnt >= ctx->dpb_count) | |
198 | return 1; | |
199 | if (ctx->state == MFCINST_RES_CHANGE_END && | |
200 | ctx->src_queue_cnt >= 1) | |
201 | return 1; | |
202 | mfc_debug(2, "ctx is not ready\n"); | |
203 | return 0; | |
204 | } | |
205 | ||
206 | static struct s5p_mfc_codec_ops decoder_codec_ops = { | |
207 | .pre_seq_start = NULL, | |
208 | .post_seq_start = NULL, | |
209 | .pre_frame_start = NULL, | |
210 | .post_frame_start = NULL, | |
211 | }; | |
212 | ||
213 | /* Query capabilities of the device */ | |
214 | static int vidioc_querycap(struct file *file, void *priv, | |
215 | struct v4l2_capability *cap) | |
216 | { | |
217 | struct s5p_mfc_dev *dev = video_drvdata(file); | |
218 | ||
219 | strncpy(cap->driver, dev->plat_dev->name, sizeof(cap->driver) - 1); | |
220 | strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1); | |
221 | cap->bus_info[0] = 0; | |
222 | cap->version = KERNEL_VERSION(1, 0, 0); | |
f0476a83 SN |
223 | /* |
224 | * This is only a mem-to-mem video device. The capture and output | |
225 | * device capability flags are left only for backward compatibility | |
226 | * and are scheduled for removal. | |
227 | */ | |
228 | cap->capabilities = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING | | |
229 | V4L2_CAP_VIDEO_CAPTURE_MPLANE | | |
230 | V4L2_CAP_VIDEO_OUTPUT_MPLANE; | |
af935746 KD |
231 | return 0; |
232 | } | |
233 | ||
234 | /* Enumerate format */ | |
235 | static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool mplane, bool out) | |
236 | { | |
237 | struct s5p_mfc_fmt *fmt; | |
238 | int i, j = 0; | |
239 | ||
240 | for (i = 0; i < ARRAY_SIZE(formats); ++i) { | |
241 | if (mplane && formats[i].num_planes == 1) | |
242 | continue; | |
243 | else if (!mplane && formats[i].num_planes > 1) | |
244 | continue; | |
245 | if (out && formats[i].type != MFC_FMT_DEC) | |
246 | continue; | |
247 | else if (!out && formats[i].type != MFC_FMT_RAW) | |
248 | continue; | |
249 | ||
250 | if (j == f->index) | |
251 | break; | |
252 | ++j; | |
253 | } | |
254 | if (i == ARRAY_SIZE(formats)) | |
255 | return -EINVAL; | |
256 | fmt = &formats[i]; | |
257 | strlcpy(f->description, fmt->name, sizeof(f->description)); | |
258 | f->pixelformat = fmt->fourcc; | |
259 | return 0; | |
260 | } | |
261 | ||
262 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv, | |
263 | struct v4l2_fmtdesc *f) | |
264 | { | |
265 | return vidioc_enum_fmt(f, false, false); | |
266 | } | |
267 | ||
268 | static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv, | |
269 | struct v4l2_fmtdesc *f) | |
270 | { | |
271 | return vidioc_enum_fmt(f, true, false); | |
272 | } | |
273 | ||
274 | static int vidioc_enum_fmt_vid_out(struct file *file, void *prov, | |
275 | struct v4l2_fmtdesc *f) | |
276 | { | |
277 | return vidioc_enum_fmt(f, false, true); | |
278 | } | |
279 | ||
280 | static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov, | |
281 | struct v4l2_fmtdesc *f) | |
282 | { | |
283 | return vidioc_enum_fmt(f, true, true); | |
284 | } | |
285 | ||
286 | /* Get format */ | |
287 | static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) | |
288 | { | |
289 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | |
290 | struct v4l2_pix_format_mplane *pix_mp; | |
291 | ||
292 | mfc_debug_enter(); | |
293 | pix_mp = &f->fmt.pix_mp; | |
294 | if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && | |
295 | (ctx->state == MFCINST_GOT_INST || ctx->state == | |
296 | MFCINST_RES_CHANGE_END)) { | |
297 | /* If the MFC is parsing the header, | |
298 | * so wait until it is finished */ | |
299 | s5p_mfc_clean_ctx_int_flags(ctx); | |
300 | s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_SEQ_DONE_RET, | |
301 | 0); | |
302 | } | |
303 | if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && | |
304 | ctx->state >= MFCINST_HEAD_PARSED && | |
305 | ctx->state < MFCINST_ABORT) { | |
306 | /* This is run on CAPTURE (decode output) */ | |
307 | /* Width and height are set to the dimensions | |
308 | of the movie, the buffer is bigger and | |
309 | further processing stages should crop to this | |
310 | rectangle. */ | |
311 | pix_mp->width = ctx->buf_width; | |
312 | pix_mp->height = ctx->buf_height; | |
313 | pix_mp->field = V4L2_FIELD_NONE; | |
314 | pix_mp->num_planes = 2; | |
315 | /* Set pixelformat to the format in which MFC | |
316 | outputs the decoded frame */ | |
317 | pix_mp->pixelformat = V4L2_PIX_FMT_NV12MT; | |
318 | pix_mp->plane_fmt[0].bytesperline = ctx->buf_width; | |
319 | pix_mp->plane_fmt[0].sizeimage = ctx->luma_size; | |
320 | pix_mp->plane_fmt[1].bytesperline = ctx->buf_width; | |
321 | pix_mp->plane_fmt[1].sizeimage = ctx->chroma_size; | |
322 | } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | |
323 | /* This is run on OUTPUT | |
324 | The buffer contains compressed image | |
325 | so width and height have no meaning */ | |
326 | pix_mp->width = 0; | |
327 | pix_mp->height = 0; | |
328 | pix_mp->field = V4L2_FIELD_NONE; | |
329 | pix_mp->plane_fmt[0].bytesperline = ctx->dec_src_buf_size; | |
330 | pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size; | |
331 | pix_mp->pixelformat = ctx->src_fmt->fourcc; | |
332 | pix_mp->num_planes = ctx->src_fmt->num_planes; | |
333 | } else { | |
334 | mfc_err("Format could not be read\n"); | |
335 | mfc_debug(2, "%s-- with error\n", __func__); | |
336 | return -EINVAL; | |
337 | } | |
338 | mfc_debug_leave(); | |
339 | return 0; | |
340 | } | |
341 | ||
342 | /* Try format */ | |
343 | static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) | |
344 | { | |
345 | struct s5p_mfc_fmt *fmt; | |
346 | ||
347 | if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | |
348 | mfc_err("This node supports decoding only\n"); | |
349 | return -EINVAL; | |
350 | } | |
351 | fmt = find_format(f, MFC_FMT_DEC); | |
352 | if (!fmt) { | |
353 | mfc_err("Unsupported format\n"); | |
354 | return -EINVAL; | |
355 | } | |
356 | if (fmt->type != MFC_FMT_DEC) { | |
357 | mfc_err("\n"); | |
358 | return -EINVAL; | |
359 | } | |
360 | return 0; | |
361 | } | |
362 | ||
363 | /* Set format */ | |
364 | static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) | |
365 | { | |
366 | struct s5p_mfc_dev *dev = video_drvdata(file); | |
367 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | |
368 | int ret = 0; | |
369 | struct s5p_mfc_fmt *fmt; | |
370 | struct v4l2_pix_format_mplane *pix_mp; | |
371 | ||
372 | mfc_debug_enter(); | |
373 | ret = vidioc_try_fmt(file, priv, f); | |
374 | pix_mp = &f->fmt.pix_mp; | |
375 | if (ret) | |
376 | return ret; | |
377 | if (ctx->vq_src.streaming || ctx->vq_dst.streaming) { | |
378 | v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__); | |
379 | ret = -EBUSY; | |
380 | goto out; | |
381 | } | |
382 | fmt = find_format(f, MFC_FMT_DEC); | |
383 | if (!fmt || fmt->codec_mode == S5P_FIMV_CODEC_NONE) { | |
384 | mfc_err("Unknown codec\n"); | |
385 | ret = -EINVAL; | |
386 | goto out; | |
387 | } | |
388 | if (fmt->type != MFC_FMT_DEC) { | |
389 | mfc_err("Wrong format selected, you should choose " | |
390 | "format for decoding\n"); | |
391 | ret = -EINVAL; | |
392 | goto out; | |
393 | } | |
394 | ctx->src_fmt = fmt; | |
395 | ctx->codec_mode = fmt->codec_mode; | |
396 | mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode); | |
397 | pix_mp->height = 0; | |
398 | pix_mp->width = 0; | |
399 | if (pix_mp->plane_fmt[0].sizeimage) | |
400 | ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage; | |
401 | else | |
402 | pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size = | |
403 | DEF_CPB_SIZE; | |
404 | pix_mp->plane_fmt[0].bytesperline = 0; | |
405 | ctx->state = MFCINST_INIT; | |
406 | out: | |
407 | mfc_debug_leave(); | |
408 | return ret; | |
409 | } | |
410 | ||
411 | /* Reqeust buffers */ | |
412 | static int vidioc_reqbufs(struct file *file, void *priv, | |
413 | struct v4l2_requestbuffers *reqbufs) | |
414 | { | |
415 | struct s5p_mfc_dev *dev = video_drvdata(file); | |
416 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | |
417 | int ret = 0; | |
418 | unsigned long flags; | |
419 | ||
420 | if (reqbufs->memory != V4L2_MEMORY_MMAP) { | |
421 | mfc_err("Only V4L2_MEMORY_MAP is supported\n"); | |
422 | return -EINVAL; | |
423 | } | |
424 | if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | |
425 | /* Can only request buffers after an instance has been opened.*/ | |
426 | if (ctx->state == MFCINST_INIT) { | |
427 | ctx->src_bufs_cnt = 0; | |
428 | if (reqbufs->count == 0) { | |
429 | mfc_debug(2, "Freeing buffers\n"); | |
430 | s5p_mfc_clock_on(); | |
431 | ret = vb2_reqbufs(&ctx->vq_src, reqbufs); | |
432 | s5p_mfc_clock_off(); | |
433 | return ret; | |
434 | } | |
435 | /* Decoding */ | |
436 | if (ctx->output_state != QUEUE_FREE) { | |
437 | mfc_err("Bufs have already been requested\n"); | |
438 | return -EINVAL; | |
439 | } | |
440 | s5p_mfc_clock_on(); | |
441 | ret = vb2_reqbufs(&ctx->vq_src, reqbufs); | |
442 | s5p_mfc_clock_off(); | |
443 | if (ret) { | |
444 | mfc_err("vb2_reqbufs on output failed\n"); | |
445 | return ret; | |
446 | } | |
447 | mfc_debug(2, "vb2_reqbufs: %d\n", ret); | |
448 | ctx->output_state = QUEUE_BUFS_REQUESTED; | |
449 | } | |
450 | } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | |
451 | ctx->dst_bufs_cnt = 0; | |
452 | if (reqbufs->count == 0) { | |
453 | mfc_debug(2, "Freeing buffers\n"); | |
454 | s5p_mfc_clock_on(); | |
455 | ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); | |
456 | s5p_mfc_clock_off(); | |
457 | return ret; | |
458 | } | |
459 | if (ctx->capture_state != QUEUE_FREE) { | |
460 | mfc_err("Bufs have already been requested\n"); | |
461 | return -EINVAL; | |
462 | } | |
463 | ctx->capture_state = QUEUE_BUFS_REQUESTED; | |
464 | s5p_mfc_clock_on(); | |
465 | ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); | |
466 | s5p_mfc_clock_off(); | |
467 | if (ret) { | |
468 | mfc_err("vb2_reqbufs on capture failed\n"); | |
469 | return ret; | |
470 | } | |
471 | if (reqbufs->count < ctx->dpb_count) { | |
472 | mfc_err("Not enough buffers allocated\n"); | |
473 | reqbufs->count = 0; | |
474 | s5p_mfc_clock_on(); | |
475 | ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); | |
476 | s5p_mfc_clock_off(); | |
477 | return -ENOMEM; | |
478 | } | |
479 | ctx->total_dpb_count = reqbufs->count; | |
480 | ret = s5p_mfc_alloc_codec_buffers(ctx); | |
481 | if (ret) { | |
482 | mfc_err("Failed to allocate decoding buffers\n"); | |
483 | reqbufs->count = 0; | |
484 | s5p_mfc_clock_on(); | |
485 | ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); | |
486 | s5p_mfc_clock_off(); | |
487 | return -ENOMEM; | |
488 | } | |
489 | if (ctx->dst_bufs_cnt == ctx->total_dpb_count) { | |
490 | ctx->capture_state = QUEUE_BUFS_MMAPED; | |
491 | } else { | |
492 | mfc_err("Not all buffers passed to buf_init\n"); | |
493 | reqbufs->count = 0; | |
494 | s5p_mfc_clock_on(); | |
495 | ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); | |
496 | s5p_mfc_release_codec_buffers(ctx); | |
497 | s5p_mfc_clock_off(); | |
498 | return -ENOMEM; | |
499 | } | |
500 | if (s5p_mfc_ctx_ready(ctx)) { | |
501 | spin_lock_irqsave(&dev->condlock, flags); | |
502 | set_bit(ctx->num, &dev->ctx_work_bits); | |
503 | spin_unlock_irqrestore(&dev->condlock, flags); | |
504 | } | |
505 | s5p_mfc_try_run(dev); | |
506 | s5p_mfc_wait_for_done_ctx(ctx, | |
507 | S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET, 0); | |
508 | } | |
509 | return ret; | |
510 | } | |
511 | ||
512 | /* Query buffer */ | |
513 | static int vidioc_querybuf(struct file *file, void *priv, | |
514 | struct v4l2_buffer *buf) | |
515 | { | |
516 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | |
517 | int ret; | |
518 | int i; | |
519 | ||
520 | if (buf->memory != V4L2_MEMORY_MMAP) { | |
521 | mfc_err("Only mmaped buffers can be used\n"); | |
522 | return -EINVAL; | |
523 | } | |
524 | mfc_debug(2, "State: %d, buf->type: %d\n", ctx->state, buf->type); | |
525 | if (ctx->state == MFCINST_INIT && | |
526 | buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | |
527 | ret = vb2_querybuf(&ctx->vq_src, buf); | |
528 | } else if (ctx->state == MFCINST_RUNNING && | |
529 | buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | |
530 | ret = vb2_querybuf(&ctx->vq_dst, buf); | |
531 | for (i = 0; i < buf->length; i++) | |
532 | buf->m.planes[i].m.mem_offset += DST_QUEUE_OFF_BASE; | |
533 | } else { | |
534 | mfc_err("vidioc_querybuf called in an inappropriate state\n"); | |
535 | ret = -EINVAL; | |
536 | } | |
537 | mfc_debug_leave(); | |
538 | return ret; | |
539 | } | |
540 | ||
541 | /* Queue a buffer */ | |
542 | static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | |
543 | { | |
544 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | |
545 | ||
546 | if (ctx->state == MFCINST_ERROR) { | |
547 | mfc_err("Call on QBUF after unrecoverable error\n"); | |
548 | return -EIO; | |
549 | } | |
550 | if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | |
551 | return vb2_qbuf(&ctx->vq_src, buf); | |
552 | else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | |
553 | return vb2_qbuf(&ctx->vq_dst, buf); | |
554 | return -EINVAL; | |
555 | } | |
556 | ||
557 | /* Dequeue a buffer */ | |
558 | static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | |
559 | { | |
560 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | |
561 | ||
562 | if (ctx->state == MFCINST_ERROR) { | |
563 | mfc_err("Call on DQBUF after unrecoverable error\n"); | |
564 | return -EIO; | |
565 | } | |
566 | if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | |
567 | return vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK); | |
568 | else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | |
569 | return vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK); | |
570 | return -EINVAL; | |
571 | } | |
572 | ||
573 | /* Stream on */ | |
574 | static int vidioc_streamon(struct file *file, void *priv, | |
575 | enum v4l2_buf_type type) | |
576 | { | |
577 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | |
578 | struct s5p_mfc_dev *dev = ctx->dev; | |
579 | unsigned long flags; | |
580 | int ret = -EINVAL; | |
581 | ||
582 | mfc_debug_enter(); | |
583 | if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | |
584 | ||
585 | if (ctx->state == MFCINST_INIT) { | |
586 | ctx->dst_bufs_cnt = 0; | |
587 | ctx->src_bufs_cnt = 0; | |
588 | ctx->capture_state = QUEUE_FREE; | |
589 | ctx->output_state = QUEUE_FREE; | |
590 | s5p_mfc_alloc_instance_buffer(ctx); | |
591 | s5p_mfc_alloc_dec_temp_buffers(ctx); | |
592 | spin_lock_irqsave(&dev->condlock, flags); | |
593 | set_bit(ctx->num, &dev->ctx_work_bits); | |
594 | spin_unlock_irqrestore(&dev->condlock, flags); | |
595 | s5p_mfc_clean_ctx_int_flags(ctx); | |
596 | s5p_mfc_try_run(dev); | |
597 | ||
598 | if (s5p_mfc_wait_for_done_ctx(ctx, | |
599 | S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET, 0)) { | |
600 | /* Error or timeout */ | |
601 | mfc_err("Error getting instance from hardware\n"); | |
602 | s5p_mfc_release_instance_buffer(ctx); | |
603 | s5p_mfc_release_dec_desc_buffer(ctx); | |
604 | return -EIO; | |
605 | } | |
606 | mfc_debug(2, "Got instance number: %d\n", ctx->inst_no); | |
607 | } | |
608 | ret = vb2_streamon(&ctx->vq_src, type); | |
609 | } | |
610 | else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | |
611 | ret = vb2_streamon(&ctx->vq_dst, type); | |
612 | mfc_debug_leave(); | |
613 | return ret; | |
614 | } | |
615 | ||
616 | /* Stream off, which equals to a pause */ | |
617 | static int vidioc_streamoff(struct file *file, void *priv, | |
618 | enum v4l2_buf_type type) | |
619 | { | |
620 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | |
621 | ||
622 | if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | |
623 | return vb2_streamoff(&ctx->vq_src, type); | |
624 | else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | |
625 | return vb2_streamoff(&ctx->vq_dst, type); | |
626 | return -EINVAL; | |
627 | } | |
628 | ||
629 | /* Set controls - v4l2 control framework */ | |
630 | static int s5p_mfc_dec_s_ctrl(struct v4l2_ctrl *ctrl) | |
631 | { | |
632 | struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl); | |
633 | ||
634 | switch (ctrl->id) { | |
635 | case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY: | |
f60935c1 | 636 | ctx->display_delay = ctrl->val; |
af935746 KD |
637 | break; |
638 | case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE: | |
639 | ctx->display_delay_enable = ctrl->val; | |
640 | break; | |
641 | case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: | |
f60935c1 | 642 | ctx->loop_filter_mpeg4 = ctrl->val; |
af935746 KD |
643 | break; |
644 | case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE: | |
645 | ctx->slice_interface = ctrl->val; | |
646 | break; | |
647 | default: | |
648 | mfc_err("Invalid control 0x%08x\n", ctrl->id); | |
649 | return -EINVAL; | |
650 | } | |
651 | return 0; | |
652 | } | |
653 | ||
654 | static int s5p_mfc_dec_g_v_ctrl(struct v4l2_ctrl *ctrl) | |
655 | { | |
656 | struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl); | |
657 | struct s5p_mfc_dev *dev = ctx->dev; | |
658 | ||
659 | switch (ctrl->id) { | |
660 | case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: | |
661 | if (ctx->state >= MFCINST_HEAD_PARSED && | |
662 | ctx->state < MFCINST_ABORT) { | |
663 | ctrl->val = ctx->dpb_count; | |
664 | break; | |
665 | } else if (ctx->state != MFCINST_INIT) { | |
666 | v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n"); | |
667 | return -EINVAL; | |
668 | } | |
669 | /* Should wait for the header to be parsed */ | |
670 | s5p_mfc_clean_ctx_int_flags(ctx); | |
671 | s5p_mfc_wait_for_done_ctx(ctx, | |
672 | S5P_FIMV_R2H_CMD_SEQ_DONE_RET, 0); | |
673 | if (ctx->state >= MFCINST_HEAD_PARSED && | |
674 | ctx->state < MFCINST_ABORT) { | |
675 | ctrl->val = ctx->dpb_count; | |
676 | } else { | |
677 | v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n"); | |
678 | return -EINVAL; | |
679 | } | |
680 | break; | |
681 | } | |
682 | return 0; | |
683 | } | |
684 | ||
685 | ||
686 | static const struct v4l2_ctrl_ops s5p_mfc_dec_ctrl_ops = { | |
687 | .s_ctrl = s5p_mfc_dec_s_ctrl, | |
688 | .g_volatile_ctrl = s5p_mfc_dec_g_v_ctrl, | |
689 | }; | |
690 | ||
691 | /* Get cropping information */ | |
692 | static int vidioc_g_crop(struct file *file, void *priv, | |
693 | struct v4l2_crop *cr) | |
694 | { | |
695 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | |
696 | u32 left, right, top, bottom; | |
697 | ||
698 | if (ctx->state != MFCINST_HEAD_PARSED && | |
699 | ctx->state != MFCINST_RUNNING && ctx->state != MFCINST_FINISHING | |
700 | && ctx->state != MFCINST_FINISHED) { | |
701 | mfc_err("Cannont set crop\n"); | |
702 | return -EINVAL; | |
703 | } | |
704 | if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264) { | |
705 | left = s5p_mfc_read_shm(ctx, CROP_INFO_H); | |
706 | right = left >> S5P_FIMV_SHARED_CROP_RIGHT_SHIFT; | |
707 | left = left & S5P_FIMV_SHARED_CROP_LEFT_MASK; | |
708 | top = s5p_mfc_read_shm(ctx, CROP_INFO_V); | |
709 | bottom = top >> S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT; | |
710 | top = top & S5P_FIMV_SHARED_CROP_TOP_MASK; | |
711 | cr->c.left = left; | |
712 | cr->c.top = top; | |
713 | cr->c.width = ctx->img_width - left - right; | |
714 | cr->c.height = ctx->img_height - top - bottom; | |
715 | mfc_debug(2, "Cropping info [h264]: l=%d t=%d " | |
716 | "w=%d h=%d (r=%d b=%d fw=%d fh=%d\n", left, top, | |
717 | cr->c.width, cr->c.height, right, bottom, | |
718 | ctx->buf_width, ctx->buf_height); | |
719 | } else { | |
720 | cr->c.left = 0; | |
721 | cr->c.top = 0; | |
722 | cr->c.width = ctx->img_width; | |
723 | cr->c.height = ctx->img_height; | |
724 | mfc_debug(2, "Cropping info: w=%d h=%d fw=%d " | |
725 | "fh=%d\n", cr->c.width, cr->c.height, ctx->buf_width, | |
726 | ctx->buf_height); | |
727 | } | |
728 | return 0; | |
729 | } | |
730 | ||
731 | /* v4l2_ioctl_ops */ | |
732 | static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = { | |
733 | .vidioc_querycap = vidioc_querycap, | |
734 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, | |
735 | .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane, | |
736 | .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, | |
737 | .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane, | |
738 | .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt, | |
739 | .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt, | |
740 | .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt, | |
741 | .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt, | |
742 | .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt, | |
743 | .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt, | |
744 | .vidioc_reqbufs = vidioc_reqbufs, | |
745 | .vidioc_querybuf = vidioc_querybuf, | |
746 | .vidioc_qbuf = vidioc_qbuf, | |
747 | .vidioc_dqbuf = vidioc_dqbuf, | |
748 | .vidioc_streamon = vidioc_streamon, | |
749 | .vidioc_streamoff = vidioc_streamoff, | |
750 | .vidioc_g_crop = vidioc_g_crop, | |
751 | }; | |
752 | ||
fc714e70 GL |
753 | static int s5p_mfc_queue_setup(struct vb2_queue *vq, |
754 | const struct v4l2_format *fmt, unsigned int *buf_count, | |
755 | unsigned int *plane_count, unsigned int psize[], | |
756 | void *allocators[]) | |
af935746 KD |
757 | { |
758 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); | |
759 | ||
760 | /* Video output for decoding (source) | |
761 | * this can be set after getting an instance */ | |
762 | if (ctx->state == MFCINST_INIT && | |
763 | vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | |
764 | /* A single plane is required for input */ | |
765 | *plane_count = 1; | |
766 | if (*buf_count < 1) | |
767 | *buf_count = 1; | |
768 | if (*buf_count > MFC_MAX_BUFFERS) | |
769 | *buf_count = MFC_MAX_BUFFERS; | |
770 | /* Video capture for decoding (destination) | |
771 | * this can be set after the header was parsed */ | |
772 | } else if (ctx->state == MFCINST_HEAD_PARSED && | |
773 | vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | |
774 | /* Output plane count is 2 - one for Y and one for CbCr */ | |
775 | *plane_count = 2; | |
776 | /* Setup buffer count */ | |
777 | if (*buf_count < ctx->dpb_count) | |
778 | *buf_count = ctx->dpb_count; | |
779 | if (*buf_count > ctx->dpb_count + MFC_MAX_EXTRA_DPB) | |
780 | *buf_count = ctx->dpb_count + MFC_MAX_EXTRA_DPB; | |
781 | if (*buf_count > MFC_MAX_BUFFERS) | |
782 | *buf_count = MFC_MAX_BUFFERS; | |
783 | } else { | |
784 | mfc_err("State seems invalid. State = %d, vq->type = %d\n", | |
785 | ctx->state, vq->type); | |
786 | return -EINVAL; | |
787 | } | |
788 | mfc_debug(2, "Buffer count=%d, plane count=%d\n", | |
789 | *buf_count, *plane_count); | |
790 | if (ctx->state == MFCINST_HEAD_PARSED && | |
791 | vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | |
792 | psize[0] = ctx->luma_size; | |
793 | psize[1] = ctx->chroma_size; | |
794 | allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; | |
795 | allocators[1] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; | |
796 | } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && | |
797 | ctx->state == MFCINST_INIT) { | |
798 | psize[0] = ctx->dec_src_buf_size; | |
799 | allocators[0] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; | |
800 | } else { | |
801 | mfc_err("This video node is dedicated to decoding. Decoding not initalised\n"); | |
802 | return -EINVAL; | |
803 | } | |
804 | return 0; | |
805 | } | |
806 | ||
807 | static void s5p_mfc_unlock(struct vb2_queue *q) | |
808 | { | |
809 | struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); | |
810 | struct s5p_mfc_dev *dev = ctx->dev; | |
811 | ||
812 | mutex_unlock(&dev->mfc_mutex); | |
813 | } | |
814 | ||
815 | static void s5p_mfc_lock(struct vb2_queue *q) | |
816 | { | |
817 | struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); | |
818 | struct s5p_mfc_dev *dev = ctx->dev; | |
819 | ||
820 | mutex_lock(&dev->mfc_mutex); | |
821 | } | |
822 | ||
823 | static int s5p_mfc_buf_init(struct vb2_buffer *vb) | |
824 | { | |
825 | struct vb2_queue *vq = vb->vb2_queue; | |
826 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); | |
827 | unsigned int i; | |
828 | ||
829 | if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | |
830 | if (ctx->capture_state == QUEUE_BUFS_MMAPED) | |
831 | return 0; | |
832 | for (i = 0; i <= ctx->src_fmt->num_planes ; i++) { | |
833 | if (IS_ERR_OR_NULL(ERR_PTR( | |
ba7fcb0c | 834 | vb2_dma_contig_plane_dma_addr(vb, i)))) { |
af935746 KD |
835 | mfc_err("Plane mem not allocated\n"); |
836 | return -EINVAL; | |
837 | } | |
838 | } | |
839 | if (vb2_plane_size(vb, 0) < ctx->luma_size || | |
840 | vb2_plane_size(vb, 1) < ctx->chroma_size) { | |
841 | mfc_err("Plane buffer (CAPTURE) is too small\n"); | |
842 | return -EINVAL; | |
843 | } | |
844 | i = vb->v4l2_buf.index; | |
845 | ctx->dst_bufs[i].b = vb; | |
846 | ctx->dst_bufs[i].cookie.raw.luma = | |
ba7fcb0c | 847 | vb2_dma_contig_plane_dma_addr(vb, 0); |
af935746 | 848 | ctx->dst_bufs[i].cookie.raw.chroma = |
ba7fcb0c | 849 | vb2_dma_contig_plane_dma_addr(vb, 1); |
af935746 KD |
850 | ctx->dst_bufs_cnt++; |
851 | } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | |
852 | if (IS_ERR_OR_NULL(ERR_PTR( | |
ba7fcb0c | 853 | vb2_dma_contig_plane_dma_addr(vb, 0)))) { |
af935746 KD |
854 | mfc_err("Plane memory not allocated\n"); |
855 | return -EINVAL; | |
856 | } | |
857 | if (vb2_plane_size(vb, 0) < ctx->dec_src_buf_size) { | |
858 | mfc_err("Plane buffer (OUTPUT) is too small\n"); | |
859 | return -EINVAL; | |
860 | } | |
861 | ||
862 | i = vb->v4l2_buf.index; | |
863 | ctx->src_bufs[i].b = vb; | |
864 | ctx->src_bufs[i].cookie.stream = | |
ba7fcb0c | 865 | vb2_dma_contig_plane_dma_addr(vb, 0); |
af935746 KD |
866 | ctx->src_bufs_cnt++; |
867 | } else { | |
868 | mfc_err("s5p_mfc_buf_init: unknown queue type\n"); | |
869 | return -EINVAL; | |
870 | } | |
871 | return 0; | |
872 | } | |
873 | ||
bd323e28 | 874 | static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) |
af935746 KD |
875 | { |
876 | struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); | |
877 | struct s5p_mfc_dev *dev = ctx->dev; | |
878 | unsigned long flags; | |
879 | ||
880 | v4l2_ctrl_handler_setup(&ctx->ctrl_handler); | |
881 | if (ctx->state == MFCINST_FINISHING || | |
882 | ctx->state == MFCINST_FINISHED) | |
883 | ctx->state = MFCINST_RUNNING; | |
884 | /* If context is ready then dev = work->data;schedule it to run */ | |
885 | if (s5p_mfc_ctx_ready(ctx)) { | |
886 | spin_lock_irqsave(&dev->condlock, flags); | |
887 | set_bit(ctx->num, &dev->ctx_work_bits); | |
888 | spin_unlock_irqrestore(&dev->condlock, flags); | |
889 | } | |
890 | s5p_mfc_try_run(dev); | |
891 | return 0; | |
892 | } | |
893 | ||
894 | static int s5p_mfc_stop_streaming(struct vb2_queue *q) | |
895 | { | |
896 | unsigned long flags; | |
897 | struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); | |
898 | struct s5p_mfc_dev *dev = ctx->dev; | |
899 | int aborted = 0; | |
900 | ||
901 | if ((ctx->state == MFCINST_FINISHING || | |
902 | ctx->state == MFCINST_RUNNING) && | |
903 | dev->curr_ctx == ctx->num && dev->hw_lock) { | |
904 | ctx->state = MFCINST_ABORT; | |
905 | s5p_mfc_wait_for_done_ctx(ctx, | |
906 | S5P_FIMV_R2H_CMD_FRAME_DONE_RET, 0); | |
907 | aborted = 1; | |
908 | } | |
909 | spin_lock_irqsave(&dev->irqlock, flags); | |
910 | if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | |
911 | s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); | |
912 | INIT_LIST_HEAD(&ctx->dst_queue); | |
913 | ctx->dst_queue_cnt = 0; | |
914 | ctx->dpb_flush_flag = 1; | |
915 | ctx->dec_dst_flag = 0; | |
916 | } | |
917 | if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | |
918 | s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); | |
919 | INIT_LIST_HEAD(&ctx->src_queue); | |
920 | ctx->src_queue_cnt = 0; | |
921 | } | |
922 | if (aborted) | |
923 | ctx->state = MFCINST_RUNNING; | |
924 | spin_unlock_irqrestore(&dev->irqlock, flags); | |
925 | return 0; | |
926 | } | |
927 | ||
928 | ||
929 | static void s5p_mfc_buf_queue(struct vb2_buffer *vb) | |
930 | { | |
931 | struct vb2_queue *vq = vb->vb2_queue; | |
932 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); | |
933 | struct s5p_mfc_dev *dev = ctx->dev; | |
934 | unsigned long flags; | |
935 | struct s5p_mfc_buf *mfc_buf; | |
936 | ||
937 | if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | |
938 | mfc_buf = &ctx->src_bufs[vb->v4l2_buf.index]; | |
939 | mfc_buf->used = 0; | |
940 | spin_lock_irqsave(&dev->irqlock, flags); | |
941 | list_add_tail(&mfc_buf->list, &ctx->src_queue); | |
942 | ctx->src_queue_cnt++; | |
943 | spin_unlock_irqrestore(&dev->irqlock, flags); | |
944 | } else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | |
945 | mfc_buf = &ctx->dst_bufs[vb->v4l2_buf.index]; | |
946 | mfc_buf->used = 0; | |
947 | /* Mark destination as available for use by MFC */ | |
948 | spin_lock_irqsave(&dev->irqlock, flags); | |
949 | set_bit(vb->v4l2_buf.index, &ctx->dec_dst_flag); | |
950 | list_add_tail(&mfc_buf->list, &ctx->dst_queue); | |
951 | ctx->dst_queue_cnt++; | |
952 | spin_unlock_irqrestore(&dev->irqlock, flags); | |
953 | } else { | |
954 | mfc_err("Unsupported buffer type (%d)\n", vq->type); | |
955 | } | |
956 | if (s5p_mfc_ctx_ready(ctx)) { | |
957 | spin_lock_irqsave(&dev->condlock, flags); | |
958 | set_bit(ctx->num, &dev->ctx_work_bits); | |
959 | spin_unlock_irqrestore(&dev->condlock, flags); | |
960 | } | |
961 | s5p_mfc_try_run(dev); | |
962 | } | |
963 | ||
964 | static struct vb2_ops s5p_mfc_dec_qops = { | |
965 | .queue_setup = s5p_mfc_queue_setup, | |
966 | .wait_prepare = s5p_mfc_unlock, | |
967 | .wait_finish = s5p_mfc_lock, | |
968 | .buf_init = s5p_mfc_buf_init, | |
969 | .start_streaming = s5p_mfc_start_streaming, | |
970 | .stop_streaming = s5p_mfc_stop_streaming, | |
971 | .buf_queue = s5p_mfc_buf_queue, | |
972 | }; | |
973 | ||
974 | struct s5p_mfc_codec_ops *get_dec_codec_ops(void) | |
975 | { | |
976 | return &decoder_codec_ops; | |
977 | } | |
978 | ||
979 | struct vb2_ops *get_dec_queue_ops(void) | |
980 | { | |
981 | return &s5p_mfc_dec_qops; | |
982 | } | |
983 | ||
984 | const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void) | |
985 | { | |
986 | return &s5p_mfc_dec_ioctl_ops; | |
987 | } | |
988 | ||
989 | #define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2CLASS(x) == V4L2_CTRL_CLASS_MPEG) \ | |
990 | && V4L2_CTRL_DRIVER_PRIV(x)) | |
991 | ||
992 | int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx) | |
993 | { | |
994 | struct v4l2_ctrl_config cfg; | |
995 | int i; | |
996 | ||
997 | v4l2_ctrl_handler_init(&ctx->ctrl_handler, NUM_CTRLS); | |
998 | if (ctx->ctrl_handler.error) { | |
999 | mfc_err("v4l2_ctrl_handler_init failed\n"); | |
1000 | return ctx->ctrl_handler.error; | |
1001 | } | |
1002 | ||
1003 | for (i = 0; i < NUM_CTRLS; i++) { | |
1004 | if (IS_MFC51_PRIV(controls[i].id)) { | |
a65c3262 | 1005 | memset(&cfg, 0, sizeof(struct v4l2_ctrl_config)); |
af935746 KD |
1006 | cfg.ops = &s5p_mfc_dec_ctrl_ops; |
1007 | cfg.id = controls[i].id; | |
1008 | cfg.min = controls[i].minimum; | |
1009 | cfg.max = controls[i].maximum; | |
1010 | cfg.def = controls[i].default_value; | |
1011 | cfg.name = controls[i].name; | |
1012 | cfg.type = controls[i].type; | |
1013 | ||
1014 | cfg.step = controls[i].step; | |
1015 | cfg.menu_skip_mask = 0; | |
1016 | ||
1017 | ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->ctrl_handler, | |
1018 | &cfg, NULL); | |
1019 | } else { | |
1020 | ctx->ctrls[i] = v4l2_ctrl_new_std(&ctx->ctrl_handler, | |
1021 | &s5p_mfc_dec_ctrl_ops, | |
1022 | controls[i].id, controls[i].minimum, | |
1023 | controls[i].maximum, controls[i].step, | |
1024 | controls[i].default_value); | |
1025 | } | |
1026 | if (ctx->ctrl_handler.error) { | |
1027 | mfc_err("Adding control (%d) failed\n", i); | |
1028 | return ctx->ctrl_handler.error; | |
1029 | } | |
1030 | if (controls[i].is_volatile && ctx->ctrls[i]) | |
88365105 | 1031 | ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE; |
af935746 KD |
1032 | } |
1033 | return 0; | |
1034 | } | |
1035 | ||
1036 | void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx) | |
1037 | { | |
1038 | int i; | |
1039 | ||
1040 | v4l2_ctrl_handler_free(&ctx->ctrl_handler); | |
1041 | for (i = 0; i < NUM_CTRLS; i++) | |
1042 | ctx->ctrls[i] = NULL; | |
1043 | } | |
1044 |