| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0+ |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * V4L2 Capture IC Preprocess Subdev for Freescale i.MX5/6 SOC |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 6 | 7 | * for resizing, colorspace conversion, and rotation. |
|---|
| 7 | 8 | * |
|---|
| 8 | 9 | * Copyright (c) 2012-2017 Mentor Graphics Inc. |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 11 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 12 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 13 | | - * (at your option) any later version. |
|---|
| 14 | 10 | */ |
|---|
| 15 | 11 | #include <linux/delay.h> |
|---|
| 16 | 12 | #include <linux/interrupt.h> |
|---|
| .. | .. |
|---|
| 39 | 35 | * has not requested a planar format, we should allow 8 pixel |
|---|
| 40 | 36 | * alignment at the source pad. |
|---|
| 41 | 37 | */ |
|---|
| 42 | | -#define MIN_W_SINK 176 |
|---|
| 43 | | -#define MIN_H_SINK 144 |
|---|
| 38 | +#define MIN_W_SINK 32 |
|---|
| 39 | +#define MIN_H_SINK 32 |
|---|
| 44 | 40 | #define MAX_W_SINK 4096 |
|---|
| 45 | 41 | #define MAX_H_SINK 4096 |
|---|
| 46 | 42 | #define W_ALIGN_SINK 3 /* multiple of 8 pixels */ |
|---|
| .. | .. |
|---|
| 48 | 44 | |
|---|
| 49 | 45 | #define MAX_W_SRC 1024 |
|---|
| 50 | 46 | #define MAX_H_SRC 1024 |
|---|
| 51 | | -#define W_ALIGN_SRC 4 /* multiple of 16 pixels */ |
|---|
| 47 | +#define W_ALIGN_SRC 1 /* multiple of 2 pixels */ |
|---|
| 52 | 48 | #define H_ALIGN_SRC 1 /* multiple of 2 lines */ |
|---|
| 53 | 49 | |
|---|
| 54 | 50 | #define S_ALIGN 1 /* multiple of 2 */ |
|---|
| 55 | 51 | |
|---|
| 56 | 52 | struct prp_priv { |
|---|
| 57 | | - struct imx_media_dev *md; |
|---|
| 58 | 53 | struct imx_ic_priv *ic_priv; |
|---|
| 59 | 54 | struct media_pad pad[PRPENCVF_NUM_PADS]; |
|---|
| 60 | 55 | /* the video device at output pad */ |
|---|
| .. | .. |
|---|
| 64 | 59 | struct mutex lock; |
|---|
| 65 | 60 | |
|---|
| 66 | 61 | /* IPU units we require */ |
|---|
| 67 | | - struct ipu_soc *ipu; |
|---|
| 68 | 62 | struct ipu_ic *ic; |
|---|
| 69 | 63 | struct ipuv3_channel *out_ch; |
|---|
| 70 | 64 | struct ipuv3_channel *rot_in_ch; |
|---|
| .. | .. |
|---|
| 106 | 100 | u32 frame_sequence; /* frame sequence counter */ |
|---|
| 107 | 101 | bool last_eof; /* waiting for last EOF at stream off */ |
|---|
| 108 | 102 | bool nfb4eof; /* NFB4EOF encountered during streaming */ |
|---|
| 103 | + bool interweave_swap; /* swap top/bottom lines when interweaving */ |
|---|
| 109 | 104 | struct completion last_eof_comp; |
|---|
| 110 | 105 | }; |
|---|
| 111 | 106 | |
|---|
| .. | .. |
|---|
| 159 | 154 | struct ipuv3_channel *out_ch, *rot_in_ch, *rot_out_ch; |
|---|
| 160 | 155 | int ret, task = ic_priv->task_id; |
|---|
| 161 | 156 | |
|---|
| 162 | | - priv->ipu = priv->md->ipu[ic_priv->ipu_id]; |
|---|
| 163 | | - |
|---|
| 164 | | - ic = ipu_ic_get(priv->ipu, task); |
|---|
| 157 | + ic = ipu_ic_get(ic_priv->ipu, task); |
|---|
| 165 | 158 | if (IS_ERR(ic)) { |
|---|
| 166 | 159 | v4l2_err(&ic_priv->sd, "failed to get IC\n"); |
|---|
| 167 | 160 | ret = PTR_ERR(ic); |
|---|
| .. | .. |
|---|
| 169 | 162 | } |
|---|
| 170 | 163 | priv->ic = ic; |
|---|
| 171 | 164 | |
|---|
| 172 | | - out_ch = ipu_idmac_get(priv->ipu, prp_channel[task].out_ch); |
|---|
| 165 | + out_ch = ipu_idmac_get(ic_priv->ipu, prp_channel[task].out_ch); |
|---|
| 173 | 166 | if (IS_ERR(out_ch)) { |
|---|
| 174 | 167 | v4l2_err(&ic_priv->sd, "could not get IDMAC channel %u\n", |
|---|
| 175 | 168 | prp_channel[task].out_ch); |
|---|
| .. | .. |
|---|
| 178 | 171 | } |
|---|
| 179 | 172 | priv->out_ch = out_ch; |
|---|
| 180 | 173 | |
|---|
| 181 | | - rot_in_ch = ipu_idmac_get(priv->ipu, prp_channel[task].rot_in_ch); |
|---|
| 174 | + rot_in_ch = ipu_idmac_get(ic_priv->ipu, prp_channel[task].rot_in_ch); |
|---|
| 182 | 175 | if (IS_ERR(rot_in_ch)) { |
|---|
| 183 | 176 | v4l2_err(&ic_priv->sd, "could not get IDMAC channel %u\n", |
|---|
| 184 | 177 | prp_channel[task].rot_in_ch); |
|---|
| .. | .. |
|---|
| 187 | 180 | } |
|---|
| 188 | 181 | priv->rot_in_ch = rot_in_ch; |
|---|
| 189 | 182 | |
|---|
| 190 | | - rot_out_ch = ipu_idmac_get(priv->ipu, prp_channel[task].rot_out_ch); |
|---|
| 183 | + rot_out_ch = ipu_idmac_get(ic_priv->ipu, prp_channel[task].rot_out_ch); |
|---|
| 191 | 184 | if (IS_ERR(rot_out_ch)) { |
|---|
| 192 | 185 | v4l2_err(&ic_priv->sd, "could not get IDMAC channel %u\n", |
|---|
| 193 | 186 | prp_channel[task].rot_out_ch); |
|---|
| .. | .. |
|---|
| 234 | 227 | |
|---|
| 235 | 228 | if (ipu_idmac_buffer_is_ready(ch, priv->ipu_buf_num)) |
|---|
| 236 | 229 | ipu_idmac_clear_buffer(ch, priv->ipu_buf_num); |
|---|
| 230 | + |
|---|
| 231 | + if (priv->interweave_swap && ch == priv->out_ch) |
|---|
| 232 | + phys += vdev->fmt.fmt.pix.bytesperline; |
|---|
| 237 | 233 | |
|---|
| 238 | 234 | ipu_cpmem_set_buffer(ch, priv->ipu_buf_num, phys); |
|---|
| 239 | 235 | } |
|---|
| .. | .. |
|---|
| 354 | 350 | { |
|---|
| 355 | 351 | struct imx_media_video_dev *vdev = priv->vdev; |
|---|
| 356 | 352 | const struct imx_media_pixfmt *outcc; |
|---|
| 357 | | - struct v4l2_mbus_framefmt *infmt; |
|---|
| 353 | + struct v4l2_mbus_framefmt *outfmt; |
|---|
| 358 | 354 | unsigned int burst_size; |
|---|
| 359 | 355 | struct ipu_image image; |
|---|
| 356 | + bool interweave; |
|---|
| 360 | 357 | int ret; |
|---|
| 361 | 358 | |
|---|
| 362 | | - infmt = &priv->format_mbus[PRPENCVF_SINK_PAD]; |
|---|
| 359 | + outfmt = &priv->format_mbus[PRPENCVF_SRC_PAD]; |
|---|
| 363 | 360 | outcc = vdev->cc; |
|---|
| 364 | 361 | |
|---|
| 365 | 362 | ipu_cpmem_zero(channel); |
|---|
| 366 | 363 | |
|---|
| 367 | 364 | memset(&image, 0, sizeof(image)); |
|---|
| 368 | 365 | image.pix = vdev->fmt.fmt.pix; |
|---|
| 369 | | - image.rect.width = image.pix.width; |
|---|
| 370 | | - image.rect.height = image.pix.height; |
|---|
| 366 | + image.rect = vdev->compose; |
|---|
| 367 | + |
|---|
| 368 | + /* |
|---|
| 369 | + * If the field type at capture interface is interlaced, and |
|---|
| 370 | + * the output IDMAC pad is sequential, enable interweave at |
|---|
| 371 | + * the IDMAC output channel. |
|---|
| 372 | + */ |
|---|
| 373 | + interweave = V4L2_FIELD_IS_INTERLACED(image.pix.field) && |
|---|
| 374 | + V4L2_FIELD_IS_SEQUENTIAL(outfmt->field); |
|---|
| 375 | + priv->interweave_swap = interweave && |
|---|
| 376 | + image.pix.field == V4L2_FIELD_INTERLACED_BT; |
|---|
| 371 | 377 | |
|---|
| 372 | 378 | if (rot_swap_width_height) { |
|---|
| 373 | 379 | swap(image.pix.width, image.pix.height); |
|---|
| .. | .. |
|---|
| 378 | 384 | (image.pix.width * outcc->bpp) >> 3; |
|---|
| 379 | 385 | } |
|---|
| 380 | 386 | |
|---|
| 387 | + if (priv->interweave_swap && channel == priv->out_ch) { |
|---|
| 388 | + /* start interweave scan at 1st top line (2nd line) */ |
|---|
| 389 | + image.rect.top = 1; |
|---|
| 390 | + } |
|---|
| 391 | + |
|---|
| 381 | 392 | image.phys0 = addr0; |
|---|
| 382 | 393 | image.phys1 = addr1; |
|---|
| 383 | 394 | |
|---|
| 384 | | - if (channel == priv->out_ch || channel == priv->rot_out_ch) { |
|---|
| 395 | + /* |
|---|
| 396 | + * Skip writing U and V components to odd rows in the output |
|---|
| 397 | + * channels for planar 4:2:0 (but not when enabling IDMAC |
|---|
| 398 | + * interweaving, they are incompatible). |
|---|
| 399 | + */ |
|---|
| 400 | + if ((channel == priv->out_ch && !interweave) || |
|---|
| 401 | + channel == priv->rot_out_ch) { |
|---|
| 385 | 402 | switch (image.pix.pixelformat) { |
|---|
| 386 | 403 | case V4L2_PIX_FMT_YUV420: |
|---|
| 387 | 404 | case V4L2_PIX_FMT_YVU420: |
|---|
| 388 | 405 | case V4L2_PIX_FMT_NV12: |
|---|
| 389 | | - /* Skip writing U and V components to odd rows */ |
|---|
| 390 | 406 | ipu_cpmem_skip_odd_chroma_rows(channel); |
|---|
| 391 | 407 | break; |
|---|
| 392 | 408 | } |
|---|
| .. | .. |
|---|
| 409 | 425 | if (rot_mode) |
|---|
| 410 | 426 | ipu_cpmem_set_rotation(channel, rot_mode); |
|---|
| 411 | 427 | |
|---|
| 412 | | - if (image.pix.field == V4L2_FIELD_NONE && |
|---|
| 413 | | - V4L2_FIELD_HAS_BOTH(infmt->field) && |
|---|
| 414 | | - channel == priv->out_ch) |
|---|
| 415 | | - ipu_cpmem_interlaced_scan(channel, image.pix.bytesperline); |
|---|
| 428 | + if (interweave && channel == priv->out_ch) |
|---|
| 429 | + ipu_cpmem_interlaced_scan(channel, |
|---|
| 430 | + priv->interweave_swap ? |
|---|
| 431 | + -image.pix.bytesperline : |
|---|
| 432 | + image.pix.bytesperline, |
|---|
| 433 | + image.pix.pixelformat); |
|---|
| 416 | 434 | |
|---|
| 417 | 435 | ret = ipu_ic_task_idma_init(priv->ic, channel, |
|---|
| 418 | 436 | image.pix.width, image.pix.height, |
|---|
| .. | .. |
|---|
| 434 | 452 | const struct imx_media_pixfmt *outcc, *incc; |
|---|
| 435 | 453 | struct v4l2_mbus_framefmt *infmt; |
|---|
| 436 | 454 | struct v4l2_pix_format *outfmt; |
|---|
| 455 | + struct ipu_ic_csc csc; |
|---|
| 437 | 456 | dma_addr_t phys[2]; |
|---|
| 438 | 457 | int ret; |
|---|
| 439 | 458 | |
|---|
| .. | .. |
|---|
| 442 | 461 | incc = priv->cc[PRPENCVF_SINK_PAD]; |
|---|
| 443 | 462 | outcc = vdev->cc; |
|---|
| 444 | 463 | |
|---|
| 445 | | - ret = imx_media_alloc_dma_buf(priv->md, &priv->rot_buf[0], |
|---|
| 464 | + ret = ipu_ic_calc_csc(&csc, |
|---|
| 465 | + infmt->ycbcr_enc, infmt->quantization, |
|---|
| 466 | + incc->cs, |
|---|
| 467 | + outfmt->ycbcr_enc, outfmt->quantization, |
|---|
| 468 | + outcc->cs); |
|---|
| 469 | + if (ret) { |
|---|
| 470 | + v4l2_err(&ic_priv->sd, "ipu_ic_calc_csc failed, %d\n", |
|---|
| 471 | + ret); |
|---|
| 472 | + return ret; |
|---|
| 473 | + } |
|---|
| 474 | + |
|---|
| 475 | + ret = imx_media_alloc_dma_buf(ic_priv->ipu_dev, &priv->rot_buf[0], |
|---|
| 446 | 476 | outfmt->sizeimage); |
|---|
| 447 | 477 | if (ret) { |
|---|
| 448 | 478 | v4l2_err(&ic_priv->sd, "failed to alloc rot_buf[0], %d\n", ret); |
|---|
| 449 | 479 | return ret; |
|---|
| 450 | 480 | } |
|---|
| 451 | | - ret = imx_media_alloc_dma_buf(priv->md, &priv->rot_buf[1], |
|---|
| 481 | + ret = imx_media_alloc_dma_buf(ic_priv->ipu_dev, &priv->rot_buf[1], |
|---|
| 452 | 482 | outfmt->sizeimage); |
|---|
| 453 | 483 | if (ret) { |
|---|
| 454 | 484 | v4l2_err(&ic_priv->sd, "failed to alloc rot_buf[1], %d\n", ret); |
|---|
| 455 | 485 | goto free_rot0; |
|---|
| 456 | 486 | } |
|---|
| 457 | 487 | |
|---|
| 458 | | - ret = ipu_ic_task_init(priv->ic, |
|---|
| 488 | + ret = ipu_ic_task_init(priv->ic, &csc, |
|---|
| 459 | 489 | infmt->width, infmt->height, |
|---|
| 460 | | - outfmt->height, outfmt->width, |
|---|
| 461 | | - incc->cs, outcc->cs); |
|---|
| 490 | + outfmt->height, outfmt->width); |
|---|
| 462 | 491 | if (ret) { |
|---|
| 463 | 492 | v4l2_err(&ic_priv->sd, "ipu_ic_task_init failed, %d\n", ret); |
|---|
| 464 | 493 | goto free_rot1; |
|---|
| .. | .. |
|---|
| 521 | 550 | unsetup_vb2: |
|---|
| 522 | 551 | prp_unsetup_vb2_buf(priv, VB2_BUF_STATE_QUEUED); |
|---|
| 523 | 552 | free_rot1: |
|---|
| 524 | | - imx_media_free_dma_buf(priv->md, &priv->rot_buf[1]); |
|---|
| 553 | + imx_media_free_dma_buf(ic_priv->ipu_dev, &priv->rot_buf[1]); |
|---|
| 525 | 554 | free_rot0: |
|---|
| 526 | | - imx_media_free_dma_buf(priv->md, &priv->rot_buf[0]); |
|---|
| 555 | + imx_media_free_dma_buf(ic_priv->ipu_dev, &priv->rot_buf[0]); |
|---|
| 527 | 556 | return ret; |
|---|
| 528 | 557 | } |
|---|
| 529 | 558 | |
|---|
| 530 | 559 | static void prp_unsetup_rotation(struct prp_priv *priv) |
|---|
| 531 | 560 | { |
|---|
| 561 | + struct imx_ic_priv *ic_priv = priv->ic_priv; |
|---|
| 562 | + |
|---|
| 532 | 563 | ipu_ic_task_disable(priv->ic); |
|---|
| 533 | 564 | |
|---|
| 534 | 565 | ipu_idmac_disable_channel(priv->out_ch); |
|---|
| .. | .. |
|---|
| 539 | 570 | |
|---|
| 540 | 571 | ipu_ic_disable(priv->ic); |
|---|
| 541 | 572 | |
|---|
| 542 | | - imx_media_free_dma_buf(priv->md, &priv->rot_buf[0]); |
|---|
| 543 | | - imx_media_free_dma_buf(priv->md, &priv->rot_buf[1]); |
|---|
| 573 | + imx_media_free_dma_buf(ic_priv->ipu_dev, &priv->rot_buf[0]); |
|---|
| 574 | + imx_media_free_dma_buf(ic_priv->ipu_dev, &priv->rot_buf[1]); |
|---|
| 544 | 575 | } |
|---|
| 545 | 576 | |
|---|
| 546 | 577 | static int prp_setup_norotation(struct prp_priv *priv) |
|---|
| .. | .. |
|---|
| 550 | 581 | const struct imx_media_pixfmt *outcc, *incc; |
|---|
| 551 | 582 | struct v4l2_mbus_framefmt *infmt; |
|---|
| 552 | 583 | struct v4l2_pix_format *outfmt; |
|---|
| 584 | + struct ipu_ic_csc csc; |
|---|
| 553 | 585 | dma_addr_t phys[2]; |
|---|
| 554 | 586 | int ret; |
|---|
| 555 | 587 | |
|---|
| .. | .. |
|---|
| 558 | 590 | incc = priv->cc[PRPENCVF_SINK_PAD]; |
|---|
| 559 | 591 | outcc = vdev->cc; |
|---|
| 560 | 592 | |
|---|
| 561 | | - ret = ipu_ic_task_init(priv->ic, |
|---|
| 593 | + ret = ipu_ic_calc_csc(&csc, |
|---|
| 594 | + infmt->ycbcr_enc, infmt->quantization, |
|---|
| 595 | + incc->cs, |
|---|
| 596 | + outfmt->ycbcr_enc, outfmt->quantization, |
|---|
| 597 | + outcc->cs); |
|---|
| 598 | + if (ret) { |
|---|
| 599 | + v4l2_err(&ic_priv->sd, "ipu_ic_calc_csc failed, %d\n", |
|---|
| 600 | + ret); |
|---|
| 601 | + return ret; |
|---|
| 602 | + } |
|---|
| 603 | + |
|---|
| 604 | + ret = ipu_ic_task_init(priv->ic, &csc, |
|---|
| 562 | 605 | infmt->width, infmt->height, |
|---|
| 563 | | - outfmt->width, outfmt->height, |
|---|
| 564 | | - incc->cs, outcc->cs); |
|---|
| 606 | + outfmt->width, outfmt->height); |
|---|
| 565 | 607 | if (ret) { |
|---|
| 566 | 608 | v4l2_err(&ic_priv->sd, "ipu_ic_task_init failed, %d\n", ret); |
|---|
| 567 | 609 | return ret; |
|---|
| .. | .. |
|---|
| 580 | 622 | |
|---|
| 581 | 623 | ipu_cpmem_dump(priv->out_ch); |
|---|
| 582 | 624 | ipu_ic_dump(priv->ic); |
|---|
| 583 | | - ipu_dump(priv->ipu); |
|---|
| 625 | + ipu_dump(ic_priv->ipu); |
|---|
| 584 | 626 | |
|---|
| 585 | 627 | ipu_ic_enable(priv->ic); |
|---|
| 586 | 628 | |
|---|
| .. | .. |
|---|
| 632 | 674 | |
|---|
| 633 | 675 | outfmt = &vdev->fmt.fmt.pix; |
|---|
| 634 | 676 | |
|---|
| 635 | | - ret = imx_media_alloc_dma_buf(priv->md, &priv->underrun_buf, |
|---|
| 677 | + ret = imx_media_alloc_dma_buf(ic_priv->ipu_dev, &priv->underrun_buf, |
|---|
| 636 | 678 | outfmt->sizeimage); |
|---|
| 637 | 679 | if (ret) |
|---|
| 638 | 680 | goto out_put_ipu; |
|---|
| .. | .. |
|---|
| 652 | 694 | if (ret) |
|---|
| 653 | 695 | goto out_free_underrun; |
|---|
| 654 | 696 | |
|---|
| 655 | | - priv->nfb4eof_irq = ipu_idmac_channel_irq(priv->ipu, |
|---|
| 697 | + priv->nfb4eof_irq = ipu_idmac_channel_irq(ic_priv->ipu, |
|---|
| 656 | 698 | priv->out_ch, |
|---|
| 657 | 699 | IPU_IRQ_NFB4EOF); |
|---|
| 658 | | - ret = devm_request_irq(ic_priv->dev, priv->nfb4eof_irq, |
|---|
| 700 | + ret = devm_request_irq(ic_priv->ipu_dev, priv->nfb4eof_irq, |
|---|
| 659 | 701 | prp_nfb4eof_interrupt, 0, |
|---|
| 660 | 702 | "imx-ic-prp-nfb4eof", priv); |
|---|
| 661 | 703 | if (ret) { |
|---|
| .. | .. |
|---|
| 666 | 708 | |
|---|
| 667 | 709 | if (ipu_rot_mode_is_irt(priv->rot_mode)) |
|---|
| 668 | 710 | priv->eof_irq = ipu_idmac_channel_irq( |
|---|
| 669 | | - priv->ipu, priv->rot_out_ch, IPU_IRQ_EOF); |
|---|
| 711 | + ic_priv->ipu, priv->rot_out_ch, IPU_IRQ_EOF); |
|---|
| 670 | 712 | else |
|---|
| 671 | 713 | priv->eof_irq = ipu_idmac_channel_irq( |
|---|
| 672 | | - priv->ipu, priv->out_ch, IPU_IRQ_EOF); |
|---|
| 714 | + ic_priv->ipu, priv->out_ch, IPU_IRQ_EOF); |
|---|
| 673 | 715 | |
|---|
| 674 | | - ret = devm_request_irq(ic_priv->dev, priv->eof_irq, |
|---|
| 716 | + ret = devm_request_irq(ic_priv->ipu_dev, priv->eof_irq, |
|---|
| 675 | 717 | prp_eof_interrupt, 0, |
|---|
| 676 | 718 | "imx-ic-prp-eof", priv); |
|---|
| 677 | 719 | if (ret) { |
|---|
| .. | .. |
|---|
| 696 | 738 | return 0; |
|---|
| 697 | 739 | |
|---|
| 698 | 740 | out_free_eof_irq: |
|---|
| 699 | | - devm_free_irq(ic_priv->dev, priv->eof_irq, priv); |
|---|
| 741 | + devm_free_irq(ic_priv->ipu_dev, priv->eof_irq, priv); |
|---|
| 700 | 742 | out_free_nfb4eof_irq: |
|---|
| 701 | | - devm_free_irq(ic_priv->dev, priv->nfb4eof_irq, priv); |
|---|
| 743 | + devm_free_irq(ic_priv->ipu_dev, priv->nfb4eof_irq, priv); |
|---|
| 702 | 744 | out_unsetup: |
|---|
| 703 | 745 | prp_unsetup(priv, VB2_BUF_STATE_QUEUED); |
|---|
| 704 | 746 | out_free_underrun: |
|---|
| 705 | | - imx_media_free_dma_buf(priv->md, &priv->underrun_buf); |
|---|
| 747 | + imx_media_free_dma_buf(ic_priv->ipu_dev, &priv->underrun_buf); |
|---|
| 706 | 748 | out_put_ipu: |
|---|
| 707 | 749 | prp_put_ipu_resources(priv); |
|---|
| 708 | 750 | return ret; |
|---|
| .. | .. |
|---|
| 734 | 776 | v4l2_warn(&ic_priv->sd, |
|---|
| 735 | 777 | "upstream stream off failed: %d\n", ret); |
|---|
| 736 | 778 | |
|---|
| 737 | | - devm_free_irq(ic_priv->dev, priv->eof_irq, priv); |
|---|
| 738 | | - devm_free_irq(ic_priv->dev, priv->nfb4eof_irq, priv); |
|---|
| 779 | + devm_free_irq(ic_priv->ipu_dev, priv->eof_irq, priv); |
|---|
| 780 | + devm_free_irq(ic_priv->ipu_dev, priv->nfb4eof_irq, priv); |
|---|
| 739 | 781 | |
|---|
| 740 | 782 | prp_unsetup(priv, VB2_BUF_STATE_ERROR); |
|---|
| 741 | 783 | |
|---|
| 742 | | - imx_media_free_dma_buf(priv->md, &priv->underrun_buf); |
|---|
| 784 | + imx_media_free_dma_buf(ic_priv->ipu_dev, &priv->underrun_buf); |
|---|
| 743 | 785 | |
|---|
| 744 | 786 | /* cancel the EOF timeout timer */ |
|---|
| 745 | 787 | del_timer_sync(&priv->eof_timeout_timer); |
|---|
| .. | .. |
|---|
| 808 | 850 | if (code->pad >= PRPENCVF_NUM_PADS) |
|---|
| 809 | 851 | return -EINVAL; |
|---|
| 810 | 852 | |
|---|
| 811 | | - return imx_media_enum_ipu_format(&code->code, code->index, CS_SEL_ANY); |
|---|
| 853 | + return imx_media_enum_ipu_formats(&code->code, code->index, |
|---|
| 854 | + PIXFMT_SEL_YUV_RGB); |
|---|
| 812 | 855 | } |
|---|
| 813 | 856 | |
|---|
| 814 | 857 | static int prp_get_fmt(struct v4l2_subdev *sd, |
|---|
| .. | .. |
|---|
| 843 | 886 | { |
|---|
| 844 | 887 | struct v4l2_mbus_framefmt *infmt; |
|---|
| 845 | 888 | |
|---|
| 846 | | - *cc = imx_media_find_ipu_format(sdformat->format.code, CS_SEL_ANY); |
|---|
| 889 | + *cc = imx_media_find_ipu_format(sdformat->format.code, |
|---|
| 890 | + PIXFMT_SEL_YUV_RGB); |
|---|
| 847 | 891 | if (!*cc) { |
|---|
| 848 | 892 | u32 code; |
|---|
| 849 | 893 | |
|---|
| 850 | | - imx_media_enum_ipu_format(&code, 0, CS_SEL_ANY); |
|---|
| 851 | | - *cc = imx_media_find_ipu_format(code, CS_SEL_ANY); |
|---|
| 894 | + imx_media_enum_ipu_formats(&code, 0, PIXFMT_SEL_YUV_RGB); |
|---|
| 895 | + *cc = imx_media_find_ipu_format(code, PIXFMT_SEL_YUV_RGB); |
|---|
| 896 | + |
|---|
| 852 | 897 | sdformat->format.code = (*cc)->codes[0]; |
|---|
| 853 | 898 | } |
|---|
| 854 | 899 | |
|---|
| 855 | 900 | infmt = __prp_get_fmt(priv, cfg, PRPENCVF_SINK_PAD, sdformat->which); |
|---|
| 856 | 901 | |
|---|
| 857 | 902 | if (sdformat->pad == PRPENCVF_SRC_PAD) { |
|---|
| 858 | | - if (sdformat->format.field != V4L2_FIELD_NONE) |
|---|
| 859 | | - sdformat->format.field = infmt->field; |
|---|
| 903 | + sdformat->format.field = infmt->field; |
|---|
| 860 | 904 | |
|---|
| 861 | 905 | prp_bound_align_output(&sdformat->format, infmt, |
|---|
| 862 | 906 | priv->rot_mode); |
|---|
| .. | .. |
|---|
| 864 | 908 | /* propagate colorimetry from sink */ |
|---|
| 865 | 909 | sdformat->format.colorspace = infmt->colorspace; |
|---|
| 866 | 910 | sdformat->format.xfer_func = infmt->xfer_func; |
|---|
| 867 | | - sdformat->format.quantization = infmt->quantization; |
|---|
| 868 | | - sdformat->format.ycbcr_enc = infmt->ycbcr_enc; |
|---|
| 869 | 911 | } else { |
|---|
| 870 | 912 | v4l_bound_align_image(&sdformat->format.width, |
|---|
| 871 | 913 | MIN_W_SINK, MAX_W_SINK, W_ALIGN_SINK, |
|---|
| .. | .. |
|---|
| 873 | 915 | MIN_H_SINK, MAX_H_SINK, H_ALIGN_SINK, |
|---|
| 874 | 916 | S_ALIGN); |
|---|
| 875 | 917 | |
|---|
| 876 | | - imx_media_fill_default_mbus_fields(&sdformat->format, infmt, |
|---|
| 877 | | - true); |
|---|
| 918 | + if (sdformat->format.field == V4L2_FIELD_ANY) |
|---|
| 919 | + sdformat->format.field = V4L2_FIELD_NONE; |
|---|
| 878 | 920 | } |
|---|
| 921 | + |
|---|
| 922 | + imx_media_try_colorimetry(&sdformat->format, true); |
|---|
| 879 | 923 | } |
|---|
| 880 | 924 | |
|---|
| 881 | 925 | static int prp_set_fmt(struct v4l2_subdev *sd, |
|---|
| .. | .. |
|---|
| 883 | 927 | struct v4l2_subdev_format *sdformat) |
|---|
| 884 | 928 | { |
|---|
| 885 | 929 | struct prp_priv *priv = sd_to_priv(sd); |
|---|
| 886 | | - struct imx_media_video_dev *vdev = priv->vdev; |
|---|
| 887 | 930 | const struct imx_media_pixfmt *cc; |
|---|
| 888 | | - struct v4l2_pix_format vdev_fmt; |
|---|
| 889 | 931 | struct v4l2_mbus_framefmt *fmt; |
|---|
| 890 | 932 | int ret = 0; |
|---|
| 891 | 933 | |
|---|
| .. | .. |
|---|
| 922 | 964 | priv->cc[PRPENCVF_SRC_PAD] = outcc; |
|---|
| 923 | 965 | } |
|---|
| 924 | 966 | |
|---|
| 925 | | - if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY) |
|---|
| 926 | | - goto out; |
|---|
| 967 | + if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) |
|---|
| 968 | + priv->cc[sdformat->pad] = cc; |
|---|
| 927 | 969 | |
|---|
| 928 | | - priv->cc[sdformat->pad] = cc; |
|---|
| 929 | | - |
|---|
| 930 | | - /* propagate output pad format to capture device */ |
|---|
| 931 | | - imx_media_mbus_fmt_to_pix_fmt(&vdev_fmt, |
|---|
| 932 | | - &priv->format_mbus[PRPENCVF_SRC_PAD], |
|---|
| 933 | | - priv->cc[PRPENCVF_SRC_PAD]); |
|---|
| 934 | | - mutex_unlock(&priv->lock); |
|---|
| 935 | | - imx_media_capture_device_set_format(vdev, &vdev_fmt); |
|---|
| 936 | | - |
|---|
| 937 | | - return 0; |
|---|
| 938 | 970 | out: |
|---|
| 939 | 971 | mutex_unlock(&priv->lock); |
|---|
| 940 | 972 | return ret; |
|---|
| .. | .. |
|---|
| 989 | 1021 | struct v4l2_subdev *remote_sd; |
|---|
| 990 | 1022 | int ret = 0; |
|---|
| 991 | 1023 | |
|---|
| 992 | | - dev_dbg(ic_priv->dev, "link setup %s -> %s", remote->entity->name, |
|---|
| 993 | | - local->entity->name); |
|---|
| 1024 | + dev_dbg(ic_priv->ipu_dev, "%s: link setup %s -> %s", |
|---|
| 1025 | + ic_priv->sd.name, remote->entity->name, local->entity->name); |
|---|
| 994 | 1026 | |
|---|
| 995 | 1027 | mutex_lock(&priv->lock); |
|---|
| 996 | 1028 | |
|---|
| .. | .. |
|---|
| 1156 | 1188 | if (priv->stream_count != !enable) |
|---|
| 1157 | 1189 | goto update_count; |
|---|
| 1158 | 1190 | |
|---|
| 1159 | | - dev_dbg(ic_priv->dev, "stream %s\n", enable ? "ON" : "OFF"); |
|---|
| 1191 | + dev_dbg(ic_priv->ipu_dev, "%s: stream %s\n", sd->name, |
|---|
| 1192 | + enable ? "ON" : "OFF"); |
|---|
| 1160 | 1193 | |
|---|
| 1161 | 1194 | if (enable) |
|---|
| 1162 | 1195 | ret = prp_start(priv); |
|---|
| .. | .. |
|---|
| 1197 | 1230 | if (fi->pad >= PRPENCVF_NUM_PADS) |
|---|
| 1198 | 1231 | return -EINVAL; |
|---|
| 1199 | 1232 | |
|---|
| 1200 | | - /* No limits on frame interval */ |
|---|
| 1201 | 1233 | mutex_lock(&priv->lock); |
|---|
| 1202 | | - priv->frame_interval = fi->interval; |
|---|
| 1234 | + |
|---|
| 1235 | + /* No limits on valid frame intervals */ |
|---|
| 1236 | + if (fi->interval.numerator == 0 || fi->interval.denominator == 0) |
|---|
| 1237 | + fi->interval = priv->frame_interval; |
|---|
| 1238 | + else |
|---|
| 1239 | + priv->frame_interval = fi->interval; |
|---|
| 1240 | + |
|---|
| 1203 | 1241 | mutex_unlock(&priv->lock); |
|---|
| 1204 | 1242 | |
|---|
| 1205 | 1243 | return 0; |
|---|
| 1206 | 1244 | } |
|---|
| 1207 | 1245 | |
|---|
| 1208 | | -/* |
|---|
| 1209 | | - * retrieve our pads parsed from the OF graph by the media device |
|---|
| 1210 | | - */ |
|---|
| 1211 | 1246 | static int prp_registered(struct v4l2_subdev *sd) |
|---|
| 1212 | 1247 | { |
|---|
| 1213 | 1248 | struct prp_priv *priv = sd_to_priv(sd); |
|---|
| 1249 | + struct imx_ic_priv *ic_priv = priv->ic_priv; |
|---|
| 1214 | 1250 | int i, ret; |
|---|
| 1215 | 1251 | u32 code; |
|---|
| 1216 | 1252 | |
|---|
| 1217 | | - /* get media device */ |
|---|
| 1218 | | - priv->md = dev_get_drvdata(sd->v4l2_dev->dev); |
|---|
| 1253 | + /* set a default mbus format */ |
|---|
| 1254 | + imx_media_enum_ipu_formats(&code, 0, PIXFMT_SEL_YUV); |
|---|
| 1219 | 1255 | |
|---|
| 1220 | 1256 | for (i = 0; i < PRPENCVF_NUM_PADS; i++) { |
|---|
| 1221 | | - priv->pad[i].flags = (i == PRPENCVF_SINK_PAD) ? |
|---|
| 1222 | | - MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; |
|---|
| 1223 | | - |
|---|
| 1224 | | - /* set a default mbus format */ |
|---|
| 1225 | | - imx_media_enum_ipu_format(&code, 0, CS_SEL_YUV); |
|---|
| 1226 | 1257 | ret = imx_media_init_mbus_fmt(&priv->format_mbus[i], |
|---|
| 1227 | 1258 | 640, 480, code, V4L2_FIELD_NONE, |
|---|
| 1228 | 1259 | &priv->cc[i]); |
|---|
| .. | .. |
|---|
| 1234 | 1265 | priv->frame_interval.numerator = 1; |
|---|
| 1235 | 1266 | priv->frame_interval.denominator = 30; |
|---|
| 1236 | 1267 | |
|---|
| 1237 | | - ret = media_entity_pads_init(&sd->entity, PRPENCVF_NUM_PADS, |
|---|
| 1238 | | - priv->pad); |
|---|
| 1239 | | - if (ret) |
|---|
| 1240 | | - return ret; |
|---|
| 1268 | + priv->vdev = imx_media_capture_device_init(ic_priv->ipu_dev, |
|---|
| 1269 | + &ic_priv->sd, |
|---|
| 1270 | + PRPENCVF_SRC_PAD); |
|---|
| 1271 | + if (IS_ERR(priv->vdev)) |
|---|
| 1272 | + return PTR_ERR(priv->vdev); |
|---|
| 1241 | 1273 | |
|---|
| 1242 | 1274 | ret = imx_media_capture_device_register(priv->vdev); |
|---|
| 1243 | 1275 | if (ret) |
|---|
| 1244 | | - return ret; |
|---|
| 1245 | | - |
|---|
| 1246 | | - ret = imx_media_add_video_device(priv->md, priv->vdev); |
|---|
| 1247 | | - if (ret) |
|---|
| 1248 | | - goto unreg; |
|---|
| 1276 | + goto remove_vdev; |
|---|
| 1249 | 1277 | |
|---|
| 1250 | 1278 | ret = prp_init_controls(priv); |
|---|
| 1251 | 1279 | if (ret) |
|---|
| 1252 | | - goto unreg; |
|---|
| 1280 | + goto unreg_vdev; |
|---|
| 1253 | 1281 | |
|---|
| 1254 | 1282 | return 0; |
|---|
| 1255 | | -unreg: |
|---|
| 1283 | + |
|---|
| 1284 | +unreg_vdev: |
|---|
| 1256 | 1285 | imx_media_capture_device_unregister(priv->vdev); |
|---|
| 1286 | +remove_vdev: |
|---|
| 1287 | + imx_media_capture_device_remove(priv->vdev); |
|---|
| 1257 | 1288 | return ret; |
|---|
| 1258 | 1289 | } |
|---|
| 1259 | 1290 | |
|---|
| .. | .. |
|---|
| 1262 | 1293 | struct prp_priv *priv = sd_to_priv(sd); |
|---|
| 1263 | 1294 | |
|---|
| 1264 | 1295 | imx_media_capture_device_unregister(priv->vdev); |
|---|
| 1296 | + imx_media_capture_device_remove(priv->vdev); |
|---|
| 1297 | + |
|---|
| 1265 | 1298 | v4l2_ctrl_handler_free(&priv->ctrl_hdlr); |
|---|
| 1266 | 1299 | } |
|---|
| 1267 | 1300 | |
|---|
| .. | .. |
|---|
| 1297 | 1330 | static int prp_init(struct imx_ic_priv *ic_priv) |
|---|
| 1298 | 1331 | { |
|---|
| 1299 | 1332 | struct prp_priv *priv; |
|---|
| 1333 | + int i, ret; |
|---|
| 1300 | 1334 | |
|---|
| 1301 | | - priv = devm_kzalloc(ic_priv->dev, sizeof(*priv), GFP_KERNEL); |
|---|
| 1335 | + priv = devm_kzalloc(ic_priv->ipu_dev, sizeof(*priv), GFP_KERNEL); |
|---|
| 1302 | 1336 | if (!priv) |
|---|
| 1303 | 1337 | return -ENOMEM; |
|---|
| 1304 | 1338 | |
|---|
| .. | .. |
|---|
| 1308 | 1342 | spin_lock_init(&priv->irqlock); |
|---|
| 1309 | 1343 | timer_setup(&priv->eof_timeout_timer, prp_eof_timeout, 0); |
|---|
| 1310 | 1344 | |
|---|
| 1311 | | - priv->vdev = imx_media_capture_device_init(&ic_priv->sd, |
|---|
| 1312 | | - PRPENCVF_SRC_PAD); |
|---|
| 1313 | | - if (IS_ERR(priv->vdev)) |
|---|
| 1314 | | - return PTR_ERR(priv->vdev); |
|---|
| 1315 | | - |
|---|
| 1316 | 1345 | mutex_init(&priv->lock); |
|---|
| 1317 | 1346 | |
|---|
| 1318 | | - return 0; |
|---|
| 1347 | + for (i = 0; i < PRPENCVF_NUM_PADS; i++) { |
|---|
| 1348 | + priv->pad[i].flags = (i == PRPENCVF_SINK_PAD) ? |
|---|
| 1349 | + MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; |
|---|
| 1350 | + } |
|---|
| 1351 | + |
|---|
| 1352 | + ret = media_entity_pads_init(&ic_priv->sd.entity, PRPENCVF_NUM_PADS, |
|---|
| 1353 | + priv->pad); |
|---|
| 1354 | + if (ret) |
|---|
| 1355 | + mutex_destroy(&priv->lock); |
|---|
| 1356 | + |
|---|
| 1357 | + return ret; |
|---|
| 1319 | 1358 | } |
|---|
| 1320 | 1359 | |
|---|
| 1321 | 1360 | static void prp_remove(struct imx_ic_priv *ic_priv) |
|---|
| .. | .. |
|---|
| 1323 | 1362 | struct prp_priv *priv = ic_priv->task_priv; |
|---|
| 1324 | 1363 | |
|---|
| 1325 | 1364 | mutex_destroy(&priv->lock); |
|---|
| 1326 | | - imx_media_capture_device_remove(priv->vdev); |
|---|
| 1327 | 1365 | } |
|---|
| 1328 | 1366 | |
|---|
| 1329 | 1367 | struct imx_ic_ops imx_ic_prpencvf_ops = { |
|---|