Re: [STLinux Kernel] [PATCH v6 09/10] [media] st-delta: add mjpeg support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, 01 Feb 2017, Hugues Fruchet wrote:

> Adds support of DELTA MJPEG video decoder back-end,
> implemented by calling JPEG_DECODER_HW0 firmware
> using RPMSG IPC communication layer.
> 
> Signed-off-by: Hugues Fruchet <hugues.fruchet@xxxxxx>

Acked-by: Peter Griffin <peter.griffin@xxxxxxxxxx>

> ---
>  drivers/media/platform/Kconfig                     |  12 +-
>  drivers/media/platform/sti/delta/Makefile          |   4 +
>  drivers/media/platform/sti/delta/delta-cfg.h       |   3 +
>  drivers/media/platform/sti/delta/delta-mjpeg-dec.c | 455 +++++++++++++++++++++
>  drivers/media/platform/sti/delta/delta-mjpeg-fw.h  | 225 ++++++++++
>  drivers/media/platform/sti/delta/delta-mjpeg-hdr.c | 149 +++++++
>  drivers/media/platform/sti/delta/delta-mjpeg.h     |  35 ++
>  drivers/media/platform/sti/delta/delta-v4l2.c      |   3 +
>  8 files changed, 885 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/media/platform/sti/delta/delta-mjpeg-dec.c
>  create mode 100644 drivers/media/platform/sti/delta/delta-mjpeg-fw.h
>  create mode 100644 drivers/media/platform/sti/delta/delta-mjpeg-hdr.c
>  create mode 100644 drivers/media/platform/sti/delta/delta-mjpeg.h
> 
> diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
> index 2e82ec6..20b26ea 100644
> --- a/drivers/media/platform/Kconfig
> +++ b/drivers/media/platform/Kconfig
> @@ -317,10 +317,20 @@ config VIDEO_STI_DELTA
>  
>  if VIDEO_STI_DELTA
>  
> +config VIDEO_STI_DELTA_MJPEG
> +	bool "STMicroelectronics DELTA MJPEG support"
> +	default y
> +	help
> +		Enables DELTA MJPEG hardware support.
> +
> +		To compile this driver as a module, choose M here:
> +		the module will be called st-delta.
> +
>  config VIDEO_STI_DELTA_DRIVER
>  	tristate
>  	depends on VIDEO_STI_DELTA
> -	default n
> +	depends on VIDEO_STI_DELTA_MJPEG
> +	default VIDEO_STI_DELTA_MJPEG
>  	select VIDEOBUF2_DMA_CONTIG
>  	select V4L2_MEM2MEM_DEV
>  	select RPMSG
> diff --git a/drivers/media/platform/sti/delta/Makefile b/drivers/media/platform/sti/delta/Makefile
> index b791ba0..b268df6 100644
> --- a/drivers/media/platform/sti/delta/Makefile
> +++ b/drivers/media/platform/sti/delta/Makefile
> @@ -1,2 +1,6 @@
>  obj-$(CONFIG_VIDEO_STI_DELTA_DRIVER) := st-delta.o
>  st-delta-y := delta-v4l2.o delta-mem.o delta-ipc.o
> +
> +# MJPEG support
> +st-delta-$(CONFIG_VIDEO_STI_DELTA_MJPEG) += delta-mjpeg-hdr.o
> +st-delta-$(CONFIG_VIDEO_STI_DELTA_MJPEG) += delta-mjpeg-dec.o
> diff --git a/drivers/media/platform/sti/delta/delta-cfg.h b/drivers/media/platform/sti/delta/delta-cfg.h
> index f6674f6..c6388f5 100644
> --- a/drivers/media/platform/sti/delta/delta-cfg.h
> +++ b/drivers/media/platform/sti/delta/delta-cfg.h
> @@ -57,5 +57,8 @@
>  #define DELTA_HW_AUTOSUSPEND_DELAY_MS 5
>  
>  #define DELTA_MAX_DECODERS 10
> +#ifdef CONFIG_VIDEO_STI_DELTA_MJPEG
> +extern const struct delta_dec mjpegdec;
> +#endif
>  
>  #endif /* DELTA_CFG_H */
> diff --git a/drivers/media/platform/sti/delta/delta-mjpeg-dec.c b/drivers/media/platform/sti/delta/delta-mjpeg-dec.c
> new file mode 100644
> index 0000000..e79bdc6
> --- /dev/null
> +++ b/drivers/media/platform/sti/delta/delta-mjpeg-dec.c
> @@ -0,0 +1,455 @@
> +/*
> + * Copyright (C) STMicroelectronics SA 2013
> + * Author: Hugues Fruchet <hugues.fruchet@xxxxxx> for STMicroelectronics.
> + * License terms:  GNU General Public License (GPL), version 2
> + */
> +
> +#include <linux/slab.h>
> +
> +#include "delta.h"
> +#include "delta-ipc.h"
> +#include "delta-mjpeg.h"
> +#include "delta-mjpeg-fw.h"
> +
> +#define DELTA_MJPEG_MAX_RESO DELTA_MAX_RESO
> +
> +struct delta_mjpeg_ctx {
> +	/* jpeg header */
> +	struct mjpeg_header header_struct;
> +	struct mjpeg_header *header;
> +
> +	/* ipc */
> +	void *ipc_hdl;
> +	struct delta_buf *ipc_buf;
> +
> +	/* decoded output frame */
> +	struct delta_frame *out_frame;
> +
> +	unsigned char str[3000];
> +};
> +
> +#define to_ctx(ctx) ((struct delta_mjpeg_ctx *)(ctx)->priv)
> +
> +static char *ipc_open_param_str(struct jpeg_video_decode_init_params_t *p,
> +				char *str, unsigned int len)
> +{
> +	char *b = str;
> +
> +	if (!p)
> +		return "";
> +
> +	b += snprintf(b, len,
> +		      "jpeg_video_decode_init_params_t\n"
> +		      "circular_buffer_begin_addr_p 0x%x\n"
> +		      "circular_buffer_end_addr_p   0x%x\n",
> +		      p->circular_buffer_begin_addr_p,
> +		      p->circular_buffer_end_addr_p);
> +
> +	return str;
> +}
> +
> +static char *ipc_decode_param_str(struct jpeg_decode_params_t *p,
> +				  char *str, unsigned int len)
> +{
> +	char *b = str;
> +
> +	if (!p)
> +		return "";
> +
> +	b += snprintf(b, len,
> +		      "jpeg_decode_params_t\n"
> +		      "picture_start_addr_p                  0x%x\n"
> +		      "picture_end_addr_p                    0x%x\n"
> +		      "decoding_mode                        %d\n"
> +		      "display_buffer_addr.display_decimated_luma_p   0x%x\n"
> +		      "display_buffer_addr.display_decimated_chroma_p 0x%x\n"
> +		      "main_aux_enable                       %d\n"
> +		      "additional_flags                     0x%x\n"
> +		      "field_flag                           %x\n"
> +		      "is_jpeg_image                        %x\n",
> +		      p->picture_start_addr_p,
> +		      p->picture_end_addr_p,
> +		      p->decoding_mode,
> +		      p->display_buffer_addr.display_decimated_luma_p,
> +		      p->display_buffer_addr.display_decimated_chroma_p,
> +		      p->main_aux_enable, p->additional_flags,
> +		      p->field_flag,
> +		      p->is_jpeg_image);
> +
> +	return str;
> +}
> +
> +static inline bool is_stream_error(enum jpeg_decoding_error_t err)
> +{
> +	switch (err) {
> +	case JPEG_DECODER_UNDEFINED_HUFF_TABLE:
> +	case JPEG_DECODER_BAD_RESTART_MARKER:
> +	case JPEG_DECODER_BAD_SOS_SPECTRAL:
> +	case JPEG_DECODER_BAD_SOS_SUCCESSIVE:
> +	case JPEG_DECODER_BAD_HEADER_LENGTH:
> +	case JPEG_DECODER_BAD_COUNT_VALUE:
> +	case JPEG_DECODER_BAD_DHT_MARKER:
> +	case JPEG_DECODER_BAD_INDEX_VALUE:
> +	case JPEG_DECODER_BAD_NUMBER_HUFFMAN_TABLES:
> +	case JPEG_DECODER_BAD_QUANT_TABLE_LENGTH:
> +	case JPEG_DECODER_BAD_NUMBER_QUANT_TABLES:
> +	case JPEG_DECODER_BAD_COMPONENT_COUNT:
> +		return true;
> +	default:
> +		return false;
> +	}
> +}
> +
> +static inline const char *err_str(enum jpeg_decoding_error_t err)
> +{
> +	switch (err) {
> +	case JPEG_DECODER_NO_ERROR:
> +		return "JPEG_DECODER_NO_ERROR";
> +	case JPEG_DECODER_UNDEFINED_HUFF_TABLE:
> +		return "JPEG_DECODER_UNDEFINED_HUFF_TABLE";
> +	case JPEG_DECODER_UNSUPPORTED_MARKER:
> +		return "JPEG_DECODER_UNSUPPORTED_MARKER";
> +	case JPEG_DECODER_UNABLE_ALLOCATE_MEMORY:
> +		return "JPEG_DECODER_UNABLE_ALLOCATE_MEMORY";
> +	case JPEG_DECODER_NON_SUPPORTED_SAMP_FACTORS:
> +		return "JPEG_DECODER_NON_SUPPORTED_SAMP_FACTORS";
> +	case JPEG_DECODER_BAD_PARAMETER:
> +		return "JPEG_DECODER_BAD_PARAMETER";
> +	case JPEG_DECODER_DECODE_ERROR:
> +		return "JPEG_DECODER_DECODE_ERROR";
> +	case JPEG_DECODER_BAD_RESTART_MARKER:
> +		return "JPEG_DECODER_BAD_RESTART_MARKER";
> +	case JPEG_DECODER_UNSUPPORTED_COLORSPACE:
> +		return "JPEG_DECODER_UNSUPPORTED_COLORSPACE";
> +	case JPEG_DECODER_BAD_SOS_SPECTRAL:
> +		return "JPEG_DECODER_BAD_SOS_SPECTRAL";
> +	case JPEG_DECODER_BAD_SOS_SUCCESSIVE:
> +		return "JPEG_DECODER_BAD_SOS_SUCCESSIVE";
> +	case JPEG_DECODER_BAD_HEADER_LENGTH:
> +		return "JPEG_DECODER_BAD_HEADER_LENGTH";
> +	case JPEG_DECODER_BAD_COUNT_VALUE:
> +		return "JPEG_DECODER_BAD_COUNT_VALUE";
> +	case JPEG_DECODER_BAD_DHT_MARKER:
> +		return "JPEG_DECODER_BAD_DHT_MARKER";
> +	case JPEG_DECODER_BAD_INDEX_VALUE:
> +		return "JPEG_DECODER_BAD_INDEX_VALUE";
> +	case JPEG_DECODER_BAD_NUMBER_HUFFMAN_TABLES:
> +		return "JPEG_DECODER_BAD_NUMBER_HUFFMAN_TABLES";
> +	case JPEG_DECODER_BAD_QUANT_TABLE_LENGTH:
> +		return "JPEG_DECODER_BAD_QUANT_TABLE_LENGTH";
> +	case JPEG_DECODER_BAD_NUMBER_QUANT_TABLES:
> +		return "JPEG_DECODER_BAD_NUMBER_QUANT_TABLES";
> +	case JPEG_DECODER_BAD_COMPONENT_COUNT:
> +		return "JPEG_DECODER_BAD_COMPONENT_COUNT";
> +	case JPEG_DECODER_DIVIDE_BY_ZERO_ERROR:
> +		return "JPEG_DECODER_DIVIDE_BY_ZERO_ERROR";
> +	case JPEG_DECODER_NOT_JPG_IMAGE:
> +		return "JPEG_DECODER_NOT_JPG_IMAGE";
> +	case JPEG_DECODER_UNSUPPORTED_ROTATION_ANGLE:
> +		return "JPEG_DECODER_UNSUPPORTED_ROTATION_ANGLE";
> +	case JPEG_DECODER_UNSUPPORTED_SCALING:
> +		return "JPEG_DECODER_UNSUPPORTED_SCALING";
> +	case JPEG_DECODER_INSUFFICIENT_OUTPUTBUFFER_SIZE:
> +		return "JPEG_DECODER_INSUFFICIENT_OUTPUTBUFFER_SIZE";
> +	case JPEG_DECODER_BAD_HWCFG_GP_VERSION_VALUE:
> +		return "JPEG_DECODER_BAD_HWCFG_GP_VERSION_VALUE";
> +	case JPEG_DECODER_BAD_VALUE_FROM_RED:
> +		return "JPEG_DECODER_BAD_VALUE_FROM_RED";
> +	case JPEG_DECODER_BAD_SUBREGION_PARAMETERS:
> +		return "JPEG_DECODER_BAD_SUBREGION_PARAMETERS";
> +	case JPEG_DECODER_PROGRESSIVE_DECODE_NOT_SUPPORTED:
> +		return "JPEG_DECODER_PROGRESSIVE_DECODE_NOT_SUPPORTED";
> +	case JPEG_DECODER_ERROR_TASK_TIMEOUT:
> +		return "JPEG_DECODER_ERROR_TASK_TIMEOUT";
> +	case JPEG_DECODER_ERROR_FEATURE_NOT_SUPPORTED:
> +		return "JPEG_DECODER_ERROR_FEATURE_NOT_SUPPORTED";
> +	default:
> +		return "!unknown MJPEG error!";
> +	}
> +}
> +
> +static bool delta_mjpeg_check_status(struct delta_ctx *pctx,
> +				     struct jpeg_decode_return_params_t *status)
> +{
> +	struct delta_dev *delta = pctx->dev;
> +	bool dump = false;
> +
> +	if (status->error_code == JPEG_DECODER_NO_ERROR)
> +		goto out;
> +
> +	if (is_stream_error(status->error_code)) {
> +		dev_warn_ratelimited(delta->dev,
> +				     "%s  firmware: stream error @ frame %d (%s)\n",
> +				     pctx->name, pctx->decoded_frames,
> +				     err_str(status->error_code));
> +		pctx->stream_errors++;
> +	} else {
> +		dev_warn_ratelimited(delta->dev,
> +				     "%s  firmware: decode error @ frame %d (%s)\n",
> +				     pctx->name, pctx->decoded_frames,
> +				     err_str(status->error_code));
> +		pctx->decode_errors++;
> +		dump = true;
> +	}
> +
> +out:
> +	dev_dbg(delta->dev,
> +		"%s  firmware: decoding time(us)=%d\n", pctx->name,
> +		status->decode_time_in_us);
> +
> +	return dump;
> +}
> +
> +static int delta_mjpeg_ipc_open(struct delta_ctx *pctx)
> +{
> +	struct delta_dev *delta = pctx->dev;
> +	struct delta_mjpeg_ctx *ctx = to_ctx(pctx);
> +	int ret = 0;
> +	struct jpeg_video_decode_init_params_t params_struct;
> +	struct jpeg_video_decode_init_params_t *params = &params_struct;
> +	struct delta_buf *ipc_buf;
> +	u32 ipc_buf_size;
> +	struct delta_ipc_param ipc_param;
> +	void *hdl;
> +
> +	memset(params, 0, sizeof(*params));
> +	params->circular_buffer_begin_addr_p = 0x00000000;
> +	params->circular_buffer_end_addr_p = 0xffffffff;
> +
> +	dev_vdbg(delta->dev,
> +		 "%s  %s\n", pctx->name,
> +		 ipc_open_param_str(params, ctx->str, sizeof(ctx->str)));
> +
> +	ipc_param.size = sizeof(*params);
> +	ipc_param.data = params;
> +	ipc_buf_size = sizeof(struct jpeg_decode_params_t) +
> +	    sizeof(struct jpeg_decode_return_params_t);
> +	ret = delta_ipc_open(pctx, "JPEG_DECODER_HW0", &ipc_param,
> +			     ipc_buf_size, &ipc_buf, &hdl);
> +	if (ret) {
> +		dev_err(delta->dev,
> +			"%s  dumping command %s\n", pctx->name,
> +			ipc_open_param_str(params, ctx->str, sizeof(ctx->str)));
> +		return ret;
> +	}
> +
> +	ctx->ipc_buf = ipc_buf;
> +	ctx->ipc_hdl = hdl;
> +
> +	return 0;
> +}
> +
> +static int delta_mjpeg_ipc_decode(struct delta_ctx *pctx, struct delta_au *au)
> +{
> +	struct delta_dev *delta = pctx->dev;
> +	struct delta_mjpeg_ctx *ctx = to_ctx(pctx);
> +	int ret = 0;
> +	struct jpeg_decode_params_t *params = ctx->ipc_buf->vaddr;
> +	struct jpeg_decode_return_params_t *status =
> +	    ctx->ipc_buf->vaddr + sizeof(*params);
> +	struct delta_frame *frame;
> +	struct delta_ipc_param ipc_param, ipc_status;
> +
> +	ret = delta_get_free_frame(pctx, &frame);
> +	if (ret)
> +		return ret;
> +
> +	memset(params, 0, sizeof(*params));
> +
> +	params->picture_start_addr_p = (u32)(au->paddr);
> +	params->picture_end_addr_p = (u32)(au->paddr + au->size - 1);
> +
> +	/*
> +	 * !WARNING!
> +	 * the NV12 decoded frame is only available
> +	 * on decimated output when enabling flag
> +	 * "JPEG_ADDITIONAL_FLAG_420MB"...
> +	 * the non decimated output gives YUV422SP
> +	 */
> +	params->main_aux_enable = JPEG_DISP_AUX_EN;
> +	params->additional_flags = JPEG_ADDITIONAL_FLAG_420MB;
> +	params->horizontal_decimation_factor = JPEG_HDEC_1;
> +	params->vertical_decimation_factor = JPEG_VDEC_1;
> +	params->decoding_mode = JPEG_NORMAL_DECODE;
> +
> +	params->display_buffer_addr.struct_size =
> +	    sizeof(struct jpeg_display_buffer_address_t);
> +	params->display_buffer_addr.display_decimated_luma_p =
> +	    (u32)frame->paddr;
> +	params->display_buffer_addr.display_decimated_chroma_p =
> +	    (u32)(frame->paddr
> +		  + frame->info.aligned_width * frame->info.aligned_height);
> +
> +	dev_vdbg(delta->dev,
> +		 "%s  %s\n", pctx->name,
> +		 ipc_decode_param_str(params, ctx->str, sizeof(ctx->str)));
> +
> +	/* status */
> +	memset(status, 0, sizeof(*status));
> +	status->error_code = JPEG_DECODER_NO_ERROR;
> +
> +	ipc_param.size = sizeof(*params);
> +	ipc_param.data = params;
> +	ipc_status.size = sizeof(*status);
> +	ipc_status.data = status;
> +	ret = delta_ipc_decode(ctx->ipc_hdl, &ipc_param, &ipc_status);
> +	if (ret) {
> +		dev_err(delta->dev,
> +			"%s  dumping command %s\n", pctx->name,
> +			ipc_decode_param_str(params, ctx->str,
> +					     sizeof(ctx->str)));
> +		return ret;
> +	}
> +
> +	pctx->decoded_frames++;
> +
> +	/* check firmware decoding status */
> +	if (delta_mjpeg_check_status(pctx, status)) {
> +		dev_err(delta->dev,
> +			"%s  dumping command %s\n", pctx->name,
> +			ipc_decode_param_str(params, ctx->str,
> +					     sizeof(ctx->str)));
> +	}
> +
> +	frame->field = V4L2_FIELD_NONE;
> +	frame->flags = V4L2_BUF_FLAG_KEYFRAME;
> +	frame->state |= DELTA_FRAME_DEC;
> +
> +	ctx->out_frame = frame;
> +
> +	return 0;
> +}
> +
> +static int delta_mjpeg_open(struct delta_ctx *pctx)
> +{
> +	struct delta_mjpeg_ctx *ctx;
> +
> +	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> +	if (!ctx)
> +		return -ENOMEM;
> +	pctx->priv = ctx;
> +
> +	return 0;
> +}
> +
> +static int delta_mjpeg_close(struct delta_ctx *pctx)
> +{
> +	struct delta_mjpeg_ctx *ctx = to_ctx(pctx);
> +
> +	if (ctx->ipc_hdl) {
> +		delta_ipc_close(ctx->ipc_hdl);
> +		ctx->ipc_hdl = NULL;
> +	}
> +
> +	kfree(ctx);
> +
> +	return 0;
> +}
> +
> +static int delta_mjpeg_get_streaminfo(struct delta_ctx *pctx,
> +				      struct delta_streaminfo *streaminfo)
> +{
> +	struct delta_mjpeg_ctx *ctx = to_ctx(pctx);
> +
> +	if (!ctx->header)
> +		goto nodata;
> +
> +	streaminfo->streamformat = V4L2_PIX_FMT_MJPEG;
> +	streaminfo->width = ctx->header->frame_width;
> +	streaminfo->height = ctx->header->frame_height;
> +
> +	/* progressive stream */
> +	streaminfo->field = V4L2_FIELD_NONE;
> +
> +	streaminfo->dpb = 1;
> +
> +	return 0;
> +
> +nodata:
> +	return -ENODATA;
> +}
> +
> +static int delta_mjpeg_decode(struct delta_ctx *pctx, struct delta_au *pau)
> +{
> +	struct delta_dev *delta = pctx->dev;
> +	struct delta_mjpeg_ctx *ctx = to_ctx(pctx);
> +	int ret;
> +	struct delta_au au = *pau;
> +	unsigned int data_offset;
> +	struct mjpeg_header *header = &ctx->header_struct;
> +
> +	if (!ctx->header) {
> +		ret = delta_mjpeg_read_header(pctx, au.vaddr, au.size,
> +					      header, &data_offset);
> +		if (ret) {
> +			pctx->stream_errors++;
> +			goto err;
> +		}
> +		if (header->frame_width * header->frame_height >
> +		    DELTA_MJPEG_MAX_RESO) {
> +			dev_err(delta->dev,
> +				"%s  stream resolution too large: %dx%d > %d pixels budget\n",
> +				pctx->name,
> +				header->frame_width,
> +				header->frame_height, DELTA_MJPEG_MAX_RESO);
> +			ret = -EINVAL;
> +			goto err;
> +		}
> +		ctx->header = header;
> +		goto out;
> +	}
> +
> +	if (!ctx->ipc_hdl) {
> +		ret = delta_mjpeg_ipc_open(pctx);
> +		if (ret)
> +			goto err;
> +	}
> +
> +	ret = delta_mjpeg_read_header(pctx, au.vaddr, au.size,
> +				      ctx->header, &data_offset);
> +	if (ret) {
> +		pctx->stream_errors++;
> +		goto err;
> +	}
> +
> +	au.paddr += data_offset;
> +	au.vaddr += data_offset;
> +
> +	ret = delta_mjpeg_ipc_decode(pctx, &au);
> +	if (ret)
> +		goto err;
> +
> +out:
> +	return 0;
> +
> +err:
> +	return ret;
> +}
> +
> +static int delta_mjpeg_get_frame(struct delta_ctx *pctx,
> +				 struct delta_frame **frame)
> +{
> +	struct delta_mjpeg_ctx *ctx = to_ctx(pctx);
> +
> +	if (!ctx->out_frame)
> +		return -ENODATA;
> +
> +	*frame = ctx->out_frame;
> +
> +	ctx->out_frame = NULL;
> +
> +	return 0;
> +}
> +
> +const struct delta_dec mjpegdec = {
> +	.name = "MJPEG",
> +	.streamformat = V4L2_PIX_FMT_MJPEG,
> +	.pixelformat = V4L2_PIX_FMT_NV12,
> +	.open = delta_mjpeg_open,
> +	.close = delta_mjpeg_close,
> +	.get_streaminfo = delta_mjpeg_get_streaminfo,
> +	.get_frameinfo = delta_get_frameinfo_default,
> +	.decode = delta_mjpeg_decode,
> +	.get_frame = delta_mjpeg_get_frame,
> +	.recycle = delta_recycle_default,
> +};
> diff --git a/drivers/media/platform/sti/delta/delta-mjpeg-fw.h b/drivers/media/platform/sti/delta/delta-mjpeg-fw.h
> new file mode 100644
> index 0000000..de803d0
> --- /dev/null
> +++ b/drivers/media/platform/sti/delta/delta-mjpeg-fw.h
> @@ -0,0 +1,225 @@
> +/*
> + * Copyright (C) STMicroelectronics SA 2015
> + * Author: Hugues Fruchet <hugues.fruchet@xxxxxx> for STMicroelectronics.
> + * License terms:  GNU General Public License (GPL), version 2
> + */
> +
> +#ifndef DELTA_MJPEG_FW_H
> +#define DELTA_MJPEG_FW_H
> +
> +/*
> + * struct jpeg_decoded_buffer_address_t
> + *
> + * defines the addresses where the decoded picture/additional
> + * info related to the block structures will be stored
> + *
> + * @display_luma_p:		address of the luma buffer
> + * @display_chroma_p:		address of the chroma buffer
> + */
> +struct jpeg_decoded_buffer_address_t {
> +	u32 luma_p;
> +	u32 chroma_p;
> +};
> +
> +/*
> + * struct jpeg_display_buffer_address_t
> + *
> + * defines the addresses (used by the Display Reconstruction block)
> + * where the pictures to be displayed will be stored
> + *
> + * @struct_size:		size of the structure in bytes
> + * @display_luma_p:		address of the luma buffer
> + * @display_chroma_p:		address of the chroma buffer
> + * @display_decimated_luma_p:	address of the decimated luma buffer
> + * @display_decimated_chroma_p:	address of the decimated chroma buffer
> + */
> +struct jpeg_display_buffer_address_t {
> +	u32 struct_size;
> +	u32 display_luma_p;
> +	u32 display_chroma_p;
> +	u32 display_decimated_luma_p;
> +	u32 display_decimated_chroma_p;
> +};
> +
> +/*
> + * used for enabling main/aux outputs for both display &
> + * reference reconstruction blocks
> + */
> +enum jpeg_rcn_ref_disp_enable_t {
> +	/* enable decimated (for display) reconstruction */
> +	JPEG_DISP_AUX_EN = 0x00000010,
> +	/* enable main (for display) reconstruction */
> +	JPEG_DISP_MAIN_EN = 0x00000020,
> +	/* enable both main & decimated (for display) reconstruction */
> +	JPEG_DISP_AUX_MAIN_EN = 0x00000030,
> +	/* enable only reference output(ex. for trick modes) */
> +	JPEG_REF_MAIN_EN = 0x00000100,
> +	/*
> +	 * enable reference output with decimated
> +	 * (for display) reconstruction
> +	 */
> +	JPEG_REF_MAIN_DISP_AUX_EN = 0x00000110,
> +	/*
> +	 * enable reference output with main
> +	 * (for display) reconstruction
> +	 */
> +	JPEG_REF_MAIN_DISP_MAIN_EN = 0x00000120,
> +	/*
> +	 * enable reference output with main & decimated
> +	 * (for display) reconstruction
> +	 */
> +	JPEG_REF_MAIN_DISP_MAIN_AUX_EN = 0x00000130
> +};
> +
> +/* identifies the horizontal decimation factor */
> +enum jpeg_horizontal_deci_factor_t {
> +	/* no resize */
> +	JPEG_HDEC_1 = 0x00000000,
> +	/* Advanced H/2 resize using improved 8-tap filters */
> +	JPEG_HDEC_ADVANCED_2 = 0x00000101,
> +	/* Advanced H/4 resize using improved 8-tap filters */
> +	JPEG_HDEC_ADVANCED_4 = 0x00000102
> +};
> +
> +/* identifies the vertical decimation factor */
> +enum jpeg_vertical_deci_factor_t {
> +	/* no resize */
> +	JPEG_VDEC_1 = 0x00000000,
> +	/* V/2 , progressive resize */
> +	JPEG_VDEC_ADVANCED_2_PROG = 0x00000204,
> +	/* V/2 , interlaced resize */
> +	JPEG_VDEC_ADVANCED_2_INT = 0x000000208
> +};
> +
> +/* status of the decoding process */
> +enum jpeg_decoding_error_t {
> +	JPEG_DECODER_NO_ERROR = 0,
> +	JPEG_DECODER_UNDEFINED_HUFF_TABLE = 1,
> +	JPEG_DECODER_UNSUPPORTED_MARKER = 2,
> +	JPEG_DECODER_UNABLE_ALLOCATE_MEMORY = 3,
> +	JPEG_DECODER_NON_SUPPORTED_SAMP_FACTORS = 4,
> +	JPEG_DECODER_BAD_PARAMETER = 5,
> +	JPEG_DECODER_DECODE_ERROR = 6,
> +	JPEG_DECODER_BAD_RESTART_MARKER = 7,
> +	JPEG_DECODER_UNSUPPORTED_COLORSPACE = 8,
> +	JPEG_DECODER_BAD_SOS_SPECTRAL = 9,
> +	JPEG_DECODER_BAD_SOS_SUCCESSIVE = 10,
> +	JPEG_DECODER_BAD_HEADER_LENGTH = 11,
> +	JPEG_DECODER_BAD_COUNT_VALUE = 12,
> +	JPEG_DECODER_BAD_DHT_MARKER = 13,
> +	JPEG_DECODER_BAD_INDEX_VALUE = 14,
> +	JPEG_DECODER_BAD_NUMBER_HUFFMAN_TABLES = 15,
> +	JPEG_DECODER_BAD_QUANT_TABLE_LENGTH = 16,
> +	JPEG_DECODER_BAD_NUMBER_QUANT_TABLES = 17,
> +	JPEG_DECODER_BAD_COMPONENT_COUNT = 18,
> +	JPEG_DECODER_DIVIDE_BY_ZERO_ERROR = 19,
> +	JPEG_DECODER_NOT_JPG_IMAGE = 20,
> +	JPEG_DECODER_UNSUPPORTED_ROTATION_ANGLE = 21,
> +	JPEG_DECODER_UNSUPPORTED_SCALING = 22,
> +	JPEG_DECODER_INSUFFICIENT_OUTPUTBUFFER_SIZE = 23,
> +	JPEG_DECODER_BAD_HWCFG_GP_VERSION_VALUE = 24,
> +	JPEG_DECODER_BAD_VALUE_FROM_RED = 25,
> +	JPEG_DECODER_BAD_SUBREGION_PARAMETERS = 26,
> +	JPEG_DECODER_PROGRESSIVE_DECODE_NOT_SUPPORTED = 27,
> +	JPEG_DECODER_ERROR_TASK_TIMEOUT = 28,
> +	JPEG_DECODER_ERROR_FEATURE_NOT_SUPPORTED = 29
> +};
> +
> +/* identifies the decoding mode */
> +enum jpeg_decoding_mode_t {
> +	JPEG_NORMAL_DECODE = 0,
> +};
> +
> +enum jpeg_additional_flags_t {
> +	JPEG_ADDITIONAL_FLAG_NONE = 0,
> +	/* request firmware to return values of the CEH registers */
> +	JPEG_ADDITIONAL_FLAG_CEH = 1,
> +	/* output storage of auxiliary reconstruction in Raster format. */
> +	JPEG_ADDITIONAL_FLAG_RASTER = 64,
> +	/* output storage of auxiliary reconstruction in 420MB format. */
> +	JPEG_ADDITIONAL_FLAG_420MB = 128
> +};
> +
> +/*
> + * struct jpeg_video_decode_init_params_t - initialization command parameters
> + *
> + * @circular_buffer_begin_addr_p:	start address of fw circular buffer
> + * @circular_buffer_end_addr_p:		end address of fw circular buffer
> + */
> +struct jpeg_video_decode_init_params_t {
> +	u32 circular_buffer_begin_addr_p;
> +	u32 circular_buffer_end_addr_p;
> +	u32 reserved;
> +};
> +
> +/*
> + * struct jpeg_decode_params_t - decode command parameters
> + *
> + * @picture_start_addr_p:	start address of jpeg picture
> + * @picture_end_addr_p:		end address of jpeg picture
> + * @decoded_buffer_addr:	decoded picture buffer
> + * @display_buffer_addr:	display picture buffer
> + * @main_aux_enable:		enable main and/or aux outputs
> + * @horizontal_decimation_factor:horizontal decimation factor
> + * @vertical_decimation_factor:	vertical decimation factor
> + * @xvalue0:			the x(0) coordinate for subregion decoding
> + * @xvalue1:			the x(1) coordinate for subregion decoding
> + * @yvalue0:			the y(0) coordinate for subregion decoding
> + * @yvalue1:			the y(1) coordinate for subregion decoding
> + * @decoding_mode:		decoding mode
> + * @additional_flags:		additional flags
> + * @field_flag:			determines frame/field scan
> + * @is_jpeg_image:		1 = still jpeg, 0 = motion jpeg
> + */
> +struct jpeg_decode_params_t {
> +	u32 picture_start_addr_p;
> +	u32 picture_end_addr_p;
> +	struct jpeg_decoded_buffer_address_t decoded_buffer_addr;
> +	struct jpeg_display_buffer_address_t display_buffer_addr;
> +	enum jpeg_rcn_ref_disp_enable_t main_aux_enable;
> +	enum jpeg_horizontal_deci_factor_t horizontal_decimation_factor;
> +	enum jpeg_vertical_deci_factor_t vertical_decimation_factor;
> +	u32 xvalue0;
> +	u32 xvalue1;
> +	u32 yvalue0;
> +	u32 yvalue1;
> +	enum jpeg_decoding_mode_t decoding_mode;
> +	u32 additional_flags;
> +	u32 field_flag;
> +	u32 reserved;
> +	u32 is_jpeg_image;
> +};
> +
> +/*
> + * struct jpeg_decode_return_params_t
> + *
> + * status returned by firmware after decoding
> + *
> + * @decode_time_in_us:	decoding time in microseconds
> + * @pm_cycles:		profiling information
> + * @pm_dmiss:		profiling information
> + * @pm_imiss:		profiling information
> + * @pm_bundles:		profiling information
> + * @pm_pft:		profiling information
> + * @error_code:		status of the decoding process
> + * @ceh_registers:	array where values of the Contrast Enhancement
> + *			Histogram (CEH) registers will be stored.
> + *			ceh_registers[0] correspond to register MBE_CEH_0_7,
> + *			ceh_registers[1] correspond to register MBE_CEH_8_15
> + *			ceh_registers[2] correspond to register MBE_CEH_16_23
> + *			Note that elements of this array will be updated only
> + *			if additional_flags has JPEG_ADDITIONAL_FLAG_CEH set.
> + */
> +struct jpeg_decode_return_params_t {
> +	/* profiling info */
> +	u32 decode_time_in_us;
> +	u32 pm_cycles;
> +	u32 pm_dmiss;
> +	u32 pm_imiss;
> +	u32 pm_bundles;
> +	u32 pm_pft;
> +	enum jpeg_decoding_error_t error_code;
> +	u32 ceh_registers[32];
> +};
> +
> +#endif /* DELTA_MJPEG_FW_H */
> diff --git a/drivers/media/platform/sti/delta/delta-mjpeg-hdr.c b/drivers/media/platform/sti/delta/delta-mjpeg-hdr.c
> new file mode 100644
> index 0000000..a8fd8fa
> --- /dev/null
> +++ b/drivers/media/platform/sti/delta/delta-mjpeg-hdr.c
> @@ -0,0 +1,149 @@
> +/*
> + * Copyright (C) STMicroelectronics SA 2013
> + * Author: Hugues Fruchet <hugues.fruchet@xxxxxx> for STMicroelectronics.
> + * License terms:  GNU General Public License (GPL), version 2
> + */
> +
> +#include "delta.h"
> +#include "delta-mjpeg.h"
> +
> +#define MJPEG_SOF_0  0xc0
> +#define MJPEG_SOF_1  0xc1
> +#define MJPEG_SOI    0xd8
> +#define MJPEG_MARKER 0xff
> +
> +static char *header_str(struct mjpeg_header *header,
> +			char *str,
> +			unsigned int len)
> +{
> +	char *cur = str;
> +	unsigned int left = len;
> +
> +	if (!header)
> +		return "";
> +
> +	snprintf(cur, left, "[MJPEG header]\n"
> +			"|- length     = %d\n"
> +			"|- precision  = %d\n"
> +			"|- width      = %d\n"
> +			"|- height     = %d\n"
> +			"|- components = %d\n",
> +			header->length,
> +			header->sample_precision,
> +			header->frame_width,
> +			header->frame_height,
> +			header->nb_of_components);
> +
> +	return str;
> +}
> +
> +static int delta_mjpeg_read_sof(struct delta_ctx *pctx,
> +				unsigned char *data, unsigned int size,
> +				struct mjpeg_header *header)
> +{
> +	struct delta_dev *delta = pctx->dev;
> +	unsigned int offset = 0;
> +
> +	if (size < 64)
> +		goto err_no_more;
> +
> +	memset(header, 0, sizeof(*header));
> +	header->length           = be16_to_cpu(*(__be16 *)(data + offset));
> +	offset += sizeof(u16);
> +	header->sample_precision = *(u8 *)(data + offset);
> +	offset += sizeof(u8);
> +	header->frame_height     = be16_to_cpu(*(__be16 *)(data + offset));
> +	offset += sizeof(u16);
> +	header->frame_width      = be16_to_cpu(*(__be16 *)(data + offset));
> +	offset += sizeof(u16);
> +	header->nb_of_components = *(u8 *)(data + offset);
> +	offset += sizeof(u8);
> +
> +	if (header->nb_of_components >= MJPEG_MAX_COMPONENTS) {
> +		dev_err(delta->dev,
> +			"%s   unsupported number of components (%d > %d)\n",
> +			pctx->name, header->nb_of_components,
> +			MJPEG_MAX_COMPONENTS);
> +		return -EINVAL;
> +	}
> +
> +	if ((offset + header->nb_of_components *
> +	     sizeof(header->components[0])) > size)
> +		goto err_no_more;
> +
> +	return 0;
> +
> +err_no_more:
> +	dev_err(delta->dev,
> +		"%s   sof: reached end of %d size input stream\n",
> +		pctx->name, size);
> +	return -ENODATA;
> +}
> +
> +int delta_mjpeg_read_header(struct delta_ctx *pctx,
> +			    unsigned char *data, unsigned int size,
> +			    struct mjpeg_header *header,
> +			    unsigned int *data_offset)
> +{
> +	struct delta_dev *delta = pctx->dev;
> +	unsigned char str[200];
> +
> +	unsigned int ret = 0;
> +	unsigned int offset = 0;
> +	unsigned int soi = 0;
> +
> +	if (size < 2)
> +		goto err_no_more;
> +
> +	offset = 0;
> +	while (1) {
> +		if (data[offset] == MJPEG_MARKER)
> +			switch (data[offset + 1]) {
> +			case MJPEG_SOI:
> +				soi = 1;
> +				*data_offset = offset;
> +				break;
> +
> +			case MJPEG_SOF_0:
> +			case MJPEG_SOF_1:
> +				if (!soi) {
> +					dev_err(delta->dev,
> +						"%s   wrong sequence, got SOF while SOI not seen\n",
> +						pctx->name);
> +					return -EINVAL;
> +				}
> +
> +				ret = delta_mjpeg_read_sof(pctx,
> +							   &data[offset + 2],
> +							   size - (offset + 2),
> +							   header);
> +				if (ret)
> +					goto err;
> +
> +				goto done;
> +
> +			default:
> +				break;
> +			}
> +
> +		offset++;
> +		if ((offset + 2) >= size)
> +			goto err_no_more;
> +	}
> +
> +done:
> +	dev_dbg(delta->dev,
> +		"%s   found header @ offset %d:\n%s", pctx->name,
> +		*data_offset,
> +		header_str(header, str, sizeof(str)));
> +	return 0;
> +
> +err_no_more:
> +	dev_err(delta->dev,
> +		"%s   no header found within %d bytes input stream\n",
> +		pctx->name, size);
> +	return -ENODATA;
> +
> +err:
> +	return ret;
> +}
> diff --git a/drivers/media/platform/sti/delta/delta-mjpeg.h b/drivers/media/platform/sti/delta/delta-mjpeg.h
> new file mode 100644
> index 0000000..18e6b37
> --- /dev/null
> +++ b/drivers/media/platform/sti/delta/delta-mjpeg.h
> @@ -0,0 +1,35 @@
> +/*
> + * Copyright (C) STMicroelectronics SA 2013
> + * Author: Hugues Fruchet <hugues.fruchet@xxxxxx> for STMicroelectronics.
> + * License terms:  GNU General Public License (GPL), version 2
> + */
> +
> +#ifndef DELTA_MJPEG_H
> +#define DELTA_MJPEG_H
> +
> +#include "delta.h"
> +
> +struct mjpeg_component {
> +	unsigned int id;/* 1=Y, 2=Cb, 3=Cr, 4=L, 5=Q */
> +	unsigned int h_sampling_factor;
> +	unsigned int v_sampling_factor;
> +	unsigned int quant_table_index;
> +};
> +
> +#define MJPEG_MAX_COMPONENTS 5
> +
> +struct mjpeg_header {
> +	unsigned int length;
> +	unsigned int sample_precision;
> +	unsigned int frame_width;
> +	unsigned int frame_height;
> +	unsigned int nb_of_components;
> +	struct mjpeg_component components[MJPEG_MAX_COMPONENTS];
> +};
> +
> +int delta_mjpeg_read_header(struct delta_ctx *pctx,
> +			    unsigned char *data, unsigned int size,
> +			    struct mjpeg_header *header,
> +			    unsigned int *data_offset);
> +
> +#endif /* DELTA_MJPEG_H */
> diff --git a/drivers/media/platform/sti/delta/delta-v4l2.c b/drivers/media/platform/sti/delta/delta-v4l2.c
> index c959614..6b29497 100644
> --- a/drivers/media/platform/sti/delta/delta-v4l2.c
> +++ b/drivers/media/platform/sti/delta/delta-v4l2.c
> @@ -32,6 +32,9 @@
>  
>  /* registry of available decoders */
>  static const struct delta_dec *delta_decoders[] = {
> +#ifdef CONFIG_VIDEO_STI_DELTA_MJPEG
> +	&mjpegdec,
> +#endif
>  };
>  
>  static inline int frame_size(u32 w, u32 h, u32 fmt)
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux