| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * TI VPE mem2mem driver, based on the virtual v4l2-mem2mem example driver |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 11 | 12 | * Marek Szyprowski, <m.szyprowski@samsung.com> |
|---|
| 12 | 13 | * |
|---|
| 13 | 14 | * Based on the virtual v4l2-mem2mem example device |
|---|
| 14 | | - * |
|---|
| 15 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 16 | | - * under the terms of the GNU General Public License version 2 as published by |
|---|
| 17 | | - * the Free Software Foundation |
|---|
| 18 | 15 | */ |
|---|
| 19 | 16 | |
|---|
| 20 | 17 | #include <linux/delay.h> |
|---|
| .. | .. |
|---|
| 55 | 52 | #define MIN_W 32 |
|---|
| 56 | 53 | #define MIN_H 32 |
|---|
| 57 | 54 | #define MAX_W 2048 |
|---|
| 58 | | -#define MAX_H 1184 |
|---|
| 55 | +#define MAX_H 2048 |
|---|
| 59 | 56 | |
|---|
| 60 | 57 | /* required alignments */ |
|---|
| 61 | 58 | #define S_ALIGN 0 /* multiple of 1 */ |
|---|
| .. | .. |
|---|
| 227 | 224 | |
|---|
| 228 | 225 | /* driver info for each of the supported video formats */ |
|---|
| 229 | 226 | struct vpe_fmt { |
|---|
| 230 | | - char *name; /* human-readable name */ |
|---|
| 231 | 227 | u32 fourcc; /* standard format identifier */ |
|---|
| 232 | 228 | u8 types; /* CAPTURE and/or OUTPUT */ |
|---|
| 233 | 229 | u8 coplanar; /* set for unpacked Luma and Chroma */ |
|---|
| .. | .. |
|---|
| 237 | 233 | |
|---|
| 238 | 234 | static struct vpe_fmt vpe_formats[] = { |
|---|
| 239 | 235 | { |
|---|
| 240 | | - .name = "NV16 YUV 422 co-planar", |
|---|
| 241 | 236 | .fourcc = V4L2_PIX_FMT_NV16, |
|---|
| 242 | 237 | .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, |
|---|
| 243 | 238 | .coplanar = 1, |
|---|
| .. | .. |
|---|
| 246 | 241 | }, |
|---|
| 247 | 242 | }, |
|---|
| 248 | 243 | { |
|---|
| 249 | | - .name = "NV12 YUV 420 co-planar", |
|---|
| 250 | 244 | .fourcc = V4L2_PIX_FMT_NV12, |
|---|
| 251 | 245 | .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, |
|---|
| 252 | 246 | .coplanar = 1, |
|---|
| .. | .. |
|---|
| 255 | 249 | }, |
|---|
| 256 | 250 | }, |
|---|
| 257 | 251 | { |
|---|
| 258 | | - .name = "YUYV 422 packed", |
|---|
| 252 | + .fourcc = V4L2_PIX_FMT_NV21, |
|---|
| 253 | + .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, |
|---|
| 254 | + .coplanar = 1, |
|---|
| 255 | + .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_Y420], |
|---|
| 256 | + &vpdma_yuv_fmts[VPDMA_DATA_FMT_CB420], |
|---|
| 257 | + }, |
|---|
| 258 | + }, |
|---|
| 259 | + { |
|---|
| 259 | 260 | .fourcc = V4L2_PIX_FMT_YUYV, |
|---|
| 260 | 261 | .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, |
|---|
| 261 | 262 | .coplanar = 0, |
|---|
| .. | .. |
|---|
| 263 | 264 | }, |
|---|
| 264 | 265 | }, |
|---|
| 265 | 266 | { |
|---|
| 266 | | - .name = "UYVY 422 packed", |
|---|
| 267 | 267 | .fourcc = V4L2_PIX_FMT_UYVY, |
|---|
| 268 | 268 | .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, |
|---|
| 269 | 269 | .coplanar = 0, |
|---|
| .. | .. |
|---|
| 271 | 271 | }, |
|---|
| 272 | 272 | }, |
|---|
| 273 | 273 | { |
|---|
| 274 | | - .name = "RGB888 packed", |
|---|
| 275 | 274 | .fourcc = V4L2_PIX_FMT_RGB24, |
|---|
| 276 | 275 | .types = VPE_FMT_TYPE_CAPTURE, |
|---|
| 277 | 276 | .coplanar = 0, |
|---|
| .. | .. |
|---|
| 279 | 278 | }, |
|---|
| 280 | 279 | }, |
|---|
| 281 | 280 | { |
|---|
| 282 | | - .name = "ARGB32", |
|---|
| 283 | 281 | .fourcc = V4L2_PIX_FMT_RGB32, |
|---|
| 284 | 282 | .types = VPE_FMT_TYPE_CAPTURE, |
|---|
| 285 | 283 | .coplanar = 0, |
|---|
| .. | .. |
|---|
| 287 | 285 | }, |
|---|
| 288 | 286 | }, |
|---|
| 289 | 287 | { |
|---|
| 290 | | - .name = "BGR888 packed", |
|---|
| 291 | 288 | .fourcc = V4L2_PIX_FMT_BGR24, |
|---|
| 292 | 289 | .types = VPE_FMT_TYPE_CAPTURE, |
|---|
| 293 | 290 | .coplanar = 0, |
|---|
| .. | .. |
|---|
| 295 | 292 | }, |
|---|
| 296 | 293 | }, |
|---|
| 297 | 294 | { |
|---|
| 298 | | - .name = "ABGR32", |
|---|
| 299 | 295 | .fourcc = V4L2_PIX_FMT_BGR32, |
|---|
| 300 | 296 | .types = VPE_FMT_TYPE_CAPTURE, |
|---|
| 301 | 297 | .coplanar = 0, |
|---|
| .. | .. |
|---|
| 303 | 299 | }, |
|---|
| 304 | 300 | }, |
|---|
| 305 | 301 | { |
|---|
| 306 | | - .name = "RGB565", |
|---|
| 307 | 302 | .fourcc = V4L2_PIX_FMT_RGB565, |
|---|
| 308 | 303 | .types = VPE_FMT_TYPE_CAPTURE, |
|---|
| 309 | 304 | .coplanar = 0, |
|---|
| .. | .. |
|---|
| 311 | 306 | }, |
|---|
| 312 | 307 | }, |
|---|
| 313 | 308 | { |
|---|
| 314 | | - .name = "RGB5551", |
|---|
| 315 | 309 | .fourcc = V4L2_PIX_FMT_RGB555, |
|---|
| 316 | 310 | .types = VPE_FMT_TYPE_CAPTURE, |
|---|
| 317 | 311 | .coplanar = 0, |
|---|
| .. | .. |
|---|
| 325 | 319 | * there is one source queue and one destination queue for each m2m context. |
|---|
| 326 | 320 | */ |
|---|
| 327 | 321 | struct vpe_q_data { |
|---|
| 328 | | - unsigned int width; /* frame width */ |
|---|
| 329 | | - unsigned int height; /* frame height */ |
|---|
| 330 | | - unsigned int nplanes; /* Current number of planes */ |
|---|
| 331 | | - unsigned int bytesperline[VPE_MAX_PLANES]; /* bytes per line in memory */ |
|---|
| 332 | | - enum v4l2_colorspace colorspace; |
|---|
| 333 | | - enum v4l2_field field; /* supported field value */ |
|---|
| 322 | + /* current v4l2 format info */ |
|---|
| 323 | + struct v4l2_format format; |
|---|
| 334 | 324 | unsigned int flags; |
|---|
| 335 | | - unsigned int sizeimage[VPE_MAX_PLANES]; /* image size in memory */ |
|---|
| 336 | 325 | struct v4l2_rect c_rect; /* crop/compose rectangle */ |
|---|
| 337 | 326 | struct vpe_fmt *fmt; /* format info */ |
|---|
| 338 | 327 | }; |
|---|
| .. | .. |
|---|
| 342 | 331 | #define Q_DATA_MODE_TILED BIT(1) |
|---|
| 343 | 332 | #define Q_DATA_INTERLACED_ALTERNATE BIT(2) |
|---|
| 344 | 333 | #define Q_DATA_INTERLACED_SEQ_TB BIT(3) |
|---|
| 334 | +#define Q_DATA_INTERLACED_SEQ_BT BIT(4) |
|---|
| 335 | + |
|---|
| 336 | +#define Q_IS_SEQ_XX (Q_DATA_INTERLACED_SEQ_TB | \ |
|---|
| 337 | + Q_DATA_INTERLACED_SEQ_BT) |
|---|
| 345 | 338 | |
|---|
| 346 | 339 | #define Q_IS_INTERLACED (Q_DATA_INTERLACED_ALTERNATE | \ |
|---|
| 347 | | - Q_DATA_INTERLACED_SEQ_TB) |
|---|
| 340 | + Q_DATA_INTERLACED_SEQ_TB | \ |
|---|
| 341 | + Q_DATA_INTERLACED_SEQ_BT) |
|---|
| 348 | 342 | |
|---|
| 349 | 343 | enum { |
|---|
| 350 | 344 | Q_DATA_SRC = 0, |
|---|
| .. | .. |
|---|
| 700 | 694 | * Cfg Mode 1: YUV422 source, disable upsampler, DEI is de-interlacing. |
|---|
| 701 | 695 | */ |
|---|
| 702 | 696 | |
|---|
| 703 | | - if (fmt->fourcc == V4L2_PIX_FMT_NV12) |
|---|
| 697 | + if (fmt->fourcc == V4L2_PIX_FMT_NV12 || |
|---|
| 698 | + fmt->fourcc == V4L2_PIX_FMT_NV21) |
|---|
| 704 | 699 | cfg_mode = 0; |
|---|
| 705 | 700 | |
|---|
| 706 | 701 | write_field(us1_reg0, cfg_mode, VPE_US_MODE_MASK, VPE_US_MODE_SHIFT); |
|---|
| .. | .. |
|---|
| 715 | 710 | struct vpe_fmt *fmt = ctx->q_data[Q_DATA_SRC].fmt; |
|---|
| 716 | 711 | int line_mode = 1; |
|---|
| 717 | 712 | |
|---|
| 718 | | - if (fmt->fourcc == V4L2_PIX_FMT_NV12) |
|---|
| 713 | + if (fmt->fourcc == V4L2_PIX_FMT_NV12 || |
|---|
| 714 | + fmt->fourcc == V4L2_PIX_FMT_NV21) |
|---|
| 719 | 715 | line_mode = 0; /* double lines to line buffer */ |
|---|
| 720 | 716 | |
|---|
| 721 | 717 | /* regs for now */ |
|---|
| .. | .. |
|---|
| 760 | 756 | static void set_dst_registers(struct vpe_ctx *ctx) |
|---|
| 761 | 757 | { |
|---|
| 762 | 758 | struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr; |
|---|
| 763 | | - enum v4l2_colorspace clrspc = ctx->q_data[Q_DATA_DST].colorspace; |
|---|
| 764 | 759 | struct vpe_fmt *fmt = ctx->q_data[Q_DATA_DST].fmt; |
|---|
| 760 | + const struct v4l2_format_info *finfo; |
|---|
| 765 | 761 | u32 val = 0; |
|---|
| 766 | 762 | |
|---|
| 767 | | - if (clrspc == V4L2_COLORSPACE_SRGB) { |
|---|
| 763 | + finfo = v4l2_format_info(fmt->fourcc); |
|---|
| 764 | + if (v4l2_is_format_rgb(finfo)) { |
|---|
| 768 | 765 | val |= VPE_RGB_OUT_SELECT; |
|---|
| 769 | 766 | vpdma_set_bg_color(ctx->dev->vpdma, |
|---|
| 770 | 767 | (struct vpdma_data_format *)fmt->vpdma_fmt[0], 0xff); |
|---|
| .. | .. |
|---|
| 777 | 774 | */ |
|---|
| 778 | 775 | val |= VPE_DS_SRC_DEI_SCALER | VPE_CSC_SRC_DEI_SCALER; |
|---|
| 779 | 776 | |
|---|
| 780 | | - if (fmt->fourcc != V4L2_PIX_FMT_NV12) |
|---|
| 777 | + if (fmt->fourcc != V4L2_PIX_FMT_NV12 && |
|---|
| 778 | + fmt->fourcc != V4L2_PIX_FMT_NV21) |
|---|
| 781 | 779 | val |= VPE_DS_BYPASS; |
|---|
| 782 | 780 | |
|---|
| 783 | 781 | mmr_adb->out_fmt_reg[0] = val; |
|---|
| .. | .. |
|---|
| 866 | 864 | unsigned int src_h = s_q_data->c_rect.height; |
|---|
| 867 | 865 | unsigned int dst_w = d_q_data->c_rect.width; |
|---|
| 868 | 866 | unsigned int dst_h = d_q_data->c_rect.height; |
|---|
| 867 | + struct v4l2_pix_format_mplane *spix; |
|---|
| 869 | 868 | size_t mv_buf_size; |
|---|
| 870 | 869 | int ret; |
|---|
| 871 | 870 | |
|---|
| 872 | 871 | ctx->sequence = 0; |
|---|
| 873 | 872 | ctx->field = V4L2_FIELD_TOP; |
|---|
| 873 | + spix = &s_q_data->format.fmt.pix_mp; |
|---|
| 874 | 874 | |
|---|
| 875 | 875 | if ((s_q_data->flags & Q_IS_INTERLACED) && |
|---|
| 876 | 876 | !(d_q_data->flags & Q_IS_INTERLACED)) { |
|---|
| .. | .. |
|---|
| 881 | 881 | /* |
|---|
| 882 | 882 | * we make sure that the source image has a 16 byte aligned |
|---|
| 883 | 883 | * stride, we need to do the same for the motion vector buffer |
|---|
| 884 | | - * by aligning it's stride to the next 16 byte boundry. this |
|---|
| 884 | + * by aligning it's stride to the next 16 byte boundary. this |
|---|
| 885 | 885 | * extra space will not be used by the de-interlacer, but will |
|---|
| 886 | 886 | * ensure that vpdma operates correctly |
|---|
| 887 | 887 | */ |
|---|
| 888 | | - bytes_per_line = ALIGN((s_q_data->width * mv->depth) >> 3, |
|---|
| 889 | | - VPDMA_STRIDE_ALIGN); |
|---|
| 890 | | - mv_buf_size = bytes_per_line * s_q_data->height; |
|---|
| 888 | + bytes_per_line = ALIGN((spix->width * mv->depth) >> 3, |
|---|
| 889 | + VPDMA_STRIDE_ALIGN); |
|---|
| 890 | + mv_buf_size = bytes_per_line * spix->height; |
|---|
| 891 | 891 | |
|---|
| 892 | 892 | ctx->deinterlacing = true; |
|---|
| 893 | 893 | src_h <<= 1; |
|---|
| .. | .. |
|---|
| 907 | 907 | set_dei_regs(ctx); |
|---|
| 908 | 908 | |
|---|
| 909 | 909 | csc_set_coeff(ctx->dev->csc, &mmr_adb->csc_regs[0], |
|---|
| 910 | | - s_q_data->colorspace, d_q_data->colorspace); |
|---|
| 910 | + &s_q_data->format, &d_q_data->format); |
|---|
| 911 | 911 | |
|---|
| 912 | 912 | sc_set_hs_coeffs(ctx->dev->sc, ctx->sc_coeff_h.addr, src_w, dst_w); |
|---|
| 913 | 913 | sc_set_vs_coeffs(ctx->dev->sc, ctx->sc_coeff_v.addr, src_h, dst_h); |
|---|
| .. | .. |
|---|
| 917 | 917 | src_w, src_h, dst_w, dst_h); |
|---|
| 918 | 918 | |
|---|
| 919 | 919 | return 0; |
|---|
| 920 | | -} |
|---|
| 921 | | - |
|---|
| 922 | | -/* |
|---|
| 923 | | - * Return the vpe_ctx structure for a given struct file |
|---|
| 924 | | - */ |
|---|
| 925 | | -static struct vpe_ctx *file2ctx(struct file *file) |
|---|
| 926 | | -{ |
|---|
| 927 | | - return container_of(file->private_data, struct vpe_ctx, fh); |
|---|
| 928 | 920 | } |
|---|
| 929 | 921 | |
|---|
| 930 | 922 | /* |
|---|
| .. | .. |
|---|
| 1029 | 1021 | struct vpe_fmt *fmt = q_data->fmt; |
|---|
| 1030 | 1022 | const struct vpdma_data_format *vpdma_fmt; |
|---|
| 1031 | 1023 | int mv_buf_selector = !ctx->src_mv_buf_selector; |
|---|
| 1024 | + struct v4l2_pix_format_mplane *pix; |
|---|
| 1032 | 1025 | dma_addr_t dma_addr; |
|---|
| 1033 | 1026 | u32 flags = 0; |
|---|
| 1034 | 1027 | u32 offset = 0; |
|---|
| .. | .. |
|---|
| 1038 | 1031 | vpdma_fmt = &vpdma_misc_fmts[VPDMA_DATA_FMT_MV]; |
|---|
| 1039 | 1032 | dma_addr = ctx->mv_buf_dma[mv_buf_selector]; |
|---|
| 1040 | 1033 | q_data = &ctx->q_data[Q_DATA_SRC]; |
|---|
| 1041 | | - stride = ALIGN((q_data->width * vpdma_fmt->depth) >> 3, |
|---|
| 1034 | + pix = &q_data->format.fmt.pix_mp; |
|---|
| 1035 | + stride = ALIGN((pix->width * vpdma_fmt->depth) >> 3, |
|---|
| 1042 | 1036 | VPDMA_STRIDE_ALIGN); |
|---|
| 1043 | 1037 | } else { |
|---|
| 1044 | 1038 | /* to incorporate interleaved formats */ |
|---|
| 1045 | 1039 | int plane = fmt->coplanar ? p_data->vb_part : 0; |
|---|
| 1046 | 1040 | |
|---|
| 1041 | + pix = &q_data->format.fmt.pix_mp; |
|---|
| 1047 | 1042 | vpdma_fmt = fmt->vpdma_fmt[plane]; |
|---|
| 1048 | 1043 | /* |
|---|
| 1049 | 1044 | * If we are using a single plane buffer and |
|---|
| 1050 | 1045 | * we need to set a separate vpdma chroma channel. |
|---|
| 1051 | 1046 | */ |
|---|
| 1052 | | - if (q_data->nplanes == 1 && plane) { |
|---|
| 1047 | + if (pix->num_planes == 1 && plane) { |
|---|
| 1053 | 1048 | dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); |
|---|
| 1054 | 1049 | /* Compute required offset */ |
|---|
| 1055 | | - offset = q_data->bytesperline[0] * q_data->height; |
|---|
| 1050 | + offset = pix->plane_fmt[0].bytesperline * pix->height; |
|---|
| 1056 | 1051 | } else { |
|---|
| 1057 | 1052 | dma_addr = vb2_dma_contig_plane_dma_addr(vb, plane); |
|---|
| 1058 | 1053 | /* Use address as is, no offset */ |
|---|
| .. | .. |
|---|
| 1066 | 1061 | } |
|---|
| 1067 | 1062 | /* Apply the offset */ |
|---|
| 1068 | 1063 | dma_addr += offset; |
|---|
| 1069 | | - stride = q_data->bytesperline[VPE_LUMA]; |
|---|
| 1064 | + stride = pix->plane_fmt[VPE_LUMA].bytesperline; |
|---|
| 1070 | 1065 | } |
|---|
| 1071 | 1066 | |
|---|
| 1072 | 1067 | if (q_data->flags & Q_DATA_FRAME_1D) |
|---|
| .. | .. |
|---|
| 1077 | 1072 | vpdma_set_max_size(ctx->dev->vpdma, VPDMA_MAX_SIZE1, |
|---|
| 1078 | 1073 | MAX_W, MAX_H); |
|---|
| 1079 | 1074 | |
|---|
| 1080 | | - vpdma_add_out_dtd(&ctx->desc_list, q_data->width, |
|---|
| 1075 | + vpdma_add_out_dtd(&ctx->desc_list, pix->width, |
|---|
| 1081 | 1076 | stride, &q_data->c_rect, |
|---|
| 1082 | 1077 | vpdma_fmt, dma_addr, MAX_OUT_WIDTH_REG1, |
|---|
| 1083 | 1078 | MAX_OUT_HEIGHT_REG1, p_data->channel, flags); |
|---|
| .. | .. |
|---|
| 1090 | 1085 | struct vb2_buffer *vb = &ctx->src_vbs[p_data->vb_index]->vb2_buf; |
|---|
| 1091 | 1086 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
|---|
| 1092 | 1087 | struct vpe_fmt *fmt = q_data->fmt; |
|---|
| 1088 | + struct v4l2_pix_format_mplane *pix; |
|---|
| 1093 | 1089 | const struct vpdma_data_format *vpdma_fmt; |
|---|
| 1094 | 1090 | int mv_buf_selector = ctx->src_mv_buf_selector; |
|---|
| 1095 | 1091 | int field = vbuf->field == V4L2_FIELD_BOTTOM; |
|---|
| .. | .. |
|---|
| 1099 | 1095 | u32 offset = 0; |
|---|
| 1100 | 1096 | u32 stride; |
|---|
| 1101 | 1097 | |
|---|
| 1098 | + pix = &q_data->format.fmt.pix_mp; |
|---|
| 1102 | 1099 | if (port == VPE_PORT_MV_IN) { |
|---|
| 1103 | 1100 | vpdma_fmt = &vpdma_misc_fmts[VPDMA_DATA_FMT_MV]; |
|---|
| 1104 | 1101 | dma_addr = ctx->mv_buf_dma[mv_buf_selector]; |
|---|
| 1105 | | - stride = ALIGN((q_data->width * vpdma_fmt->depth) >> 3, |
|---|
| 1102 | + stride = ALIGN((pix->width * vpdma_fmt->depth) >> 3, |
|---|
| 1106 | 1103 | VPDMA_STRIDE_ALIGN); |
|---|
| 1107 | 1104 | } else { |
|---|
| 1108 | 1105 | /* to incorporate interleaved formats */ |
|---|
| .. | .. |
|---|
| 1113 | 1110 | * If we are using a single plane buffer and |
|---|
| 1114 | 1111 | * we need to set a separate vpdma chroma channel. |
|---|
| 1115 | 1112 | */ |
|---|
| 1116 | | - if (q_data->nplanes == 1 && plane) { |
|---|
| 1113 | + if (pix->num_planes == 1 && plane) { |
|---|
| 1117 | 1114 | dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); |
|---|
| 1118 | 1115 | /* Compute required offset */ |
|---|
| 1119 | | - offset = q_data->bytesperline[0] * q_data->height; |
|---|
| 1116 | + offset = pix->plane_fmt[0].bytesperline * pix->height; |
|---|
| 1120 | 1117 | } else { |
|---|
| 1121 | 1118 | dma_addr = vb2_dma_contig_plane_dma_addr(vb, plane); |
|---|
| 1122 | 1119 | /* Use address as is, no offset */ |
|---|
| .. | .. |
|---|
| 1130 | 1127 | } |
|---|
| 1131 | 1128 | /* Apply the offset */ |
|---|
| 1132 | 1129 | dma_addr += offset; |
|---|
| 1133 | | - stride = q_data->bytesperline[VPE_LUMA]; |
|---|
| 1130 | + stride = pix->plane_fmt[VPE_LUMA].bytesperline; |
|---|
| 1134 | 1131 | |
|---|
| 1135 | | - if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB) { |
|---|
| 1136 | | - /* |
|---|
| 1137 | | - * Use top or bottom field from same vb alternately |
|---|
| 1138 | | - * f,f-1,f-2 = TBT when seq is even |
|---|
| 1139 | | - * f,f-1,f-2 = BTB when seq is odd |
|---|
| 1140 | | - */ |
|---|
| 1141 | | - field = (p_data->vb_index + (ctx->sequence % 2)) % 2; |
|---|
| 1132 | + /* |
|---|
| 1133 | + * field used in VPDMA desc = 0 (top) / 1 (bottom) |
|---|
| 1134 | + * Use top or bottom field from same vb alternately |
|---|
| 1135 | + * For each de-interlacing operation, f,f-1,f-2 should be one |
|---|
| 1136 | + * of TBT or BTB |
|---|
| 1137 | + */ |
|---|
| 1138 | + if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB || |
|---|
| 1139 | + q_data->flags & Q_DATA_INTERLACED_SEQ_BT) { |
|---|
| 1140 | + /* Select initial value based on format */ |
|---|
| 1141 | + if (q_data->flags & Q_DATA_INTERLACED_SEQ_BT) |
|---|
| 1142 | + field = 1; |
|---|
| 1143 | + else |
|---|
| 1144 | + field = 0; |
|---|
| 1145 | + |
|---|
| 1146 | + /* Toggle for each vb_index and each operation */ |
|---|
| 1147 | + field = (field + p_data->vb_index + ctx->sequence) % 2; |
|---|
| 1142 | 1148 | |
|---|
| 1143 | 1149 | if (field) { |
|---|
| 1144 | | - /* |
|---|
| 1145 | | - * bottom field of a SEQ_TB buffer |
|---|
| 1146 | | - * Skip the top field data by |
|---|
| 1147 | | - */ |
|---|
| 1148 | | - int height = q_data->height / 2; |
|---|
| 1149 | | - int bpp = fmt->fourcc == V4L2_PIX_FMT_NV12 ? |
|---|
| 1150 | | - 1 : (vpdma_fmt->depth >> 3); |
|---|
| 1150 | + int height = pix->height / 2; |
|---|
| 1151 | + int bpp; |
|---|
| 1152 | + |
|---|
| 1153 | + if (fmt->fourcc == V4L2_PIX_FMT_NV12 || |
|---|
| 1154 | + fmt->fourcc == V4L2_PIX_FMT_NV21) |
|---|
| 1155 | + bpp = 1; |
|---|
| 1156 | + else |
|---|
| 1157 | + bpp = vpdma_fmt->depth >> 3; |
|---|
| 1158 | + |
|---|
| 1151 | 1159 | if (plane) |
|---|
| 1152 | 1160 | height /= 2; |
|---|
| 1153 | | - dma_addr += q_data->width * height * bpp; |
|---|
| 1161 | + |
|---|
| 1162 | + dma_addr += pix->width * height * bpp; |
|---|
| 1154 | 1163 | } |
|---|
| 1155 | 1164 | } |
|---|
| 1156 | 1165 | } |
|---|
| .. | .. |
|---|
| 1163 | 1172 | frame_width = q_data->c_rect.width; |
|---|
| 1164 | 1173 | frame_height = q_data->c_rect.height; |
|---|
| 1165 | 1174 | |
|---|
| 1166 | | - if (p_data->vb_part && fmt->fourcc == V4L2_PIX_FMT_NV12) |
|---|
| 1175 | + if (p_data->vb_part && (fmt->fourcc == V4L2_PIX_FMT_NV12 || |
|---|
| 1176 | + fmt->fourcc == V4L2_PIX_FMT_NV21)) |
|---|
| 1167 | 1177 | frame_height /= 2; |
|---|
| 1168 | 1178 | |
|---|
| 1169 | | - vpdma_add_in_dtd(&ctx->desc_list, q_data->width, stride, |
|---|
| 1179 | + vpdma_add_in_dtd(&ctx->desc_list, pix->width, stride, |
|---|
| 1170 | 1180 | &q_data->c_rect, vpdma_fmt, dma_addr, |
|---|
| 1171 | 1181 | p_data->channel, field, flags, frame_width, |
|---|
| 1172 | 1182 | frame_height, 0, 0); |
|---|
| .. | .. |
|---|
| 1203 | 1213 | struct sc_data *sc = ctx->dev->sc; |
|---|
| 1204 | 1214 | struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST]; |
|---|
| 1205 | 1215 | struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC]; |
|---|
| 1216 | + const struct v4l2_format_info *d_finfo; |
|---|
| 1206 | 1217 | |
|---|
| 1207 | | - if (ctx->deinterlacing && s_q_data->flags & Q_DATA_INTERLACED_SEQ_TB && |
|---|
| 1208 | | - ctx->sequence % 2 == 0) { |
|---|
| 1209 | | - /* When using SEQ_TB buffers, When using it first time, |
|---|
| 1210 | | - * No need to remove the buffer as the next field is present |
|---|
| 1211 | | - * in the same buffer. (so that job_ready won't fail) |
|---|
| 1212 | | - * It will be removed when using bottom field |
|---|
| 1218 | + d_finfo = v4l2_format_info(d_q_data->fmt->fourcc); |
|---|
| 1219 | + |
|---|
| 1220 | + if (ctx->deinterlacing && s_q_data->flags & Q_IS_SEQ_XX && |
|---|
| 1221 | + ctx->sequence % 2 == 0) { |
|---|
| 1222 | + /* When using SEQ_XX type buffers, each buffer has two fields |
|---|
| 1223 | + * each buffer has two fields (top & bottom) |
|---|
| 1224 | + * Removing one buffer is actually getting two fields |
|---|
| 1225 | + * Alternate between two operations:- |
|---|
| 1226 | + * Even : consume one field but DO NOT REMOVE from queue |
|---|
| 1227 | + * Odd : consume other field and REMOVE from queue |
|---|
| 1213 | 1228 | */ |
|---|
| 1214 | 1229 | ctx->src_vbs[0] = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); |
|---|
| 1215 | 1230 | WARN_ON(ctx->src_vbs[0] == NULL); |
|---|
| .. | .. |
|---|
| 1273 | 1288 | if (ctx->deinterlacing) |
|---|
| 1274 | 1289 | add_out_dtd(ctx, VPE_PORT_MV_OUT); |
|---|
| 1275 | 1290 | |
|---|
| 1276 | | - if (d_q_data->colorspace == V4L2_COLORSPACE_SRGB) { |
|---|
| 1291 | + if (v4l2_is_format_rgb(d_finfo)) { |
|---|
| 1277 | 1292 | add_out_dtd(ctx, VPE_PORT_RGB_OUT); |
|---|
| 1278 | 1293 | } else { |
|---|
| 1279 | 1294 | add_out_dtd(ctx, VPE_PORT_LUMA_OUT); |
|---|
| .. | .. |
|---|
| 1315 | 1330 | } |
|---|
| 1316 | 1331 | |
|---|
| 1317 | 1332 | /* sync on channel control descriptors for output ports */ |
|---|
| 1318 | | - if (d_q_data->colorspace == V4L2_COLORSPACE_SRGB) { |
|---|
| 1333 | + if (v4l2_is_format_rgb(d_finfo)) { |
|---|
| 1319 | 1334 | vpdma_add_sync_on_channel_ctd(&ctx->desc_list, |
|---|
| 1320 | 1335 | VPE_CHAN_RGB_OUT); |
|---|
| 1321 | 1336 | } else { |
|---|
| .. | .. |
|---|
| 1505 | 1520 | static int vpe_querycap(struct file *file, void *priv, |
|---|
| 1506 | 1521 | struct v4l2_capability *cap) |
|---|
| 1507 | 1522 | { |
|---|
| 1508 | | - strncpy(cap->driver, VPE_MODULE_NAME, sizeof(cap->driver) - 1); |
|---|
| 1509 | | - strncpy(cap->card, VPE_MODULE_NAME, sizeof(cap->card) - 1); |
|---|
| 1523 | + strscpy(cap->driver, VPE_MODULE_NAME, sizeof(cap->driver)); |
|---|
| 1524 | + strscpy(cap->card, VPE_MODULE_NAME, sizeof(cap->card)); |
|---|
| 1510 | 1525 | snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", |
|---|
| 1511 | 1526 | VPE_MODULE_NAME); |
|---|
| 1512 | | - cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; |
|---|
| 1513 | | - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; |
|---|
| 1514 | 1527 | return 0; |
|---|
| 1515 | 1528 | } |
|---|
| 1516 | 1529 | |
|---|
| .. | .. |
|---|
| 1533 | 1546 | if (!fmt) |
|---|
| 1534 | 1547 | return -EINVAL; |
|---|
| 1535 | 1548 | |
|---|
| 1536 | | - strncpy(f->description, fmt->name, sizeof(f->description) - 1); |
|---|
| 1537 | 1549 | f->pixelformat = fmt->fourcc; |
|---|
| 1538 | 1550 | return 0; |
|---|
| 1539 | 1551 | } |
|---|
| .. | .. |
|---|
| 1550 | 1562 | static int vpe_g_fmt(struct file *file, void *priv, struct v4l2_format *f) |
|---|
| 1551 | 1563 | { |
|---|
| 1552 | 1564 | struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; |
|---|
| 1553 | | - struct vpe_ctx *ctx = file2ctx(file); |
|---|
| 1565 | + struct vpe_ctx *ctx = file->private_data; |
|---|
| 1554 | 1566 | struct vb2_queue *vq; |
|---|
| 1555 | 1567 | struct vpe_q_data *q_data; |
|---|
| 1556 | | - int i; |
|---|
| 1557 | 1568 | |
|---|
| 1558 | 1569 | vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); |
|---|
| 1559 | 1570 | if (!vq) |
|---|
| 1560 | 1571 | return -EINVAL; |
|---|
| 1561 | 1572 | |
|---|
| 1562 | 1573 | q_data = get_q_data(ctx, f->type); |
|---|
| 1574 | + if (!q_data) |
|---|
| 1575 | + return -EINVAL; |
|---|
| 1563 | 1576 | |
|---|
| 1564 | | - pix->width = q_data->width; |
|---|
| 1565 | | - pix->height = q_data->height; |
|---|
| 1566 | | - pix->pixelformat = q_data->fmt->fourcc; |
|---|
| 1567 | | - pix->field = q_data->field; |
|---|
| 1577 | + *f = q_data->format; |
|---|
| 1568 | 1578 | |
|---|
| 1569 | | - if (V4L2_TYPE_IS_OUTPUT(f->type)) { |
|---|
| 1570 | | - pix->colorspace = q_data->colorspace; |
|---|
| 1571 | | - } else { |
|---|
| 1579 | + if (V4L2_TYPE_IS_CAPTURE(f->type)) { |
|---|
| 1572 | 1580 | struct vpe_q_data *s_q_data; |
|---|
| 1581 | + struct v4l2_pix_format_mplane *spix; |
|---|
| 1573 | 1582 | |
|---|
| 1574 | | - /* get colorspace from the source queue */ |
|---|
| 1583 | + /* get colorimetry from the source queue */ |
|---|
| 1575 | 1584 | s_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); |
|---|
| 1585 | + spix = &s_q_data->format.fmt.pix_mp; |
|---|
| 1576 | 1586 | |
|---|
| 1577 | | - pix->colorspace = s_q_data->colorspace; |
|---|
| 1578 | | - } |
|---|
| 1579 | | - |
|---|
| 1580 | | - pix->num_planes = q_data->nplanes; |
|---|
| 1581 | | - |
|---|
| 1582 | | - for (i = 0; i < pix->num_planes; i++) { |
|---|
| 1583 | | - pix->plane_fmt[i].bytesperline = q_data->bytesperline[i]; |
|---|
| 1584 | | - pix->plane_fmt[i].sizeimage = q_data->sizeimage[i]; |
|---|
| 1587 | + pix->colorspace = spix->colorspace; |
|---|
| 1588 | + pix->xfer_func = spix->xfer_func; |
|---|
| 1589 | + pix->ycbcr_enc = spix->ycbcr_enc; |
|---|
| 1590 | + pix->quantization = spix->quantization; |
|---|
| 1585 | 1591 | } |
|---|
| 1586 | 1592 | |
|---|
| 1587 | 1593 | return 0; |
|---|
| .. | .. |
|---|
| 1595 | 1601 | unsigned int w_align; |
|---|
| 1596 | 1602 | int i, depth, depth_bytes, height; |
|---|
| 1597 | 1603 | unsigned int stride = 0; |
|---|
| 1604 | + const struct v4l2_format_info *finfo; |
|---|
| 1598 | 1605 | |
|---|
| 1599 | 1606 | if (!fmt || !(fmt->types & type)) { |
|---|
| 1600 | 1607 | vpe_dbg(ctx->dev, "Fourcc format (0x%08x) invalid.\n", |
|---|
| .. | .. |
|---|
| 1602 | 1609 | fmt = __find_format(V4L2_PIX_FMT_YUYV); |
|---|
| 1603 | 1610 | } |
|---|
| 1604 | 1611 | |
|---|
| 1605 | | - if (pix->field != V4L2_FIELD_NONE && pix->field != V4L2_FIELD_ALTERNATE |
|---|
| 1606 | | - && pix->field != V4L2_FIELD_SEQ_TB) |
|---|
| 1612 | + if (pix->field != V4L2_FIELD_NONE && |
|---|
| 1613 | + pix->field != V4L2_FIELD_ALTERNATE && |
|---|
| 1614 | + pix->field != V4L2_FIELD_SEQ_TB && |
|---|
| 1615 | + pix->field != V4L2_FIELD_SEQ_BT) |
|---|
| 1607 | 1616 | pix->field = V4L2_FIELD_NONE; |
|---|
| 1608 | 1617 | |
|---|
| 1609 | 1618 | depth = fmt->vpdma_fmt[VPE_LUMA]->depth; |
|---|
| .. | .. |
|---|
| 1652 | 1661 | pix->num_planes = 1; |
|---|
| 1653 | 1662 | |
|---|
| 1654 | 1663 | pix->pixelformat = fmt->fourcc; |
|---|
| 1664 | + finfo = v4l2_format_info(fmt->fourcc); |
|---|
| 1655 | 1665 | |
|---|
| 1656 | 1666 | /* |
|---|
| 1657 | 1667 | * For the actual image parameters, we need to consider the field |
|---|
| 1658 | | - * height of the image for SEQ_TB buffers. |
|---|
| 1668 | + * height of the image for SEQ_XX buffers. |
|---|
| 1659 | 1669 | */ |
|---|
| 1660 | | - if (pix->field == V4L2_FIELD_SEQ_TB) |
|---|
| 1670 | + if (pix->field == V4L2_FIELD_SEQ_TB || pix->field == V4L2_FIELD_SEQ_BT) |
|---|
| 1661 | 1671 | height = pix->height / 2; |
|---|
| 1662 | 1672 | else |
|---|
| 1663 | 1673 | height = pix->height; |
|---|
| 1664 | 1674 | |
|---|
| 1665 | 1675 | if (!pix->colorspace) { |
|---|
| 1666 | | - if (fmt->fourcc == V4L2_PIX_FMT_RGB24 || |
|---|
| 1667 | | - fmt->fourcc == V4L2_PIX_FMT_BGR24 || |
|---|
| 1668 | | - fmt->fourcc == V4L2_PIX_FMT_RGB32 || |
|---|
| 1669 | | - fmt->fourcc == V4L2_PIX_FMT_BGR32) { |
|---|
| 1676 | + if (v4l2_is_format_rgb(finfo)) { |
|---|
| 1670 | 1677 | pix->colorspace = V4L2_COLORSPACE_SRGB; |
|---|
| 1671 | 1678 | } else { |
|---|
| 1672 | 1679 | if (height > 1280) /* HD */ |
|---|
| .. | .. |
|---|
| 1714 | 1721 | |
|---|
| 1715 | 1722 | static int vpe_try_fmt(struct file *file, void *priv, struct v4l2_format *f) |
|---|
| 1716 | 1723 | { |
|---|
| 1717 | | - struct vpe_ctx *ctx = file2ctx(file); |
|---|
| 1724 | + struct vpe_ctx *ctx = file->private_data; |
|---|
| 1718 | 1725 | struct vpe_fmt *fmt = find_format(f); |
|---|
| 1719 | 1726 | |
|---|
| 1720 | 1727 | if (V4L2_TYPE_IS_OUTPUT(f->type)) |
|---|
| .. | .. |
|---|
| 1726 | 1733 | static int __vpe_s_fmt(struct vpe_ctx *ctx, struct v4l2_format *f) |
|---|
| 1727 | 1734 | { |
|---|
| 1728 | 1735 | struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; |
|---|
| 1729 | | - struct v4l2_plane_pix_format *plane_fmt; |
|---|
| 1736 | + struct v4l2_pix_format_mplane *qpix; |
|---|
| 1730 | 1737 | struct vpe_q_data *q_data; |
|---|
| 1731 | 1738 | struct vb2_queue *vq; |
|---|
| 1732 | | - int i; |
|---|
| 1733 | 1739 | |
|---|
| 1734 | 1740 | vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); |
|---|
| 1735 | 1741 | if (!vq) |
|---|
| .. | .. |
|---|
| 1744 | 1750 | if (!q_data) |
|---|
| 1745 | 1751 | return -EINVAL; |
|---|
| 1746 | 1752 | |
|---|
| 1753 | + qpix = &q_data->format.fmt.pix_mp; |
|---|
| 1747 | 1754 | q_data->fmt = find_format(f); |
|---|
| 1748 | | - q_data->width = pix->width; |
|---|
| 1749 | | - q_data->height = pix->height; |
|---|
| 1750 | | - q_data->colorspace = pix->colorspace; |
|---|
| 1751 | | - q_data->field = pix->field; |
|---|
| 1752 | | - q_data->nplanes = pix->num_planes; |
|---|
| 1753 | | - |
|---|
| 1754 | | - for (i = 0; i < pix->num_planes; i++) { |
|---|
| 1755 | | - plane_fmt = &pix->plane_fmt[i]; |
|---|
| 1756 | | - |
|---|
| 1757 | | - q_data->bytesperline[i] = plane_fmt->bytesperline; |
|---|
| 1758 | | - q_data->sizeimage[i] = plane_fmt->sizeimage; |
|---|
| 1759 | | - } |
|---|
| 1755 | + q_data->format = *f; |
|---|
| 1760 | 1756 | |
|---|
| 1761 | 1757 | q_data->c_rect.left = 0; |
|---|
| 1762 | 1758 | q_data->c_rect.top = 0; |
|---|
| 1763 | | - q_data->c_rect.width = q_data->width; |
|---|
| 1764 | | - q_data->c_rect.height = q_data->height; |
|---|
| 1759 | + q_data->c_rect.width = pix->width; |
|---|
| 1760 | + q_data->c_rect.height = pix->height; |
|---|
| 1765 | 1761 | |
|---|
| 1766 | | - if (q_data->field == V4L2_FIELD_ALTERNATE) |
|---|
| 1762 | + if (qpix->field == V4L2_FIELD_ALTERNATE) |
|---|
| 1767 | 1763 | q_data->flags |= Q_DATA_INTERLACED_ALTERNATE; |
|---|
| 1768 | | - else if (q_data->field == V4L2_FIELD_SEQ_TB) |
|---|
| 1764 | + else if (qpix->field == V4L2_FIELD_SEQ_TB) |
|---|
| 1769 | 1765 | q_data->flags |= Q_DATA_INTERLACED_SEQ_TB; |
|---|
| 1766 | + else if (qpix->field == V4L2_FIELD_SEQ_BT) |
|---|
| 1767 | + q_data->flags |= Q_DATA_INTERLACED_SEQ_BT; |
|---|
| 1770 | 1768 | else |
|---|
| 1771 | 1769 | q_data->flags &= ~Q_IS_INTERLACED; |
|---|
| 1772 | 1770 | |
|---|
| 1773 | | - /* the crop height is halved for the case of SEQ_TB buffers */ |
|---|
| 1774 | | - if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB) |
|---|
| 1771 | + /* the crop height is halved for the case of SEQ_XX buffers */ |
|---|
| 1772 | + if (q_data->flags & Q_IS_SEQ_XX) |
|---|
| 1775 | 1773 | q_data->c_rect.height /= 2; |
|---|
| 1776 | 1774 | |
|---|
| 1777 | 1775 | vpe_dbg(ctx->dev, "Setting format for type %d, wxh: %dx%d, fmt: %d bpl_y %d", |
|---|
| 1778 | | - f->type, q_data->width, q_data->height, q_data->fmt->fourcc, |
|---|
| 1779 | | - q_data->bytesperline[VPE_LUMA]); |
|---|
| 1780 | | - if (q_data->nplanes == 2) |
|---|
| 1776 | + f->type, pix->width, pix->height, pix->pixelformat, |
|---|
| 1777 | + pix->plane_fmt[0].bytesperline); |
|---|
| 1778 | + if (pix->num_planes == 2) |
|---|
| 1781 | 1779 | vpe_dbg(ctx->dev, " bpl_uv %d\n", |
|---|
| 1782 | | - q_data->bytesperline[VPE_CHROMA]); |
|---|
| 1780 | + pix->plane_fmt[1].bytesperline); |
|---|
| 1783 | 1781 | |
|---|
| 1784 | 1782 | return 0; |
|---|
| 1785 | 1783 | } |
|---|
| .. | .. |
|---|
| 1787 | 1785 | static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) |
|---|
| 1788 | 1786 | { |
|---|
| 1789 | 1787 | int ret; |
|---|
| 1790 | | - struct vpe_ctx *ctx = file2ctx(file); |
|---|
| 1788 | + struct vpe_ctx *ctx = file->private_data; |
|---|
| 1791 | 1789 | |
|---|
| 1792 | 1790 | ret = vpe_try_fmt(file, priv, f); |
|---|
| 1793 | 1791 | if (ret) |
|---|
| .. | .. |
|---|
| 1808 | 1806 | static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s) |
|---|
| 1809 | 1807 | { |
|---|
| 1810 | 1808 | struct vpe_q_data *q_data; |
|---|
| 1809 | + struct v4l2_pix_format_mplane *pix; |
|---|
| 1811 | 1810 | int height; |
|---|
| 1812 | 1811 | |
|---|
| 1813 | 1812 | if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && |
|---|
| .. | .. |
|---|
| 1817 | 1816 | q_data = get_q_data(ctx, s->type); |
|---|
| 1818 | 1817 | if (!q_data) |
|---|
| 1819 | 1818 | return -EINVAL; |
|---|
| 1819 | + |
|---|
| 1820 | + pix = &q_data->format.fmt.pix_mp; |
|---|
| 1820 | 1821 | |
|---|
| 1821 | 1822 | switch (s->target) { |
|---|
| 1822 | 1823 | case V4L2_SEL_TGT_COMPOSE: |
|---|
| .. | .. |
|---|
| 1844 | 1845 | } |
|---|
| 1845 | 1846 | |
|---|
| 1846 | 1847 | /* |
|---|
| 1847 | | - * For SEQ_TB buffers, crop height should be less than the height of |
|---|
| 1848 | + * For SEQ_XX buffers, crop height should be less than the height of |
|---|
| 1848 | 1849 | * the field height, not the buffer height |
|---|
| 1849 | 1850 | */ |
|---|
| 1850 | | - if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB) |
|---|
| 1851 | | - height = q_data->height / 2; |
|---|
| 1851 | + if (q_data->flags & Q_IS_SEQ_XX) |
|---|
| 1852 | + height = pix->height / 2; |
|---|
| 1852 | 1853 | else |
|---|
| 1853 | | - height = q_data->height; |
|---|
| 1854 | + height = pix->height; |
|---|
| 1854 | 1855 | |
|---|
| 1855 | 1856 | if (s->r.top < 0 || s->r.left < 0) { |
|---|
| 1856 | 1857 | vpe_err(ctx->dev, "negative values for top and left\n"); |
|---|
| 1857 | 1858 | s->r.top = s->r.left = 0; |
|---|
| 1858 | 1859 | } |
|---|
| 1859 | 1860 | |
|---|
| 1860 | | - v4l_bound_align_image(&s->r.width, MIN_W, q_data->width, 1, |
|---|
| 1861 | + v4l_bound_align_image(&s->r.width, MIN_W, pix->width, 1, |
|---|
| 1861 | 1862 | &s->r.height, MIN_H, height, H_ALIGN, S_ALIGN); |
|---|
| 1862 | 1863 | |
|---|
| 1863 | 1864 | /* adjust left/top if cropping rectangle is out of bounds */ |
|---|
| 1864 | | - if (s->r.left + s->r.width > q_data->width) |
|---|
| 1865 | | - s->r.left = q_data->width - s->r.width; |
|---|
| 1866 | | - if (s->r.top + s->r.height > q_data->height) |
|---|
| 1867 | | - s->r.top = q_data->height - s->r.height; |
|---|
| 1865 | + if (s->r.left + s->r.width > pix->width) |
|---|
| 1866 | + s->r.left = pix->width - s->r.width; |
|---|
| 1867 | + if (s->r.top + s->r.height > pix->height) |
|---|
| 1868 | + s->r.top = pix->height - s->r.height; |
|---|
| 1868 | 1869 | |
|---|
| 1869 | 1870 | return 0; |
|---|
| 1870 | 1871 | } |
|---|
| .. | .. |
|---|
| 1872 | 1873 | static int vpe_g_selection(struct file *file, void *fh, |
|---|
| 1873 | 1874 | struct v4l2_selection *s) |
|---|
| 1874 | 1875 | { |
|---|
| 1875 | | - struct vpe_ctx *ctx = file2ctx(file); |
|---|
| 1876 | + struct vpe_ctx *ctx = file->private_data; |
|---|
| 1876 | 1877 | struct vpe_q_data *q_data; |
|---|
| 1878 | + struct v4l2_pix_format_mplane *pix; |
|---|
| 1877 | 1879 | bool use_c_rect = false; |
|---|
| 1878 | 1880 | |
|---|
| 1879 | 1881 | if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && |
|---|
| .. | .. |
|---|
| 1883 | 1885 | q_data = get_q_data(ctx, s->type); |
|---|
| 1884 | 1886 | if (!q_data) |
|---|
| 1885 | 1887 | return -EINVAL; |
|---|
| 1888 | + |
|---|
| 1889 | + pix = &q_data->format.fmt.pix_mp; |
|---|
| 1886 | 1890 | |
|---|
| 1887 | 1891 | switch (s->target) { |
|---|
| 1888 | 1892 | case V4L2_SEL_TGT_COMPOSE_DEFAULT: |
|---|
| .. | .. |
|---|
| 1922 | 1926 | */ |
|---|
| 1923 | 1927 | s->r.left = 0; |
|---|
| 1924 | 1928 | s->r.top = 0; |
|---|
| 1925 | | - s->r.width = q_data->width; |
|---|
| 1926 | | - s->r.height = q_data->height; |
|---|
| 1929 | + s->r.width = pix->width; |
|---|
| 1930 | + s->r.height = pix->height; |
|---|
| 1927 | 1931 | } |
|---|
| 1928 | 1932 | |
|---|
| 1929 | 1933 | return 0; |
|---|
| .. | .. |
|---|
| 1933 | 1937 | static int vpe_s_selection(struct file *file, void *fh, |
|---|
| 1934 | 1938 | struct v4l2_selection *s) |
|---|
| 1935 | 1939 | { |
|---|
| 1936 | | - struct vpe_ctx *ctx = file2ctx(file); |
|---|
| 1940 | + struct vpe_ctx *ctx = file->private_data; |
|---|
| 1937 | 1941 | struct vpe_q_data *q_data; |
|---|
| 1938 | 1942 | struct v4l2_selection sel = *s; |
|---|
| 1939 | 1943 | int ret; |
|---|
| .. | .. |
|---|
| 1991 | 1995 | static const struct v4l2_ioctl_ops vpe_ioctl_ops = { |
|---|
| 1992 | 1996 | .vidioc_querycap = vpe_querycap, |
|---|
| 1993 | 1997 | |
|---|
| 1994 | | - .vidioc_enum_fmt_vid_cap_mplane = vpe_enum_fmt, |
|---|
| 1998 | + .vidioc_enum_fmt_vid_cap = vpe_enum_fmt, |
|---|
| 1995 | 1999 | .vidioc_g_fmt_vid_cap_mplane = vpe_g_fmt, |
|---|
| 1996 | 2000 | .vidioc_try_fmt_vid_cap_mplane = vpe_try_fmt, |
|---|
| 1997 | 2001 | .vidioc_s_fmt_vid_cap_mplane = vpe_s_fmt, |
|---|
| 1998 | 2002 | |
|---|
| 1999 | | - .vidioc_enum_fmt_vid_out_mplane = vpe_enum_fmt, |
|---|
| 2003 | + .vidioc_enum_fmt_vid_out = vpe_enum_fmt, |
|---|
| 2000 | 2004 | .vidioc_g_fmt_vid_out_mplane = vpe_g_fmt, |
|---|
| 2001 | 2005 | .vidioc_try_fmt_vid_out_mplane = vpe_try_fmt, |
|---|
| 2002 | 2006 | .vidioc_s_fmt_vid_out_mplane = vpe_s_fmt, |
|---|
| .. | .. |
|---|
| 2026 | 2030 | int i; |
|---|
| 2027 | 2031 | struct vpe_ctx *ctx = vb2_get_drv_priv(vq); |
|---|
| 2028 | 2032 | struct vpe_q_data *q_data; |
|---|
| 2033 | + struct v4l2_pix_format_mplane *pix; |
|---|
| 2029 | 2034 | |
|---|
| 2030 | 2035 | q_data = get_q_data(ctx, vq->type); |
|---|
| 2036 | + if (!q_data) |
|---|
| 2037 | + return -EINVAL; |
|---|
| 2031 | 2038 | |
|---|
| 2032 | | - *nplanes = q_data->nplanes; |
|---|
| 2039 | + pix = &q_data->format.fmt.pix_mp; |
|---|
| 2040 | + *nplanes = pix->num_planes; |
|---|
| 2033 | 2041 | |
|---|
| 2034 | 2042 | for (i = 0; i < *nplanes; i++) |
|---|
| 2035 | | - sizes[i] = q_data->sizeimage[i]; |
|---|
| 2043 | + sizes[i] = pix->plane_fmt[i].sizeimage; |
|---|
| 2036 | 2044 | |
|---|
| 2037 | 2045 | vpe_dbg(ctx->dev, "get %d buffer(s) of size %d", *nbuffers, |
|---|
| 2038 | 2046 | sizes[VPE_LUMA]); |
|---|
| 2039 | | - if (q_data->nplanes == 2) |
|---|
| 2047 | + if (*nplanes == 2) |
|---|
| 2040 | 2048 | vpe_dbg(ctx->dev, " and %d\n", sizes[VPE_CHROMA]); |
|---|
| 2041 | 2049 | |
|---|
| 2042 | 2050 | return 0; |
|---|
| .. | .. |
|---|
| 2047 | 2055 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
|---|
| 2048 | 2056 | struct vpe_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); |
|---|
| 2049 | 2057 | struct vpe_q_data *q_data; |
|---|
| 2050 | | - int i, num_planes; |
|---|
| 2058 | + struct v4l2_pix_format_mplane *pix; |
|---|
| 2059 | + int i; |
|---|
| 2051 | 2060 | |
|---|
| 2052 | 2061 | vpe_dbg(ctx->dev, "type: %d\n", vb->vb2_queue->type); |
|---|
| 2053 | 2062 | |
|---|
| 2054 | 2063 | q_data = get_q_data(ctx, vb->vb2_queue->type); |
|---|
| 2055 | | - num_planes = q_data->nplanes; |
|---|
| 2064 | + if (!q_data) |
|---|
| 2065 | + return -EINVAL; |
|---|
| 2066 | + |
|---|
| 2067 | + pix = &q_data->format.fmt.pix_mp; |
|---|
| 2056 | 2068 | |
|---|
| 2057 | 2069 | if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { |
|---|
| 2058 | 2070 | if (!(q_data->flags & Q_IS_INTERLACED)) { |
|---|
| .. | .. |
|---|
| 2060 | 2072 | } else { |
|---|
| 2061 | 2073 | if (vbuf->field != V4L2_FIELD_TOP && |
|---|
| 2062 | 2074 | vbuf->field != V4L2_FIELD_BOTTOM && |
|---|
| 2063 | | - vbuf->field != V4L2_FIELD_SEQ_TB) |
|---|
| 2075 | + vbuf->field != V4L2_FIELD_SEQ_TB && |
|---|
| 2076 | + vbuf->field != V4L2_FIELD_SEQ_BT) |
|---|
| 2064 | 2077 | return -EINVAL; |
|---|
| 2065 | 2078 | } |
|---|
| 2066 | 2079 | } |
|---|
| 2067 | 2080 | |
|---|
| 2068 | | - for (i = 0; i < num_planes; i++) { |
|---|
| 2069 | | - if (vb2_plane_size(vb, i) < q_data->sizeimage[i]) { |
|---|
| 2081 | + for (i = 0; i < pix->num_planes; i++) { |
|---|
| 2082 | + if (vb2_plane_size(vb, i) < pix->plane_fmt[i].sizeimage) { |
|---|
| 2070 | 2083 | vpe_err(ctx->dev, |
|---|
| 2071 | 2084 | "data will not fit into plane (%lu < %lu)\n", |
|---|
| 2072 | 2085 | vb2_plane_size(vb, i), |
|---|
| 2073 | | - (long) q_data->sizeimage[i]); |
|---|
| 2086 | + (long)pix->plane_fmt[i].sizeimage); |
|---|
| 2074 | 2087 | return -EINVAL; |
|---|
| 2075 | 2088 | } |
|---|
| 2076 | 2089 | } |
|---|
| 2077 | 2090 | |
|---|
| 2078 | | - for (i = 0; i < num_planes; i++) |
|---|
| 2079 | | - vb2_set_plane_payload(vb, i, q_data->sizeimage[i]); |
|---|
| 2091 | + for (i = 0; i < pix->num_planes; i++) |
|---|
| 2092 | + vb2_set_plane_payload(vb, i, pix->plane_fmt[i].sizeimage); |
|---|
| 2080 | 2093 | |
|---|
| 2081 | 2094 | return 0; |
|---|
| 2082 | 2095 | } |
|---|
| .. | .. |
|---|
| 2261 | 2274 | struct vpe_q_data *s_q_data; |
|---|
| 2262 | 2275 | struct v4l2_ctrl_handler *hdl; |
|---|
| 2263 | 2276 | struct vpe_ctx *ctx; |
|---|
| 2277 | + struct v4l2_pix_format_mplane *pix; |
|---|
| 2264 | 2278 | int ret; |
|---|
| 2265 | 2279 | |
|---|
| 2266 | 2280 | vpe_dbg(dev, "vpe_open\n"); |
|---|
| .. | .. |
|---|
| 2296 | 2310 | init_adb_hdrs(ctx); |
|---|
| 2297 | 2311 | |
|---|
| 2298 | 2312 | v4l2_fh_init(&ctx->fh, video_devdata(file)); |
|---|
| 2299 | | - file->private_data = &ctx->fh; |
|---|
| 2313 | + file->private_data = ctx; |
|---|
| 2300 | 2314 | |
|---|
| 2301 | 2315 | hdl = &ctx->hdl; |
|---|
| 2302 | 2316 | v4l2_ctrl_handler_init(hdl, 1); |
|---|
| .. | .. |
|---|
| 2309 | 2323 | v4l2_ctrl_handler_setup(hdl); |
|---|
| 2310 | 2324 | |
|---|
| 2311 | 2325 | s_q_data = &ctx->q_data[Q_DATA_SRC]; |
|---|
| 2326 | + pix = &s_q_data->format.fmt.pix_mp; |
|---|
| 2312 | 2327 | s_q_data->fmt = __find_format(V4L2_PIX_FMT_YUYV); |
|---|
| 2313 | | - s_q_data->width = 1920; |
|---|
| 2314 | | - s_q_data->height = 1080; |
|---|
| 2315 | | - s_q_data->nplanes = 1; |
|---|
| 2316 | | - s_q_data->bytesperline[VPE_LUMA] = (s_q_data->width * |
|---|
| 2328 | + pix->pixelformat = s_q_data->fmt->fourcc; |
|---|
| 2329 | + s_q_data->format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
|---|
| 2330 | + pix->width = 1920; |
|---|
| 2331 | + pix->height = 1080; |
|---|
| 2332 | + pix->num_planes = 1; |
|---|
| 2333 | + pix->plane_fmt[VPE_LUMA].bytesperline = (pix->width * |
|---|
| 2317 | 2334 | s_q_data->fmt->vpdma_fmt[VPE_LUMA]->depth) >> 3; |
|---|
| 2318 | | - s_q_data->sizeimage[VPE_LUMA] = (s_q_data->bytesperline[VPE_LUMA] * |
|---|
| 2319 | | - s_q_data->height); |
|---|
| 2320 | | - s_q_data->colorspace = V4L2_COLORSPACE_REC709; |
|---|
| 2321 | | - s_q_data->field = V4L2_FIELD_NONE; |
|---|
| 2335 | + pix->plane_fmt[VPE_LUMA].sizeimage = |
|---|
| 2336 | + pix->plane_fmt[VPE_LUMA].bytesperline * |
|---|
| 2337 | + pix->height; |
|---|
| 2338 | + pix->colorspace = V4L2_COLORSPACE_REC709; |
|---|
| 2339 | + pix->xfer_func = V4L2_XFER_FUNC_DEFAULT; |
|---|
| 2340 | + pix->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; |
|---|
| 2341 | + pix->quantization = V4L2_QUANTIZATION_DEFAULT; |
|---|
| 2342 | + pix->field = V4L2_FIELD_NONE; |
|---|
| 2322 | 2343 | s_q_data->c_rect.left = 0; |
|---|
| 2323 | 2344 | s_q_data->c_rect.top = 0; |
|---|
| 2324 | | - s_q_data->c_rect.width = s_q_data->width; |
|---|
| 2325 | | - s_q_data->c_rect.height = s_q_data->height; |
|---|
| 2345 | + s_q_data->c_rect.width = pix->width; |
|---|
| 2346 | + s_q_data->c_rect.height = pix->height; |
|---|
| 2326 | 2347 | s_q_data->flags = 0; |
|---|
| 2327 | 2348 | |
|---|
| 2328 | 2349 | ctx->q_data[Q_DATA_DST] = *s_q_data; |
|---|
| 2350 | + ctx->q_data[Q_DATA_DST].format.type = |
|---|
| 2351 | + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
|---|
| 2329 | 2352 | |
|---|
| 2330 | 2353 | set_dei_shadow_registers(ctx); |
|---|
| 2331 | 2354 | set_src_registers(ctx); |
|---|
| .. | .. |
|---|
| 2381 | 2404 | static int vpe_release(struct file *file) |
|---|
| 2382 | 2405 | { |
|---|
| 2383 | 2406 | struct vpe_dev *dev = video_drvdata(file); |
|---|
| 2384 | | - struct vpe_ctx *ctx = file2ctx(file); |
|---|
| 2407 | + struct vpe_ctx *ctx = file->private_data; |
|---|
| 2385 | 2408 | |
|---|
| 2386 | 2409 | vpe_dbg(dev, "releasing instance %p\n", ctx); |
|---|
| 2387 | 2410 | |
|---|
| .. | .. |
|---|
| 2435 | 2458 | .minor = -1, |
|---|
| 2436 | 2459 | .release = video_device_release_empty, |
|---|
| 2437 | 2460 | .vfl_dir = VFL_DIR_M2M, |
|---|
| 2461 | + .device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING, |
|---|
| 2438 | 2462 | }; |
|---|
| 2439 | 2463 | |
|---|
| 2440 | 2464 | static const struct v4l2_m2m_ops m2m_ops = { |
|---|
| .. | .. |
|---|
| 2478 | 2502 | vfd->lock = &dev->dev_mutex; |
|---|
| 2479 | 2503 | vfd->v4l2_dev = &dev->v4l2_dev; |
|---|
| 2480 | 2504 | |
|---|
| 2481 | | - ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); |
|---|
| 2505 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); |
|---|
| 2482 | 2506 | if (ret) { |
|---|
| 2483 | 2507 | vpe_err(dev, "Failed to register video device\n"); |
|---|
| 2484 | 2508 | |
|---|
| .. | .. |
|---|
| 2501 | 2525 | struct vpe_dev *dev; |
|---|
| 2502 | 2526 | int ret, irq, func; |
|---|
| 2503 | 2527 | |
|---|
| 2528 | + ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); |
|---|
| 2529 | + if (ret) { |
|---|
| 2530 | + dev_err(&pdev->dev, |
|---|
| 2531 | + "32-bit consistent DMA enable failed\n"); |
|---|
| 2532 | + return ret; |
|---|
| 2533 | + } |
|---|
| 2534 | + |
|---|
| 2504 | 2535 | dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); |
|---|
| 2505 | 2536 | if (!dev) |
|---|
| 2506 | 2537 | return -ENOMEM; |
|---|
| .. | .. |
|---|
| 2515 | 2546 | mutex_init(&dev->dev_mutex); |
|---|
| 2516 | 2547 | |
|---|
| 2517 | 2548 | dev->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, |
|---|
| 2518 | | - "vpe_top"); |
|---|
| 2549 | + "vpe_top"); |
|---|
| 2550 | + if (!dev->res) { |
|---|
| 2551 | + dev_err(&pdev->dev, "missing 'vpe_top' resources data\n"); |
|---|
| 2552 | + return -ENODEV; |
|---|
| 2553 | + } |
|---|
| 2554 | + |
|---|
| 2519 | 2555 | /* |
|---|
| 2520 | 2556 | * HACK: we get resource info from device tree in the form of a list of |
|---|
| 2521 | 2557 | * VPE sub blocks, the driver currently uses only the base of vpe_top |
|---|
| .. | .. |
|---|
| 2610 | 2646 | #if defined(CONFIG_OF) |
|---|
| 2611 | 2647 | static const struct of_device_id vpe_of_match[] = { |
|---|
| 2612 | 2648 | { |
|---|
| 2613 | | - .compatible = "ti,vpe", |
|---|
| 2649 | + .compatible = "ti,dra7-vpe", |
|---|
| 2614 | 2650 | }, |
|---|
| 2615 | 2651 | {}, |
|---|
| 2616 | 2652 | }; |
|---|