void smfc_hwconfigure_reset(struct smfc_dev *smfc)
{
- u32 cfg = __raw_readl(smfc->reg + REG_JPEG_CNTL) & ~((1 << 29) | 3);
- __raw_writel(cfg, smfc->reg + REG_JPEG_CNTL);
- __raw_writel(cfg | (1 << 29), smfc->reg + REG_JPEG_CNTL);
+ u32 cfg = __raw_readl(smfc->reg + REG_MAIN_JPEG_CNTL);
+ cfg &= ~((1 << 29) | 3);
+ __raw_writel(cfg, smfc->reg + REG_MAIN_JPEG_CNTL);
+ __raw_writel(cfg | (1 << 29), smfc->reg + REG_MAIN_JPEG_CNTL);
}
/*
}
#pragma GCC diagnostic pop
+static void smfc_hwconfigure_qtable(void __iomem *reg, unsigned int factor,
+ const unsigned char table[])
+{
+ size_t i;
+
+ for (i = 0; i < SMFC_MCU_SIZE; i += 4)
+ __raw_writel(smfc_calc_quantizers(i, factor, table), reg + i);
+}
+
void smfc_hwconfigure_tables(struct smfc_ctx *ctx)
{
size_t i;
unsigned int factor = ctx->quality_factor;
factor = (factor < 50) ? 5000 / factor : 200 - factor * 2;
- /* Quantizer table 0 */
- for (i = 0; i < SMFC_MCU_SIZE; i += 4) {
- __raw_writel(smfc_calc_quantizers(i, factor, default_luma_qtbl),
- base + REG_QTBL_BASE + i);
- __raw_writel(
- smfc_calc_quantizers(i, factor, default_chroma_qtbl),
- base + REG_QTBL_BASE + SMFC_MCU_SIZE + i);
- }
+ smfc_hwconfigure_qtable(base + REG_QTBL_BASE,
+ factor, default_luma_qtbl);
+ smfc_hwconfigure_qtable(base + REG_QTBL_BASE + SMFC_MCU_SIZE,
+ factor, default_chroma_qtbl);
/* Huffman tables */
for (i = 0; i < 4; i++) {
__raw_writel(ITU_H_TBL_VAL_AC_CHROMINANCE[i],
base + REG_HTBL_CHROMA_ACVAL + i * sizeof(u32));
- __raw_writel(VAL_TABLE_SELECT, base + REG_TABLE_SELECT);
- __raw_writel(SMFC_DHT_LEN, base + REG_DHT_LEN);
+ __raw_writel(VAL_MAIN_TABLE_SELECT, base + REG_MAIN_TABLE_SELECT);
+ __raw_writel(SMFC_DHT_LEN, base + REG_MAIN_DHT_LEN);
}
+void smfc_hwconfigure_2nd_tables(struct smfc_ctx *ctx)
+{
+ /* Qunatiazation table 2 and 3 will be used by the secondary image */
+ void __iomem *base = ctx->smfc->reg;
+ void __iomem *qtblbase = base + REG_QTBL_BASE + SMFC_MCU_SIZE * 2;
+ unsigned int factor = ctx->thumb_quality_factor;
+ factor = (factor < 50) ? 5000 / factor : 200 - factor * 2;
+
+ smfc_hwconfigure_qtable(qtblbase, factor, default_luma_qtbl);
+ smfc_hwconfigure_qtable(qtblbase + SMFC_MCU_SIZE,
+ factor, default_chroma_qtbl);
+ /* Huffman table for the secondary image is the same as the main image */
+ __raw_writel(VAL_SEC_TABLE_SELECT, base + REG_SEC_TABLE_SELECT);
+ __raw_writel(SMFC_DHT_LEN, base + REG_SEC_DHT_LEN);
+}
static void smfc_hwconfigure_image_base(struct smfc_ctx *ctx,
- struct vb2_buffer *vb2buf)
+ struct vb2_buffer *vb2buf,
+ bool thumbnail)
{
dma_addr_t addr;
unsigned int i;
- bool multiplane =
- (ctx->img_fmt->num_buffers == ctx->img_fmt->num_planes);
+ unsigned int num_buffers = ctx->img_fmt->num_buffers;
+ bool multiplane = (num_buffers == ctx->img_fmt->num_planes);
+ u32 off = thumbnail ? REG_SEC_IMAGE_BASE : REG_MAIN_IMAGE_BASE;
if (multiplane) {
/* Note that this includes a single-plane format such as YUYV */
- for (i = 0; i < ctx->img_fmt->num_buffers; i++) {
+ for (i = 0; i < num_buffers; i++) {
addr = vb2_dma_sg_plane_dma_addr(vb2buf, i);
__raw_writel((u32)addr,
- ctx->smfc->reg + REG_MAIN_IMAGE_BASE(i));
+ ctx->smfc->reg + REG_IMAGE_BASE(off, i));
}
} else {
- addr = vb2_dma_sg_plane_dma_addr(vb2buf, i);
+ u32 width = thumbnail ? ctx->thumb_width : ctx->width;
+ u32 height = thumbnail ? ctx->thumb_height : ctx->height;
+ addr = vb2_dma_sg_plane_dma_addr(vb2buf, thumbnail ? 1 : 0);
for (i = 0; i < ctx->img_fmt->num_planes; i++) {
__raw_writel((u32)addr,
- ctx->smfc->reg + REG_MAIN_IMAGE_BASE(i));
- addr += (ctx->width * ctx->height *
- ctx->img_fmt->bpp_pix[i]) / 8;
+ ctx->smfc->reg + REG_IMAGE_BASE(off, i));
+ addr += (width * height * ctx->img_fmt->bpp_pix[i]) / 8;
}
}
}
static u32 smfc_hwconfigure_jpeg_base(struct smfc_ctx *ctx,
- struct vb2_buffer *vb2buf)
+ struct vb2_buffer *vb2buf,
+ bool thumbnail)
{
dma_addr_t addr;
+ u32 off = thumbnail ? REG_SEC_JPEG_BASE : REG_MAIN_JPEG_BASE;
- BUG_ON(vb2buf->num_planes != 1);
- addr = vb2_dma_sg_plane_dma_addr(vb2buf, 0);
- __raw_writel((u32)addr, ctx->smfc->reg + REG_MAIN_JPEG_BASE);
+ addr = vb2_dma_sg_plane_dma_addr(vb2buf, thumbnail ? 1 : 0);
+ __raw_writel((u32)addr, ctx->smfc->reg + off);
return (u32)addr;
}
return 2 << 24; /* default: YUV422 */
}
+void smfc_hwconfigure_2nd_image(struct smfc_ctx *ctx)
+{
+ struct vb2_buffer *vb2buf_img, *vb2buf_jpg;
+ u32 format;
+
+ if (!(ctx->flags & SMFC_CTX_COMPRESS))
+ return;
+
+ __raw_writel(ctx->thumb_width | (ctx->thumb_height << 16),
+ ctx->smfc->reg + REG_SEC_IMAGE_SIZE);
+
+ vb2buf_img = v4l2_m2m_next_src_buf(ctx->m2mctx);
+ vb2buf_jpg = v4l2_m2m_next_dst_buf(ctx->m2mctx);
+
+ smfc_hwconfigure_image_base(ctx, vb2buf_img, true);
+ /*
+ * secondary image stream base is not required because there is no
+ * MAX_COMPRESSED_SIZE register for the secondary image
+ */
+ smfc_hwconfigure_jpeg_base(ctx, vb2buf_jpg, true);
+
+ /*
+ * Chroma subsampling is always 1/2 for both of horizontal and vertical
+ * directions to reduce the compressed size of the secondary image
+ */
+ format = ctx->img_fmt->regcfg | smfc_get_jpeg_format(2, 2);
+ __raw_writel(format, ctx->smfc->reg + REG_SEC_IMAGE_FORMAT);
+}
+
void smfc_hwconfigure_image(struct smfc_ctx *ctx)
{
struct vb2_v4l2_buffer *vb2buf_img, *vb2buf_jpg;
max(ctx->chroma_vfactor, ctx->img_fmt->chroma_vfactor));
}
- smfc_hwconfigure_image_base(ctx, &vb2buf_img->vb2_buf);
- stream_address = smfc_hwconfigure_jpeg_base(ctx, &vb2buf_jpg->vb2_buf);
+ smfc_hwconfigure_image_base(ctx, &vb2buf_img->vb2_buf, false);
+ stream_address = smfc_hwconfigure_jpeg_base(ctx, &vb2buf_jpg->vb2_buf,
+ false);
__raw_writel(format, ctx->smfc->reg + REG_MAIN_IMAGE_FORMAT);
__raw_writel(vb2_plane_size(&vb2buf_jpg->vb2_buf, 0) -
u32 cfg;
void __iomem *base = ctx->smfc->reg;
+ __raw_writel(!(ctx->flags & SMFC_CTX_B2B_COMPRESS) ? 0 : 1,
+ base + REG_SEC_JPEG_CNTL);
+
/* configure "Error max compressed size" interrupt */
cfg = __raw_readl(base + REG_INT_EN);
__raw_writel(cfg | (1 << 11), base + REG_INT_EN);
- cfg = __raw_readl(base + REG_JPEG_CNTL) & ~3;
+ cfg = __raw_readl(base + REG_MAIN_JPEG_CNTL) & ~3;
cfg |= !(ctx->flags & SMFC_CTX_COMPRESS) ? 1 : 2;
cfg |= 1 << 19; /* update huffman table from SFR */
cfg |= 1 << 28; /* enables interrupt */
cfg |= 1 << 29; /* Release reset */
if (ctx->restart_interval != 0)
cfg |= (ctx->restart_interval << 3) | (1 << 2);
+ if (!!(ctx->flags & SMFC_CTX_B2B_COMPRESS))
+ cfg |= 1 << 31; /* back-to-back enable */
- writel(cfg, base + REG_JPEG_CNTL);
+ writel(cfg, base + REG_MAIN_JPEG_CNTL);
}
-bool smfc_hwstatus_okay(struct smfc_dev *smfc)
+bool smfc_hwstatus_okay(struct smfc_dev *smfc, struct smfc_ctx *ctx)
{
- u32 val = __raw_readl(smfc->reg + REG_INT_STATUS);
+ u32 val = __raw_readl(smfc->reg + REG_MAIN_INT_STATUS);
if (!val) {
dev_err(smfc->dev, "Interrupt with no status change\n");
return false;
return false;
}
+ if (!(ctx->flags & SMFC_CTX_B2B_COMPRESS))
+ return true;
+ val = __raw_readl(smfc->reg + REG_SEC_INT_STATUS);
+ if (!val) {
+ dev_err(smfc->dev, "Secondary image is not completed\n");
+ return false;
+ }
+
+ if ((val & ~2)) {
+ dev_err(smfc->dev, "Error interrupt %#010x for the secondary\n",
+ val);
+ return false;
+ }
+
return true;
}
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 4,
smfc->reg + 0x000, 0xD4, false);
/* Reading quantization tables */
- val = __raw_readl(smfc->reg + REG_TABLE_SELECT);
+ val = __raw_readl(smfc->reg + REG_MAIN_TABLE_SELECT);
__raw_writel(val | SMFC_TABLE_READ_REQ_MASK,
- smfc->reg + REG_TABLE_SELECT);
+ smfc->reg + REG_MAIN_TABLE_SELECT);
for (val = 0; val < 512; val++) {
- if (!!(__raw_readl(smfc->reg + REG_TABLE_SELECT)
+ if (!!(__raw_readl(smfc->reg + REG_MAIN_TABLE_SELECT)
& SMFC_TABLE_READ_OK_MASK))
break;
cpu_relax();
}
if ((val == 512) &&
- !(__raw_readl(smfc->reg + REG_TABLE_SELECT)
+ !(__raw_readl(smfc->reg + REG_MAIN_TABLE_SELECT)
& SMFC_TABLE_READ_OK_MASK)) {
pr_info("** FAILED TO READ HUFFMAN and QUANTIZER TABLES **\n");
return;
#define SMFC_ADDR_ALIGN_MASK (16 - 1) /* 128-bit align */
/********** H/W REGISTERS and DEFAULT VALUES **********************************/
-#define REG_JPEG_CNTL 0x000
+#define REG_MAIN_JPEG_CNTL 0x000
#define REG_INT_EN 0x004
#define REG_TIMER_COUNT 0x008
-#define REG_INT_STATUS 0x00C
+#define REG_MAIN_INT_STATUS 0x00C
#define REG_MAIN_IMAGE_SIZE 0x014
#define REG_MAIN_JPEG_BASE 0x010
-#define REG_MAIN_IMAGE_BASE(n) (0x018 + (n) * 12)
+#define REG_MAIN_IMAGE_BASE 0x018
+#define REG_SEC_JPEG_CNTL 0x080
+#define REG_SEC_JPEG_BASE 0x088
+#define REG_SEC_IMAGE_BASE 0x090
+#define REG_SEC_IMAGE_FORMAT 0x0B8
+#define REG_SEC_IMAGE_SIZE 0x08C
+#define REG_SEC_INT_STATUS 0x084
+#define REG_IMAGE_BASE(off, n) ((off) + (n) * 12)
#define REG_MAIN_IMAGE_FORMAT 0x040
#define REG_MAIN_STREAM_SIZE 0x044
+#define REG_SEC_STREAM_SIZE 0x0BC
#define REG_MAIN_MAX_STREAM_SIZE 0x06C
#define REG_IP_VERSION_NUMBER 0x064
-#define REG_SECD_IMAGE_FORMAT 0x0B8
-
-#define REG_TABLE_SELECT 0x03C
+#define REG_MAIN_TABLE_SELECT 0x03C
+#define REG_SEC_TABLE_SELECT 0x0B4
/*
* Component 0: Q-table 0, AC/DC table 0
* Component 1 and 2: Q-table 1, AC/DC table 1
*/
-#define VAL_TABLE_SELECT 0xF14
+#define VAL_MAIN_TABLE_SELECT 0xF14
+/*
+ * Component 0: Q-table 2, AC/DC table 0
+ * Component 1 and 2: Q-table 3, AC/DC table 1
+ */
+#define VAL_SEC_TABLE_SELECT 0xF3E
#define SMFC_TABLE_READ_REQ_MASK (1 << 13)
#define SMFC_TABLE_READ_OK_MASK (1 << 12)
# define REG_HTBL_LUMA_ACVAL (REG_HTBL_LUMA_ACLEN + 4 * sizeof(u32))
# define REG_HTBL_CHROMA_ACLEN (REG_HTBL_LUMA_ACVAL + 44 * sizeof(u32))
# define REG_HTBL_CHROMA_ACVAL (REG_HTBL_CHROMA_ACLEN + 4 * sizeof(u32))
-#define REG_DHT_LEN 0x04C
+#define REG_MAIN_DHT_LEN 0x04C
+#define REG_SEC_DHT_LEN 0x0C4
#define SMFC_DHT_LEN 0x1A2
/* Value definitions of MAIN/SECONDARY_IMAGE_FORMAT */
/* set if H/W does not have 128-bit alignment constraint for image base */
#define V4L2_CAP_EXYNOS_JPEG_NO_IMAGEBASE_ALIGN 0x4000
+/* SMFC SPECIFIC CONTROLS */
+#define V4L2_CID_JPEG_SEC_COMP_QUALITY (V4L2_CID_JPEG_CLASS_BASE + 20)
+
#define SMFC_DEFAULT_OUTPUT_FORMAT (&smfc_image_formats[1])
#define SMFC_DEFAULT_CAPTURE_FORMAT (&smfc_image_formats[0])
+#define SMFC_FMT_MAIN_SIZE(val) ((val) & 0xFFFF)
+#define SMFC_FMT_SEC_SIZE(val) (((val) >> 16) & 0xFFFF)
+
const struct smfc_image_format smfc_image_formats[] = {
{
/* JPEG should be the first format */
struct smfc_ctx *ctx = v4l2_m2m_get_curr_priv(smfc->m2mdev);
enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
u32 streamsize = smfc_get_streamsize(smfc);
+ u32 thumb_streamsize = smfc_get_2nd_streamsize(smfc);
- if (!smfc_hwstatus_okay(smfc)) {
+ if (!smfc_hwstatus_okay(smfc, ctx)) {
smfc_dump_registers(smfc);
state = VB2_BUF_STATE_ERROR;
smfc_hwconfigure_reset(smfc);
struct vb2_v4l2_buffer *vb_capture =
v4l2_m2m_dst_buf_remove(ctx->m2mctx);
- vb2_set_plane_payload(&vb_capture->vb2_buf, 0, streamsize);
+ if (!!(ctx->flags & SMFC_CTX_COMPRESS)) {
+ vb2_set_plane_payload(&vb_capture->vb2_buf,
+ 0, streamsize);
+ if (!!(ctx->flags & SMFC_CTX_B2B_COMPRESS))
+ vb2_set_plane_payload(&vb_capture->vb2_buf, 1,
+ thumb_streamsize);
+ }
v4l2_m2m_buf_done(v4l2_m2m_src_buf_remove(ctx->m2mctx), state);
v4l2_m2m_buf_done(vb_capture, state);
v4l2_m2m_job_finish(smfc->m2mdev, ctx->m2mctx);
sizes[0] = PAGE_SIZE;
*num_planes = 1;
alloc_devs[i] = ctx->smfc->dev;
+ if (!!(ctx->flags & SMFC_CTX_B2B_COMPRESS)) {
+ sizes[1] = PAGE_SIZE;
+ alloc_devs[1] = ctx->smfc->dev;
+ (*num_planes)++;
+ }
} else {
unsigned int i;
*num_planes = ctx->img_fmt->num_buffers;
sizes[i] = (sizes[i] * ctx->img_fmt->bpp_buf[i]) / 8;
alloc_devs[i] = ctx->smfc->dev;
}
+
+ if (!!(ctx->flags & SMFC_CTX_B2B_COMPRESS)) {
+ unsigned int idx;
+ for (i = 0; i < *num_planes; i++) {
+ idx = *num_planes + i;
+ sizes[idx] = ctx->thumb_width;
+ sizes[idx] *= ctx->thumb_height;
+ sizes[idx] *= ctx->img_fmt->bpp_buf[i];
+ sizes[idx] /= 8;
+ alloc_devs[idx] = ctx->smfc->dev;
+ }
+
+ *num_planes *= 2;
+ }
}
return 0;
case V4L2_CID_JPEG_COMPRESSION_QUALITY:
ctx->quality_factor = (unsigned char)ctrl->val;
break;
+ case V4L2_CID_JPEG_SEC_COMP_QUALITY:
+ ctx->thumb_quality_factor = (unsigned char)ctrl->val;
+ break;
case V4L2_CID_JPEG_RESTART_INTERVAL:
ctx->restart_interval = (unsigned char)ctrl->val;
break;
struct v4l2_ctrl_handler *hdlr)
{
const char *msg;
+ struct v4l2_ctrl_config ctrlcfg;
v4l2_ctrl_handler_init(hdlr, 1);
goto err;
}
+ memset(&ctrlcfg, 0, sizeof(ctrlcfg));
+ ctrlcfg.ops = &smfc_ctrl_ops;
+ ctrlcfg.id = V4L2_CID_JPEG_SEC_COMP_QUALITY;
+ ctrlcfg.name = "Quality factor of secondray image";
+ ctrlcfg.type = V4L2_CTRL_TYPE_INTEGER;
+ ctrlcfg.min = 1;
+ ctrlcfg.max = 100;
+ ctrlcfg.step = 1;
+ ctrlcfg.def = 50;
+ if (!v4l2_ctrl_new_custom(hdlr, &ctrlcfg, NULL)) {
+ msg = "secondary quality factor";
+ goto err;
+ }
+
if (!v4l2_ctrl_new_std(hdlr, &smfc_ctrl_ops,
V4L2_CID_JPEG_RESTART_INTERVAL,
0, 64, 1, 0)) {
* default mode: compression
* default image format: YUYV
* default size: 16x8
+ * default thumbnail size: 0x0 (back2back comp. not enabled)
* default chroma subsampling for JPEG: YUV422
* default quality factor for compression: 96
+ * default quality factor of thumbnail for compression: 50
*/
ctx->img_fmt = SMFC_DEFAULT_OUTPUT_FORMAT;
ctx->width = SMFC_MIN_WIDTH << ctx->img_fmt->chroma_hfactor;
ctx->flags |= SMFC_CTX_COMPRESS;
ctx->quality_factor = 96;
ctx->restart_interval = 0;
+ ctx->thumb_quality_factor = 50;
ctx->smfc = smfc;
return 0;
}
-static bool smfc_check_image_size(struct device *dev, __u32 type,
+static bool __smfc_check_image_size(struct device *dev, __u32 type,
const struct smfc_image_format *smfc_fmt,
__u32 width, __u32 height)
{
return true;
}
+static bool smfc_check_image_size(struct device *dev, __u32 type,
+ const struct smfc_image_format *smfc_fmt,
+ __u32 width, __u32 height)
+{
+ __u32 twidth = SMFC_FMT_SEC_SIZE(width);
+ __u32 theight = SMFC_FMT_SEC_SIZE(height);
+ width = SMFC_FMT_MAIN_SIZE(width);
+ height = SMFC_FMT_MAIN_SIZE(height);
+
+ if (!__smfc_check_image_size(dev, type, smfc_fmt, width, height))
+ return false;
+
+ if (!twidth || !theight) /* thumbnail image size is not specified */
+ return true;
+
+ if (!__smfc_check_image_size(dev, type, smfc_fmt, twidth, theight))
+ return false;
+
+ return true;
+}
static bool smfc_v4l2_init_fmt_mplane(const struct smfc_ctx *ctx,
const struct smfc_image_format *smfc_fmt,
/* JPEG format has zero in smfc_fmt->bpp_buf[0] */
for (i = 0; i < smfc_fmt->num_buffers; i++) {
pix_mp->plane_fmt[i].bytesperline =
- (pix_mp->width * smfc_fmt->bpp_buf[i]) / 8;
+ (SMFC_FMT_MAIN_SIZE(pix_mp->width) *
+ smfc_fmt->bpp_buf[i]) / 8;
pix_mp->plane_fmt[i].sizeimage =
- pix_mp->plane_fmt[i].bytesperline;
- pix_mp->plane_fmt[i].sizeimage *= pix_mp->height;
+ pix_mp->plane_fmt[i].bytesperline *
+ SMFC_FMT_MAIN_SIZE(pix_mp->height);
}
pix_mp->field = 0;
pix_mp->num_planes = smfc_fmt->num_buffers;
+ if (SMFC_FMT_SEC_SIZE(pix_mp->width) &&
+ SMFC_FMT_SEC_SIZE(pix_mp->height)) {
+ /*
+ * Format information for the secondary image is stored after
+ * the last plane of the main image. It is okay to use more
+ * planes because the maximum valid planes are eight
+ */
+ unsigned int j;
+ for (j = 0; j < smfc_fmt->num_buffers; j++) {
+ pix_mp->plane_fmt[i + j].bytesperline =
+ (SMFC_FMT_SEC_SIZE(pix_mp->width) *
+ smfc_fmt->bpp_buf[j]) / 8;
+ pix_mp->plane_fmt[i + j].sizeimage =
+ pix_mp->plane_fmt[i + j].bytesperline *
+ SMFC_FMT_SEC_SIZE(pix_mp->height);
+ }
+
+ pix_mp->num_planes *= 2;
+ }
+
return true;
}
return 0;
}
-
+static __u32 v4l2_to_multiplane_type(__u32 type)
+{
+ /* V4L2_BUF_TYPE_VIDEO_CAPTURE+8 = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
+ return V4L2_TYPE_IS_MULTIPLANAR(type) ? type : type + 8;
+}
static int smfc_v4l2_s_fmt_mplane(struct file *filp, void *fh,
struct v4l2_format *f)
if (!smfc_v4l2_init_fmt_mplane(ctx, smfc_fmt, f->type, &f->fmt.pix_mp))
return -EINVAL;
- ctx->width = f->fmt.pix_mp.width;
- ctx->height = f->fmt.pix_mp.height;
+ ctx->width = SMFC_FMT_MAIN_SIZE(f->fmt.pix_mp.width);
+ ctx->height = SMFC_FMT_MAIN_SIZE(f->fmt.pix_mp.height);
+ ctx->thumb_width = SMFC_FMT_SEC_SIZE(f->fmt.pix_mp.width);
+ ctx->thumb_height = SMFC_FMT_SEC_SIZE(f->fmt.pix_mp.height);
+
+ if (ctx->thumb_width && ctx->thumb_height)
+ ctx->flags |= SMFC_CTX_B2B_COMPRESS;
+ else
+ ctx->flags &= ~SMFC_CTX_B2B_COMPRESS;
if (f->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_JPEG)
ctx->img_fmt = smfc_fmt;
+ if (ctx->flags & SMFC_CTX_B2B_COMPRESS) {
+ struct vb2_queue *othervq = v4l2_m2m_get_vq(ctx->m2mctx,
+ V4L2_TYPE_IS_OUTPUT(f->type) ?
+ V4L2_BUF_TYPE_VIDEO_CAPTURE :
+ V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ /*
+ * type change of the current queue is completed in
+ * smfc_v4l2_check_s_fmt()
+ */
+ othervq->type = v4l2_to_multiplane_type(othervq->type);
+ }
+
return 0;
}
if (!smfc_v4l2_init_fmt(ctx, smfc_fmt, f->type, &f->fmt.pix))
return -EINVAL;
- ctx->width = f->fmt.pix.width;
- ctx->height = f->fmt.pix.height;
+ ctx->width = SMFC_FMT_MAIN_SIZE(f->fmt.pix.width);
+ ctx->height = SMFC_FMT_MAIN_SIZE(f->fmt.pix.height);
+ /* back-to-back compression is not supported with single plane */
+ ctx->thumb_width = 0;
+ ctx->thumb_height = 0;
if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
ctx->img_fmt = smfc_fmt;
.vidioc_streamoff = smfc_v4l2_streamoff,
};
+static void smfc_configure_secondary_image(struct smfc_ctx *ctx)
+{
+ if (!(ctx->flags & SMFC_CTX_B2B_COMPRESS) ||
+ WARN_ON(!(ctx->flags & SMFC_CTX_COMPRESS)))
+ return;
+
+ smfc_hwconfigure_2nd_tables(ctx);
+ smfc_hwconfigure_2nd_image(ctx);
+}
+
static void smfc_m2m_device_run(void *priv)
{
struct smfc_ctx *ctx = priv;
smfc_hwconfigure_reset(ctx->smfc);
smfc_hwconfigure_tables(ctx);
smfc_hwconfigure_image(ctx);
+ smfc_configure_secondary_image(ctx);
smfc_hwconfigure_start(ctx);
}
};
#define SMFC_CTX_COMPRESS (1 << 0)
+#define SMFC_CTX_B2B_COMPRESS (1 << 1) /* valid if SMFC_CTX_COMPRESS is set */
struct smfc_ctx {
struct v4l2_fh v4l2_fh;
unsigned char chroma_vfactor;
unsigned char restart_interval;
unsigned char quality_factor;
+ /*
+ * thumbnail information:
+ * format of thumbnail should be the same as the main image
+ * It is not the H/W restriction. Just a choice for simpler S/W design.
+ */
+ __u32 thumb_width;
+ __u32 thumb_height;
+ unsigned char thumb_quality_factor;
};
static inline struct smfc_ctx *v4l2_fh_to_smfc_ctx(struct v4l2_fh *fh)
void smfc_hwconfigure_tables(struct smfc_ctx *ctx);
void smfc_hwconfigure_image(struct smfc_ctx *ctx);
void smfc_hwconfigure_start(struct smfc_ctx *ctx);
-bool smfc_hwstatus_okay(struct smfc_dev *smfc);
+void smfc_hwconfigure_2nd_tables(struct smfc_ctx *ctx);
+void smfc_hwconfigure_2nd_image(struct smfc_ctx *ctx);
+bool smfc_hwstatus_okay(struct smfc_dev *smfc, struct smfc_ctx *ctx);
void smfc_hwconfigure_reset(struct smfc_dev *smfc);
void smfc_dump_registers(struct smfc_dev *smfc);
static inline u32 smfc_get_streamsize(struct smfc_dev *smfc)
return __raw_readl(smfc->reg + REG_MAIN_STREAM_SIZE);
}
+static inline u32 smfc_get_2nd_streamsize(struct smfc_dev *smfc)
+{
+ return __raw_readl(smfc->reg + REG_SEC_STREAM_SIZE);
+}
+
#endif /* _MEDIA_EXYNOS_SMFC_H_ */