* Quantization tables in ZIG-ZAG order provided by IOC/IEC 10918-1 K.1 and K.2
* for YUV420 and YUV422
*/
-static const unsigned char default_luma_qtbl[SMFC_MCU_SIZE] __aligned(64) = {
+static const u8 default_luma_qtbl[SMFC_MCU_SIZE] __aligned(64) = {
16, 11, 12, 14, 12, 10, 16, 14,
13, 14, 18, 17, 16, 19, 24, 40,
26, 24, 22, 22, 24, 49, 35, 37,
121, 112, 100, 120, 92, 101, 103, 99,
};
-static const unsigned char default_chroma_qtbl[SMFC_MCU_SIZE] __aligned(64) = {
+static const u8 default_chroma_qtbl[SMFC_MCU_SIZE] __aligned(64) = {
17, 18, 18, 24, 21, 24, 47, 26,
26, 47, 99, 66, 56, 66, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
#pragma GCC diagnostic pop
static void smfc_hwconfigure_qtable(void __iomem *reg, unsigned int factor,
- const unsigned char table[])
+ const u8 table[])
{
size_t i;
__raw_writel(smfc_calc_quantizers(i, factor, table), reg + i);
}
-void smfc_hwconfigure_tables(struct smfc_ctx *ctx, unsigned int qfactor)
+static void smfc_hwconfigure_custom_qtable(void __iomem *reg, const u8 table[])
+{
+ size_t i;
+
+ for (i = 0; i < SMFC_MCU_SIZE; i += 4) {
+ u32 val;
+
+ val = table[i];
+ val |= table[i + 1] << 8;
+ val |= table[i + 2] << 16;
+ val |= table[i + 3] << 24;
+ __raw_writel(val, reg + i);
+ }
+}
+
+void smfc_hwconfigure_tables(struct smfc_ctx *ctx,
+ unsigned int qfactor, const u8 qtbl[])
{
size_t i;
void __iomem *base = ctx->smfc->reg;
- qfactor = (qfactor < 50) ? 5000 / qfactor : 200 - qfactor * 2;
- smfc_hwconfigure_qtable(base + REG_QTBL_BASE,
- qfactor, default_luma_qtbl);
- smfc_hwconfigure_qtable(base + REG_QTBL_BASE + SMFC_MCU_SIZE,
- qfactor, default_chroma_qtbl);
+ if (qfactor > 0) {
+ qfactor = (qfactor < 50) ? 5000 / qfactor : 200 - qfactor * 2;
+ smfc_hwconfigure_qtable(base + REG_QTBL_BASE,
+ qfactor, default_luma_qtbl);
+ smfc_hwconfigure_qtable(base + REG_QTBL_BASE + SMFC_MCU_SIZE,
+ qfactor, default_chroma_qtbl);
+ } else {
+ smfc_hwconfigure_custom_qtable(base + REG_QTBL_BASE, qtbl);
+ smfc_hwconfigure_custom_qtable(
+ base + REG_QTBL_BASE + SMFC_MCU_SIZE,
+ qtbl + SMFC_MCU_SIZE);
+ }
/* Huffman tables */
for (i = 0; i < 4; i++) {
/* SMFC SPECIFIC CONTROLS */
#define V4L2_CID_JPEG_SEC_COMP_QUALITY (V4L2_CID_JPEG_CLASS_BASE + 20)
+#define V4L2_CID_JPEG_QTABLES2 (V4L2_CID_JPEG_CLASS_BASE + 22)
#define V4L2_CID_JPEG_HWFC_ENABLE (V4L2_CID_JPEG_CLASS_BASE + 25)
#define SMFC_FMT_MAIN_SIZE(val) ((val) & 0xFFFF)
break;
}
break;
- default:
+ case V4L2_CID_JPEG_QTABLES2:
+ /*
+ * reset the quality factor to indicate that the custom q-table
+ * is configured. It is sustained until the new quality factor
+ * is configured.
+ */
+ ctx->quality_factor = 0;
break;
+ default:
+ dev_err(ctx->smfc->dev, "Unsupported CID %#x\n", ctrl->id);
+ return -EINVAL;
}
return 0;
int smfc_init_controls(struct smfc_dev *smfc,
struct v4l2_ctrl_handler *hdlr)
{
+ struct smfc_ctx *ctx =
+ container_of(hdlr, struct smfc_ctx, v4l2_ctrlhdlr);
const char *msg;
struct v4l2_ctrl_config ctrlcfg;
goto err;
}
+ if (!v4l2_ctrl_new_std(hdlr, &smfc_ctrl_ops,
+ V4L2_CID_JPEG_RESTART_INTERVAL,
+ 0, 64, 1, 0)) {
+ msg = "restart interval";
+ goto err;
+ }
+
+ if (!v4l2_ctrl_new_std_menu(hdlr, &smfc_ctrl_ops,
+ V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
+ V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, 0,
+ V4L2_JPEG_CHROMA_SUBSAMPLING_422)) {
+ msg = "chroma subsampling";
+ goto err;
+ }
+
memset(&ctrlcfg, 0, sizeof(ctrlcfg));
ctrlcfg.ops = &smfc_ctrl_ops;
ctrlcfg.id = V4L2_CID_JPEG_SEC_COMP_QUALITY;
goto err;
}
- if (!v4l2_ctrl_new_std(hdlr, &smfc_ctrl_ops,
- V4L2_CID_JPEG_RESTART_INTERVAL,
- 0, 64, 1, 0)) {
- msg = "restart interval";
- goto err;
- }
-
- if (!v4l2_ctrl_new_std_menu(hdlr, &smfc_ctrl_ops,
- V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
- V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, 0,
- V4L2_JPEG_CHROMA_SUBSAMPLING_422)) {
- msg = "chroma subsampling";
+ memset(&ctrlcfg, 0, sizeof(ctrlcfg));
+ ctrlcfg.ops = &smfc_ctrl_ops;
+ ctrlcfg.id = V4L2_CID_JPEG_QTABLES2;
+ ctrlcfg.name = "Quantization table configration";
+ ctrlcfg.type = V4L2_CTRL_TYPE_U8;
+ ctrlcfg.min = 1;
+ ctrlcfg.max = 255;
+ ctrlcfg.step = 1;
+ ctrlcfg.def = 1;
+ ctrlcfg.dims[0] = SMFC_MCU_SIZE; /* A qtable has 64 values */
+ ctrlcfg.dims[1] = 2; /* 2 qtables are required for 0:luma, 1:chroma */
+ ctx->ctrl_qtbl2 = v4l2_ctrl_new_custom(hdlr, &ctrlcfg, NULL);
+ if (!ctx->ctrl_qtbl2) {
+ msg = "Q-Table";
goto err;
}
smfc_hwconfigure_reset(ctx->smfc);
if (!!(ctx->flags & SMFC_CTX_COMPRESS)) {
- smfc_hwconfigure_tables(ctx, quality_factor);
+ smfc_hwconfigure_tables(ctx, quality_factor,
+ ctx->ctrl_qtbl2->p_cur.p_u8);
smfc_hwconfigure_image(ctx, chroma_hfactor, chroma_vfactor);
if (!!(ctx->flags & SMFC_CTX_B2B_COMPRESS)) {
smfc_hwconfigure_2nd_tables(ctx, thumb_quality_factor);
unsigned char chroma_vfactor; /* vertical chroma subsampling factor */
unsigned char restart_interval;
unsigned char quality_factor;
+ struct v4l2_ctrl *ctrl_qtbl2;
/*
* thumbnail information:
* format of thumbnail should be the same as the main image
int smfc_parse_jpeg_header(struct smfc_ctx *ctx, struct vb2_buffer *vb);
/* H/W Configuration */
-void smfc_hwconfigure_tables(struct smfc_ctx *ctx, unsigned int qfactor);
+void smfc_hwconfigure_tables(struct smfc_ctx *ctx,
+ unsigned int qfactor, const u8 qtbl[]);
void smfc_hwconfigure_tables_for_decompression(struct smfc_ctx *ctx);
void smfc_hwconfigure_image(struct smfc_ctx *ctx,
unsigned int hfactor, unsigned int vfactor);