diff options
Diffstat (limited to 'drivers/media/platform/coda/coda-bit.c')
| -rw-r--r-- | drivers/media/platform/coda/coda-bit.c | 123 | 
1 files changed, 74 insertions, 49 deletions
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 68ed2a564ad1..d26c2d85a009 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -261,11 +261,12 @@ void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list)  	while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) {  		/* -		 * Only queue a single JPEG into the bitstream buffer, except -		 * to increase payload over 512 bytes or if in hold state. +		 * Only queue two JPEGs into the bitstream buffer to keep +		 * latency low. We need at least one complete buffer and the +		 * header of another buffer (for prescan) in the bitstream.  		 */  		if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG && -		    (coda_get_bitstream_payload(ctx) >= 512) && !ctx->hold) +		    ctx->num_metas > 1)  			break;  		src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); @@ -389,32 +390,29 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx,  				   struct coda_q_data *q_data, u32 fourcc)  {  	struct coda_dev *dev = ctx->dev; -	int width, height; -	int ysize; +	unsigned int ysize, ycbcr_size;  	int ret;  	int i;  	if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 ||  	    ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264 ||  	    ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4 || -	    ctx->codec->dst_fourcc == V4L2_PIX_FMT_MPEG4) { -		width = round_up(q_data->width, 16); -		height = round_up(q_data->height, 16); -	} else { -		width = round_up(q_data->width, 8); -		height = q_data->height; -	} -	ysize = width * height; +	    ctx->codec->dst_fourcc == V4L2_PIX_FMT_MPEG4) +		ysize = round_up(q_data->rect.width, 16) * +			round_up(q_data->rect.height, 16); +	else +		ysize = round_up(q_data->rect.width, 8) * q_data->rect.height; + +	if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) +		ycbcr_size = round_up(ysize, 4096) + ysize / 2; +	else +		ycbcr_size = ysize + ysize / 2;  	/* Allocate frame buffers */  	for (i = 0; i < ctx->num_internal_frames; i++) { -		size_t size; +		size_t size = ycbcr_size;  		char *name; -		if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) -			size = round_up(ysize, 4096) + ysize / 2; -		else -			size = ysize + ysize / 2;  		/* Add space for mvcol buffers */  		if (dev->devtype->product != CODA_DX6 &&  		    (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 || @@ -499,8 +497,8 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx,  	if (!ctx->slicebuf.vaddr && q_data->fourcc == V4L2_PIX_FMT_H264) {  		/* worst case slice size */ -		size = (DIV_ROUND_UP(q_data->width, 16) * -			DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512; +		size = (DIV_ROUND_UP(q_data->rect.width, 16) * +			DIV_ROUND_UP(q_data->rect.height, 16)) * 3200 / 8 + 512;  		ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size,  					     "slicebuf");  		if (ret < 0) @@ -538,6 +536,8 @@ static int coda_encode_header(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf,  {  	struct vb2_buffer *vb = &buf->vb2_buf;  	struct coda_dev *dev = ctx->dev; +	struct coda_q_data *q_data_src; +	struct v4l2_rect *r;  	size_t bufsize;  	int ret;  	int i; @@ -551,6 +551,23 @@ static int coda_encode_header(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf,  	if (dev->devtype->product == CODA_960)  		bufsize /= 1024;  	coda_write(dev, bufsize, CODA_CMD_ENC_HEADER_BB_SIZE); +	if (dev->devtype->product == CODA_960 && +	    ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264 && +	    header_code == CODA_HEADER_H264_SPS) { +		q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); +		r = &q_data_src->rect; + +		if (r->width % 16 || r->height % 16) { +			u32 crop_right = round_up(r->width, 16) -  r->width; +			u32 crop_bottom = round_up(r->height, 16) - r->height; + +			coda_write(dev, crop_right, +				   CODA9_CMD_ENC_HEADER_FRAME_CROP_H); +			coda_write(dev, crop_bottom, +				   CODA9_CMD_ENC_HEADER_FRAME_CROP_V); +			header_code |= CODA9_HEADER_FRAME_CROP; +		} +	}  	coda_write(dev, header_code, CODA_CMD_ENC_HEADER_CODE);  	ret = coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER);  	if (ret < 0) { @@ -632,7 +649,7 @@ static void coda_setup_iram(struct coda_ctx *ctx)  		struct coda_q_data *q_data_src;  		q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); -		mb_width = DIV_ROUND_UP(q_data_src->width, 16); +		mb_width = DIV_ROUND_UP(q_data_src->rect.width, 16);  		w128 = mb_width * 128;  		w64 = mb_width * 64; @@ -721,6 +738,7 @@ static u32 coda_supported_firmwares[] = {  	CODA_FIRMWARE_VERNUM(CODA_HX4, 1, 4, 50),  	CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50),  	CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5), +	CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 9),  	CODA_FIRMWARE_VERNUM(CODA_960, 2, 3, 10),  	CODA_FIRMWARE_VERNUM(CODA_960, 3, 1, 1),  }; @@ -928,25 +946,25 @@ static int coda_start_encoding(struct coda_ctx *ctx)  	value = 0;  	switch (dev->devtype->product) {  	case CODA_DX6: -		value = (q_data_src->width & CODADX6_PICWIDTH_MASK) +		value = (q_data_src->rect.width & CODADX6_PICWIDTH_MASK)  			<< CODADX6_PICWIDTH_OFFSET; -		value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK) +		value |= (q_data_src->rect.height & CODADX6_PICHEIGHT_MASK)  			 << CODA_PICHEIGHT_OFFSET;  		break;  	case CODA_HX4:  	case CODA_7541:  		if (dst_fourcc == V4L2_PIX_FMT_H264) { -			value = (round_up(q_data_src->width, 16) & +			value = (round_up(q_data_src->rect.width, 16) &  				 CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; -			value |= (round_up(q_data_src->height, 16) & +			value |= (round_up(q_data_src->rect.height, 16) &  				 CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;  			break;  		}  		/* fallthrough */  	case CODA_960: -		value = (q_data_src->width & CODA7_PICWIDTH_MASK) +		value = (q_data_src->rect.width & CODA7_PICWIDTH_MASK)  			<< CODA7_PICWIDTH_OFFSET; -		value |= (q_data_src->height & CODA7_PICHEIGHT_MASK) +		value |= (q_data_src->rect.height & CODA7_PICHEIGHT_MASK)  			 << CODA_PICHEIGHT_OFFSET;  	}  	coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE); @@ -1198,6 +1216,27 @@ static int coda_start_encoding(struct coda_ctx *ctx)  			goto out;  		/* +		 * If visible width or height are not aligned to macroblock +		 * size, the crop_right and crop_bottom SPS fields must be set +		 * to the difference between visible and coded size.  This is +		 * only supported by CODA960 firmware. All others do not allow +		 * writing frame cropping parameters, so we have to manually +		 * fix up the SPS RBSP (Sequence Parameter Set Raw Byte +		 * Sequence Payload) ourselves. +		 */ +		if (ctx->dev->devtype->product != CODA_960 && +		    ((q_data_src->rect.width % 16) || +		     (q_data_src->rect.height % 16))) { +			ret = coda_h264_sps_fixup(ctx, q_data_src->rect.width, +						  q_data_src->rect.height, +						  &ctx->vpu_header[0][0], +						  &ctx->vpu_header_size[0], +						  sizeof(ctx->vpu_header[0])); +			if (ret < 0) +				goto out; +		} + +		/*  		 * Get PPS in the first frame and copy it to an  		 * intermediate buffer.  		 */ @@ -1362,7 +1401,8 @@ static int coda_prepare_encode(struct coda_ctx *ctx)  	if (dev->devtype->product == CODA_960) {  		coda_write(dev, 4/*FIXME: 0*/, CODA9_CMD_ENC_PIC_SRC_INDEX); -		coda_write(dev, q_data_src->width, CODA9_CMD_ENC_PIC_SRC_STRIDE); +		coda_write(dev, q_data_src->bytesperline, +			   CODA9_CMD_ENC_PIC_SRC_STRIDE);  		coda_write(dev, 0, CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC);  		reg = CODA9_CMD_ENC_PIC_SRC_ADDR_Y; @@ -1582,10 +1622,8 @@ static int coda_decoder_reqbufs(struct coda_ctx *ctx,  static bool coda_reorder_enable(struct coda_ctx *ctx)  { -	const char * const *profile_names; -	const char * const *level_names;  	struct coda_dev *dev = ctx->dev; -	int profile, level; +	int profile;  	if (dev->devtype->product != CODA_HX4 &&  	    dev->devtype->product != CODA_7541 && @@ -1599,24 +1637,9 @@ static bool coda_reorder_enable(struct coda_ctx *ctx)  		return true;  	profile = coda_h264_profile(ctx->params.h264_profile_idc); -	if (profile < 0) { -		v4l2_warn(&dev->v4l2_dev, "Invalid H264 Profile: %d\n", -			 ctx->params.h264_profile_idc); -		return false; -	} - -	level = coda_h264_level(ctx->params.h264_level_idc); -	if (level < 0) { -		v4l2_warn(&dev->v4l2_dev, "Invalid H264 Level: %d\n", -			 ctx->params.h264_level_idc); -		return false; -	} - -	profile_names = v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_PROFILE); -	level_names = v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_LEVEL); - -	v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "H264 Profile/Level: %s L%s\n", -		 profile_names[profile], level_names[level]); +	if (profile < 0) +		v4l2_warn(&dev->v4l2_dev, "Unknown H264 Profile: %u\n", +			  ctx->params.h264_profile_idc);  	/* Baseline profile does not support reordering */  	return profile > V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; @@ -1694,6 +1717,8 @@ static int __coda_start_decoding(struct coda_ctx *ctx)  			coda_write(dev, 512, CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE);  		}  	} +	if (src_fourcc == V4L2_PIX_FMT_JPEG) +		coda_write(dev, 0, CODA_CMD_DEC_SEQ_JPG_THUMB_EN);  	if (dev->devtype->product != CODA_960)  		coda_write(dev, 0, CODA_CMD_DEC_SEQ_SRC_SIZE);  |