From 390df7ac97d29728170bc4f155a87d85f7bdd5df Mon Sep 17 00:00:00 2001 From: Cho KyongHo Date: Tue, 6 Oct 2015 01:08:22 +0900 Subject: [PATCH] [COMMON] media: smfc: add support for custom quantization tables Some users needs to configure their own quantization tables instead of the quality factors that is the factor to calculate the quantization tables based on the ones suggested by ITU-81 Appendix K.1 and K.2. Now the driver supports for the new custom control variable, V4L2_CID_JPEG_QTABLES2 that is an array of V4L2_CTRL_TYPE_U8 with 128 values (two arrays with 64 elements). One of the table is for the quantization table of the Luma and the other table is for the chroma components. The values in the quantization tables should be specified in the zig-zag scan order. Note that once the custom quantization tables are configured, it is used for the compressions until a new quality factor or a new quantization is configured. Also note that the custom quantization tables are configured to H/W even though the table stored in the v4l2_ctrl is in transient state. Therefore, configuring new custom quantization tables with s_ctrl or s_ext_ctrl during the H/W is working for the current context may cause an unpredictable result which means the quantization tables that is used by the H/W may be incorrect and it impacts the compression quality of the compressed stream. Change-Id: Ifa8e346e188b118c480e576676de8c6a46e1468d Signed-off-by: Cho KyongHo --- .../media/platform/exynos/smfc/smfc-regs.c | 41 +++++++++++--- .../platform/exynos/smfc/smfc-v4l2-ioctls.c | 55 ++++++++++++++----- drivers/media/platform/exynos/smfc/smfc.c | 3 +- drivers/media/platform/exynos/smfc/smfc.h | 4 +- 4 files changed, 79 insertions(+), 24 deletions(-) diff --git a/drivers/media/platform/exynos/smfc/smfc-regs.c b/drivers/media/platform/exynos/smfc/smfc-regs.c index d88a4d5514e8..9ed95af186a3 100644 --- a/drivers/media/platform/exynos/smfc/smfc-regs.c +++ b/drivers/media/platform/exynos/smfc/smfc-regs.c @@ -33,7 +33,7 @@ void smfc_hwconfigure_reset(struct smfc_dev *smfc) * 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, @@ -44,7 +44,7 @@ static const unsigned char default_luma_qtbl[SMFC_MCU_SIZE] __aligned(64) = { 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, @@ -124,7 +124,7 @@ static inline u32 smfc_calc_quantizers(unsigned int idx, unsigned int factor, #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; @@ -132,16 +132,39 @@ static void smfc_hwconfigure_qtable(void __iomem *reg, unsigned int factor, __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++) { diff --git a/drivers/media/platform/exynos/smfc/smfc-v4l2-ioctls.c b/drivers/media/platform/exynos/smfc/smfc-v4l2-ioctls.c index 75112e5825a2..c7faeeed2522 100644 --- a/drivers/media/platform/exynos/smfc/smfc-v4l2-ioctls.c +++ b/drivers/media/platform/exynos/smfc/smfc-v4l2-ioctls.c @@ -15,6 +15,7 @@ /* 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) @@ -312,8 +313,17 @@ static int smfc_s_ctrl(struct v4l2_ctrl *ctrl) 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; @@ -326,6 +336,8 @@ static const struct v4l2_ctrl_ops smfc_ctrl_ops = { 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; @@ -338,6 +350,21 @@ int smfc_init_controls(struct smfc_dev *smfc, 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; @@ -366,18 +393,20 @@ int smfc_init_controls(struct smfc_dev *smfc, 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; } diff --git a/drivers/media/platform/exynos/smfc/smfc.c b/drivers/media/platform/exynos/smfc/smfc.c index 5da080119b12..384d1cea22df 100644 --- a/drivers/media/platform/exynos/smfc/smfc.c +++ b/drivers/media/platform/exynos/smfc/smfc.c @@ -546,7 +546,8 @@ static void smfc_m2m_device_run(void *priv) 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); diff --git a/drivers/media/platform/exynos/smfc/smfc.h b/drivers/media/platform/exynos/smfc/smfc.h index 222f53ff3ab3..a0caee204ff0 100644 --- a/drivers/media/platform/exynos/smfc/smfc.h +++ b/drivers/media/platform/exynos/smfc/smfc.h @@ -167,6 +167,7 @@ struct smfc_ctx { 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 @@ -213,7 +214,8 @@ int smfc_init_controls(struct smfc_dev *smfc, struct v4l2_ctrl_handler *hdlr); 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); -- 2.20.1