diff options
author | Philipp Zabel <p.zabel@pengutronix.de> | 2014-10-02 13:08:28 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2014-10-28 13:01:05 -0400 |
commit | 2c11d1bdfc7175cc75a603e433367caaf038ab69 (patch) | |
tree | 1240519636dc02fb446ca4c5cba90ad28cc429b1 | |
parent | b2f91ae30edfa95500183179082f0568e3e9b38e (diff) |
[media] coda: add coda_video_device descriptors
Each video device descriptor determines the name, callback ops, and input and
output formats on the corresponding video device. This simplifies coda_enum_fmt
and coda_try_fmt a bit and will simplify adding separate video devices for JPEG
codecs due to the slightly different behavior in the CodaDx6/CODA7542 case and
a separate hardware unit on CODA960.
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Kamil Debski <k.debski@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
-rw-r--r-- | drivers/media/platform/coda/coda-common.c | 350 | ||||
-rw-r--r-- | drivers/media/platform/coda/coda.h | 7 |
2 files changed, 204 insertions, 153 deletions
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index fb83c56afd26..45db1da2dbcf 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #define CODA_NAME "coda" | 43 | #define CODA_NAME "coda" |
44 | 44 | ||
45 | #define CODADX6_MAX_INSTANCES 4 | 45 | #define CODADX6_MAX_INSTANCES 4 |
46 | #define CODA_MAX_FORMATS 4 | ||
46 | 47 | ||
47 | #define CODA_PARA_BUF_SIZE (10 * 1024) | 48 | #define CODA_PARA_BUF_SIZE (10 * 1024) |
48 | #define CODA_ISRAM_SIZE (2048 * 2) | 49 | #define CODA_ISRAM_SIZE (2048 * 2) |
@@ -169,6 +170,58 @@ static const struct coda_codec coda9_codecs[] = { | |||
169 | CODA_CODEC(CODA9_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1088), | 170 | CODA_CODEC(CODA9_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1088), |
170 | }; | 171 | }; |
171 | 172 | ||
173 | struct coda_video_device { | ||
174 | const char *name; | ||
175 | enum coda_inst_type type; | ||
176 | const struct coda_context_ops *ops; | ||
177 | u32 src_formats[CODA_MAX_FORMATS]; | ||
178 | u32 dst_formats[CODA_MAX_FORMATS]; | ||
179 | }; | ||
180 | |||
181 | static const struct coda_video_device coda_bit_encoder = { | ||
182 | .name = "coda-encoder", | ||
183 | .type = CODA_INST_ENCODER, | ||
184 | .ops = &coda_bit_encode_ops, | ||
185 | .src_formats = { | ||
186 | V4L2_PIX_FMT_YUV420, | ||
187 | V4L2_PIX_FMT_YVU420, | ||
188 | V4L2_PIX_FMT_NV12, | ||
189 | }, | ||
190 | .dst_formats = { | ||
191 | V4L2_PIX_FMT_H264, | ||
192 | V4L2_PIX_FMT_MPEG4, | ||
193 | }, | ||
194 | }; | ||
195 | |||
196 | static const struct coda_video_device coda_bit_decoder = { | ||
197 | .name = "coda-decoder", | ||
198 | .type = CODA_INST_DECODER, | ||
199 | .ops = &coda_bit_decode_ops, | ||
200 | .src_formats = { | ||
201 | V4L2_PIX_FMT_H264, | ||
202 | V4L2_PIX_FMT_MPEG4, | ||
203 | }, | ||
204 | .dst_formats = { | ||
205 | V4L2_PIX_FMT_YUV420, | ||
206 | V4L2_PIX_FMT_YVU420, | ||
207 | V4L2_PIX_FMT_NV12, | ||
208 | }, | ||
209 | }; | ||
210 | |||
211 | static const struct coda_video_device *codadx6_video_devices[] = { | ||
212 | &coda_bit_encoder, | ||
213 | }; | ||
214 | |||
215 | static const struct coda_video_device *coda7_video_devices[] = { | ||
216 | &coda_bit_encoder, | ||
217 | &coda_bit_decoder, | ||
218 | }; | ||
219 | |||
220 | static const struct coda_video_device *coda9_video_devices[] = { | ||
221 | &coda_bit_encoder, | ||
222 | &coda_bit_decoder, | ||
223 | }; | ||
224 | |||
172 | static bool coda_format_is_yuv(u32 fourcc) | 225 | static bool coda_format_is_yuv(u32 fourcc) |
173 | { | 226 | { |
174 | switch (fourcc) { | 227 | switch (fourcc) { |
@@ -182,6 +235,18 @@ static bool coda_format_is_yuv(u32 fourcc) | |||
182 | } | 235 | } |
183 | } | 236 | } |
184 | 237 | ||
238 | static const char *coda_format_name(u32 fourcc) | ||
239 | { | ||
240 | int i; | ||
241 | |||
242 | for (i = 0; i < ARRAY_SIZE(coda_formats); i++) { | ||
243 | if (coda_formats[i].fourcc == fourcc) | ||
244 | return coda_formats[i].name; | ||
245 | } | ||
246 | |||
247 | return NULL; | ||
248 | } | ||
249 | |||
185 | /* | 250 | /* |
186 | * Normalize all supported YUV 4:2:0 formats to the value used in the codec | 251 | * Normalize all supported YUV 4:2:0 formats to the value used in the codec |
187 | * tables. | 252 | * tables. |
@@ -240,6 +305,17 @@ static void coda_get_max_dimensions(struct coda_dev *dev, | |||
240 | *max_h = h; | 305 | *max_h = h; |
241 | } | 306 | } |
242 | 307 | ||
308 | const struct coda_video_device *to_coda_video_device(struct video_device *vdev) | ||
309 | { | ||
310 | struct coda_dev *dev = video_get_drvdata(vdev); | ||
311 | unsigned int i = vdev - dev->vfd; | ||
312 | |||
313 | if (i >= dev->devtype->num_vdevs) | ||
314 | return NULL; | ||
315 | |||
316 | return dev->devtype->vdevs[i]; | ||
317 | } | ||
318 | |||
243 | const char *coda_product_name(int product) | 319 | const char *coda_product_name(int product) |
244 | { | 320 | { |
245 | static char buf[9]; | 321 | static char buf[9]; |
@@ -278,58 +354,28 @@ static int coda_querycap(struct file *file, void *priv, | |||
278 | static int coda_enum_fmt(struct file *file, void *priv, | 354 | static int coda_enum_fmt(struct file *file, void *priv, |
279 | struct v4l2_fmtdesc *f) | 355 | struct v4l2_fmtdesc *f) |
280 | { | 356 | { |
281 | struct coda_ctx *ctx = fh_to_ctx(priv); | 357 | struct video_device *vdev = video_devdata(file); |
282 | const struct coda_codec *codecs = ctx->dev->devtype->codecs; | 358 | const struct coda_video_device *cvd = to_coda_video_device(vdev); |
283 | const struct coda_fmt *formats = coda_formats; | 359 | const u32 *formats; |
284 | const struct coda_fmt *fmt; | 360 | const char *name; |
285 | int num_codecs = ctx->dev->devtype->num_codecs; | 361 | |
286 | int num_formats = ARRAY_SIZE(coda_formats); | 362 | if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) |
287 | int i, k, num = 0; | 363 | formats = cvd->src_formats; |
288 | bool yuv; | 364 | else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
289 | 365 | formats = cvd->dst_formats; | |
290 | if (ctx->inst_type == CODA_INST_ENCODER) | ||
291 | yuv = (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT); | ||
292 | else | 366 | else |
293 | yuv = (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE); | 367 | return -EINVAL; |
294 | |||
295 | for (i = 0; i < num_formats; i++) { | ||
296 | /* Skip either raw or compressed formats */ | ||
297 | if (yuv != coda_format_is_yuv(formats[i].fourcc)) | ||
298 | continue; | ||
299 | /* All uncompressed formats are always supported */ | ||
300 | if (yuv) { | ||
301 | if (num == f->index) | ||
302 | break; | ||
303 | ++num; | ||
304 | continue; | ||
305 | } | ||
306 | /* Compressed formats may be supported, check the codec list */ | ||
307 | for (k = 0; k < num_codecs; k++) { | ||
308 | if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && | ||
309 | formats[i].fourcc == codecs[k].dst_fourcc) | ||
310 | break; | ||
311 | if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && | ||
312 | formats[i].fourcc == codecs[k].src_fourcc) | ||
313 | break; | ||
314 | } | ||
315 | if (k < num_codecs) { | ||
316 | if (num == f->index) | ||
317 | break; | ||
318 | ++num; | ||
319 | } | ||
320 | } | ||
321 | 368 | ||
322 | if (i < num_formats) { | 369 | if (f->index >= CODA_MAX_FORMATS || formats[f->index] == 0) |
323 | fmt = &formats[i]; | 370 | return -EINVAL; |
324 | strlcpy(f->description, fmt->name, sizeof(f->description)); | 371 | |
325 | f->pixelformat = fmt->fourcc; | 372 | name = coda_format_name(formats[f->index]); |
326 | if (!yuv) | 373 | strlcpy(f->description, name, sizeof(f->description)); |
327 | f->flags |= V4L2_FMT_FLAG_COMPRESSED; | 374 | f->pixelformat = formats[f->index]; |
328 | return 0; | 375 | if (!coda_format_is_yuv(formats[f->index])) |
329 | } | 376 | f->flags |= V4L2_FMT_FLAG_COMPRESSED; |
330 | 377 | ||
331 | /* Format not found */ | 378 | return 0; |
332 | return -EINVAL; | ||
333 | } | 379 | } |
334 | 380 | ||
335 | static int coda_g_fmt(struct file *file, void *priv, | 381 | static int coda_g_fmt(struct file *file, void *priv, |
@@ -354,11 +400,37 @@ static int coda_g_fmt(struct file *file, void *priv, | |||
354 | return 0; | 400 | return 0; |
355 | } | 401 | } |
356 | 402 | ||
403 | static int coda_try_pixelformat(struct coda_ctx *ctx, struct v4l2_format *f) | ||
404 | { | ||
405 | struct coda_q_data *q_data; | ||
406 | const u32 *formats; | ||
407 | int i; | ||
408 | |||
409 | if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) | ||
410 | formats = ctx->cvd->src_formats; | ||
411 | else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
412 | formats = ctx->cvd->dst_formats; | ||
413 | else | ||
414 | return -EINVAL; | ||
415 | |||
416 | for (i = 0; i < CODA_MAX_FORMATS; i++) { | ||
417 | if (formats[i] == f->fmt.pix.pixelformat) { | ||
418 | f->fmt.pix.pixelformat = formats[i]; | ||
419 | return 0; | ||
420 | } | ||
421 | } | ||
422 | |||
423 | /* Fall back to currently set pixelformat */ | ||
424 | q_data = get_q_data(ctx, f->type); | ||
425 | f->fmt.pix.pixelformat = q_data->fourcc; | ||
426 | |||
427 | return 0; | ||
428 | } | ||
429 | |||
357 | static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec, | 430 | static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec, |
358 | struct v4l2_format *f) | 431 | struct v4l2_format *f) |
359 | { | 432 | { |
360 | struct coda_dev *dev = ctx->dev; | 433 | struct coda_dev *dev = ctx->dev; |
361 | struct coda_q_data *q_data; | ||
362 | unsigned int max_w, max_h; | 434 | unsigned int max_w, max_h; |
363 | enum v4l2_field field; | 435 | enum v4l2_field field; |
364 | 436 | ||
@@ -381,21 +453,6 @@ static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec, | |||
381 | case V4L2_PIX_FMT_YUV420: | 453 | case V4L2_PIX_FMT_YUV420: |
382 | case V4L2_PIX_FMT_YVU420: | 454 | case V4L2_PIX_FMT_YVU420: |
383 | case V4L2_PIX_FMT_NV12: | 455 | case V4L2_PIX_FMT_NV12: |
384 | case V4L2_PIX_FMT_H264: | ||
385 | case V4L2_PIX_FMT_MPEG4: | ||
386 | case V4L2_PIX_FMT_JPEG: | ||
387 | break; | ||
388 | default: | ||
389 | q_data = get_q_data(ctx, f->type); | ||
390 | if (!q_data) | ||
391 | return -EINVAL; | ||
392 | f->fmt.pix.pixelformat = q_data->fourcc; | ||
393 | } | ||
394 | |||
395 | switch (f->fmt.pix.pixelformat) { | ||
396 | case V4L2_PIX_FMT_YUV420: | ||
397 | case V4L2_PIX_FMT_YVU420: | ||
398 | case V4L2_PIX_FMT_NV12: | ||
399 | /* Frame stride must be multiple of 8, but 16 for h.264 */ | 456 | /* Frame stride must be multiple of 8, but 16 for h.264 */ |
400 | f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16); | 457 | f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16); |
401 | f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * | 458 | f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * |
@@ -423,34 +480,35 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv, | |||
423 | struct v4l2_format *f) | 480 | struct v4l2_format *f) |
424 | { | 481 | { |
425 | struct coda_ctx *ctx = fh_to_ctx(priv); | 482 | struct coda_ctx *ctx = fh_to_ctx(priv); |
426 | const struct coda_codec *codec = NULL; | 483 | const struct coda_q_data *q_data_src; |
484 | const struct coda_codec *codec; | ||
427 | struct vb2_queue *src_vq; | 485 | struct vb2_queue *src_vq; |
428 | int ret; | 486 | int ret; |
429 | 487 | ||
488 | ret = coda_try_pixelformat(ctx, f); | ||
489 | if (ret < 0) | ||
490 | return ret; | ||
491 | |||
492 | q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); | ||
493 | |||
430 | /* | 494 | /* |
431 | * If the source format is already fixed, try to find a codec that | 495 | * If the source format is already fixed, only allow the same output |
432 | * converts to the given destination format | 496 | * resolution |
433 | */ | 497 | */ |
434 | src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); | 498 | src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); |
435 | if (vb2_is_streaming(src_vq)) { | 499 | if (vb2_is_streaming(src_vq)) { |
436 | struct coda_q_data *q_data_src; | ||
437 | |||
438 | q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); | ||
439 | codec = coda_find_codec(ctx->dev, q_data_src->fourcc, | ||
440 | f->fmt.pix.pixelformat); | ||
441 | if (!codec) | ||
442 | return -EINVAL; | ||
443 | |||
444 | f->fmt.pix.width = q_data_src->width; | 500 | f->fmt.pix.width = q_data_src->width; |
445 | f->fmt.pix.height = q_data_src->height; | 501 | f->fmt.pix.height = q_data_src->height; |
446 | } else { | ||
447 | /* Otherwise determine codec by encoded format, if possible */ | ||
448 | codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420, | ||
449 | f->fmt.pix.pixelformat); | ||
450 | } | 502 | } |
451 | 503 | ||
452 | f->fmt.pix.colorspace = ctx->colorspace; | 504 | f->fmt.pix.colorspace = ctx->colorspace; |
453 | 505 | ||
506 | q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); | ||
507 | codec = coda_find_codec(ctx->dev, q_data_src->fourcc, | ||
508 | f->fmt.pix.pixelformat); | ||
509 | if (!codec) | ||
510 | return -EINVAL; | ||
511 | |||
454 | ret = coda_try_fmt(ctx, codec, f); | 512 | ret = coda_try_fmt(ctx, codec, f); |
455 | if (ret < 0) | 513 | if (ret < 0) |
456 | return ret; | 514 | return ret; |
@@ -471,22 +529,21 @@ static int coda_try_fmt_vid_out(struct file *file, void *priv, | |||
471 | struct v4l2_format *f) | 529 | struct v4l2_format *f) |
472 | { | 530 | { |
473 | struct coda_ctx *ctx = fh_to_ctx(priv); | 531 | struct coda_ctx *ctx = fh_to_ctx(priv); |
474 | const struct coda_codec *codec = NULL; | 532 | struct coda_dev *dev = ctx->dev; |
533 | const struct coda_q_data *q_data_dst; | ||
534 | const struct coda_codec *codec; | ||
535 | int ret; | ||
475 | 536 | ||
476 | /* Determine codec by encoded format, returns NULL if raw or invalid */ | 537 | ret = coda_try_pixelformat(ctx, f); |
477 | if (ctx->inst_type == CODA_INST_DECODER) { | 538 | if (ret < 0) |
478 | codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat, | 539 | return ret; |
479 | V4L2_PIX_FMT_YUV420); | ||
480 | if (!codec) | ||
481 | codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_H264, | ||
482 | V4L2_PIX_FMT_YUV420); | ||
483 | if (!codec) | ||
484 | return -EINVAL; | ||
485 | } | ||
486 | 540 | ||
487 | if (!f->fmt.pix.colorspace) | 541 | if (!f->fmt.pix.colorspace) |
488 | f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; | 542 | f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; |
489 | 543 | ||
544 | q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); | ||
545 | codec = coda_find_codec(dev, f->fmt.pix.pixelformat, q_data_dst->fourcc); | ||
546 | |||
490 | return coda_try_fmt(ctx, codec, f); | 547 | return coda_try_fmt(ctx, codec, f); |
491 | } | 548 | } |
492 | 549 | ||
@@ -907,18 +964,10 @@ static void coda_set_tiled_map_type(struct coda_ctx *ctx, int tiled_map_type) | |||
907 | 964 | ||
908 | static void set_default_params(struct coda_ctx *ctx) | 965 | static void set_default_params(struct coda_ctx *ctx) |
909 | { | 966 | { |
910 | u32 src_fourcc, dst_fourcc; | 967 | int max_w, max_h; |
911 | int max_w; | ||
912 | int max_h; | ||
913 | 968 | ||
914 | if (ctx->inst_type == CODA_INST_ENCODER) { | 969 | ctx->codec = coda_find_codec(ctx->dev, ctx->cvd->src_formats[0], |
915 | src_fourcc = V4L2_PIX_FMT_YUV420; | 970 | ctx->cvd->dst_formats[0]); |
916 | dst_fourcc = V4L2_PIX_FMT_H264; | ||
917 | } else { | ||
918 | src_fourcc = V4L2_PIX_FMT_H264; | ||
919 | dst_fourcc = V4L2_PIX_FMT_YUV420; | ||
920 | } | ||
921 | ctx->codec = coda_find_codec(ctx->dev, src_fourcc, dst_fourcc); | ||
922 | max_w = ctx->codec->max_w; | 971 | max_w = ctx->codec->max_w; |
923 | max_h = ctx->codec->max_h; | 972 | max_h = ctx->codec->max_h; |
924 | 973 | ||
@@ -1409,10 +1458,14 @@ static int coda_next_free_instance(struct coda_dev *dev) | |||
1409 | return idx; | 1458 | return idx; |
1410 | } | 1459 | } |
1411 | 1460 | ||
1412 | static int coda_open(struct file *file, enum coda_inst_type inst_type, | 1461 | /* |
1413 | const struct coda_context_ops *ctx_ops) | 1462 | * File operations |
1463 | */ | ||
1464 | |||
1465 | static int coda_open(struct file *file) | ||
1414 | { | 1466 | { |
1415 | struct coda_dev *dev = video_drvdata(file); | 1467 | struct video_device *vdev = video_devdata(file); |
1468 | struct coda_dev *dev = video_get_drvdata(vdev); | ||
1416 | struct coda_ctx *ctx = NULL; | 1469 | struct coda_ctx *ctx = NULL; |
1417 | char *name; | 1470 | char *name; |
1418 | int ret; | 1471 | int ret; |
@@ -1433,8 +1486,9 @@ static int coda_open(struct file *file, enum coda_inst_type inst_type, | |||
1433 | ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root); | 1486 | ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root); |
1434 | kfree(name); | 1487 | kfree(name); |
1435 | 1488 | ||
1436 | ctx->inst_type = inst_type; | 1489 | ctx->cvd = to_coda_video_device(vdev); |
1437 | ctx->ops = ctx_ops; | 1490 | ctx->inst_type = ctx->cvd->type; |
1491 | ctx->ops = ctx->cvd->ops; | ||
1438 | init_completion(&ctx->completion); | 1492 | init_completion(&ctx->completion); |
1439 | INIT_WORK(&ctx->pic_run_work, coda_pic_run_work); | 1493 | INIT_WORK(&ctx->pic_run_work, coda_pic_run_work); |
1440 | INIT_WORK(&ctx->seq_end_work, ctx->ops->seq_end_work); | 1494 | INIT_WORK(&ctx->seq_end_work, ctx->ops->seq_end_work); |
@@ -1542,16 +1596,6 @@ err_coda_max: | |||
1542 | return ret; | 1596 | return ret; |
1543 | } | 1597 | } |
1544 | 1598 | ||
1545 | static int coda_encoder_open(struct file *file) | ||
1546 | { | ||
1547 | return coda_open(file, CODA_INST_ENCODER, &coda_bit_encode_ops); | ||
1548 | } | ||
1549 | |||
1550 | static int coda_decoder_open(struct file *file) | ||
1551 | { | ||
1552 | return coda_open(file, CODA_INST_DECODER, &coda_bit_decode_ops); | ||
1553 | } | ||
1554 | |||
1555 | static int coda_release(struct file *file) | 1599 | static int coda_release(struct file *file) |
1556 | { | 1600 | { |
1557 | struct coda_dev *dev = video_drvdata(file); | 1601 | struct coda_dev *dev = video_drvdata(file); |
@@ -1595,18 +1639,9 @@ static int coda_release(struct file *file) | |||
1595 | return 0; | 1639 | return 0; |
1596 | } | 1640 | } |
1597 | 1641 | ||
1598 | static const struct v4l2_file_operations coda_encoder_fops = { | 1642 | static const struct v4l2_file_operations coda_fops = { |
1599 | .owner = THIS_MODULE, | ||
1600 | .open = coda_encoder_open, | ||
1601 | .release = coda_release, | ||
1602 | .poll = v4l2_m2m_fop_poll, | ||
1603 | .unlocked_ioctl = video_ioctl2, | ||
1604 | .mmap = v4l2_m2m_fop_mmap, | ||
1605 | }; | ||
1606 | |||
1607 | static const struct v4l2_file_operations coda_decoder_fops = { | ||
1608 | .owner = THIS_MODULE, | 1643 | .owner = THIS_MODULE, |
1609 | .open = coda_decoder_open, | 1644 | .open = coda_open, |
1610 | .release = coda_release, | 1645 | .release = coda_release, |
1611 | .poll = v4l2_m2m_fop_poll, | 1646 | .poll = v4l2_m2m_fop_poll, |
1612 | .unlocked_ioctl = video_ioctl2, | 1647 | .unlocked_ioctl = video_ioctl2, |
@@ -1711,8 +1746,16 @@ err_clk_per: | |||
1711 | return ret; | 1746 | return ret; |
1712 | } | 1747 | } |
1713 | 1748 | ||
1714 | static int coda_register_device(struct coda_dev *dev, struct video_device *vfd) | 1749 | static int coda_register_device(struct coda_dev *dev, int i) |
1715 | { | 1750 | { |
1751 | struct video_device *vfd = &dev->vfd[i]; | ||
1752 | |||
1753 | if (i > ARRAY_SIZE(dev->vfd)) | ||
1754 | return -EINVAL; | ||
1755 | |||
1756 | snprintf(vfd->name, sizeof(vfd->name), dev->devtype->vdevs[i]->name); | ||
1757 | vfd->fops = &coda_fops; | ||
1758 | vfd->ioctl_ops = &coda_ioctl_ops; | ||
1716 | vfd->release = video_device_release_empty, | 1759 | vfd->release = video_device_release_empty, |
1717 | vfd->lock = &dev->dev_mutex; | 1760 | vfd->lock = &dev->dev_mutex; |
1718 | vfd->v4l2_dev = &dev->v4l2_dev; | 1761 | vfd->v4l2_dev = &dev->v4l2_dev; |
@@ -1731,7 +1774,7 @@ static void coda_fw_callback(const struct firmware *fw, void *context) | |||
1731 | { | 1774 | { |
1732 | struct coda_dev *dev = context; | 1775 | struct coda_dev *dev = context; |
1733 | struct platform_device *pdev = dev->plat_dev; | 1776 | struct platform_device *pdev = dev->plat_dev; |
1734 | int ret; | 1777 | int i, ret; |
1735 | 1778 | ||
1736 | if (!fw) { | 1779 | if (!fw) { |
1737 | v4l2_err(&dev->v4l2_dev, "firmware request failed\n"); | 1780 | v4l2_err(&dev->v4l2_dev, "firmware request failed\n"); |
@@ -1772,33 +1815,25 @@ static void coda_fw_callback(const struct firmware *fw, void *context) | |||
1772 | goto rel_ctx; | 1815 | goto rel_ctx; |
1773 | } | 1816 | } |
1774 | 1817 | ||
1775 | dev->vfd[0].fops = &coda_encoder_fops, | 1818 | for (i = 0; i < dev->devtype->num_vdevs; i++) { |
1776 | dev->vfd[0].ioctl_ops = &coda_ioctl_ops; | 1819 | ret = coda_register_device(dev, i); |
1777 | snprintf(dev->vfd[0].name, sizeof(dev->vfd[0].name), "coda-encoder"); | 1820 | if (ret) { |
1778 | ret = coda_register_device(dev, &dev->vfd[0]); | 1821 | v4l2_err(&dev->v4l2_dev, |
1779 | if (ret) { | 1822 | "Failed to register %s video device: %d\n", |
1780 | v4l2_err(&dev->v4l2_dev, | 1823 | dev->devtype->vdevs[i]->name, ret); |
1781 | "Failed to register encoder video device\n"); | 1824 | goto rel_vfd; |
1782 | goto rel_m2m; | 1825 | } |
1783 | } | ||
1784 | |||
1785 | dev->vfd[1].fops = &coda_decoder_fops, | ||
1786 | dev->vfd[1].ioctl_ops = &coda_ioctl_ops; | ||
1787 | snprintf(dev->vfd[1].name, sizeof(dev->vfd[1].name), "coda-decoder"); | ||
1788 | ret = coda_register_device(dev, &dev->vfd[1]); | ||
1789 | if (ret) { | ||
1790 | v4l2_err(&dev->v4l2_dev, | ||
1791 | "Failed to register decoder video device\n"); | ||
1792 | goto rel_m2m; | ||
1793 | } | 1826 | } |
1794 | 1827 | ||
1795 | v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video[%d-%d]\n", | 1828 | v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video[%d-%d]\n", |
1796 | dev->vfd[0].num, dev->vfd[1].num); | 1829 | dev->vfd[0].num, dev->vfd[i - 1].num); |
1797 | 1830 | ||
1798 | pm_runtime_put_sync(&pdev->dev); | 1831 | pm_runtime_put_sync(&pdev->dev); |
1799 | return; | 1832 | return; |
1800 | 1833 | ||
1801 | rel_m2m: | 1834 | rel_vfd: |
1835 | while (--i >= 0) | ||
1836 | video_unregister_device(&dev->vfd[i]); | ||
1802 | v4l2_m2m_release(dev->m2m_dev); | 1837 | v4l2_m2m_release(dev->m2m_dev); |
1803 | rel_ctx: | 1838 | rel_ctx: |
1804 | vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); | 1839 | vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); |
@@ -1830,6 +1865,8 @@ static const struct coda_devtype coda_devdata[] = { | |||
1830 | .product = CODA_DX6, | 1865 | .product = CODA_DX6, |
1831 | .codecs = codadx6_codecs, | 1866 | .codecs = codadx6_codecs, |
1832 | .num_codecs = ARRAY_SIZE(codadx6_codecs), | 1867 | .num_codecs = ARRAY_SIZE(codadx6_codecs), |
1868 | .vdevs = codadx6_video_devices, | ||
1869 | .num_vdevs = ARRAY_SIZE(codadx6_video_devices), | ||
1833 | .workbuf_size = 288 * 1024 + FMO_SLICE_SAVE_BUF_SIZE * 8 * 1024, | 1870 | .workbuf_size = 288 * 1024 + FMO_SLICE_SAVE_BUF_SIZE * 8 * 1024, |
1834 | .iram_size = 0xb000, | 1871 | .iram_size = 0xb000, |
1835 | }, | 1872 | }, |
@@ -1838,6 +1875,8 @@ static const struct coda_devtype coda_devdata[] = { | |||
1838 | .product = CODA_7541, | 1875 | .product = CODA_7541, |
1839 | .codecs = coda7_codecs, | 1876 | .codecs = coda7_codecs, |
1840 | .num_codecs = ARRAY_SIZE(coda7_codecs), | 1877 | .num_codecs = ARRAY_SIZE(coda7_codecs), |
1878 | .vdevs = coda7_video_devices, | ||
1879 | .num_vdevs = ARRAY_SIZE(coda7_video_devices), | ||
1841 | .workbuf_size = 128 * 1024, | 1880 | .workbuf_size = 128 * 1024, |
1842 | .tempbuf_size = 304 * 1024, | 1881 | .tempbuf_size = 304 * 1024, |
1843 | .iram_size = 0x14000, | 1882 | .iram_size = 0x14000, |
@@ -1847,6 +1886,8 @@ static const struct coda_devtype coda_devdata[] = { | |||
1847 | .product = CODA_960, | 1886 | .product = CODA_960, |
1848 | .codecs = coda9_codecs, | 1887 | .codecs = coda9_codecs, |
1849 | .num_codecs = ARRAY_SIZE(coda9_codecs), | 1888 | .num_codecs = ARRAY_SIZE(coda9_codecs), |
1889 | .vdevs = coda9_video_devices, | ||
1890 | .num_vdevs = ARRAY_SIZE(coda9_video_devices), | ||
1850 | .workbuf_size = 80 * 1024, | 1891 | .workbuf_size = 80 * 1024, |
1851 | .tempbuf_size = 204 * 1024, | 1892 | .tempbuf_size = 204 * 1024, |
1852 | .iram_size = 0x21000, | 1893 | .iram_size = 0x21000, |
@@ -1856,6 +1897,8 @@ static const struct coda_devtype coda_devdata[] = { | |||
1856 | .product = CODA_960, | 1897 | .product = CODA_960, |
1857 | .codecs = coda9_codecs, | 1898 | .codecs = coda9_codecs, |
1858 | .num_codecs = ARRAY_SIZE(coda9_codecs), | 1899 | .num_codecs = ARRAY_SIZE(coda9_codecs), |
1900 | .vdevs = coda9_video_devices, | ||
1901 | .num_vdevs = ARRAY_SIZE(coda9_video_devices), | ||
1859 | .workbuf_size = 80 * 1024, | 1902 | .workbuf_size = 80 * 1024, |
1860 | .tempbuf_size = 204 * 1024, | 1903 | .tempbuf_size = 204 * 1024, |
1861 | .iram_size = 0x20000, | 1904 | .iram_size = 0x20000, |
@@ -2035,9 +2078,12 @@ static int coda_probe(struct platform_device *pdev) | |||
2035 | static int coda_remove(struct platform_device *pdev) | 2078 | static int coda_remove(struct platform_device *pdev) |
2036 | { | 2079 | { |
2037 | struct coda_dev *dev = platform_get_drvdata(pdev); | 2080 | struct coda_dev *dev = platform_get_drvdata(pdev); |
2081 | int i; | ||
2038 | 2082 | ||
2039 | video_unregister_device(&dev->vfd[0]); | 2083 | for (i = 0; i < ARRAY_SIZE(dev->vfd); i++) { |
2040 | video_unregister_device(&dev->vfd[1]); | 2084 | if (video_get_drvdata(&dev->vfd[i])) |
2085 | video_unregister_device(&dev->vfd[i]); | ||
2086 | } | ||
2041 | if (dev->m2m_dev) | 2087 | if (dev->m2m_dev) |
2042 | v4l2_m2m_release(dev->m2m_dev); | 2088 | v4l2_m2m_release(dev->m2m_dev); |
2043 | pm_runtime_disable(&pdev->dev); | 2089 | pm_runtime_disable(&pdev->dev); |
diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 76ba83c03191..07eaf58303ef 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h | |||
@@ -45,11 +45,15 @@ enum coda_product { | |||
45 | CODA_960 = 0xf020, | 45 | CODA_960 = 0xf020, |
46 | }; | 46 | }; |
47 | 47 | ||
48 | struct coda_video_device; | ||
49 | |||
48 | struct coda_devtype { | 50 | struct coda_devtype { |
49 | char *firmware; | 51 | char *firmware; |
50 | enum coda_product product; | 52 | enum coda_product product; |
51 | const struct coda_codec *codecs; | 53 | const struct coda_codec *codecs; |
52 | unsigned int num_codecs; | 54 | unsigned int num_codecs; |
55 | const struct coda_video_device **vdevs; | ||
56 | unsigned int num_vdevs; | ||
53 | size_t workbuf_size; | 57 | size_t workbuf_size; |
54 | size_t tempbuf_size; | 58 | size_t tempbuf_size; |
55 | size_t iram_size; | 59 | size_t iram_size; |
@@ -65,7 +69,7 @@ struct coda_aux_buf { | |||
65 | 69 | ||
66 | struct coda_dev { | 70 | struct coda_dev { |
67 | struct v4l2_device v4l2_dev; | 71 | struct v4l2_device v4l2_dev; |
68 | struct video_device vfd[2]; | 72 | struct video_device vfd[3]; |
69 | struct platform_device *plat_dev; | 73 | struct platform_device *plat_dev; |
70 | const struct coda_devtype *devtype; | 74 | const struct coda_devtype *devtype; |
71 | 75 | ||
@@ -183,6 +187,7 @@ struct coda_ctx { | |||
183 | struct work_struct pic_run_work; | 187 | struct work_struct pic_run_work; |
184 | struct work_struct seq_end_work; | 188 | struct work_struct seq_end_work; |
185 | struct completion completion; | 189 | struct completion completion; |
190 | const struct coda_video_device *cvd; | ||
186 | const struct coda_context_ops *ops; | 191 | const struct coda_context_ops *ops; |
187 | int aborting; | 192 | int aborting; |
188 | int initialized; | 193 | int initialized; |