From 9a34cef01392358421b764645073601c352d0a85 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Wed, 25 Jun 2014 18:05:53 -0700 Subject: 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 Signed-off-by: Mohsin Kazmi Signed-off-by: Steve Longerbeam 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 --- drivers/gpu/ipu-v3/ipu-common.c | 21 ++++++++ drivers/gpu/ipu-v3/ipu-cpmem.c | 117 +++++++++++++++++++++++++++++++++------- 2 files changed, 120 insertions(+), 18 deletions(-) (limited to 'drivers/gpu/ipu-v3') 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) case DRM_FORMAT_UYVY: case DRM_FORMAT_YUV420: case DRM_FORMAT_YVU420: + case DRM_FORMAT_YUV422: + case DRM_FORMAT_YVU422: + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: return IPUV3_COLORSPACE_YUV; default: return IPUV3_COLORSPACE_UNKNOWN; @@ -86,8 +92,13 @@ enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat) switch (pixelformat) { case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_YUV422P: case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: return IPUV3_COLORSPACE_YUV; case V4L2_PIX_FMT_RGB32: case V4L2_PIX_FMT_BGR32: @@ -106,6 +117,11 @@ bool ipu_pixelformat_is_planar(u32 pixelformat) switch (pixelformat) { case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: return true; } @@ -131,6 +147,11 @@ int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat) switch (pixelformat) { case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: /* * for the planar YUV formats, the stride passed to * 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) return DRM_FORMAT_YUYV; case V4L2_PIX_FMT_YUV420: return DRM_FORMAT_YUV420; + case V4L2_PIX_FMT_YUV422P: + return DRM_FORMAT_YUV422; case V4L2_PIX_FMT_YVU420: return DRM_FORMAT_YVU420; + case V4L2_PIX_FMT_NV12: + return DRM_FORMAT_NV12; + case V4L2_PIX_FMT_NV16: + return DRM_FORMAT_NV16; } return -EINVAL; @@ -394,6 +400,7 @@ void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch, { switch (pixel_format) { case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YUV422P: ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, (stride / 2) - 1); ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8); 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, ipu_ch_param_write_field(ch, IPU_FIELD_UBO, v_offset / 8); ipu_ch_param_write_field(ch, IPU_FIELD_VBO, u_offset / 8); break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV16: + ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, stride - 1); + ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8); + ipu_ch_param_write_field(ch, IPU_FIELD_VBO, u_offset / 8); + break; } } EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full); @@ -422,6 +435,19 @@ void ipu_cpmem_set_yuv_planar(struct ipuv3_channel *ch, ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride, u_offset, v_offset); break; + case V4L2_PIX_FMT_YUV422P: + uv_stride = stride / 2; + u_offset = stride * height; + v_offset = u_offset + (uv_stride * height); + ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride, + u_offset, v_offset); + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV16: + u_offset = stride * height; + ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride, + u_offset, 0); + break; } } EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar); @@ -475,11 +501,20 @@ static const struct ipu_rgb def_bgr_16 = { }; #define Y_OFFSET(pix, x, y) ((x) + pix->width * (y)) -#define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \ - (pix->width * (y) / 4) + (x) / 2) -#define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \ - (pix->width * pix->height / 4) + \ - (pix->width * (y) / 4) + (x) / 2) +#define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \ + (pix->width * (y) / 4) + (x) / 2) +#define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \ + (pix->width * pix->height / 4) + \ + (pix->width * (y) / 4) + (x) / 2) +#define U2_OFFSET(pix, x, y) ((pix->width * pix->height) + \ + (pix->width * (y) / 2) + (x) / 2) +#define V2_OFFSET(pix, x, y) ((pix->width * pix->height) + \ + (pix->width * pix->height / 2) + \ + (pix->width * (y) / 2) + (x) / 2) +#define UV_OFFSET(pix, x, y) ((pix->width * pix->height) + \ + (pix->width * (y) / 2) + (x)) +#define UV2_OFFSET(pix, x, y) ((pix->width * pix->height) + \ + (pix->width * y) + (x)) int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc) { @@ -491,6 +526,25 @@ int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc) /* burst size */ ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); break; + case DRM_FORMAT_YUV422: + case DRM_FORMAT_YVU422: + /* pix format */ + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 1); + /* burst size */ + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); + break; + case DRM_FORMAT_NV12: + /* pix format */ + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4); + /* burst size */ + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); + break; + case DRM_FORMAT_NV16: + /* pix format */ + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 3); + /* burst size */ + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); + break; case DRM_FORMAT_UYVY: /* bits/pixel */ ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); @@ -538,7 +592,7 @@ EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt); int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image) { struct v4l2_pix_format *pix = &image->pix; - int offset, y_offset, u_offset, v_offset; + int offset, u_offset, v_offset; pr_debug("%s: resolution: %dx%d stride: %d\n", __func__, pix->width, pix->height, @@ -552,43 +606,70 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image) switch (pix->pixelformat) { case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: - y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top); + offset = Y_OFFSET(pix, image->rect.left, image->rect.top); u_offset = U_OFFSET(pix, image->rect.left, - image->rect.top) - y_offset; + image->rect.top) - offset; v_offset = V_OFFSET(pix, image->rect.left, - image->rect.top) - y_offset; + image->rect.top) - offset; + + ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat, + pix->bytesperline, + u_offset, v_offset); + break; + case V4L2_PIX_FMT_YUV422P: + offset = Y_OFFSET(pix, image->rect.left, image->rect.top); + u_offset = U2_OFFSET(pix, image->rect.left, + image->rect.top) - offset; + v_offset = V2_OFFSET(pix, image->rect.left, + image->rect.top) - offset; + + ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat, + pix->bytesperline, + u_offset, v_offset); + break; + case V4L2_PIX_FMT_NV12: + offset = Y_OFFSET(pix, image->rect.left, image->rect.top); + u_offset = UV_OFFSET(pix, image->rect.left, + image->rect.top) - offset; + v_offset = 0; ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat, - pix->bytesperline, u_offset, v_offset); - ipu_cpmem_set_buffer(ch, 0, image->phys0 + y_offset); - ipu_cpmem_set_buffer(ch, 1, image->phys1 + y_offset); + pix->bytesperline, + u_offset, v_offset); + break; + case V4L2_PIX_FMT_NV16: + offset = Y_OFFSET(pix, image->rect.left, image->rect.top); + u_offset = UV2_OFFSET(pix, image->rect.left, + image->rect.top) - offset; + v_offset = 0; + + ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat, + pix->bytesperline, + u_offset, v_offset); break; case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_RGB565: offset = image->rect.left * 2 + image->rect.top * pix->bytesperline; - ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset); - ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset); break; case V4L2_PIX_FMT_RGB32: case V4L2_PIX_FMT_BGR32: offset = image->rect.left * 4 + image->rect.top * pix->bytesperline; - ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset); - ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset); break; case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_BGR24: offset = image->rect.left * 3 + image->rect.top * pix->bytesperline; - ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset); - ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset); break; default: return -EINVAL; } + ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset); + ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset); + return 0; } EXPORT_SYMBOL_GPL(ipu_cpmem_set_image); -- cgit v1.2.3