Skip to content
Snippets Groups Projects
Commit d590c85e authored by Mirela Rabulea's avatar Mirela Rabulea Committed by Leonard Crestez
Browse files

MLK-19247: mxc-jpeg: Remove jpeg-encoder hardcoding to 64x64 yuv422


Remove hardcodings for encoder (configuration stream especially).
This fix also requires a fixed version of the test applications,
encoder_test.out/decoder_test.out (linux-test repo).

Also fixed MLK-19453: Add support for YUV420 format in jpeg decoder
YUV420 is generally working on encoder/decoder,
but for some particular small files the decoder enters infinite error:
"Instance released before the end of transaction".
RGB24 is working, but the colors are strange in jpeg.
Since YUV444 and RGB24 have the same subsampling,
a RGB24 raw file can be encoded/decoded as YUV444 with the same results.
Fixes for invalid pixel formats.
Full battery of tests run.

Signed-off-by: default avatarMirela Rabulea <mirela.rabulea@nxp.com>
parent 2b44d184
No related merge requests found
......@@ -85,6 +85,7 @@
/* STM_CTRL fields */
#define STM_CTRL_PIXEL_PRECISION (0x1 << 2)
#define STM_CTRL_IMAGE_FORMAT(img_fmt) ((img_fmt) << 3)
#define STM_CTRL_IMAGE_FORMAT_MASK (0xF << 3)
#define STM_CTRL_BITBUF_PTR_CLR(clr) ((clr) << 7)
#define STM_CTRL_AUTO_START(go) ((go) << 8)
#define STM_CTRL_CONFIG_MOD(mod) ((mod) << 9)
......@@ -101,6 +102,7 @@
/* JPEG-Decoder Wrapper - STM_CTRL Register Fields */
#define MXC_PIXEL_PRECISION(precision) ((precision)/8 << 2)
enum mxc_jpeg_image_format {
MXC_JPEG_INVALID = -1,
MXC_JPEG_YUV420 = 0x0, /* 2 Plannar, Y=1st plane UV=2nd plane */
MXC_JPEG_YUV422 = 0x1, /* 1 Plannar, YUYV sequence */
MXC_JPEG_RGB = 0x2, /* RGBRGB packed format */
......
......@@ -38,8 +38,17 @@ static struct mxc_jpeg_fmt mxc_formats[] = {
.flags = MXC_JPEG_FMT_TYPE_ENC,
},
{
.name = "RGB32",
.fourcc = V4L2_PIX_FMT_RGB32,
.name = "RGB", /*RGBRGB packed format*/
.fourcc = V4L2_PIX_FMT_RGB24,
.depth = 24,
.colplanes = 1,
.h_align = 0,
.v_align = 0,
.flags = MXC_JPEG_FMT_TYPE_RAW,
},
{
.name = "ARGB", /* ARGBARGB packed format */
.fourcc = V4L2_PIX_FMT_ARGB32,
.depth = 32,
.colplanes = 1,
.h_align = 0,
......@@ -47,7 +56,16 @@ static struct mxc_jpeg_fmt mxc_formats[] = {
.flags = MXC_JPEG_FMT_TYPE_RAW,
},
{
.name = "YUV422",
.name = "YUV420", /* 1st plane = Y, 2nd plane = UV */
.fourcc = V4L2_PIX_FMT_NV12,
.depth = 12, /* 6 bytes (4Y + UV) for 4 pixels */
.colplanes = 2, /* 1 plane Y, 1 plane UV interleaved */
.h_align = 2,
.v_align = 0,
.flags = MXC_JPEG_FMT_TYPE_RAW,
},
{
.name = "YUV422", /* YUYV */
.fourcc = V4L2_PIX_FMT_YUYV,
.depth = 16,
.colplanes = 1,
......@@ -56,15 +74,25 @@ static struct mxc_jpeg_fmt mxc_formats[] = {
.flags = MXC_JPEG_FMT_TYPE_RAW,
},
{
.name = "YUV444",
.name = "YUV444", /* YUVYUV */
.fourcc = V4L2_PIX_FMT_YUV32,
.depth = 32,
.depth = 24,
.colplanes = 1,
.h_align = 0,
.v_align = 0,
.flags = MXC_JPEG_FMT_TYPE_RAW,
},
{
.name = "Gray", /* Gray (Y8/Y12) or Single Comp */
.fourcc = V4L2_PIX_FMT_GREY,
.depth = 8,
.colplanes = 1,
.h_align = 0,
.v_align = 0,
.flags = MXC_JPEG_FMT_TYPE_RAW,
},
};
#define MXC_JPEG_NUM_FORMATS ARRAY_SIZE(mxc_formats)
static const struct of_device_id mxc_jpeg_match[] = {
{
......@@ -168,6 +196,25 @@ static const unsigned char hactbl[615] = {
0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03,
0x11, 0x00, 0x3F, 0x00, 0xFF, 0xD9
};
#define HACTBL_H_OFFSET 159
#define HACTBL_W_OFFSET 161
#define HACTBL_COMP1_SUBSAMPLING 165
#define HACTBL_COMP2_SUBSAMPLING 168
#define HACTBL_COMP3_SUBSAMPLING 171
/* Print Four-character-code (FOURCC) */
static char *fourcc_to_str(u32 format)
{
char *buf = kmalloc(32, GFP_KERNEL);
snprintf(buf, 32,
"%c%c%c%c",
format & 0xff,
(format >> 8) & 0xff,
(format >> 16) & 0xff,
(format >> 24) & 0x7f);
return buf;
}
static void print_buf(struct device *dev, struct vb2_buffer *buf)
{
......@@ -185,7 +232,6 @@ static void print_buf(struct device *dev, struct vb2_buffer *buf)
data[0], data[1], data[2], data[3]);
}
#define MXC_NUM_FORMATS ARRAY_SIZE(mxc_formats)
static inline u32 mxc_jpeg_align(u32 val, u32 align)
{
return (val + align - 1) & ~(align - 1);
......@@ -225,12 +271,91 @@ static int enum_fmt(struct mxc_jpeg_fmt *mxc_formats, int n,
return 0;
}
static struct mxc_jpeg_fmt *mxc_jpeg_find_format(struct mxc_jpeg_ctx *ctx,
u32 pixelformat)
{
unsigned int k;
for (k = 0; k < MXC_JPEG_NUM_FORMATS; k++) {
struct mxc_jpeg_fmt *fmt = &mxc_formats[k];
if (fmt->fourcc == pixelformat)
return fmt;
}
return NULL;
}
static enum mxc_jpeg_image_format mxc_jpeg_fourcc_to_imgfmt(
u32 fourcc)
{
switch (fourcc) {
case V4L2_PIX_FMT_GREY:
return MXC_JPEG_GRAY;
case V4L2_PIX_FMT_YUYV:
return MXC_JPEG_YUV422;
case V4L2_PIX_FMT_NV12:
return MXC_JPEG_YUV420;
case V4L2_PIX_FMT_YUV32:
return MXC_JPEG_YUV444;
case V4L2_PIX_FMT_RGB24:
return MXC_JPEG_RGB;
case V4L2_PIX_FMT_ARGB32:
return MXC_JPEG_ARGB;
default:
return MXC_JPEG_INVALID;
}
}
static int mxc_jpeg_imgfmt_to_fourcc(enum mxc_jpeg_image_format imgfmt,
u32 *fourcc)
{
switch (imgfmt) {
case MXC_JPEG_GRAY:
*fourcc = V4L2_PIX_FMT_GREY;
return 0;
case MXC_JPEG_YUV422:
*fourcc = V4L2_PIX_FMT_YUYV;
return 0;
case MXC_JPEG_YUV420:
*fourcc = V4L2_PIX_FMT_NV12;
return 0;
case MXC_JPEG_YUV444:
*fourcc = V4L2_PIX_FMT_YUV32;
return 0;
case MXC_JPEG_RGB:
*fourcc = V4L2_PIX_FMT_RGB24;
return 0;
case MXC_JPEG_ARGB:
*fourcc = V4L2_PIX_FMT_ARGB32;
return 0;
default:
return 1;
}
}
static struct mxc_jpeg_q_data *mxc_jpeg_get_q_data(struct mxc_jpeg_ctx *ctx,
enum v4l2_buf_type type)
{
if (V4L2_TYPE_IS_OUTPUT(type))
return &ctx->out_q;
return &ctx->cap_q;
}
static void mxc_jpeg_addrs(struct mxc_jpeg_desc *desc,
struct vb2_buffer *b_base0_buf,
struct vb2_buffer *bufbase_buf, int offset)
{
int img_fmt = desc->stm_ctrl & STM_CTRL_IMAGE_FORMAT_MASK;
desc->buf_base0 = vb2_dma_contig_plane_dma_addr(b_base0_buf, 0);
desc->buf_base1 = 0; /* TODO for YUV420*/
desc->buf_base1 = 0;
if (img_fmt == STM_CTRL_IMAGE_FORMAT(MXC_JPEG_YUV420)) {
u32 h = desc->imgsize & 0xFFFF;
u32 w = (desc->imgsize >> 16) & 0xFFFF;
u32 luma_plane_size = w * h;
desc->buf_base1 = desc->buf_base0 + luma_plane_size;
}
desc->stm_bufbase = vb2_dma_contig_plane_dma_addr(bufbase_buf, 0) +
offset;
}
......@@ -243,6 +368,8 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
struct device *dev = jpeg->dev;
struct vb2_buffer *src_buf, *dst_buf;
u32 dec_ret;
unsigned long payload_size;
struct mxc_jpeg_q_data *q_data;
int slot = 0; /* TODO remove hardcoded slot 0 */
spin_lock(&jpeg->hw_lock);
......@@ -254,7 +381,7 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
goto job_unlock;
}
if (ctx->aborting) {
dev_dbg(dev, "Aborting current job\n");
dev_warn(dev, "Aborting current job\n");
mxc_jpeg_sw_reset(reg);
goto job_finish;
}
......@@ -278,10 +405,18 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
dev_dbg(dev, "Encoder config finished. Start encoding...\n");
goto job_unlock;
}
if (ctx->mode == MXC_JPEG_ENCODE)
dev_dbg(dev, "Encoding finished\n");
else
dev_dbg(dev, "Decoding finished\n");
if (ctx->mode == MXC_JPEG_ENCODE) {
payload_size = readl(reg + MXC_SLOT_OFFSET(slot, SLOT_BUF_PTR));
vb2_set_plane_payload(dst_buf, 0, payload_size);
dev_dbg(dev, "Encoding finished, payload_size: %ld\n",
payload_size);
} else {
q_data = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
payload_size = q_data->sizeimage[0];
vb2_set_plane_payload(dst_buf, 0, payload_size);
dev_dbg(dev, "Decoding finished, payload_size: %ld\n",
payload_size);
}
/* short preview of the results */
dev_dbg(dev, "src_buf preview: ");
......@@ -318,17 +453,62 @@ static void mxc_jpeg_config_dec_desc(struct vb2_buffer *out_buf,
mxc_jpeg_set_desc(desc_handle, reg, slot);
}
static void mxc_jpeg_fixup_cfg_stream(void *cfg_stream_vaddr,
enum mxc_jpeg_image_format img_fmt,
u16 w, u16 h)
{
u8 *hactbl = (u8 *)cfg_stream_vaddr;
hactbl[HACTBL_W_OFFSET] = w >> 8;
hactbl[HACTBL_W_OFFSET+1] = (u8)w;
hactbl[HACTBL_H_OFFSET] = h >> 8;
hactbl[HACTBL_H_OFFSET+1] = (u8)h;
switch (img_fmt) {
case MXC_JPEG_YUV420:
hactbl[HACTBL_COMP1_SUBSAMPLING] = 0x22;
hactbl[HACTBL_COMP2_SUBSAMPLING] = 0x11;
hactbl[HACTBL_COMP3_SUBSAMPLING] = 0x11;
break;
case MXC_JPEG_YUV422:
hactbl[HACTBL_COMP1_SUBSAMPLING] = 0x21;
hactbl[HACTBL_COMP2_SUBSAMPLING] = 0x11;
hactbl[HACTBL_COMP3_SUBSAMPLING] = 0x11;
break;
case MXC_JPEG_YUV444:
case MXC_JPEG_RGB:
default:
hactbl[HACTBL_COMP1_SUBSAMPLING] = 0x11;
hactbl[HACTBL_COMP2_SUBSAMPLING] = 0x11;
hactbl[HACTBL_COMP3_SUBSAMPLING] = 0x11;
break;
case MXC_JPEG_ARGB:
/* TODO: should be 4 componennts, SOF0 length should change*/
hactbl[HACTBL_COMP1_SUBSAMPLING] = 0x11;
hactbl[HACTBL_COMP2_SUBSAMPLING] = 0x11;
hactbl[HACTBL_COMP3_SUBSAMPLING] = 0x11;
break;
case MXC_JPEG_GRAY:
/* TODO: should be 1 comp only, SOF0 length should change*/
hactbl[HACTBL_COMP1_SUBSAMPLING] = 0x11;
break;
}
}
static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf,
int slot,
struct mxc_jpeg_dev *jpeg,
struct mxc_jpeg_ctx *ctx,
struct vb2_buffer *src_buf, struct vb2_buffer *dst_buf)
{
struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
void __iomem *reg = jpeg->base_reg;
struct mxc_jpeg_desc *desc = jpeg->slot_data[slot].desc;
struct mxc_jpeg_desc *cfg_desc = jpeg->slot_data[slot].cfg_desc;
dma_addr_t desc_handle = jpeg->slot_data[slot].desc_handle;
dma_addr_t cfg_desc_handle = jpeg->slot_data[slot].cfg_desc_handle;
struct mxc_jpeg_q_data *q_data;
enum mxc_jpeg_image_format img_fmt;
q_data = mxc_jpeg_get_q_data(ctx, src_buf->vb2_queue->type);
/* chain the config descriptor with the encoding descriptor */
cfg_desc->next_descpt_ptr = desc_handle | MXC_NXT_DESCPT_EN;
......@@ -342,14 +522,17 @@ static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf,
cfg_desc->stm_ctrl = STM_CTRL_CONFIG_MOD(1);
desc->next_descpt_ptr = 0; /* end of chain */
mxc_jpeg_addrs(desc, src_buf, dst_buf, 0);
/* TODO remove hardcodings*/
mxc_jpeg_set_bufsize(desc, 0x1000);
mxc_jpeg_set_res(desc, 64, 64);
mxc_jpeg_set_line_pitch(desc, 64 * 2);
mxc_jpeg_set_res(desc, q_data->w, q_data->h);
mxc_jpeg_set_line_pitch(desc, q_data->w * (q_data->fmt->depth / 8));
mxc_jpeg_set_bufsize(desc, desc->line_pitch * q_data->h);
img_fmt = mxc_jpeg_fourcc_to_imgfmt(q_data->fmt->fourcc);
if (img_fmt == MXC_JPEG_INVALID)
dev_err(jpeg->dev, "No valid image format detected\n");
desc->stm_ctrl = STM_CTRL_CONFIG_MOD(0) |
STM_CTRL_IMAGE_FORMAT(MXC_JPEG_YUV422);
STM_CTRL_IMAGE_FORMAT(img_fmt);
mxc_jpeg_fixup_cfg_stream(jpeg->slot_data[slot].cfg_stream_vaddr,
img_fmt, q_data->w, q_data->h);
mxc_jpeg_addrs(desc, src_buf, dst_buf, 0);
dev_dbg(jpeg->dev, "cfg_desc - 0x%llx:\n", cfg_desc_handle);
print_descriptor_info(jpeg->dev, cfg_desc);
dev_dbg(jpeg->dev, "enc desc - 0x%llx:\n", desc_handle);
......@@ -390,7 +573,7 @@ static void mxc_jpeg_device_run(void *priv)
if (ctx->mode == MXC_JPEG_ENCODE) {
dev_dbg(dev, "Encoding on slot %d\n", slot);
ctx->enc_state = MXC_JPEG_ENC_CONF;
mxc_jpeg_config_enc_desc(dst_buf, slot, jpeg, src_buf, dst_buf);
mxc_jpeg_config_enc_desc(dst_buf, slot, ctx, src_buf, dst_buf);
mxc_jpeg_go_enc(dev, reg);
} else {
dev_dbg(dev, "Decoding on slot %d\n", slot);
......@@ -427,14 +610,6 @@ static void mxc_jpeg_job_abort(void *priv)
dev_dbg(ctx->mxc_jpeg->dev, "Abort requested\n");
}
static struct mxc_jpeg_q_data *mxc_jpeg_get_q_data(struct mxc_jpeg_ctx *ctx,
enum v4l2_buf_type type)
{
if (V4L2_TYPE_IS_OUTPUT(type))
return &ctx->out_q;
return &ctx->cap_q;
}
static int mxc_jpeg_queue_setup(struct vb2_queue *q,
unsigned int *num_buffers,
unsigned int *num_planes,
......@@ -448,7 +623,9 @@ static int mxc_jpeg_queue_setup(struct vb2_queue *q,
if (!q_data)
return -EINVAL;
*num_planes = 1;
sizes[0] = 10;
/* assuming worst case jpeg compression: 6 x raw file size */
sizes[0] = q_data->w * q_data->h * 6;
if (q_data->sizeimage[0] > 0)
sizes[0] = q_data->sizeimage[0];
......@@ -505,11 +682,11 @@ static u8 get_sof(struct device *dev,
_bswap16(&sof->length);
_bswap16(&sof->height);
_bswap16(&sof->width);
dev_info(dev, "JPEG SOF: precision=%d\n", sof->precision);
dev_info(dev, "JPEG SOF: height=%d, width=%d\n",
dev_dbg(dev, "JPEG SOF: precision=%d\n", sof->precision);
dev_dbg(dev, "JPEG SOF: height=%d, width=%d\n",
sof->height, sof->width);
for (i = 0; i < sof->components_no; i++) {
dev_info(dev, "JPEG SOF: comp_id=%d, H=0x%x, V=0x%x\n",
dev_dbg(dev, "JPEG SOF: comp_id=%d, H=0x%x, V=0x%x\n",
sof->comp[i].id, sof->comp[i].v, sof->comp[i].h);
}
return 0;
......@@ -520,31 +697,41 @@ static enum mxc_jpeg_image_format mxc_jpeg_get_image_format(
const struct mxc_jpeg_sof *sof)
{
if (sof->components_no == 1) {
dev_info(dev, "IMAGE_FORMAT is: MXC_JPEG_GRAY\n");
dev_dbg(dev, "IMAGE_FORMAT is: MXC_JPEG_GRAY\n");
return MXC_JPEG_GRAY;
}
if (sof->components_no == 3) {
if (sof->comp[0].h == 2 && sof->comp[0].v == 2 &&
sof->comp[1].h == 1 && sof->comp[1].v == 1 &&
sof->comp[2].h == 1 && sof->comp[2].v == 1){
dev_info(dev, "IMAGE_FORMAT is: MXC_JPEG_YUV420\n");
dev_dbg(dev, "IMAGE_FORMAT is: MXC_JPEG_YUV420\n");
return MXC_JPEG_YUV420;
}
if (sof->comp[0].h == 2 && sof->comp[0].v == 1 &&
sof->comp[1].h == 1 && sof->comp[1].v == 1 &&
sof->comp[2].h == 1 && sof->comp[2].v == 1){
dev_info(dev, "IMAGE_FORMAT is: MXC_JPEG_YUV422\n");
dev_dbg(dev, "IMAGE_FORMAT is: MXC_JPEG_YUV422\n");
return MXC_JPEG_YUV422;
}
if (sof->comp[0].h == 1 && sof->comp[0].v == 1 &&
sof->comp[1].h == 1 && sof->comp[1].v == 1 &&
sof->comp[2].h == 1 && sof->comp[2].v == 1){
dev_info(dev, "IMAGE_FORMAT is: MXC_JPEG_YUV444\n");
dev_dbg(dev, "IMAGE_FORMAT is: MXC_JPEG_YUV444\n");
return MXC_JPEG_YUV444;
}
}
dev_info(dev, "IMAGE_FORMAT is: MXC_JPEG_RESERVED\n");
return MXC_JPEG_RESERVED;
if (sof->components_no == 4) {
if (sof->comp[0].h == 1 && sof->comp[0].v == 1 &&
sof->comp[1].h == 1 && sof->comp[1].v == 1 &&
sof->comp[2].h == 1 && sof->comp[2].v == 1 &&
sof->comp[3].h == 1 && sof->comp[3].v == 1){
/* this is not tested */
dev_dbg(dev, "IMAGE_FORMAT is: MXC_JPEG_ARGB\n");
return MXC_JPEG_ARGB;
}
}
dev_err(dev, "Could not identify image format\n");
return MXC_JPEG_INVALID;
}
static u32 mxc_jpeg_get_line_pitch(
......@@ -564,6 +751,9 @@ static u32 mxc_jpeg_get_line_pitch(
case MXC_JPEG_RGB:
line_pitch = sof->width * (sof->precision/8) * 3;
break;
case MXC_JPEG_ARGB:
line_pitch = sof->width * (sof->precision/8) * 4;
break;
case MXC_JPEG_YUV444:
line_pitch = sof->width * (sof->precision/8) * 3;
break;
......@@ -574,18 +764,21 @@ static u32 mxc_jpeg_get_line_pitch(
line_pitch = sof->width * (sof->precision/8) * 3;
break;
}
dev_info(dev, "line_pitch = %d\n", line_pitch);
dev_dbg(dev, "line_pitch = %d\n", line_pitch);
return line_pitch;
}
static int mxc_jpeg_parse(struct device *dev,
static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx,
struct mxc_jpeg_desc *desc, u8 *src_addr, u32 size)
{
struct device *dev = ctx->mxc_jpeg->dev;
struct mxc_jpeg_q_data *q_data;
struct mxc_jpeg_stream stream;
bool notfound = true;
struct mxc_jpeg_sof sof;
int byte;
enum mxc_jpeg_image_format img_fmt;
u32 fourcc;
memset(&sof, 0, sizeof(struct mxc_jpeg_sof));
stream.addr = src_addr;
......@@ -615,22 +808,51 @@ static int mxc_jpeg_parse(struct device *dev,
notfound = true;
}
}
q_data = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
if (sof.width != q_data->w || sof.height != q_data->h) {
dev_err(dev,
"Resolution mismatch: %dx%d (JPEG) versus %dx%d(user)",
sof.width, sof.height, q_data->w, q_data->h);
return -EINVAL;
}
if (sof.width % 8 != 0 || sof.height % 8 != 0) {
dev_info(dev, "JPEG width or height not multiple of 8: %dx%d\n",
dev_err(dev, "JPEG width or height not multiple of 8: %dx%d\n",
sof.width, sof.height);
return -EINVAL;
}
if (sof.width > 0x2000 || sof.height > 0x2000) {
dev_info(dev, "JPEG width or height should be <= 8192: %dx%d\n",
dev_err(dev, "JPEG width or height should be <= 8192: %dx%d\n",
sof.width, sof.height);
return -EINVAL;
}
desc->imgsize = sof.width << 16 | sof.height;
dev_info(dev, "JPEG imgsize = 0x%x (%dx%d)\n", desc->imgsize,
dev_dbg(dev, "JPEG imgsize = 0x%x (%dx%d)\n", desc->imgsize,
sof.width, sof.height);
img_fmt = mxc_jpeg_get_image_format(dev, &sof);
if (img_fmt == MXC_JPEG_INVALID)
return -EINVAL;
if (mxc_jpeg_imgfmt_to_fourcc(img_fmt, &fourcc)) {
dev_err(dev, "Fourcc not found for %d", img_fmt);
return -EINVAL;
}
if (fourcc != q_data->fmt->fourcc) {
char *jpeg_format_name = fourcc_to_str(fourcc);
char *user_format_name = fourcc_to_str(q_data->fmt->fourcc);
dev_warn(dev,
"Pixel format mismatch: jpeg(%s) versus user (%s)",
jpeg_format_name, user_format_name);
dev_warn(dev, "Keeping user settings\n");
kfree(jpeg_format_name);
kfree(user_format_name);
img_fmt = mxc_jpeg_fourcc_to_imgfmt(q_data->fmt->fourcc);
}
desc->stm_ctrl |= STM_CTRL_IMAGE_FORMAT(img_fmt);
desc->line_pitch = mxc_jpeg_get_line_pitch(dev, &sof, img_fmt);
q_data->stride = desc->line_pitch;
q_data->sizeimage[0] = sof.width * sof.height;
return 0;
}
......@@ -640,23 +862,30 @@ static void mxc_jpeg_buf_queue(struct vb2_buffer *vb)
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
int slot = 0; /* TODO get slot*/
struct mxc_jpeg_q_data *q_data;
int decoded_jpeg_size;
if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
goto end;
if (ctx->mode != MXC_JPEG_DECODE)
goto end;
ret = mxc_jpeg_parse(ctx->mxc_jpeg->dev,
ret = mxc_jpeg_parse(ctx,
ctx->mxc_jpeg->slot_data[slot].desc,
(u8 *)vb2_plane_vaddr(vb, 0),
vb2_get_plane_payload(vb, 0));
if (ret) {
v4l2_err(&ctx->mxc_jpeg->v4l2_dev,
"driver does not support this resolution\n");
"driver does not support this resolution/format\n");
vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
return;
}
q_data = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
decoded_jpeg_size = q_data->w * q_data->h * q_data->fmt->depth / 8;
if (q_data->sizeimage[0] != decoded_jpeg_size)
q_data->sizeimage[0] = decoded_jpeg_size;
if (ctx->state == MXC_JPEG_INIT) {
struct vb2_queue *dst_vq = v4l2_m2m_get_vq(
ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
......@@ -736,28 +965,6 @@ static int mxc_jpeg_queue_init(void *priv, struct vb2_queue *src_vq,
return ret;
}
static struct mxc_jpeg_fmt *mxc_jpeg_find_format(struct mxc_jpeg_ctx *ctx,
u32 pixelformat,
unsigned int fmt_type)
{
unsigned int k, fmt_flag;
fmt_flag = fmt_type;
if (ctx->mode == MXC_JPEG_ENCODE)
fmt_flag = (fmt_type == MXC_JPEG_FMT_TYPE_RAW) ?
MXC_JPEG_FMT_TYPE_ENC :
MXC_JPEG_FMT_TYPE_RAW;
for (k = 0; k < MXC_JPEG_NUM_FORMATS; k++) {
struct mxc_jpeg_fmt *fmt = &mxc_formats[k];
if (fmt->fourcc == pixelformat && fmt->flags == fmt_flag)
return fmt;
}
return NULL;
}
static int mxc_jpeg_alloc_slot_data(struct mxc_jpeg_dev *jpeg)
{
int slot;
......@@ -855,16 +1062,12 @@ static int mxc_jpeg_open(struct file *file)
ctx->mxc_jpeg = mxc_jpeg;
if (mxc_jpeg->mode == MXC_JPEG_ENCODE) {
ctx->mode = MXC_JPEG_ENCODE;
cap_fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB24,
MXC_JPEG_FMT_TYPE_ENC);
out_fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
MXC_JPEG_FMT_TYPE_RAW);
out_fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB24);
cap_fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG);
} else {
ctx->mode = MXC_JPEG_DECODE;
out_fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB24,
MXC_JPEG_FMT_TYPE_RAW);
cap_fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
MXC_JPEG_FMT_TYPE_ENC);
out_fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG);
cap_fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB24);
}
ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(mxc_jpeg->m2m_dev, ctx,
mxc_jpeg_queue_init);
......@@ -910,10 +1113,10 @@ static int mxc_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
if (ctx->mode == MXC_JPEG_ENCODE)
return enum_fmt(mxc_formats, MXC_NUM_FORMATS, f,
return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f,
MXC_IN_FORMAT);
else
return enum_fmt(mxc_formats, MXC_NUM_FORMATS, f,
return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f,
MXC_OUT_FORMAT);
}
......@@ -923,14 +1126,14 @@ static int mxc_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
if (ctx->mode == MXC_JPEG_DECODE)
return enum_fmt(mxc_formats, MXC_NUM_FORMATS, f,
return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f,
MXC_IN_FORMAT);
else
return enum_fmt(mxc_formats, MXC_NUM_FORMATS, f,
return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f,
MXC_OUT_FORMAT);
}
static void mxc_jpeg_bound_align_image(u32 *w, unsigned int wmin,
static int mxc_jpeg_bound_align_image(u32 *w, unsigned int wmin,
unsigned int wmax, unsigned int walign,
u32 *h, unsigned int hmin,
unsigned int hmax, unsigned int halign)
......@@ -947,74 +1150,101 @@ static void mxc_jpeg_bound_align_image(u32 *w, unsigned int wmin,
*w += w_step;
if (*h < height && (*h + h_step) <= hmax)
*h += h_step;
return (width != *w || height != *h);
}
static int mxc_jpeg_try_fmt(struct v4l2_format *f, struct mxc_jpeg_fmt *fmt,
struct mxc_jpeg_ctx *ctx, int q_type)
{
struct device *dev = ctx->mxc_jpeg->dev;
struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[0];
u32 stride, h;
u32 w = pix_mp->width;
u32 h = pix_mp->height;
unsigned int mode = ctx->mode;
memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
pix_mp->field = V4L2_FIELD_NONE;
pix_mp->num_planes = fmt->colplanes;
pix_mp->pixelformat = fmt->fourcc;
if (mxc_jpeg_bound_align_image(&w,
MXC_JPEG_MIN_WIDTH,
MXC_JPEG_MAX_WIDTH,
MXC_JPEG_W_ALIGN,
&h,
MXC_JPEG_MIN_HEIGHT,
MXC_JPEG_MAX_HEIGHT,
MXC_JPEG_H_ALIGN))
dev_warn(dev, "Image was aligned to %dx%d", w, h);
if (q_type == MXC_JPEG_FMT_TYPE_ENC && ctx->mode == MXC_JPEG_DECODE) {
struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[0];
mxc_jpeg_bound_align_image(&pix_mp->width,
MXC_JPEG_MIN_WIDTH,
MXC_JPEG_MAX_WIDTH,
MXC_JPEG_MIN_WIDTH,
&pix_mp->height,
MXC_JPEG_MIN_HEIGHT,
MXC_JPEG_MAX_HEIGHT,
MXC_JPEG_MIN_WIDTH);
memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
/* TODO try_fmt should not modify the state, move to s_fmt */
if (q_type == MXC_JPEG_FMT_TYPE_ENC && mode == MXC_JPEG_DECODE) {
pfmt->bytesperline = 0;
/* Source size must be aligned to 128 */
pfmt->sizeimage = mxc_jpeg_align(pfmt->sizeimage, 128);
if (pfmt->sizeimage == 0)
pfmt->sizeimage = MXC_JPEG_DEFAULT_SIZEIMAGE;
return 0;
} else if (q_type == MXC_JPEG_FMT_TYPE_RAW && mode == MXC_JPEG_DECODE) {
pfmt->bytesperline = w * (fmt->depth / 8);
pfmt->sizeimage = w * h * fmt->depth / 8;
} else if (q_type == MXC_JPEG_FMT_TYPE_ENC && mode == MXC_JPEG_ENCODE) {
pfmt->bytesperline = 0;
/* assuming worst jpeg compression */
pfmt->sizeimage = w * h * 6;
} else { /* MXC_JPEG_FMT_TYPE_RAW && MXC_JPEG_ENCODE */
pfmt->bytesperline = w * (fmt->depth / 8);
pfmt->sizeimage = w * h * fmt->depth / 8;
}
/* type is MXC_JPEG_FMT_TYPE_RAW */
mxc_jpeg_bound_align_image(&pix_mp->width, MXC_JPEG_MIN_WIDTH,
MXC_JPEG_MAX_WIDTH, MXC_JPEG_MIN_WIDTH,
&pix_mp->height, MXC_JPEG_MIN_HEIGHT,
MXC_JPEG_MAX_HEIGHT, MXC_JPEG_MIN_WIDTH);
pfmt = &pix_mp->plane_fmt[0];
stride = pix_mp->width * 3;
h = pix_mp->height;
memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
pfmt->bytesperline = stride;
pfmt->sizeimage = stride * h;
return 0;
}
static int mxc_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
struct device *dev = jpeg->dev;
struct mxc_jpeg_fmt *fmt;
u32 fourcc = f->fmt.pix_mp.pixelformat;
int q_type = (ctx->mode == MXC_JPEG_DECODE) ?
MXC_JPEG_FMT_TYPE_RAW : MXC_JPEG_FMT_TYPE_ENC;
fmt = mxc_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat,
MXC_JPEG_FMT_TYPE_RAW);
return mxc_jpeg_try_fmt(f, fmt, ctx, MXC_JPEG_FMT_TYPE_RAW);
fmt = mxc_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat);
if (!fmt || (fmt->flags != q_type)) {
char *format_name = fourcc_to_str(fourcc);
dev_err(dev, "Format not supported: %s.\n",
format_name);
kfree(format_name);
return -1;
}
return mxc_jpeg_try_fmt(f, fmt, ctx, q_type);
}
static int mxc_jpeg_try_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *f)
{
struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
struct device *dev = jpeg->dev;
struct mxc_jpeg_fmt *fmt;
u32 fourcc = f->fmt.pix_mp.pixelformat;
int q_type = (ctx->mode == MXC_JPEG_ENCODE) ?
MXC_JPEG_FMT_TYPE_RAW : MXC_JPEG_FMT_TYPE_ENC;
fmt = mxc_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat,
MXC_JPEG_FMT_TYPE_ENC);
return mxc_jpeg_try_fmt(f, fmt, ctx, MXC_JPEG_FMT_TYPE_ENC);
fmt = mxc_jpeg_find_format(ctx, fourcc);
if (!fmt || (fmt->flags != q_type)) {
char *format_name = fourcc_to_str(fourcc);
dev_err(dev, "Format not supported: %s.\n",
format_name);
kfree(format_name);
return -1;
}
return mxc_jpeg_try_fmt(f, fmt, ctx, q_type);
}
static int mxc_jpeg_s_fmt(struct mxc_jpeg_ctx *ctx,
struct v4l2_format *f)
......@@ -1023,7 +1253,6 @@ static int mxc_jpeg_s_fmt(struct mxc_jpeg_ctx *ctx,
struct mxc_jpeg_q_data *q_data = NULL;
struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
unsigned int f_type;
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
if (!vq)
......@@ -1036,9 +1265,7 @@ static int mxc_jpeg_s_fmt(struct mxc_jpeg_ctx *ctx,
return -EBUSY;
}
f_type = f->type;
q_data->fmt = mxc_jpeg_find_format(ctx, pix_mp->pixelformat, f_type);
q_data->fmt = mxc_jpeg_find_format(ctx, pix_mp->pixelformat);
q_data->w = pix_mp->width;
q_data->h = pix_mp->height;
q_data->bytesperline[0] = pix_mp->plane_fmt[0].bytesperline;
......
......@@ -25,11 +25,12 @@
#define MXC_JPEG_RUNNING 1
#define MXC_JPEG_FMT_TYPE_ENC 0
#define MXC_JPEG_FMT_TYPE_RAW 1
#define MXC_JPEG_NUM_FORMATS 4
#define MXC_JPEG_MIN_HEIGHT 0x8
#define MXC_JPEG_MIN_WIDTH 0x8
#define MXC_JPEG_MAX_HEIGHT 0x2000
#define MXC_JPEG_MAX_WIDTH 0x2000
#define MXC_JPEG_H_ALIGN 3
#define MXC_JPEG_W_ALIGN 3
#define MXC_JPEG_DEFAULT_SIZEIMAGE 10000
#define MXC_JPEG_ENC_CONF 1
#define MXC_JPEG_ENC_DONE 0
......@@ -135,7 +136,7 @@ struct mxc_jpeg_sof {
u8 precision;
u16 height, width;
u8 components_no;
struct mxc_jpeg_sof_comp comp[3];
struct mxc_jpeg_sof_comp comp[4];
} __packed;
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment