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); | |
43defb11 KD |
223 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE | |
224 | V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_STREAMING; | |
af935746 KD |
225 | return 0; |
226 | } | |
227 | ||
228 | /* Enumerate format */ | |
229 | static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool mplane, bool out) | |
230 | { | |
231 | struct s5p_mfc_fmt *fmt; | |
232 | int i, j = 0; | |
233 | ||
234 | for (i = 0; i < ARRAY_SIZE(formats); ++i) { | |
235 | if (mplane && formats[i].num_planes == 1) | |
236 | continue; | |
237 | else if (!mplane && formats[i].num_planes > 1) | |
238 | continue; | |
239 | if (out && formats[i].type != MFC_FMT_DEC) | |
240 | continue; | |
241 | else if (!out && formats[i].type != MFC_FMT_RAW) | |
242 | continue; | |
243 | ||
244 | if (j == f->index) | |
245 | break; | |
246 | ++j; | |
247 | } | |
248 | if (i == ARRAY_SIZE(formats)) | |
249 | return -EINVAL; | |
250 | fmt = &formats[i]; | |
251 | strlcpy(f->description, fmt->name, sizeof(f->description)); | |
252 | f->pixelformat = fmt->fourcc; | |
253 | return 0; | |
254 | } | |
255 | ||
256 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv, | |
257 | struct v4l2_fmtdesc *f) | |
258 | { | |
259 | return vidioc_enum_fmt(f, false, false); | |
260 | } | |
261 | ||
262 | static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv, | |
263 | struct v4l2_fmtdesc *f) | |
264 | { | |
265 | return vidioc_enum_fmt(f, true, false); | |
266 | } | |
267 | ||
268 | static int vidioc_enum_fmt_vid_out(struct file *file, void *prov, | |
269 | struct v4l2_fmtdesc *f) | |
270 | { | |
271 | return vidioc_enum_fmt(f, false, true); | |
272 | } | |
273 | ||
274 | static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov, | |
275 | struct v4l2_fmtdesc *f) | |
276 | { | |
277 | return vidioc_enum_fmt(f, true, true); | |
278 | } | |
279 | ||
280 | /* Get format */ | |
281 | static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) | |
282 | { | |
283 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | |
284 | struct v4l2_pix_format_mplane *pix_mp; | |
285 | ||
286 | mfc_debug_enter(); | |
287 | pix_mp = &f->fmt.pix_mp; | |
288 | if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && | |
289 | (ctx->state == MFCINST_GOT_INST || ctx->state == | |
290 | MFCINST_RES_CHANGE_END)) { | |
291 | /* If the MFC is parsing the header, | |
292 | * so wait until it is finished */ | |
293 | s5p_mfc_clean_ctx_int_flags(ctx); | |
294 | s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_SEQ_DONE_RET, | |
295 | 0); | |
296 | } | |
297 | if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && | |
298 | ctx->state >= MFCINST_HEAD_PARSED && | |
299 | ctx->state < MFCINST_ABORT) { | |
300 | /* This is run on CAPTURE (decode output) */ | |
301 | /* Width and height are set to the dimensions | |
302 | of the movie, the buffer is bigger and | |
303 | further processing stages should crop to this | |
304 | rectangle. */ | |
305 | pix_mp->width = ctx->buf_width; | |
306 | pix_mp->height = ctx->buf_height; | |
307 | pix_mp->field = V4L2_FIELD_NONE; | |
308 | pix_mp->num_planes = 2; | |
309 | /* Set pixelformat to the format in which MFC | |
310 | outputs the decoded frame */ | |
311 | pix_mp->pixelformat = V4L2_PIX_FMT_NV12MT; | |
312 | pix_mp->plane_fmt[0].bytesperline = ctx->buf_width; | |
313 | pix_mp->plane_fmt[0].sizeimage = ctx->luma_size; | |
314 | pix_mp->plane_fmt[1].bytesperline = ctx->buf_width; | |
315 | pix_mp->plane_fmt[1].sizeimage = ctx->chroma_size; | |
316 | } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | |
317 | /* This is run on OUTPUT | |
318 | The buffer contains compressed image | |
319 | so width and height have no meaning */ | |
320 | pix_mp->width = 0; | |
321 | pix_mp->height = 0; | |
322 | pix_mp->field = V4L2_FIELD_NONE; | |
323 | pix_mp->plane_fmt[0].bytesperline = ctx->dec_src_buf_size; | |
324 | pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size; | |
325 | pix_mp->pixelformat = ctx->src_fmt->fourcc; | |
326 | pix_mp->num_planes = ctx->src_fmt->num_planes; | |
327 | } else { | |
328 | mfc_err("Format could not be read\n"); | |
329 | mfc_debug(2, "%s-- with error\n", __func__); | |
330 | return -EINVAL; | |
331 | } | |
332 | mfc_debug_leave(); | |
333 | return 0; | |
334 | } | |
335 | ||
336 | /* Try format */ | |
337 | static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) | |
338 | { | |
339 | struct s5p_mfc_fmt *fmt; | |
340 | ||
341 | if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | |
342 | mfc_err("This node supports decoding only\n"); | |
343 | return -EINVAL; | |
344 | } | |
345 | fmt = find_format(f, MFC_FMT_DEC); | |
346 | if (!fmt) { | |
347 | mfc_err("Unsupported format\n"); | |
348 | return -EINVAL; | |
349 | } | |
350 | if (fmt->type != MFC_FMT_DEC) { | |
351 | mfc_err("\n"); | |
352 | return -EINVAL; | |
353 | } | |
354 | return 0; | |
355 | } | |
356 | ||
357 | /* Set format */ | |
358 | static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) | |
359 | { | |
360 | struct s5p_mfc_dev *dev = video_drvdata(file); | |
361 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | |
362 | int ret = 0; | |
363 | struct s5p_mfc_fmt *fmt; | |
364 | struct v4l2_pix_format_mplane *pix_mp; | |
365 | ||
366 | mfc_debug_enter(); | |
367 | ret = vidioc_try_fmt(file, priv, f); | |
368 | pix_mp = &f->fmt.pix_mp; | |
369 | if (ret) | |
370 | return ret; | |
371 | if (ctx->vq_src.streaming || ctx->vq_dst.streaming) { | |
372 | v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__); | |
373 | ret = -EBUSY; | |
374 | goto out; | |
375 | } | |
376 | fmt = find_format(f, MFC_FMT_DEC); | |
377 | if (!fmt || fmt->codec_mode == S5P_FIMV_CODEC_NONE) { | |
378 | mfc_err("Unknown codec\n"); | |
379 | ret = -EINVAL; | |
380 | goto out; | |
381 | } | |
382 | if (fmt->type != MFC_FMT_DEC) { | |
383 | mfc_err("Wrong format selected, you should choose " | |
384 | "format for decoding\n"); | |
385 | ret = -EINVAL; | |
386 | goto out; | |
387 | } | |
388 | ctx->src_fmt = fmt; | |
389 | ctx->codec_mode = fmt->codec_mode; | |
390 | mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode); | |
391 | pix_mp->height = 0; | |
392 | pix_mp->width = 0; | |
393 | if (pix_mp->plane_fmt[0].sizeimage) | |
394 | ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage; | |
395 | else | |
396 | pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size = | |
397 | DEF_CPB_SIZE; | |
398 | pix_mp->plane_fmt[0].bytesperline = 0; | |
399 | ctx->state = MFCINST_INIT; | |
400 | out: | |
401 | mfc_debug_leave(); | |
402 | return ret; | |
403 | } | |
404 | ||
405 | /* Reqeust buffers */ | |
406 | static int vidioc_reqbufs(struct file *file, void *priv, | |
407 | struct v4l2_requestbuffers *reqbufs) | |
408 | { | |
409 | struct s5p_mfc_dev *dev = video_drvdata(file); | |
410 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | |
411 | int ret = 0; | |
412 | unsigned long flags; | |
413 | ||
414 | if (reqbufs->memory != V4L2_MEMORY_MMAP) { | |
415 | mfc_err("Only V4L2_MEMORY_MAP is supported\n"); | |
416 | return -EINVAL; | |
417 | } | |
418 | if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | |
419 | /* Can only request buffers after an instance has been opened.*/ | |
420 | if (ctx->state == MFCINST_INIT) { | |
421 | ctx->src_bufs_cnt = 0; | |
422 | if (reqbufs->count == 0) { | |
423 | mfc_debug(2, "Freeing buffers\n"); | |
424 | s5p_mfc_clock_on(); | |
425 | ret = vb2_reqbufs(&ctx->vq_src, reqbufs); | |
426 | s5p_mfc_clock_off(); | |
427 | return ret; | |
428 | } | |
429 | /* Decoding */ | |
430 | if (ctx->output_state != QUEUE_FREE) { | |
431 | mfc_err("Bufs have already been requested\n"); | |
432 | return -EINVAL; | |
433 | } | |
434 | s5p_mfc_clock_on(); | |
435 | ret = vb2_reqbufs(&ctx->vq_src, reqbufs); | |
436 | s5p_mfc_clock_off(); | |
437 | if (ret) { | |
438 | mfc_err("vb2_reqbufs on output failed\n"); | |
439 | return ret; | |
440 | } | |
441 | mfc_debug(2, "vb2_reqbufs: %d\n", ret); | |
442 | ctx->output_state = QUEUE_BUFS_REQUESTED; | |
443 | } | |
444 | } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | |
445 | ctx->dst_bufs_cnt = 0; | |
446 | if (reqbufs->count == 0) { | |
447 | mfc_debug(2, "Freeing buffers\n"); | |
448 | s5p_mfc_clock_on(); | |
449 | ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); | |
450 | s5p_mfc_clock_off(); | |
451 | return ret; | |
452 | } | |
453 | if (ctx->capture_state != QUEUE_FREE) { | |
454 | mfc_err("Bufs have already been requested\n"); | |
455 | return -EINVAL; | |
456 | } | |
457 | ctx->capture_state = QUEUE_BUFS_REQUESTED; | |
458 | s5p_mfc_clock_on(); | |
459 | ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); | |
460 | s5p_mfc_clock_off(); | |
461 | if (ret) { | |
462 | mfc_err("vb2_reqbufs on capture failed\n"); | |
463 | return ret; | |
464 | } | |
465 | if (reqbufs->count < ctx->dpb_count) { | |
466 | mfc_err("Not enough buffers allocated\n"); | |
467 | reqbufs->count = 0; | |
468 | s5p_mfc_clock_on(); | |
469 | ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); | |
470 | s5p_mfc_clock_off(); | |
471 | return -ENOMEM; | |
472 | } | |
473 | ctx->total_dpb_count = reqbufs->count; | |
474 | ret = s5p_mfc_alloc_codec_buffers(ctx); | |
475 | if (ret) { | |
476 | mfc_err("Failed to allocate decoding buffers\n"); | |
477 | reqbufs->count = 0; | |
478 | s5p_mfc_clock_on(); | |
479 | ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); | |
480 | s5p_mfc_clock_off(); | |
481 | return -ENOMEM; | |
482 | } | |
483 | if (ctx->dst_bufs_cnt == ctx->total_dpb_count) { | |
484 | ctx->capture_state = QUEUE_BUFS_MMAPED; | |
485 | } else { | |
486 | mfc_err("Not all buffers passed to buf_init\n"); | |
487 | reqbufs->count = 0; | |
488 | s5p_mfc_clock_on(); | |
489 | ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); | |
490 | s5p_mfc_release_codec_buffers(ctx); | |
491 | s5p_mfc_clock_off(); | |
492 | return -ENOMEM; | |
493 | } | |
494 | if (s5p_mfc_ctx_ready(ctx)) { | |
495 | spin_lock_irqsave(&dev->condlock, flags); | |
496 | set_bit(ctx->num, &dev->ctx_work_bits); | |
497 | spin_unlock_irqrestore(&dev->condlock, flags); | |
498 | } | |
499 | s5p_mfc_try_run(dev); | |
500 | s5p_mfc_wait_for_done_ctx(ctx, | |
501 | S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET, 0); | |
502 | } | |
503 | return ret; | |
504 | } | |
505 | ||
506 | /* Query buffer */ | |
507 | static int vidioc_querybuf(struct file *file, void *priv, | |
508 | struct v4l2_buffer *buf) | |
509 | { | |
510 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | |
511 | int ret; | |
512 | int i; | |
513 | ||
514 | if (buf->memory != V4L2_MEMORY_MMAP) { | |
515 | mfc_err("Only mmaped buffers can be used\n"); | |
516 | return -EINVAL; | |
517 | } | |
518 | mfc_debug(2, "State: %d, buf->type: %d\n", ctx->state, buf->type); | |
519 | if (ctx->state == MFCINST_INIT && | |
520 | buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | |
521 | ret = vb2_querybuf(&ctx->vq_src, buf); | |
522 | } else if (ctx->state == MFCINST_RUNNING && | |
523 | buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | |
524 | ret = vb2_querybuf(&ctx->vq_dst, buf); | |
525 | for (i = 0; i < buf->length; i++) | |
526 | buf->m.planes[i].m.mem_offset += DST_QUEUE_OFF_BASE; | |
527 | } else { | |
528 | mfc_err("vidioc_querybuf called in an inappropriate state\n"); | |
529 | ret = -EINVAL; | |
530 | } | |
531 | mfc_debug_leave(); | |
532 | return ret; | |
533 | } | |
534 | ||
535 | /* Queue a buffer */ | |
536 | static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | |
537 | { | |
538 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | |
539 | ||
540 | if (ctx->state == MFCINST_ERROR) { | |
541 | mfc_err("Call on QBUF after unrecoverable error\n"); | |
542 | return -EIO; | |
543 | } | |
544 | if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | |
545 | return vb2_qbuf(&ctx->vq_src, buf); | |
546 | else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | |
547 | return vb2_qbuf(&ctx->vq_dst, buf); | |
548 | return -EINVAL; | |
549 | } | |
550 | ||
551 | /* Dequeue a buffer */ | |
552 | static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | |
553 | { | |
554 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | |
555 | ||
556 | if (ctx->state == MFCINST_ERROR) { | |
557 | mfc_err("Call on DQBUF after unrecoverable error\n"); | |
558 | return -EIO; | |
559 | } | |
560 | if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | |
561 | return vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK); | |
562 | else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | |
563 | return vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK); | |
564 | return -EINVAL; | |
565 | } | |
566 | ||
567 | /* Stream on */ | |
568 | static int vidioc_streamon(struct file *file, void *priv, | |
569 | enum v4l2_buf_type type) | |
570 | { | |
571 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | |
572 | struct s5p_mfc_dev *dev = ctx->dev; | |
573 | unsigned long flags; | |
574 | int ret = -EINVAL; | |
575 | ||
576 | mfc_debug_enter(); | |
577 | if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | |
578 | ||
579 | if (ctx->state == MFCINST_INIT) { | |
580 | ctx->dst_bufs_cnt = 0; | |
581 | ctx->src_bufs_cnt = 0; | |
582 | ctx->capture_state = QUEUE_FREE; | |
583 | ctx->output_state = QUEUE_FREE; | |
584 | s5p_mfc_alloc_instance_buffer(ctx); | |
585 | s5p_mfc_alloc_dec_temp_buffers(ctx); | |
586 | spin_lock_irqsave(&dev->condlock, flags); | |
587 | set_bit(ctx->num, &dev->ctx_work_bits); | |
588 | spin_unlock_irqrestore(&dev->condlock, flags); | |
589 | s5p_mfc_clean_ctx_int_flags(ctx); | |
590 | s5p_mfc_try_run(dev); | |
591 | ||
592 | if (s5p_mfc_wait_for_done_ctx(ctx, | |
593 | S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET, 0)) { | |
594 | /* Error or timeout */ | |
595 | mfc_err("Error getting instance from hardware\n"); | |
596 | s5p_mfc_release_instance_buffer(ctx); | |
597 | s5p_mfc_release_dec_desc_buffer(ctx); | |
598 | return -EIO; | |
599 | } | |
600 | mfc_debug(2, "Got instance number: %d\n", ctx->inst_no); | |
601 | } | |
602 | ret = vb2_streamon(&ctx->vq_src, type); | |
603 | } | |
604 | else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | |
605 | ret = vb2_streamon(&ctx->vq_dst, type); | |
606 | mfc_debug_leave(); | |
607 | return ret; | |
608 | } | |
609 | ||
610 | /* Stream off, which equals to a pause */ | |
611 | static int vidioc_streamoff(struct file *file, void *priv, | |
612 | enum v4l2_buf_type type) | |
613 | { | |
614 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | |
615 | ||
616 | if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | |
617 | return vb2_streamoff(&ctx->vq_src, type); | |
618 | else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | |
619 | return vb2_streamoff(&ctx->vq_dst, type); | |
620 | return -EINVAL; | |
621 | } | |
622 | ||
623 | /* Set controls - v4l2 control framework */ | |
624 | static int s5p_mfc_dec_s_ctrl(struct v4l2_ctrl *ctrl) | |
625 | { | |
626 | struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl); | |
627 | ||
628 | switch (ctrl->id) { | |
629 | case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY: | |
f60935c1 | 630 | ctx->display_delay = ctrl->val; |
af935746 KD |
631 | break; |
632 | case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE: | |
633 | ctx->display_delay_enable = ctrl->val; | |
634 | break; | |
635 | case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: | |
f60935c1 | 636 | ctx->loop_filter_mpeg4 = ctrl->val; |
af935746 KD |
637 | break; |
638 | case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE: | |
639 | ctx->slice_interface = ctrl->val; | |
640 | break; | |
641 | default: | |
642 | mfc_err("Invalid control 0x%08x\n", ctrl->id); | |
643 | return -EINVAL; | |
644 | } | |
645 | return 0; | |
646 | } | |
647 | ||
648 | static int s5p_mfc_dec_g_v_ctrl(struct v4l2_ctrl *ctrl) | |
649 | { | |
650 | struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl); | |
651 | struct s5p_mfc_dev *dev = ctx->dev; | |
652 | ||
653 | switch (ctrl->id) { | |
654 | case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: | |
655 | if (ctx->state >= MFCINST_HEAD_PARSED && | |
656 | ctx->state < MFCINST_ABORT) { | |
657 | ctrl->val = ctx->dpb_count; | |
658 | break; | |
659 | } else if (ctx->state != MFCINST_INIT) { | |
660 | v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n"); | |
661 | return -EINVAL; | |
662 | } | |
663 | /* Should wait for the header to be parsed */ | |
664 | s5p_mfc_clean_ctx_int_flags(ctx); | |
665 | s5p_mfc_wait_for_done_ctx(ctx, | |
666 | S5P_FIMV_R2H_CMD_SEQ_DONE_RET, 0); | |
667 | if (ctx->state >= MFCINST_HEAD_PARSED && | |
668 | ctx->state < MFCINST_ABORT) { | |
669 | ctrl->val = ctx->dpb_count; | |
670 | } else { | |
671 | v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n"); | |
672 | return -EINVAL; | |
673 | } | |
674 | break; | |
675 | } | |
676 | return 0; | |
677 | } | |
678 | ||
679 | ||
680 | static const struct v4l2_ctrl_ops s5p_mfc_dec_ctrl_ops = { | |
681 | .s_ctrl = s5p_mfc_dec_s_ctrl, | |
682 | .g_volatile_ctrl = s5p_mfc_dec_g_v_ctrl, | |
683 | }; | |
684 | ||
685 | /* Get cropping information */ | |
686 | static int vidioc_g_crop(struct file *file, void *priv, | |
687 | struct v4l2_crop *cr) | |
688 | { | |
689 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | |
690 | u32 left, right, top, bottom; | |
691 | ||
692 | if (ctx->state != MFCINST_HEAD_PARSED && | |
693 | ctx->state != MFCINST_RUNNING && ctx->state != MFCINST_FINISHING | |
694 | && ctx->state != MFCINST_FINISHED) { | |
695 | mfc_err("Cannont set crop\n"); | |
696 | return -EINVAL; | |
697 | } | |
698 | if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264) { | |
699 | left = s5p_mfc_read_shm(ctx, CROP_INFO_H); | |
700 | right = left >> S5P_FIMV_SHARED_CROP_RIGHT_SHIFT; | |
701 | left = left & S5P_FIMV_SHARED_CROP_LEFT_MASK; | |
702 | top = s5p_mfc_read_shm(ctx, CROP_INFO_V); | |
703 | bottom = top >> S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT; | |
704 | top = top & S5P_FIMV_SHARED_CROP_TOP_MASK; | |
705 | cr->c.left = left; | |
706 | cr->c.top = top; | |
707 | cr->c.width = ctx->img_width - left - right; | |
708 | cr->c.height = ctx->img_height - top - bottom; | |
709 | mfc_debug(2, "Cropping info [h264]: l=%d t=%d " | |
710 | "w=%d h=%d (r=%d b=%d fw=%d fh=%d\n", left, top, | |
711 | cr->c.width, cr->c.height, right, bottom, | |
712 | ctx->buf_width, ctx->buf_height); | |
713 | } else { | |
714 | cr->c.left = 0; | |
715 | cr->c.top = 0; | |
716 | cr->c.width = ctx->img_width; | |
717 | cr->c.height = ctx->img_height; | |
718 | mfc_debug(2, "Cropping info: w=%d h=%d fw=%d " | |
719 | "fh=%d\n", cr->c.width, cr->c.height, ctx->buf_width, | |
720 | ctx->buf_height); | |
721 | } | |
722 | return 0; | |
723 | } | |
724 | ||
725 | /* v4l2_ioctl_ops */ | |
726 | static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = { | |
727 | .vidioc_querycap = vidioc_querycap, | |
728 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, | |
729 | .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane, | |
730 | .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, | |
731 | .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane, | |
732 | .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt, | |
733 | .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt, | |
734 | .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt, | |
735 | .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt, | |
736 | .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt, | |
737 | .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt, | |
738 | .vidioc_reqbufs = vidioc_reqbufs, | |
739 | .vidioc_querybuf = vidioc_querybuf, | |
740 | .vidioc_qbuf = vidioc_qbuf, | |
741 | .vidioc_dqbuf = vidioc_dqbuf, | |
742 | .vidioc_streamon = vidioc_streamon, | |
743 | .vidioc_streamoff = vidioc_streamoff, | |
744 | .vidioc_g_crop = vidioc_g_crop, | |
745 | }; | |
746 | ||
fc714e70 GL |
747 | static int s5p_mfc_queue_setup(struct vb2_queue *vq, |
748 | const struct v4l2_format *fmt, unsigned int *buf_count, | |
749 | unsigned int *plane_count, unsigned int psize[], | |
750 | void *allocators[]) | |
af935746 KD |
751 | { |
752 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); | |
753 | ||
754 | /* Video output for decoding (source) | |
755 | * this can be set after getting an instance */ | |
756 | if (ctx->state == MFCINST_INIT && | |
757 | vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | |
758 | /* A single plane is required for input */ | |
759 | *plane_count = 1; | |
760 | if (*buf_count < 1) | |
761 | *buf_count = 1; | |
762 | if (*buf_count > MFC_MAX_BUFFERS) | |
763 | *buf_count = MFC_MAX_BUFFERS; | |
764 | /* Video capture for decoding (destination) | |
765 | * this can be set after the header was parsed */ | |
766 | } else if (ctx->state == MFCINST_HEAD_PARSED && | |
767 | vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | |
768 | /* Output plane count is 2 - one for Y and one for CbCr */ | |
769 | *plane_count = 2; | |
770 | /* Setup buffer count */ | |
771 | if (*buf_count < ctx->dpb_count) | |
772 | *buf_count = ctx->dpb_count; | |
773 | if (*buf_count > ctx->dpb_count + MFC_MAX_EXTRA_DPB) | |
774 | *buf_count = ctx->dpb_count + MFC_MAX_EXTRA_DPB; | |
775 | if (*buf_count > MFC_MAX_BUFFERS) | |
776 | *buf_count = MFC_MAX_BUFFERS; | |
777 | } else { | |
778 | mfc_err("State seems invalid. State = %d, vq->type = %d\n", | |
779 | ctx->state, vq->type); | |
780 | return -EINVAL; | |
781 | } | |
782 | mfc_debug(2, "Buffer count=%d, plane count=%d\n", | |
783 | *buf_count, *plane_count); | |
784 | if (ctx->state == MFCINST_HEAD_PARSED && | |
785 | vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | |
786 | psize[0] = ctx->luma_size; | |
787 | psize[1] = ctx->chroma_size; | |
788 | allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; | |
789 | allocators[1] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; | |
790 | } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && | |
791 | ctx->state == MFCINST_INIT) { | |
792 | psize[0] = ctx->dec_src_buf_size; | |
793 | allocators[0] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; | |
794 | } else { | |
795 | mfc_err("This video node is dedicated to decoding. Decoding not initalised\n"); | |
796 | return -EINVAL; | |
797 | } | |
798 | return 0; | |
799 | } | |
800 | ||
801 | static void s5p_mfc_unlock(struct vb2_queue *q) | |
802 | { | |
803 | struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); | |
804 | struct s5p_mfc_dev *dev = ctx->dev; | |
805 | ||
806 | mutex_unlock(&dev->mfc_mutex); | |
807 | } | |
808 | ||
809 | static void s5p_mfc_lock(struct vb2_queue *q) | |
810 | { | |
811 | struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); | |
812 | struct s5p_mfc_dev *dev = ctx->dev; | |
813 | ||
814 | mutex_lock(&dev->mfc_mutex); | |
815 | } | |
816 | ||
817 | static int s5p_mfc_buf_init(struct vb2_buffer *vb) | |
818 | { | |
819 | struct vb2_queue *vq = vb->vb2_queue; | |
820 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); | |
821 | unsigned int i; | |
822 | ||
823 | if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | |
824 | if (ctx->capture_state == QUEUE_BUFS_MMAPED) | |
825 | return 0; | |
826 | for (i = 0; i <= ctx->src_fmt->num_planes ; i++) { | |
827 | if (IS_ERR_OR_NULL(ERR_PTR( | |
ba7fcb0c | 828 | vb2_dma_contig_plane_dma_addr(vb, i)))) { |
af935746 KD |
829 | mfc_err("Plane mem not allocated\n"); |
830 | return -EINVAL; | |
831 | } | |
832 | } | |
833 | if (vb2_plane_size(vb, 0) < ctx->luma_size || | |
834 | vb2_plane_size(vb, 1) < ctx->chroma_size) { | |
835 | mfc_err("Plane buffer (CAPTURE) is too small\n"); | |
836 | return -EINVAL; | |
837 | } | |
838 | i = vb->v4l2_buf.index; | |
839 | ctx->dst_bufs[i].b = vb; | |
840 | ctx->dst_bufs[i].cookie.raw.luma = | |
ba7fcb0c | 841 | vb2_dma_contig_plane_dma_addr(vb, 0); |
af935746 | 842 | ctx->dst_bufs[i].cookie.raw.chroma = |
ba7fcb0c | 843 | vb2_dma_contig_plane_dma_addr(vb, 1); |
af935746 KD |
844 | ctx->dst_bufs_cnt++; |
845 | } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | |
846 | if (IS_ERR_OR_NULL(ERR_PTR( | |
ba7fcb0c | 847 | vb2_dma_contig_plane_dma_addr(vb, 0)))) { |
af935746 KD |
848 | mfc_err("Plane memory not allocated\n"); |
849 | return -EINVAL; | |
850 | } | |
851 | if (vb2_plane_size(vb, 0) < ctx->dec_src_buf_size) { | |
852 | mfc_err("Plane buffer (OUTPUT) is too small\n"); | |
853 | return -EINVAL; | |
854 | } | |
855 | ||
856 | i = vb->v4l2_buf.index; | |
857 | ctx->src_bufs[i].b = vb; | |
858 | ctx->src_bufs[i].cookie.stream = | |
ba7fcb0c | 859 | vb2_dma_contig_plane_dma_addr(vb, 0); |
af935746 KD |
860 | ctx->src_bufs_cnt++; |
861 | } else { | |
862 | mfc_err("s5p_mfc_buf_init: unknown queue type\n"); | |
863 | return -EINVAL; | |
864 | } | |
865 | return 0; | |
866 | } | |
867 | ||
bd323e28 | 868 | static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) |
af935746 KD |
869 | { |
870 | struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); | |
871 | struct s5p_mfc_dev *dev = ctx->dev; | |
872 | unsigned long flags; | |
873 | ||
874 | v4l2_ctrl_handler_setup(&ctx->ctrl_handler); | |
875 | if (ctx->state == MFCINST_FINISHING || | |
876 | ctx->state == MFCINST_FINISHED) | |
877 | ctx->state = MFCINST_RUNNING; | |
878 | /* If context is ready then dev = work->data;schedule it to run */ | |
879 | if (s5p_mfc_ctx_ready(ctx)) { | |
880 | spin_lock_irqsave(&dev->condlock, flags); | |
881 | set_bit(ctx->num, &dev->ctx_work_bits); | |
882 | spin_unlock_irqrestore(&dev->condlock, flags); | |
883 | } | |
884 | s5p_mfc_try_run(dev); | |
885 | return 0; | |
886 | } | |
887 | ||
888 | static int s5p_mfc_stop_streaming(struct vb2_queue *q) | |
889 | { | |
890 | unsigned long flags; | |
891 | struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); | |
892 | struct s5p_mfc_dev *dev = ctx->dev; | |
893 | int aborted = 0; | |
894 | ||
895 | if ((ctx->state == MFCINST_FINISHING || | |
896 | ctx->state == MFCINST_RUNNING) && | |
897 | dev->curr_ctx == ctx->num && dev->hw_lock) { | |
898 | ctx->state = MFCINST_ABORT; | |
899 | s5p_mfc_wait_for_done_ctx(ctx, | |
900 | S5P_FIMV_R2H_CMD_FRAME_DONE_RET, 0); | |
901 | aborted = 1; | |
902 | } | |
903 | spin_lock_irqsave(&dev->irqlock, flags); | |
904 | if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | |
905 | s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); | |
906 | INIT_LIST_HEAD(&ctx->dst_queue); | |
907 | ctx->dst_queue_cnt = 0; | |
908 | ctx->dpb_flush_flag = 1; | |
909 | ctx->dec_dst_flag = 0; | |
910 | } | |
911 | if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | |
912 | s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); | |
913 | INIT_LIST_HEAD(&ctx->src_queue); | |
914 | ctx->src_queue_cnt = 0; | |
915 | } | |
916 | if (aborted) | |
917 | ctx->state = MFCINST_RUNNING; | |
918 | spin_unlock_irqrestore(&dev->irqlock, flags); | |
919 | return 0; | |
920 | } | |
921 | ||
922 | ||
923 | static void s5p_mfc_buf_queue(struct vb2_buffer *vb) | |
924 | { | |
925 | struct vb2_queue *vq = vb->vb2_queue; | |
926 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); | |
927 | struct s5p_mfc_dev *dev = ctx->dev; | |
928 | unsigned long flags; | |
929 | struct s5p_mfc_buf *mfc_buf; | |
930 | ||
931 | if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | |
932 | mfc_buf = &ctx->src_bufs[vb->v4l2_buf.index]; | |
933 | mfc_buf->used = 0; | |
934 | spin_lock_irqsave(&dev->irqlock, flags); | |
935 | list_add_tail(&mfc_buf->list, &ctx->src_queue); | |
936 | ctx->src_queue_cnt++; | |
937 | spin_unlock_irqrestore(&dev->irqlock, flags); | |
938 | } else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | |
939 | mfc_buf = &ctx->dst_bufs[vb->v4l2_buf.index]; | |
940 | mfc_buf->used = 0; | |
941 | /* Mark destination as available for use by MFC */ | |
942 | spin_lock_irqsave(&dev->irqlock, flags); | |
943 | set_bit(vb->v4l2_buf.index, &ctx->dec_dst_flag); | |
944 | list_add_tail(&mfc_buf->list, &ctx->dst_queue); | |
945 | ctx->dst_queue_cnt++; | |
946 | spin_unlock_irqrestore(&dev->irqlock, flags); | |
947 | } else { | |
948 | mfc_err("Unsupported buffer type (%d)\n", vq->type); | |
949 | } | |
950 | if (s5p_mfc_ctx_ready(ctx)) { | |
951 | spin_lock_irqsave(&dev->condlock, flags); | |
952 | set_bit(ctx->num, &dev->ctx_work_bits); | |
953 | spin_unlock_irqrestore(&dev->condlock, flags); | |
954 | } | |
955 | s5p_mfc_try_run(dev); | |
956 | } | |
957 | ||
958 | static struct vb2_ops s5p_mfc_dec_qops = { | |
959 | .queue_setup = s5p_mfc_queue_setup, | |
960 | .wait_prepare = s5p_mfc_unlock, | |
961 | .wait_finish = s5p_mfc_lock, | |
962 | .buf_init = s5p_mfc_buf_init, | |
963 | .start_streaming = s5p_mfc_start_streaming, | |
964 | .stop_streaming = s5p_mfc_stop_streaming, | |
965 | .buf_queue = s5p_mfc_buf_queue, | |
966 | }; | |
967 | ||
968 | struct s5p_mfc_codec_ops *get_dec_codec_ops(void) | |
969 | { | |
970 | return &decoder_codec_ops; | |
971 | } | |
972 | ||
973 | struct vb2_ops *get_dec_queue_ops(void) | |
974 | { | |
975 | return &s5p_mfc_dec_qops; | |
976 | } | |
977 | ||
978 | const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void) | |
979 | { | |
980 | return &s5p_mfc_dec_ioctl_ops; | |
981 | } | |
982 | ||
983 | #define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2CLASS(x) == V4L2_CTRL_CLASS_MPEG) \ | |
984 | && V4L2_CTRL_DRIVER_PRIV(x)) | |
985 | ||
986 | int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx) | |
987 | { | |
988 | struct v4l2_ctrl_config cfg; | |
989 | int i; | |
990 | ||
991 | v4l2_ctrl_handler_init(&ctx->ctrl_handler, NUM_CTRLS); | |
992 | if (ctx->ctrl_handler.error) { | |
993 | mfc_err("v4l2_ctrl_handler_init failed\n"); | |
994 | return ctx->ctrl_handler.error; | |
995 | } | |
996 | ||
997 | for (i = 0; i < NUM_CTRLS; i++) { | |
998 | if (IS_MFC51_PRIV(controls[i].id)) { | |
999 | cfg.ops = &s5p_mfc_dec_ctrl_ops; | |
1000 | cfg.id = controls[i].id; | |
1001 | cfg.min = controls[i].minimum; | |
1002 | cfg.max = controls[i].maximum; | |
1003 | cfg.def = controls[i].default_value; | |
1004 | cfg.name = controls[i].name; | |
1005 | cfg.type = controls[i].type; | |
1006 | ||
1007 | cfg.step = controls[i].step; | |
1008 | cfg.menu_skip_mask = 0; | |
1009 | ||
1010 | ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->ctrl_handler, | |
1011 | &cfg, NULL); | |
1012 | } else { | |
1013 | ctx->ctrls[i] = v4l2_ctrl_new_std(&ctx->ctrl_handler, | |
1014 | &s5p_mfc_dec_ctrl_ops, | |
1015 | controls[i].id, controls[i].minimum, | |
1016 | controls[i].maximum, controls[i].step, | |
1017 | controls[i].default_value); | |
1018 | } | |
1019 | if (ctx->ctrl_handler.error) { | |
1020 | mfc_err("Adding control (%d) failed\n", i); | |
1021 | return ctx->ctrl_handler.error; | |
1022 | } | |
1023 | if (controls[i].is_volatile && ctx->ctrls[i]) | |
88365105 | 1024 | ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE; |
af935746 KD |
1025 | } |
1026 | return 0; | |
1027 | } | |
1028 | ||
1029 | void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx) | |
1030 | { | |
1031 | int i; | |
1032 | ||
1033 | v4l2_ctrl_handler_free(&ctx->ctrl_handler); | |
1034 | for (i = 0; i < NUM_CTRLS; i++) | |
1035 | ctx->ctrls[i] = NULL; | |
1036 | } | |
1037 |