diff options
author | Steve Longerbeam <slongerbeam@gmail.com> | 2014-06-25 21:05:53 -0400 |
---|---|---|
committer | Philipp Zabel <p.zabel@pengutronix.de> | 2014-09-02 08:55:55 -0400 |
commit | 9a34cef01392358421b764645073601c352d0a85 (patch) | |
tree | 66fc5d4dc4e585ae26de170e067a5ccc106d5905 | |
parent | 2094b603ae59be6785e52a00d09b47b6ae910154 (diff) |
gpu: ipu-v3: Add more planar formats support
Adds support for the following planar and partial-planar formats:
YUV422
NV12
NV16
Signed-off-by: Dmitry Eremin-Solenikov <dmitry_eremin@mentor.com>
Signed-off-by: Mohsin Kazmi <mohsin_kazmi@mentor.com>
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
Unified base offset and Y plane offset into a single variable,
moved all ipu_cpmem_set_buffer calls to a single location.
Removed NV21 and NV61 for now. The IDMAC doesn't understand U/V
order for chroma interleaved formats, so we'd need to work around
this by implenting U/V switching via the CSC unit.
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-common.c | 21 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-cpmem.c | 117 |
2 files changed, 120 insertions, 18 deletions
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index 28be7415a198..5c3d5269056e 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c | |||
@@ -74,6 +74,12 @@ enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc) | |||
74 | case DRM_FORMAT_UYVY: | 74 | case DRM_FORMAT_UYVY: |
75 | case DRM_FORMAT_YUV420: | 75 | case DRM_FORMAT_YUV420: |
76 | case DRM_FORMAT_YVU420: | 76 | case DRM_FORMAT_YVU420: |
77 | case DRM_FORMAT_YUV422: | ||
78 | case DRM_FORMAT_YVU422: | ||
79 | case DRM_FORMAT_NV12: | ||
80 | case DRM_FORMAT_NV21: | ||
81 | case DRM_FORMAT_NV16: | ||
82 | case DRM_FORMAT_NV61: | ||
77 | return IPUV3_COLORSPACE_YUV; | 83 | return IPUV3_COLORSPACE_YUV; |
78 | default: | 84 | default: |
79 | return IPUV3_COLORSPACE_UNKNOWN; | 85 | return IPUV3_COLORSPACE_UNKNOWN; |
@@ -86,8 +92,13 @@ enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat) | |||
86 | switch (pixelformat) { | 92 | switch (pixelformat) { |
87 | case V4L2_PIX_FMT_YUV420: | 93 | case V4L2_PIX_FMT_YUV420: |
88 | case V4L2_PIX_FMT_YVU420: | 94 | case V4L2_PIX_FMT_YVU420: |
95 | case V4L2_PIX_FMT_YUV422P: | ||
89 | case V4L2_PIX_FMT_UYVY: | 96 | case V4L2_PIX_FMT_UYVY: |
90 | case V4L2_PIX_FMT_YUYV: | 97 | case V4L2_PIX_FMT_YUYV: |
98 | case V4L2_PIX_FMT_NV12: | ||
99 | case V4L2_PIX_FMT_NV21: | ||
100 | case V4L2_PIX_FMT_NV16: | ||
101 | case V4L2_PIX_FMT_NV61: | ||
91 | return IPUV3_COLORSPACE_YUV; | 102 | return IPUV3_COLORSPACE_YUV; |
92 | case V4L2_PIX_FMT_RGB32: | 103 | case V4L2_PIX_FMT_RGB32: |
93 | case V4L2_PIX_FMT_BGR32: | 104 | case V4L2_PIX_FMT_BGR32: |
@@ -106,6 +117,11 @@ bool ipu_pixelformat_is_planar(u32 pixelformat) | |||
106 | switch (pixelformat) { | 117 | switch (pixelformat) { |
107 | case V4L2_PIX_FMT_YUV420: | 118 | case V4L2_PIX_FMT_YUV420: |
108 | case V4L2_PIX_FMT_YVU420: | 119 | case V4L2_PIX_FMT_YVU420: |
120 | case V4L2_PIX_FMT_YUV422P: | ||
121 | case V4L2_PIX_FMT_NV12: | ||
122 | case V4L2_PIX_FMT_NV21: | ||
123 | case V4L2_PIX_FMT_NV16: | ||
124 | case V4L2_PIX_FMT_NV61: | ||
109 | return true; | 125 | return true; |
110 | } | 126 | } |
111 | 127 | ||
@@ -131,6 +147,11 @@ int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat) | |||
131 | switch (pixelformat) { | 147 | switch (pixelformat) { |
132 | case V4L2_PIX_FMT_YUV420: | 148 | case V4L2_PIX_FMT_YUV420: |
133 | case V4L2_PIX_FMT_YVU420: | 149 | case V4L2_PIX_FMT_YVU420: |
150 | case V4L2_PIX_FMT_YUV422P: | ||
151 | case V4L2_PIX_FMT_NV12: | ||
152 | case V4L2_PIX_FMT_NV21: | ||
153 | case V4L2_PIX_FMT_NV16: | ||
154 | case V4L2_PIX_FMT_NV61: | ||
134 | /* | 155 | /* |
135 | * for the planar YUV formats, the stride passed to | 156 | * for the planar YUV formats, the stride passed to |
136 | * cpmem must be the stride in bytes of the Y plane. | 157 | * cpmem must be the stride in bytes of the Y plane. |
diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c index cfe2f53f2c17..c55f3620e84a 100644 --- a/drivers/gpu/ipu-v3/ipu-cpmem.c +++ b/drivers/gpu/ipu-v3/ipu-cpmem.c | |||
@@ -193,8 +193,14 @@ static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat) | |||
193 | return DRM_FORMAT_YUYV; | 193 | return DRM_FORMAT_YUYV; |
194 | case V4L2_PIX_FMT_YUV420: | 194 | case V4L2_PIX_FMT_YUV420: |
195 | return DRM_FORMAT_YUV420; | 195 | return DRM_FORMAT_YUV420; |
196 | case V4L2_PIX_FMT_YUV422P: | ||
197 | return DRM_FORMAT_YUV422; | ||
196 | case V4L2_PIX_FMT_YVU420: | 198 | case V4L2_PIX_FMT_YVU420: |
197 | return DRM_FORMAT_YVU420; | 199 | return DRM_FORMAT_YVU420; |
200 | case V4L2_PIX_FMT_NV12: | ||
201 | return DRM_FORMAT_NV12; | ||
202 | case V4L2_PIX_FMT_NV16: | ||
203 | return DRM_FORMAT_NV16; | ||
198 | } | 204 | } |
199 | 205 | ||
200 | return -EINVAL; | 206 | return -EINVAL; |
@@ -394,6 +400,7 @@ void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch, | |||
394 | { | 400 | { |
395 | switch (pixel_format) { | 401 | switch (pixel_format) { |
396 | case V4L2_PIX_FMT_YUV420: | 402 | case V4L2_PIX_FMT_YUV420: |
403 | case V4L2_PIX_FMT_YUV422P: | ||
397 | ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, (stride / 2) - 1); | 404 | ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, (stride / 2) - 1); |
398 | ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8); | 405 | ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8); |
399 | ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8); | 406 | ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8); |
@@ -403,6 +410,12 @@ void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch, | |||
403 | ipu_ch_param_write_field(ch, IPU_FIELD_UBO, v_offset / 8); | 410 | ipu_ch_param_write_field(ch, IPU_FIELD_UBO, v_offset / 8); |
404 | ipu_ch_param_write_field(ch, IPU_FIELD_VBO, u_offset / 8); | 411 | ipu_ch_param_write_field(ch, IPU_FIELD_VBO, u_offset / 8); |
405 | break; | 412 | break; |
413 | case V4L2_PIX_FMT_NV12: | ||
414 | case V4L2_PIX_FMT_NV16: | ||
415 | ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, stride - 1); | ||
416 | ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8); | ||
417 | ipu_ch_param_write_field(ch, IPU_FIELD_VBO, u_offset / 8); | ||
418 | break; | ||
406 | } | 419 | } |
407 | } | 420 | } |
408 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full); | 421 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full); |
@@ -422,6 +435,19 @@ void ipu_cpmem_set_yuv_planar(struct ipuv3_channel *ch, | |||
422 | ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride, | 435 | ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride, |
423 | u_offset, v_offset); | 436 | u_offset, v_offset); |
424 | break; | 437 | break; |
438 | case V4L2_PIX_FMT_YUV422P: | ||
439 | uv_stride = stride / 2; | ||
440 | u_offset = stride * height; | ||
441 | v_offset = u_offset + (uv_stride * height); | ||
442 | ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride, | ||
443 | u_offset, v_offset); | ||
444 | break; | ||
445 | case V4L2_PIX_FMT_NV12: | ||
446 | case V4L2_PIX_FMT_NV16: | ||
447 | u_offset = stride * height; | ||
448 | ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride, | ||
449 | u_offset, 0); | ||
450 | break; | ||
425 | } | 451 | } |
426 | } | 452 | } |
427 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar); | 453 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar); |
@@ -475,11 +501,20 @@ static const struct ipu_rgb def_bgr_16 = { | |||
475 | }; | 501 | }; |
476 | 502 | ||
477 | #define Y_OFFSET(pix, x, y) ((x) + pix->width * (y)) | 503 | #define Y_OFFSET(pix, x, y) ((x) + pix->width * (y)) |
478 | #define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \ | 504 | #define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \ |
479 | (pix->width * (y) / 4) + (x) / 2) | 505 | (pix->width * (y) / 4) + (x) / 2) |
480 | #define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \ | 506 | #define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \ |
481 | (pix->width * pix->height / 4) + \ | 507 | (pix->width * pix->height / 4) + \ |
482 | (pix->width * (y) / 4) + (x) / 2) | 508 | (pix->width * (y) / 4) + (x) / 2) |
509 | #define U2_OFFSET(pix, x, y) ((pix->width * pix->height) + \ | ||
510 | (pix->width * (y) / 2) + (x) / 2) | ||
511 | #define V2_OFFSET(pix, x, y) ((pix->width * pix->height) + \ | ||
512 | (pix->width * pix->height / 2) + \ | ||
513 | (pix->width * (y) / 2) + (x) / 2) | ||
514 | #define UV_OFFSET(pix, x, y) ((pix->width * pix->height) + \ | ||
515 | (pix->width * (y) / 2) + (x)) | ||
516 | #define UV2_OFFSET(pix, x, y) ((pix->width * pix->height) + \ | ||
517 | (pix->width * y) + (x)) | ||
483 | 518 | ||
484 | int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc) | 519 | int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc) |
485 | { | 520 | { |
@@ -491,6 +526,25 @@ int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc) | |||
491 | /* burst size */ | 526 | /* burst size */ |
492 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); | 527 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); |
493 | break; | 528 | break; |
529 | case DRM_FORMAT_YUV422: | ||
530 | case DRM_FORMAT_YVU422: | ||
531 | /* pix format */ | ||
532 | ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 1); | ||
533 | /* burst size */ | ||
534 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); | ||
535 | break; | ||
536 | case DRM_FORMAT_NV12: | ||
537 | /* pix format */ | ||
538 | ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4); | ||
539 | /* burst size */ | ||
540 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); | ||
541 | break; | ||
542 | case DRM_FORMAT_NV16: | ||
543 | /* pix format */ | ||
544 | ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 3); | ||
545 | /* burst size */ | ||
546 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); | ||
547 | break; | ||
494 | case DRM_FORMAT_UYVY: | 548 | case DRM_FORMAT_UYVY: |
495 | /* bits/pixel */ | 549 | /* bits/pixel */ |
496 | ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); | 550 | ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); |
@@ -538,7 +592,7 @@ EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt); | |||
538 | int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image) | 592 | int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image) |
539 | { | 593 | { |
540 | struct v4l2_pix_format *pix = &image->pix; | 594 | struct v4l2_pix_format *pix = &image->pix; |
541 | int offset, y_offset, u_offset, v_offset; | 595 | int offset, u_offset, v_offset; |
542 | 596 | ||
543 | pr_debug("%s: resolution: %dx%d stride: %d\n", | 597 | pr_debug("%s: resolution: %dx%d stride: %d\n", |
544 | __func__, pix->width, pix->height, | 598 | __func__, pix->width, pix->height, |
@@ -552,43 +606,70 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image) | |||
552 | switch (pix->pixelformat) { | 606 | switch (pix->pixelformat) { |
553 | case V4L2_PIX_FMT_YUV420: | 607 | case V4L2_PIX_FMT_YUV420: |
554 | case V4L2_PIX_FMT_YVU420: | 608 | case V4L2_PIX_FMT_YVU420: |
555 | y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top); | 609 | offset = Y_OFFSET(pix, image->rect.left, image->rect.top); |
556 | u_offset = U_OFFSET(pix, image->rect.left, | 610 | u_offset = U_OFFSET(pix, image->rect.left, |
557 | image->rect.top) - y_offset; | 611 | image->rect.top) - offset; |
558 | v_offset = V_OFFSET(pix, image->rect.left, | 612 | v_offset = V_OFFSET(pix, image->rect.left, |
559 | image->rect.top) - y_offset; | 613 | image->rect.top) - offset; |
614 | |||
615 | ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat, | ||
616 | pix->bytesperline, | ||
617 | u_offset, v_offset); | ||
618 | break; | ||
619 | case V4L2_PIX_FMT_YUV422P: | ||
620 | offset = Y_OFFSET(pix, image->rect.left, image->rect.top); | ||
621 | u_offset = U2_OFFSET(pix, image->rect.left, | ||
622 | image->rect.top) - offset; | ||
623 | v_offset = V2_OFFSET(pix, image->rect.left, | ||
624 | image->rect.top) - offset; | ||
625 | |||
626 | ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat, | ||
627 | pix->bytesperline, | ||
628 | u_offset, v_offset); | ||
629 | break; | ||
630 | case V4L2_PIX_FMT_NV12: | ||
631 | offset = Y_OFFSET(pix, image->rect.left, image->rect.top); | ||
632 | u_offset = UV_OFFSET(pix, image->rect.left, | ||
633 | image->rect.top) - offset; | ||
634 | v_offset = 0; | ||
560 | 635 | ||
561 | ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat, | 636 | ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat, |
562 | pix->bytesperline, u_offset, v_offset); | 637 | pix->bytesperline, |
563 | ipu_cpmem_set_buffer(ch, 0, image->phys0 + y_offset); | 638 | u_offset, v_offset); |
564 | ipu_cpmem_set_buffer(ch, 1, image->phys1 + y_offset); | 639 | break; |
640 | case V4L2_PIX_FMT_NV16: | ||
641 | offset = Y_OFFSET(pix, image->rect.left, image->rect.top); | ||
642 | u_offset = UV2_OFFSET(pix, image->rect.left, | ||
643 | image->rect.top) - offset; | ||
644 | v_offset = 0; | ||
645 | |||
646 | ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat, | ||
647 | pix->bytesperline, | ||
648 | u_offset, v_offset); | ||
565 | break; | 649 | break; |
566 | case V4L2_PIX_FMT_UYVY: | 650 | case V4L2_PIX_FMT_UYVY: |
567 | case V4L2_PIX_FMT_YUYV: | 651 | case V4L2_PIX_FMT_YUYV: |
568 | case V4L2_PIX_FMT_RGB565: | 652 | case V4L2_PIX_FMT_RGB565: |
569 | offset = image->rect.left * 2 + | 653 | offset = image->rect.left * 2 + |
570 | image->rect.top * pix->bytesperline; | 654 | image->rect.top * pix->bytesperline; |
571 | ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset); | ||
572 | ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset); | ||
573 | break; | 655 | break; |
574 | case V4L2_PIX_FMT_RGB32: | 656 | case V4L2_PIX_FMT_RGB32: |
575 | case V4L2_PIX_FMT_BGR32: | 657 | case V4L2_PIX_FMT_BGR32: |
576 | offset = image->rect.left * 4 + | 658 | offset = image->rect.left * 4 + |
577 | image->rect.top * pix->bytesperline; | 659 | image->rect.top * pix->bytesperline; |
578 | ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset); | ||
579 | ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset); | ||
580 | break; | 660 | break; |
581 | case V4L2_PIX_FMT_RGB24: | 661 | case V4L2_PIX_FMT_RGB24: |
582 | case V4L2_PIX_FMT_BGR24: | 662 | case V4L2_PIX_FMT_BGR24: |
583 | offset = image->rect.left * 3 + | 663 | offset = image->rect.left * 3 + |
584 | image->rect.top * pix->bytesperline; | 664 | image->rect.top * pix->bytesperline; |
585 | ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset); | ||
586 | ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset); | ||
587 | break; | 665 | break; |
588 | default: | 666 | default: |
589 | return -EINVAL; | 667 | return -EINVAL; |
590 | } | 668 | } |
591 | 669 | ||
670 | ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset); | ||
671 | ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset); | ||
672 | |||
592 | return 0; | 673 | return 0; |
593 | } | 674 | } |
594 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_image); | 675 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_image); |