aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/s5p-tv/mixer_video.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/s5p-tv/mixer_video.c')
-rw-r--r--drivers/media/video/s5p-tv/mixer_video.c342
1 files changed, 222 insertions, 120 deletions
diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c
index b47d0c06ecf5..7884baeff76a 100644
--- a/drivers/media/video/s5p-tv/mixer_video.c
+++ b/drivers/media/video/s5p-tv/mixer_video.c
@@ -170,18 +170,22 @@ static int mxr_querycap(struct file *file, void *priv,
170 return 0; 170 return 0;
171} 171}
172 172
173/* Geometry handling */ 173static void mxr_geometry_dump(struct mxr_device *mdev, struct mxr_geometry *geo)
174static void mxr_layer_geo_fix(struct mxr_layer *layer)
175{ 174{
176 struct mxr_device *mdev = layer->mdev; 175 mxr_dbg(mdev, "src.full_size = (%u, %u)\n",
177 struct v4l2_mbus_framefmt mbus_fmt; 176 geo->src.full_width, geo->src.full_height);
178 177 mxr_dbg(mdev, "src.size = (%u, %u)\n",
179 /* TODO: add some dirty flag to avoid unnecessary adjustments */ 178 geo->src.width, geo->src.height);
180 mxr_get_mbus_fmt(mdev, &mbus_fmt); 179 mxr_dbg(mdev, "src.offset = (%u, %u)\n",
181 layer->geo.dst.full_width = mbus_fmt.width; 180 geo->src.x_offset, geo->src.y_offset);
182 layer->geo.dst.full_height = mbus_fmt.height; 181 mxr_dbg(mdev, "dst.full_size = (%u, %u)\n",
183 layer->geo.dst.field = mbus_fmt.field; 182 geo->dst.full_width, geo->dst.full_height);
184 layer->ops.fix_geometry(layer); 183 mxr_dbg(mdev, "dst.size = (%u, %u)\n",
184 geo->dst.width, geo->dst.height);
185 mxr_dbg(mdev, "dst.offset = (%u, %u)\n",
186 geo->dst.x_offset, geo->dst.y_offset);
187 mxr_dbg(mdev, "ratio = (%u, %u)\n",
188 geo->x_ratio, geo->y_ratio);
185} 189}
186 190
187static void mxr_layer_default_geo(struct mxr_layer *layer) 191static void mxr_layer_default_geo(struct mxr_layer *layer)
@@ -204,27 +208,29 @@ static void mxr_layer_default_geo(struct mxr_layer *layer)
204 layer->geo.src.width = layer->geo.src.full_width; 208 layer->geo.src.width = layer->geo.src.full_width;
205 layer->geo.src.height = layer->geo.src.full_height; 209 layer->geo.src.height = layer->geo.src.full_height;
206 210
207 layer->ops.fix_geometry(layer); 211 mxr_geometry_dump(mdev, &layer->geo);
212 layer->ops.fix_geometry(layer, MXR_GEOMETRY_SINK, 0);
213 mxr_geometry_dump(mdev, &layer->geo);
208} 214}
209 215
210static void mxr_geometry_dump(struct mxr_device *mdev, struct mxr_geometry *geo) 216static void mxr_layer_update_output(struct mxr_layer *layer)
211{ 217{
212 mxr_dbg(mdev, "src.full_size = (%u, %u)\n", 218 struct mxr_device *mdev = layer->mdev;
213 geo->src.full_width, geo->src.full_height); 219 struct v4l2_mbus_framefmt mbus_fmt;
214 mxr_dbg(mdev, "src.size = (%u, %u)\n", 220
215 geo->src.width, geo->src.height); 221 mxr_get_mbus_fmt(mdev, &mbus_fmt);
216 mxr_dbg(mdev, "src.offset = (%u, %u)\n", 222 /* checking if update is needed */
217 geo->src.x_offset, geo->src.y_offset); 223 if (layer->geo.dst.full_width == mbus_fmt.width &&
218 mxr_dbg(mdev, "dst.full_size = (%u, %u)\n", 224 layer->geo.dst.full_height == mbus_fmt.width)
219 geo->dst.full_width, geo->dst.full_height); 225 return;
220 mxr_dbg(mdev, "dst.size = (%u, %u)\n",
221 geo->dst.width, geo->dst.height);
222 mxr_dbg(mdev, "dst.offset = (%u, %u)\n",
223 geo->dst.x_offset, geo->dst.y_offset);
224 mxr_dbg(mdev, "ratio = (%u, %u)\n",
225 geo->x_ratio, geo->y_ratio);
226}
227 226
227 layer->geo.dst.full_width = mbus_fmt.width;
228 layer->geo.dst.full_height = mbus_fmt.height;
229 layer->geo.dst.field = mbus_fmt.field;
230 layer->ops.fix_geometry(layer, MXR_GEOMETRY_SINK, 0);
231
232 mxr_geometry_dump(mdev, &layer->geo);
233}
228 234
229static const struct mxr_format *find_format_by_fourcc( 235static const struct mxr_format *find_format_by_fourcc(
230 struct mxr_layer *layer, unsigned long fourcc); 236 struct mxr_layer *layer, unsigned long fourcc);
@@ -249,37 +255,6 @@ static int mxr_enum_fmt(struct file *file, void *priv,
249 return 0; 255 return 0;
250} 256}
251 257
252static int mxr_s_fmt(struct file *file, void *priv,
253 struct v4l2_format *f)
254{
255 struct mxr_layer *layer = video_drvdata(file);
256 const struct mxr_format *fmt;
257 struct v4l2_pix_format_mplane *pix;
258 struct mxr_device *mdev = layer->mdev;
259 struct mxr_geometry *geo = &layer->geo;
260
261 mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
262
263 pix = &f->fmt.pix_mp;
264 fmt = find_format_by_fourcc(layer, pix->pixelformat);
265 if (fmt == NULL) {
266 mxr_warn(mdev, "not recognized fourcc: %08x\n",
267 pix->pixelformat);
268 return -EINVAL;
269 }
270 layer->fmt = fmt;
271 geo->src.full_width = pix->width;
272 geo->src.width = pix->width;
273 geo->src.full_height = pix->height;
274 geo->src.height = pix->height;
275 /* assure consistency of geometry */
276 mxr_layer_geo_fix(layer);
277 mxr_dbg(mdev, "width=%u height=%u span=%u\n",
278 geo->src.width, geo->src.height, geo->src.full_width);
279
280 return 0;
281}
282
283static unsigned int divup(unsigned int divident, unsigned int divisor) 258static unsigned int divup(unsigned int divident, unsigned int divisor)
284{ 259{
285 return (divident + divisor - 1) / divisor; 260 return (divident + divisor - 1) / divisor;
@@ -299,6 +274,10 @@ static void mxr_mplane_fill(struct v4l2_plane_pix_format *planes,
299{ 274{
300 int i; 275 int i;
301 276
277 /* checking if nothing to fill */
278 if (!planes)
279 return;
280
302 memset(planes, 0, sizeof(*planes) * fmt->num_subframes); 281 memset(planes, 0, sizeof(*planes) * fmt->num_subframes);
303 for (i = 0; i < fmt->num_planes; ++i) { 282 for (i = 0; i < fmt->num_planes; ++i) {
304 struct v4l2_plane_pix_format *plane = planes 283 struct v4l2_plane_pix_format *plane = planes
@@ -332,73 +311,194 @@ static int mxr_g_fmt(struct file *file, void *priv,
332 return 0; 311 return 0;
333} 312}
334 313
335static inline struct mxr_crop *choose_crop_by_type(struct mxr_geometry *geo, 314static int mxr_s_fmt(struct file *file, void *priv,
336 enum v4l2_buf_type type) 315 struct v4l2_format *f)
337{
338 switch (type) {
339 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
340 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
341 return &geo->dst;
342 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
343 return &geo->src;
344 default:
345 return NULL;
346 }
347}
348
349static int mxr_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
350{ 316{
351 struct mxr_layer *layer = video_drvdata(file); 317 struct mxr_layer *layer = video_drvdata(file);
352 struct mxr_crop *crop; 318 const struct mxr_format *fmt;
319 struct v4l2_pix_format_mplane *pix;
320 struct mxr_device *mdev = layer->mdev;
321 struct mxr_geometry *geo = &layer->geo;
353 322
354 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__); 323 mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
355 crop = choose_crop_by_type(&layer->geo, a->type); 324
356 if (crop == NULL) 325 pix = &f->fmt.pix_mp;
326 fmt = find_format_by_fourcc(layer, pix->pixelformat);
327 if (fmt == NULL) {
328 mxr_warn(mdev, "not recognized fourcc: %08x\n",
329 pix->pixelformat);
357 return -EINVAL; 330 return -EINVAL;
358 mxr_layer_geo_fix(layer); 331 }
359 a->c.left = crop->x_offset; 332 layer->fmt = fmt;
360 a->c.top = crop->y_offset; 333 /* set source size to highest accepted value */
361 a->c.width = crop->width; 334 geo->src.full_width = max(geo->dst.full_width, pix->width);
362 a->c.height = crop->height; 335 geo->src.full_height = max(geo->dst.full_height, pix->height);
336 layer->ops.fix_geometry(layer, MXR_GEOMETRY_SOURCE, 0);
337 mxr_geometry_dump(mdev, &layer->geo);
338 /* set cropping to total visible screen */
339 geo->src.width = pix->width;
340 geo->src.height = pix->height;
341 geo->src.x_offset = 0;
342 geo->src.y_offset = 0;
343 /* assure consistency of geometry */
344 layer->ops.fix_geometry(layer, MXR_GEOMETRY_CROP, MXR_NO_OFFSET);
345 mxr_geometry_dump(mdev, &layer->geo);
346 /* set full size to lowest possible value */
347 geo->src.full_width = 0;
348 geo->src.full_height = 0;
349 layer->ops.fix_geometry(layer, MXR_GEOMETRY_SOURCE, 0);
350 mxr_geometry_dump(mdev, &layer->geo);
351
352 /* returning results */
353 mxr_g_fmt(file, priv, f);
354
363 return 0; 355 return 0;
364} 356}
365 357
366static int mxr_s_crop(struct file *file, void *fh, struct v4l2_crop *a) 358static int mxr_g_selection(struct file *file, void *fh,
359 struct v4l2_selection *s)
367{ 360{
368 struct mxr_layer *layer = video_drvdata(file); 361 struct mxr_layer *layer = video_drvdata(file);
369 struct mxr_crop *crop; 362 struct mxr_geometry *geo = &layer->geo;
370 363
371 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__); 364 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
372 crop = choose_crop_by_type(&layer->geo, a->type); 365
373 if (crop == NULL) 366 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
367 s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
368 return -EINVAL;
369
370 switch (s->target) {
371 case V4L2_SEL_TGT_CROP_ACTIVE:
372 s->r.left = geo->src.x_offset;
373 s->r.top = geo->src.y_offset;
374 s->r.width = geo->src.width;
375 s->r.height = geo->src.height;
376 break;
377 case V4L2_SEL_TGT_CROP_DEFAULT:
378 case V4L2_SEL_TGT_CROP_BOUNDS:
379 s->r.left = 0;
380 s->r.top = 0;
381 s->r.width = geo->src.full_width;
382 s->r.height = geo->src.full_height;
383 break;
384 case V4L2_SEL_TGT_COMPOSE_ACTIVE:
385 case V4L2_SEL_TGT_COMPOSE_PADDED:
386 s->r.left = geo->dst.x_offset;
387 s->r.top = geo->dst.y_offset;
388 s->r.width = geo->dst.width;
389 s->r.height = geo->dst.height;
390 break;
391 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
392 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
393 s->r.left = 0;
394 s->r.top = 0;
395 s->r.width = geo->dst.full_width;
396 s->r.height = geo->dst.full_height;
397 break;
398 default:
374 return -EINVAL; 399 return -EINVAL;
375 crop->x_offset = a->c.left; 400 }
376 crop->y_offset = a->c.top; 401
377 crop->width = a->c.width;
378 crop->height = a->c.height;
379 mxr_layer_geo_fix(layer);
380 return 0; 402 return 0;
381} 403}
382 404
383static int mxr_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a) 405/* returns 1 if rectangle 'a' is inside 'b' */
406static int mxr_is_rect_inside(struct v4l2_rect *a, struct v4l2_rect *b)
407{
408 if (a->left < b->left)
409 return 0;
410 if (a->top < b->top)
411 return 0;
412 if (a->left + a->width > b->left + b->width)
413 return 0;
414 if (a->top + a->height > b->top + b->height)
415 return 0;
416 return 1;
417}
418
419static int mxr_s_selection(struct file *file, void *fh,
420 struct v4l2_selection *s)
384{ 421{
385 struct mxr_layer *layer = video_drvdata(file); 422 struct mxr_layer *layer = video_drvdata(file);
386 struct mxr_crop *crop; 423 struct mxr_geometry *geo = &layer->geo;
424 struct mxr_crop *target = NULL;
425 enum mxr_geometry_stage stage;
426 struct mxr_geometry tmp;
427 struct v4l2_rect res;
387 428
388 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__); 429 memset(&res, 0, sizeof res);
389 crop = choose_crop_by_type(&layer->geo, a->type); 430
390 if (crop == NULL) 431 mxr_dbg(layer->mdev, "%s: rect: %dx%d@%d,%d\n", __func__,
432 s->r.width, s->r.height, s->r.left, s->r.top);
433
434 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
435 s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
391 return -EINVAL; 436 return -EINVAL;
392 mxr_layer_geo_fix(layer); 437
393 a->bounds.left = 0; 438 switch (s->target) {
394 a->bounds.top = 0; 439 /* ignore read-only targets */
395 a->bounds.width = crop->full_width; 440 case V4L2_SEL_TGT_CROP_DEFAULT:
396 a->bounds.top = crop->full_height; 441 case V4L2_SEL_TGT_CROP_BOUNDS:
397 a->defrect = a->bounds; 442 res.width = geo->src.full_width;
398 /* setting pixel aspect to 1/1 */ 443 res.height = geo->src.full_height;
399 a->pixelaspect.numerator = 1; 444 break;
400 a->pixelaspect.denominator = 1; 445
446 /* ignore read-only targets */
447 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
448 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
449 res.width = geo->dst.full_width;
450 res.height = geo->dst.full_height;
451 break;
452
453 case V4L2_SEL_TGT_CROP_ACTIVE:
454 target = &geo->src;
455 stage = MXR_GEOMETRY_CROP;
456 break;
457 case V4L2_SEL_TGT_COMPOSE_ACTIVE:
458 case V4L2_SEL_TGT_COMPOSE_PADDED:
459 target = &geo->dst;
460 stage = MXR_GEOMETRY_COMPOSE;
461 break;
462 default:
463 return -EINVAL;
464 }
465 /* apply change and update geometry if needed */
466 if (target) {
467 /* backup current geometry if setup fails */
468 memcpy(&tmp, geo, sizeof tmp);
469
470 /* apply requested selection */
471 target->x_offset = s->r.left;
472 target->y_offset = s->r.top;
473 target->width = s->r.width;
474 target->height = s->r.height;
475
476 layer->ops.fix_geometry(layer, stage, s->flags);
477
478 /* retrieve update selection rectangle */
479 res.left = target->x_offset;
480 res.top = target->y_offset;
481 res.width = target->width;
482 res.height = target->height;
483
484 mxr_geometry_dump(layer->mdev, &layer->geo);
485 }
486
487 /* checking if the rectangle satisfies constraints */
488 if ((s->flags & V4L2_SEL_FLAG_LE) && !mxr_is_rect_inside(&res, &s->r))
489 goto fail;
490 if ((s->flags & V4L2_SEL_FLAG_GE) && !mxr_is_rect_inside(&s->r, &res))
491 goto fail;
492
493 /* return result rectangle */
494 s->r = res;
495
401 return 0; 496 return 0;
497fail:
498 /* restore old geometry, which is not touched if target is NULL */
499 if (target)
500 memcpy(geo, &tmp, sizeof tmp);
501 return -ERANGE;
402} 502}
403 503
404static int mxr_enum_dv_presets(struct file *file, void *fh, 504static int mxr_enum_dv_presets(struct file *file, void *fh,
@@ -438,6 +538,8 @@ static int mxr_s_dv_preset(struct file *file, void *fh,
438 538
439 mutex_unlock(&mdev->mutex); 539 mutex_unlock(&mdev->mutex);
440 540
541 mxr_layer_update_output(layer);
542
441 /* any failure should return EINVAL according to V4L2 doc */ 543 /* any failure should return EINVAL according to V4L2 doc */
442 return ret ? -EINVAL : 0; 544 return ret ? -EINVAL : 0;
443} 545}
@@ -478,6 +580,8 @@ static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm)
478 580
479 mutex_unlock(&mdev->mutex); 581 mutex_unlock(&mdev->mutex);
480 582
583 mxr_layer_update_output(layer);
584
481 return ret ? -EINVAL : 0; 585 return ret ? -EINVAL : 0;
482} 586}
483 587
@@ -526,25 +630,27 @@ static int mxr_s_output(struct file *file, void *fh, unsigned int i)
526 struct video_device *vfd = video_devdata(file); 630 struct video_device *vfd = video_devdata(file);
527 struct mxr_layer *layer = video_drvdata(file); 631 struct mxr_layer *layer = video_drvdata(file);
528 struct mxr_device *mdev = layer->mdev; 632 struct mxr_device *mdev = layer->mdev;
529 int ret = 0;
530 633
531 if (i >= mdev->output_cnt || mdev->output[i] == NULL) 634 if (i >= mdev->output_cnt || mdev->output[i] == NULL)
532 return -EINVAL; 635 return -EINVAL;
533 636
534 mutex_lock(&mdev->mutex); 637 mutex_lock(&mdev->mutex);
535 if (mdev->n_output > 0) { 638 if (mdev->n_output > 0) {
536 ret = -EBUSY; 639 mutex_unlock(&mdev->mutex);
537 goto done; 640 return -EBUSY;
538 } 641 }
539 mdev->current_output = i; 642 mdev->current_output = i;
540 vfd->tvnorms = 0; 643 vfd->tvnorms = 0;
541 v4l2_subdev_call(to_outsd(mdev), video, g_tvnorms_output, 644 v4l2_subdev_call(to_outsd(mdev), video, g_tvnorms_output,
542 &vfd->tvnorms); 645 &vfd->tvnorms);
646 mutex_unlock(&mdev->mutex);
647
648 /* update layers geometry */
649 mxr_layer_update_output(layer);
650
543 mxr_dbg(mdev, "tvnorms = %08llx\n", vfd->tvnorms); 651 mxr_dbg(mdev, "tvnorms = %08llx\n", vfd->tvnorms);
544 652
545done: 653 return 0;
546 mutex_unlock(&mdev->mutex);
547 return ret;
548} 654}
549 655
550static int mxr_g_output(struct file *file, void *fh, unsigned int *p) 656static int mxr_g_output(struct file *file, void *fh, unsigned int *p)
@@ -633,10 +739,9 @@ static const struct v4l2_ioctl_ops mxr_ioctl_ops = {
633 .vidioc_enum_output = mxr_enum_output, 739 .vidioc_enum_output = mxr_enum_output,
634 .vidioc_s_output = mxr_s_output, 740 .vidioc_s_output = mxr_s_output,
635 .vidioc_g_output = mxr_g_output, 741 .vidioc_g_output = mxr_g_output,
636 /* Crop ioctls */ 742 /* selection ioctls */
637 .vidioc_g_crop = mxr_g_crop, 743 .vidioc_g_selection = mxr_g_selection,
638 .vidioc_s_crop = mxr_s_crop, 744 .vidioc_s_selection = mxr_s_selection,
639 .vidioc_cropcap = mxr_cropcap,
640}; 745};
641 746
642static int mxr_video_open(struct file *file) 747static int mxr_video_open(struct file *file)
@@ -805,10 +910,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
805 /* block any changes in output configuration */ 910 /* block any changes in output configuration */
806 mxr_output_get(mdev); 911 mxr_output_get(mdev);
807 912
808 /* update layers geometry */ 913 mxr_layer_update_output(layer);
809 mxr_layer_geo_fix(layer);
810 mxr_geometry_dump(mdev, &layer->geo);
811
812 layer->ops.format_set(layer); 914 layer->ops.format_set(layer);
813 /* enabling layer in hardware */ 915 /* enabling layer in hardware */
814 spin_lock_irqsave(&layer->enq_slock, flags); 916 spin_lock_irqsave(&layer->enq_slock, flags);