mirror of
https://github.com/FEX-Emu/linux.git
synced 2025-01-08 02:21:18 +00:00
[media] st-delta: add mjpeg support
Adds support of DELTA MJPEG video decoder back-end, implemented by calling JPEG_DECODER_HW0 firmware using RPMSG IPC communication layer. Acked-by: Peter Griffin <peter.griffin@linaro.org> Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
This commit is contained in:
parent
017c324242
commit
433ff5b4a2
@ -331,10 +331,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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
455
drivers/media/platform/sti/delta/delta-mjpeg-dec.c
Normal file
455
drivers/media/platform/sti/delta/delta-mjpeg-dec.c
Normal file
@ -0,0 +1,455 @@
|
||||
/*
|
||||
* Copyright (C) STMicroelectronics SA 2013
|
||||
* Author: Hugues Fruchet <hugues.fruchet@st.com> 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 = ¶ms_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,
|
||||
};
|
225
drivers/media/platform/sti/delta/delta-mjpeg-fw.h
Normal file
225
drivers/media/platform/sti/delta/delta-mjpeg-fw.h
Normal file
@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright (C) STMicroelectronics SA 2015
|
||||
* Author: Hugues Fruchet <hugues.fruchet@st.com> 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 */
|
149
drivers/media/platform/sti/delta/delta-mjpeg-hdr.c
Normal file
149
drivers/media/platform/sti/delta/delta-mjpeg-hdr.c
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (C) STMicroelectronics SA 2013
|
||||
* Author: Hugues Fruchet <hugues.fruchet@st.com> 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;
|
||||
}
|
35
drivers/media/platform/sti/delta/delta-mjpeg.h
Normal file
35
drivers/media/platform/sti/delta/delta-mjpeg.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) STMicroelectronics SA 2013
|
||||
* Author: Hugues Fruchet <hugues.fruchet@st.com> 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 */
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user