This patch add a driver for a version 2.x of jpeg H/W in ths Samsung Exynos5 Soc. A jpeg H/W version of Exynos4 SoC is 3.0 1. Encoding - input format : V4L2_PIX_FMT_RGB565X and V4L2_PIX_FMT_YUYV 2. Decoding - output format : V4L2_PIX_FMT_YUYV and V4L2_PIX_FMT_YUV420 Signed-off-by: youngmok song <ym.song@xxxxxxxxxxx> --- drivers/media/video/Kconfig | 17 + drivers/media/video/s5p-jpeg/Makefile | 5 +- drivers/media/video/s5p-jpeg/jpeg-core.c | 303 +------------------- drivers/media/video/s5p-jpeg/jpeg-hw-common.h | 34 +++ drivers/media/video/s5p-jpeg/jpeg-hw-v2x.h | 387 +++++++++++++++++++++++++ drivers/media/video/s5p-jpeg/jpeg-regs-v2x.h | 150 ++++++++++ drivers/media/video/s5p-jpeg/jpeg-v2x.c | 129 ++++++++ drivers/media/video/s5p-jpeg/jpeg-v3.c | 340 ++++++++++++++++++++++ 8 files changed, 1066 insertions(+), 299 deletions(-) create mode 100644 drivers/media/video/s5p-jpeg/jpeg-hw-common.h create mode 100644 drivers/media/video/s5p-jpeg/jpeg-hw-v2x.h create mode 100644 drivers/media/video/s5p-jpeg/jpeg-regs-v2x.h create mode 100644 drivers/media/video/s5p-jpeg/jpeg-v2x.c create mode 100644 drivers/media/video/s5p-jpeg/jpeg-v3.c diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 9adada0..551f925 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -1167,6 +1167,23 @@ config VIDEO_SAMSUNG_S5P_JPEG select V4L2_MEM2MEM_DEV ---help--- This is a v4l2 driver for Samsung S5P and EXYNOS4 JPEG codec +choice + prompt "JPEG V4L2 Driver" + default S5P_JPEG_V3 + depends on VIDEO_SAMSUNG_S5P_JPEG + ---help--- + Select version of MFC driver + +config S5P_JPEG_V3 + bool "JPEG 3.x" + ---help--- + Use JPEG 3.x V4L2 Driver + +config S5P_JPEG_V2 + bool "JPEG 2.x" + ---help--- + Use JPEG 2.x V4L2 Driver +endchoice config VIDEO_SAMSUNG_S5P_MFC tristate "Samsung S5P MFC 5.1 Video Codec" diff --git a/drivers/media/video/s5p-jpeg/Makefile b/drivers/media/video/s5p-jpeg/Makefile index ddc2900..446d07f 100644 --- a/drivers/media/video/s5p-jpeg/Makefile +++ b/drivers/media/video/s5p-jpeg/Makefile @@ -1,2 +1,5 @@ -s5p-jpeg-objs := jpeg-core.o obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) := s5p-jpeg.o + +s5p-jpeg-objs := jpeg-core.o +obj-$(CONFIG_S5P_JPEG_V3) += jpeg-v3.o +obj-$(CONFIG_S5P_JPEG_V2) += jpeg-v2x.o diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.c b/drivers/media/video/s5p-jpeg/jpeg-core.c index 1105a87..cf917cd 100644 --- a/drivers/media/video/s5p-jpeg/jpeg-core.c +++ b/drivers/media/video/s5p-jpeg/jpeg-core.c @@ -28,7 +28,7 @@ #include <media/videobuf2-dma-contig.h> #include "jpeg-core.h" -#include "jpeg-hw.h" +#include "jpeg-hw-common.h" static struct s5p_jpeg_fmt formats_enc[] = { { @@ -83,182 +83,6 @@ static struct s5p_jpeg_fmt formats_dec[] = { }; #define NUM_FORMATS_DEC ARRAY_SIZE(formats_dec) -static const unsigned char qtbl_luminance[4][64] = { - {/* level 1 - high quality */ - 8, 6, 6, 8, 12, 14, 16, 17, - 6, 6, 6, 8, 10, 13, 12, 15, - 6, 6, 7, 8, 13, 14, 18, 24, - 8, 8, 8, 14, 13, 19, 24, 35, - 12, 10, 13, 13, 20, 26, 34, 39, - 14, 13, 14, 19, 26, 34, 39, 39, - 16, 12, 18, 24, 34, 39, 39, 39, - 17, 15, 24, 35, 39, 39, 39, 39 - }, - {/* level 2 */ - 12, 8, 8, 12, 17, 21, 24, 23, - 8, 9, 9, 11, 15, 19, 18, 23, - 8, 9, 10, 12, 19, 20, 27, 36, - 12, 11, 12, 21, 20, 28, 36, 53, - 17, 15, 19, 20, 30, 39, 51, 59, - 21, 19, 20, 28, 39, 51, 59, 59, - 24, 18, 27, 36, 51, 59, 59, 59, - 23, 23, 36, 53, 59, 59, 59, 59 - }, - {/* level 3 */ - 16, 11, 11, 16, 23, 27, 31, 30, - 11, 12, 12, 15, 20, 23, 23, 30, - 11, 12, 13, 16, 23, 26, 35, 47, - 16, 15, 16, 23, 26, 37, 47, 64, - 23, 20, 23, 26, 39, 51, 64, 64, - 27, 23, 26, 37, 51, 64, 64, 64, - 31, 23, 35, 47, 64, 64, 64, 64, - 30, 30, 47, 64, 64, 64, 64, 64 - }, - {/*level 4 - low quality */ - 20, 16, 25, 39, 50, 46, 62, 68, - 16, 18, 23, 38, 38, 53, 65, 68, - 25, 23, 31, 38, 53, 65, 68, 68, - 39, 38, 38, 53, 65, 68, 68, 68, - 50, 38, 53, 65, 68, 68, 68, 68, - 46, 53, 65, 68, 68, 68, 68, 68, - 62, 65, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68 - } -}; - -static const unsigned char qtbl_chrominance[4][64] = { - {/* level 1 - high quality */ - 9, 8, 9, 11, 14, 17, 19, 24, - 8, 10, 9, 11, 14, 13, 17, 22, - 9, 9, 13, 14, 13, 15, 23, 26, - 11, 11, 14, 14, 15, 20, 26, 33, - 14, 14, 13, 15, 20, 24, 33, 39, - 17, 13, 15, 20, 24, 32, 39, 39, - 19, 17, 23, 26, 33, 39, 39, 39, - 24, 22, 26, 33, 39, 39, 39, 39 - }, - {/* level 2 */ - 13, 11, 13, 16, 20, 20, 29, 37, - 11, 14, 14, 14, 16, 20, 26, 32, - 13, 14, 15, 17, 20, 23, 35, 40, - 16, 14, 17, 21, 23, 30, 40, 50, - 20, 16, 20, 23, 30, 37, 50, 59, - 20, 20, 23, 30, 37, 48, 59, 59, - 29, 26, 35, 40, 50, 59, 59, 59, - 37, 32, 40, 50, 59, 59, 59, 59 - }, - {/* level 3 */ - 17, 15, 17, 21, 20, 26, 38, 48, - 15, 19, 18, 17, 20, 26, 35, 43, - 17, 18, 20, 22, 26, 30, 46, 53, - 21, 17, 22, 28, 30, 39, 53, 64, - 20, 20, 26, 30, 39, 48, 64, 64, - 26, 26, 30, 39, 48, 63, 64, 64, - 38, 35, 46, 53, 64, 64, 64, 64, - 48, 43, 53, 64, 64, 64, 64, 64 - }, - {/*level 4 - low quality */ - 21, 25, 32, 38, 54, 68, 68, 68, - 25, 28, 24, 38, 54, 68, 68, 68, - 32, 24, 32, 43, 66, 68, 68, 68, - 38, 38, 43, 53, 68, 68, 68, 68, - 54, 54, 66, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68 - } -}; - -static const unsigned char hdctbl0[16] = { - 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 -}; - -static const unsigned char hdctblg0[12] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb -}; -static const unsigned char hactbl0[16] = { - 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d -}; -static const unsigned char hactblg0[162] = { - 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, - 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, - 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, - 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, - 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, - 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, - 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, - 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, - 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, - 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, - 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, - 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, - 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, - 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, - 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, - 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, - 0xf9, 0xfa -}; - -static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl, - unsigned long tab, int len) -{ - int i; - - for (i = 0; i < len; i++) - writel((unsigned int)qtbl[i], regs + tab + (i * 0x04)); -} - -static inline void jpeg_set_qtbl_lum(void __iomem *regs, int quality) -{ - /* this driver fills quantisation table 0 with data for luma */ - jpeg_set_qtbl(regs, qtbl_luminance[quality], S5P_JPG_QTBL_CONTENT(0), - ARRAY_SIZE(qtbl_luminance[quality])); -} - -static inline void jpeg_set_qtbl_chr(void __iomem *regs, int quality) -{ - /* this driver fills quantisation table 1 with data for chroma */ - jpeg_set_qtbl(regs, qtbl_chrominance[quality], S5P_JPG_QTBL_CONTENT(1), - ARRAY_SIZE(qtbl_chrominance[quality])); -} - -static inline void jpeg_set_htbl(void __iomem *regs, const unsigned char *htbl, - unsigned long tab, int len) -{ - int i; - - for (i = 0; i < len; i++) - writel((unsigned int)htbl[i], regs + tab + (i * 0x04)); -} - -static inline void jpeg_set_hdctbl(void __iomem *regs) -{ - /* this driver fills table 0 for this component */ - jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0), ARRAY_SIZE(hdctbl0)); -} - -static inline void jpeg_set_hdctblg(void __iomem *regs) -{ - /* this driver fills table 0 for this component */ - jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0), ARRAY_SIZE(hdctblg0)); -} - -static inline void jpeg_set_hactbl(void __iomem *regs) -{ - /* this driver fills table 0 for this component */ - jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0), ARRAY_SIZE(hactbl0)); -} - -static inline void jpeg_set_hactblg(void __iomem *regs) -{ - /* this driver fills table 0 for this component */ - jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0), ARRAY_SIZE(hactblg0)); -} - /* * ============================================================================ * Device file operations @@ -890,78 +714,7 @@ static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = { static void s5p_jpeg_device_run(void *priv) { - struct s5p_jpeg_ctx *ctx = priv; - struct s5p_jpeg *jpeg = ctx->jpeg; - struct vb2_buffer *src_buf, *dst_buf; - unsigned long src_addr, dst_addr; - - src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); - src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); - dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); - - jpeg_reset(jpeg->regs); - jpeg_poweron(jpeg->regs); - jpeg_proc_mode(jpeg->regs, ctx->mode); - if (ctx->mode == S5P_JPEG_ENCODE) { - if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565) - jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_565); - else - jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_422); - if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV) - jpeg_subsampling_mode(jpeg->regs, - S5P_JPEG_SUBSAMPLING_422); - else - jpeg_subsampling_mode(jpeg->regs, - S5P_JPEG_SUBSAMPLING_420); - jpeg_dri(jpeg->regs, 0); - jpeg_x(jpeg->regs, ctx->out_q.w); - jpeg_y(jpeg->regs, ctx->out_q.h); - jpeg_imgadr(jpeg->regs, src_addr); - jpeg_jpgadr(jpeg->regs, dst_addr); - - /* ultimately comes from sizeimage from userspace */ - jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size); - - /* JPEG RGB to YCbCr conversion matrix */ - jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11); - jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12); - jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13); - jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21); - jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22); - jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23); - jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31); - jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32); - jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33); - - /* - * JPEG IP allows storing 4 quantization tables - * We fill table 0 for luma and table 1 for chroma - */ - jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality); - jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality); - /* use table 0 for Y */ - jpeg_qtbl(jpeg->regs, 1, 0); - /* use table 1 for Cb and Cr*/ - jpeg_qtbl(jpeg->regs, 2, 1); - jpeg_qtbl(jpeg->regs, 3, 1); - - /* Y, Cb, Cr use Huffman table 0 */ - jpeg_htbl_ac(jpeg->regs, 1); - jpeg_htbl_dc(jpeg->regs, 1); - jpeg_htbl_ac(jpeg->regs, 2); - jpeg_htbl_dc(jpeg->regs, 2); - jpeg_htbl_ac(jpeg->regs, 3); - jpeg_htbl_dc(jpeg->regs, 3); - } else { - jpeg_rst_int_enable(jpeg->regs, true); - jpeg_data_num_int_enable(jpeg->regs, true); - jpeg_final_mcu_num_int_enable(jpeg->regs, true); - jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422); - jpeg_jpgadr(jpeg->regs, src_addr); - jpeg_imgadr(jpeg->regs, dst_addr); - } - jpeg_start(jpeg->regs); + s5p_jpeg_execute(priv); } static int s5p_jpeg_job_ready(void *priv) @@ -1153,46 +906,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id) { - struct s5p_jpeg *jpeg = dev_id; - struct s5p_jpeg_ctx *curr_ctx; - struct vb2_buffer *src_buf, *dst_buf; - unsigned long payload_size = 0; - enum vb2_buffer_state state = VB2_BUF_STATE_DONE; - bool enc_jpeg_too_large = false; - bool timer_elapsed = false; - bool op_completed = false; - - curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); - - src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); - dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); - - if (curr_ctx->mode == S5P_JPEG_ENCODE) - enc_jpeg_too_large = jpeg_enc_stream_stat(jpeg->regs); - timer_elapsed = jpeg_timer_stat(jpeg->regs); - op_completed = jpeg_result_stat_ok(jpeg->regs); - if (curr_ctx->mode == S5P_JPEG_DECODE) - op_completed = op_completed && jpeg_stream_stat_ok(jpeg->regs); - - if (enc_jpeg_too_large) { - state = VB2_BUF_STATE_ERROR; - jpeg_clear_enc_stream_stat(jpeg->regs); - } else if (timer_elapsed) { - state = VB2_BUF_STATE_ERROR; - jpeg_clear_timer_stat(jpeg->regs); - } else if (!op_completed) { - state = VB2_BUF_STATE_ERROR; - } else { - payload_size = jpeg_compressed_size(jpeg->regs); - } - - v4l2_m2m_buf_done(src_buf, state); - if (curr_ctx->mode == S5P_JPEG_ENCODE) - vb2_set_plane_payload(dst_buf, 0, payload_size); - v4l2_m2m_buf_done(dst_buf, state); - v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->m2m_ctx); - - jpeg_clear_int(jpeg->regs); + s5p_jpeg_irq_execute(dev_id); return IRQ_HANDLED; } @@ -1425,15 +1139,8 @@ static int s5p_jpeg_runtime_suspend(struct device *dev) static int s5p_jpeg_runtime_resume(struct device *dev) { - struct s5p_jpeg *jpeg = dev_get_drvdata(dev); - /* - * JPEG IP allows storing two Huffman tables for each component - * We fill table 0 for each component - */ - jpeg_set_hdctbl(jpeg->regs); - jpeg_set_hdctblg(jpeg->regs); - jpeg_set_hactbl(jpeg->regs); - jpeg_set_hactblg(jpeg->regs); + s5p_jpeg_runtime_resume_execute(dev); + return 0; } diff --git a/drivers/media/video/s5p-jpeg/jpeg-hw-common.h b/drivers/media/video/s5p-jpeg/jpeg-hw-common.h new file mode 100644 index 0000000..c649598 --- /dev/null +++ b/drivers/media/video/s5p-jpeg/jpeg-hw-common.h @@ -0,0 +1,34 @@ +/* linux/drivers/media/video/s5p-jpeg/jpeg-hw.h + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz <andrzej.p@xxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef JPEG_HW_COMMON_H_ +#define JPEG_HW_COMMON_H_ + +#include <linux/io.h> +#include <linux/delay.h> + +void s5p_jpeg_execute(void *priv); +void s5p_jpeg_irq_execute(void *dev_id); +void s5p_jpeg_runtime_resume_execute(struct device *dev); + +#define S5P_JPEG_MIN_WIDTH 32 +#define S5P_JPEG_MIN_HEIGHT 32 +#define S5P_JPEG_MAX_WIDTH 8192 +#define S5P_JPEG_MAX_HEIGHT 8192 +#define S5P_JPEG_ENCODE 0 +#define S5P_JPEG_DECODE 1 +#define S5P_JPEG_RAW_IN_565 0 +#define S5P_JPEG_RAW_IN_422 1 +#define S5P_JPEG_SUBSAMPLING_422 0 +#define S5P_JPEG_SUBSAMPLING_420 1 +#define S5P_JPEG_RAW_OUT_422 0 +#define S5P_JPEG_RAW_OUT_420 1 +#endif /* JPEG_HW_COMMON_H_ */ diff --git a/drivers/media/video/s5p-jpeg/jpeg-hw-v2x.h b/drivers/media/video/s5p-jpeg/jpeg-hw-v2x.h new file mode 100644 index 0000000..90bd60b --- /dev/null +++ b/drivers/media/video/s5p-jpeg/jpeg-hw-v2x.h @@ -0,0 +1,387 @@ +/* linux/drivers/media/video/s5p-jpeg/jpeg-hw-v2x.h + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef JPEG_HW_V2X_H_ +#define JPEG_HW_V2X_H_ + +#include <linux/io.h> +#include <linux/delay.h> + +#include "jpeg-regs-v2x.h" + +#define S5P_JPEG_MIN_WIDTH 32 +#define S5P_JPEG_MIN_HEIGHT 32 +#define S5P_JPEG_MAX_WIDTH 8192 +#define S5P_JPEG_MAX_HEIGHT 8192 +#define S5P_JPEG_ENCODE 0 +#define S5P_JPEG_DECODE 1 +#define S5P_JPEG_RAW_IN_565 0 +#define S5P_JPEG_RAW_IN_422 1 +#define S5P_JPEG_SUBSAMPLING_422 0 +#define S5P_JPEG_SUBSAMPLING_420 1 +#define S5P_JPEG_RAW_OUT_422 0 +#define S5P_JPEG_RAW_OUT_420 1 + +/* Q-table for JPEG */ +/* ITU standard Q-table */ +static unsigned int ITU_Q_tbl[4][16] = { + { + 0x01010101, 0x01020303, 0x01010101, 0x01030303, /* Y */ + 0x01010101, 0x02030303, 0x01010101, 0x03040403, + 0x01010203, 0x03050504, 0x01020303, 0x04050605, + 0x02030404, 0x05060605, 0x04050505, 0x06050505 + } , { + 0x01010102, 0x05050505, 0x01010103, 0x05050505, /* CbCr */ + 0x01010503, 0x05050505, 0x02030505, 0x05050505, + 0x05050505, 0x05050505, 0x05050505, 0x05050505, + 0x05050505, 0x05050505, 0x05050505, 0x05050505 + } , { + 0x05020205, 0x0a161e25, 0x02020307, 0x0c232521, /* Y */ + 0x0302050a, 0x16222b22, 0x0305090e, 0x1e393326, + 0x06091422, 0x2a384431, 0x0a122118, 0x34454b3c, + 0x1d283238, 0x44525142, 0x2d3c3e40, 0x4a424441 + } , { + 0x05020205, 0x251e160a, 0x07030202, 0x2125230c, /* CbCr */ + 0x0a050203, 0x222b2216, 0x0e090503, 0x2633391e, + 0x22140906, 0x3144382a, 0x1821120a, 0x3c4b4534, + 0x3832281d, 0x42515244, 0x403e3c2d, 0x4144424a + } +}; + +/* ITU Luminace Huffman Table */ +static unsigned int ITU_H_tbl_len_DC_luminance[4] = { + 0x01050100, 0x01010101, 0x00000001, 0x00000000 +}; +static unsigned int ITU_H_tbl_val_DC_luminance[3] = { + 0x03020100, 0x07060504, 0x0b0a0908 +}; + +/* ITU Chrominace Huffman Table */ +static unsigned int ITU_H_tbl_len_DC_chrominance[4] = { + 0x01010300, 0x01010101, 0x00010101, 0x00000000 +}; +static unsigned int ITU_H_tbl_val_DC_chrominance[3] = { + 0x03020100, 0x07060504, 0x0b0a0908 +}; + +static unsigned int ITU_H_tbl_len_AC_luminance[4] = { + 0x03010200, 0x03040203, 0x04040505, 0x7d010000 +}; + +static unsigned int ITU_H_tbl_val_AC_luminance[41] = { + 0x00030201, 0x12051104, 0x06413121, 0x07615113, + 0x32147122, 0x08a19181, 0xc1b14223, 0xf0d15215, + 0x72623324, 0x160a0982, 0x1a191817, 0x28272625, + 0x35342a29, 0x39383736, 0x4544433a, 0x49484746, + 0x5554534a, 0x59585756, 0x6564635a, 0x69686766, + 0x7574736a, 0x79787776, 0x8584837a, 0x89888786, + 0x9493928a, 0x98979695, 0xa3a29a99, 0xa7a6a5a4, + 0xb2aaa9a8, 0xb6b5b4b3, 0xbab9b8b7, 0xc5c4c3c2, + 0xc9c8c7c6, 0xd4d3d2ca, 0xd8d7d6d5, 0xe2e1dad9, + 0xe6e5e4e3, 0xeae9e8e7, 0xf4f3f2f1, 0xf8f7f6f5, + 0x0000faf9 +}; + +static u32 ITU_H_tbl_len_AC_chrominance[4] = { + 0x02010200, 0x04030404, 0x04040507, 0x77020100 +}; +static u32 ITU_H_tbl_val_AC_chrominance[41] = { + 0x03020100, 0x21050411, 0x41120631, 0x71610751, + 0x81322213, 0x91421408, 0x09c1b1a1, 0xf0523323, + 0xd1726215, 0x3424160a, 0x17f125e1, 0x261a1918, + 0x2a292827, 0x38373635, 0x44433a39, 0x48474645, + 0x54534a49, 0x58575655, 0x64635a59, 0x68676665, + 0x74736a69, 0x78777675, 0x83827a79, 0x87868584, + 0x928a8988, 0x96959493, 0x9a999897, 0xa5a4a3a2, + 0xa9a8a7a6, 0xb4b3b2aa, 0xb8b7b6b5, 0xc3c2bab9, + 0xc7c6c5c4, 0xd2cac9c8, 0xd6d5d4d3, 0xdad9d8d7, + 0xe5e4e3e2, 0xe9e8e7e6, 0xf4f3f2ea, 0xf8f7f6f5, + 0x0000faf9 +}; + +static inline void jpeg_reset(void __iomem *regs) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPEG_CNTL_REG); + writel(reg & ~S5P_JPEG_SOFT_RESET_HI, + regs + S5P_JPEG_CNTL_REG); + + ndelay(100000); + + writel(reg | S5P_JPEG_SOFT_RESET_HI, + regs + S5P_JPEG_CNTL_REG); + +} + +static inline void jpeg_input_raw_mode(void __iomem *regs, unsigned long mode) +{ + unsigned long reg, m; + + if (mode == S5P_JPEG_RAW_IN_565) + m = S5P_JPEG_ENC_RGB_IMG | + S5P_JPEG_RGB_IP_RGB_16BIT_IMG; + else if (mode == S5P_JPEG_RAW_IN_422) + m = S5P_JPEG_ENC_YUV_422_IMG | + S5P_JPEG_YUV_422_IP_YUV_422_1P_IMG; + + reg = readl(regs + S5P_JPEG_IMG_FMT_REG) & + S5P_JPEG_ENC_IN_FMT_MASK; /* clear except enc format */ + reg |= m; + + writel(reg, regs + S5P_JPEG_IMG_FMT_REG); +} + +static inline void jpeg_proc_mode(void __iomem *regs, unsigned long mode) +{ + unsigned int reg, m; + + m = S5P_JPEG_DEC_MODE; + if (mode == S5P_JPEG_ENCODE) + m = S5P_JPEG_ENC_MODE; + else + m = S5P_JPEG_DEC_MODE; + + reg = readl(regs + S5P_JPEG_CNTL_REG); + reg &= S5P_JPEG_ENC_DEC_MODE_MASK; + reg |= m; + + writel(reg, regs + S5P_JPEG_CNTL_REG); +} + +static inline void jpeg_set_dec_bitstream_size(void __iomem *regs, u32 size) +{ + writel(size, regs + S5P_JPEG_BITSTREAM_SIZE_REG); +} + +static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned long mode) +{ + unsigned long reg, m; + + m = S5P_JPEG_ENC_FMT_YUV_422; + if (mode == S5P_JPEG_SUBSAMPLING_422) + m = S5P_JPEG_ENC_FMT_YUV_422; + else if (mode == S5P_JPEG_SUBSAMPLING_420) + m = S5P_JPEG_ENC_FMT_YUV_420; + + reg = readl(regs + S5P_JPEG_IMG_FMT_REG); + reg &= ~S5P_JPEG_ENC_FMT_MASK; + reg |= m; + + writel(reg, regs + S5P_JPEG_IMG_FMT_REG); +} + +static void jpeg_set_encode_tbl_select(void __iomem *regs, + int quality) +{ + unsigned int reg; + + switch (quality) { + case 0: + reg = S5P_JPEG_Q_TBL_COMP1_0 | S5P_JPEG_Q_TBL_COMP2_1 | + S5P_JPEG_Q_TBL_COMP3_1 | + S5P_JPEG_HUFF_TBL_COMP1_AC_0_DC_0 | + S5P_JPEG_HUFF_TBL_COMP2_AC_0_DC_0 | + S5P_JPEG_HUFF_TBL_COMP3_AC_1_DC_1; + break; + case 1: + reg = S5P_JPEG_Q_TBL_COMP1_0 | S5P_JPEG_Q_TBL_COMP2_3 | + S5P_JPEG_Q_TBL_COMP3_3 | + S5P_JPEG_HUFF_TBL_COMP1_AC_0_DC_0 | + S5P_JPEG_HUFF_TBL_COMP2_AC_0_DC_0 | + S5P_JPEG_HUFF_TBL_COMP3_AC_1_DC_1; + break; + case 2: + reg = S5P_JPEG_Q_TBL_COMP1_2 | S5P_JPEG_Q_TBL_COMP2_1 | + S5P_JPEG_Q_TBL_COMP3_1 | + S5P_JPEG_HUFF_TBL_COMP1_AC_0_DC_0 | + S5P_JPEG_HUFF_TBL_COMP2_AC_0_DC_0 | + S5P_JPEG_HUFF_TBL_COMP3_AC_1_DC_1; + break; + case 3: + reg = S5P_JPEG_Q_TBL_COMP1_2 | S5P_JPEG_Q_TBL_COMP2_3 | + S5P_JPEG_Q_TBL_COMP3_3 | + S5P_JPEG_HUFF_TBL_COMP1_AC_0_DC_0 | + S5P_JPEG_HUFF_TBL_COMP2_AC_0_DC_0 | + S5P_JPEG_HUFF_TBL_COMP3_AC_1_DC_1; + break; + default: + reg = S5P_JPEG_Q_TBL_COMP1_0 | S5P_JPEG_Q_TBL_COMP2_1 | + S5P_JPEG_Q_TBL_COMP3_1 | + S5P_JPEG_HUFF_TBL_COMP1_AC_0_DC_0 | + S5P_JPEG_HUFF_TBL_COMP2_AC_0_DC_0 | + S5P_JPEG_HUFF_TBL_COMP3_AC_1_DC_1; + break; + } + writel(reg, regs + S5P_JPEG_TBL_SEL_REG); +} + +static inline void jpeg_x_y(void __iomem *regs, unsigned int x, unsigned int y) +{ + writel(0x0, regs + S5P_JPEG_IMG_SIZE_REG); /* clear */ + writel(S5P_JPEG_X_SIZE(x) | S5P_JPEG_Y_SIZE(y), + regs + S5P_JPEG_IMG_SIZE_REG); +} + +static inline void jpeg_set_dec_scaling(void __iomem *regs, + int x_value, int y_value) +{ + unsigned int reg; + + reg = readl(regs + S5P_JPEG_CNTL_REG) & + ~(S5P_JPEG_HOR_SCALING_MASK | + S5P_JPEG_VER_SCALING_MASK); + + writel(reg | S5P_JPEG_HOR_SCALING(x_value) | + S5P_JPEG_VER_SCALING(y_value), + regs + S5P_JPEG_CNTL_REG); +} + +static inline void jpeg_outform_raw(void __iomem *regs, unsigned long format) +{ + unsigned long reg; + + writel(0, regs + S5P_JPEG_IMG_FMT_REG); /* clear */ + + if (format == S5P_JPEG_RAW_OUT_422) + reg = S5P_JPEG_DEC_YUV_422_IMG | + S5P_JPEG_YUV_422_IP_YUV_422_1P_IMG; + else if (format == S5P_JPEG_RAW_OUT_420) + reg = S5P_JPEG_DEC_YUV_420_IMG | + S5P_JPEG_YUV_420_IP_YUV_420_3P_IMG; + + writel(reg, regs + S5P_JPEG_IMG_FMT_REG); +} + +static inline void jpeg_jpgadr(void __iomem *regs, unsigned long addr) +{ + writel(addr, regs + S5P_JPEG_OUT_MEM_BASE_REG); +} + +static inline void jpeg_dec_imgadr(void __iomem *regs, unsigned long addr, + unsigned long format, u32 width, u32 height) +{ + if (format == S5P_JPEG_RAW_OUT_422) { + writel(addr, regs + S5P_JPEG_IMG_BA_PLANE_1_REG); + writel(0, regs + S5P_JPEG_IMG_BA_PLANE_2_REG); + writel(0, regs + S5P_JPEG_IMG_BA_PLANE_3_REG); + } else if (format == S5P_JPEG_RAW_OUT_420) { + writel(addr, regs + S5P_JPEG_IMG_BA_PLANE_1_REG); + writel(addr + width * height, + regs + S5P_JPEG_IMG_BA_PLANE_2_REG); + writel(addr + width * height + (width * height / 4), + regs + S5P_JPEG_IMG_BA_PLANE_3_REG); + } +} + +static inline void jpeg_enc_imgadr(void __iomem *regs, unsigned long addr) +{ + writel(addr, regs + S5P_JPEG_IMG_BA_PLANE_1_REG); +} + +static unsigned int jpeg_get_int_status(void __iomem *regs) +{ + return readl(regs + S5P_JPEG_INT_STATUS_REG); +} + +static void jpeg_set_interrupt(void __iomem *regs) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPEG_INT_EN_REG) & ~S5P_JPEG_INT_EN_MASK; + writel(S5P_JPEG_INT_EN_ALL, regs + S5P_JPEG_INT_EN_REG); +} + +static void jpeg_set_huf_table_enable(void __iomem *regs, int value) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPEG_CNTL_REG) & ~S5P_JPEG_HUF_TBL_EN; + + if (value == 1) + writel(reg | S5P_JPEG_HUF_TBL_EN, regs + S5P_JPEG_CNTL_REG); + else + writel(reg | ~S5P_JPEG_HUF_TBL_EN, regs + S5P_JPEG_CNTL_REG); +} + +static inline void jpeg_qtbl(void __iomem *regs) +{ + int i; + + for (i = 0; i < 16; i++) + writel((unsigned int)ITU_Q_tbl[0][i], + regs + S5P_JPEG_QUAN_TBL_ENTRY_REG + (i*0x04)); + + for (i = 0; i < 16; i++) + writel((unsigned int)ITU_Q_tbl[1][i], + regs + S5P_JPEG_QUAN_TBL_ENTRY_REG + 0x40 + (i*0x04)); + + for (i = 0; i < 16; i++) + writel((unsigned int)ITU_Q_tbl[2][i], + regs + S5P_JPEG_QUAN_TBL_ENTRY_REG + 0x80 + (i*0x04)); + + for (i = 0; i < 16; i++) + writel((unsigned int)ITU_Q_tbl[3][i], + regs + S5P_JPEG_QUAN_TBL_ENTRY_REG + 0xc0 + (i*0x04)); +} + +static inline void jpeg_htbl_ac(void __iomem *regs) +{ + int i; + + for (i = 0; i < 4; i++) + writel((unsigned int)ITU_H_tbl_len_AC_luminance[i], + regs + S5P_JPEG_HUFF_TBL_ENTRY_REG + 0x40 + (i*0x04)); + + for (i = 0; i < 41; i++) + writel((unsigned int)ITU_H_tbl_val_AC_luminance[i], + regs + S5P_JPEG_HUFF_TBL_ENTRY_REG + 0x50 + (i*0x04)); + + for (i = 0; i < 4; i++) + writel((unsigned int)ITU_H_tbl_len_AC_chrominance[i], + regs + S5P_JPEG_HUFF_TBL_ENTRY_REG + 0x100 + (i*0x04)); + + for (i = 0; i < 41; i++) + writel((unsigned int)ITU_H_tbl_val_AC_chrominance[i], + regs + S5P_JPEG_HUFF_TBL_ENTRY_REG + 0x110 + (i*0x04)); +} + +static inline void jpeg_htbl_dc(void __iomem *regs) +{ + int i; + + for (i = 0; i < 4; i++) + writel((unsigned int)ITU_H_tbl_len_DC_luminance[i], + regs + S5P_JPEG_HUFF_TBL_ENTRY_REG + (i*0x04)); + + for (i = 0; i < 3; i++) + writel((unsigned int)ITU_H_tbl_val_DC_luminance[i], + regs + S5P_JPEG_HUFF_TBL_ENTRY_REG + 0x10 + (i*0x04)); + + for (i = 0; i < 4; i++) + writel((unsigned int)ITU_H_tbl_len_DC_chrominance[i], + regs + S5P_JPEG_HUFF_TBL_ENTRY_REG + 0x20 + (i*0x04)); + + for (i = 0; i < 3; i++) + writel((unsigned int)ITU_H_tbl_val_DC_chrominance[i], + regs + S5P_JPEG_HUFF_TBL_ENTRY_REG + 0x30 + (i*0x04)); +} + +static void jpeg_set_encode_hoff_cnt(void __iomem *regs) +{ + writel(0x1a2, regs + S5P_JPEG_HUFF_CNT_REG); +} + +static unsigned int jpeg_compressed_size(void __iomem *regs) +{ + return readl(regs + S5P_JPEG_BITSTREAM_SIZE_REG); +} + +#endif /* JPEG_HW_V2X_H_ */ diff --git a/drivers/media/video/s5p-jpeg/jpeg-regs-v2x.h b/drivers/media/video/s5p-jpeg/jpeg-regs-v2x.h new file mode 100644 index 0000000..8305475 --- /dev/null +++ b/drivers/media/video/s5p-jpeg/jpeg-regs-v2x.h @@ -0,0 +1,150 @@ +/* linux/drivers/media/video/s5p-jpeg/jpeg-regs-v2x.h + * + * Register definition file for Samsung JPEG codec driver + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http:www.samsung.com + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef JPEG_REGS_H_ +#define JPEG_REGS_H_ + +/* JPEG Codec Control Registers */ +#define S5P_JPEG_CNTL_REG 0x00 +#define S5P_JPEG_INT_EN_REG 0x04 +#define S5P_JPEG_INT_STATUS_REG 0x0c +#define S5P_JPEG_OUT_MEM_BASE_REG 0x10 +#define S5P_JPEG_IMG_SIZE_REG 0x14 +#define S5P_JPEG_IMG_BA_PLANE_1_REG 0x18 +#define S5P_JPEG_IMG_BA_PLANE_2_REG 0x24 +#define S5P_JPEG_IMG_BA_PLANE_3_REG 0x30 + +#define S5P_JPEG_TBL_SEL_REG 0x3c + +#define S5P_JPEG_IMG_FMT_REG 0x40 + +#define S5P_JPEG_BITSTREAM_SIZE_REG 0x44 +#define S5P_JPEG_HUFF_CNT_REG 0x4c + +#define S5P_JPEG_QUAN_TBL_ENTRY_REG 0x100 +#define S5P_JPEG_HUFF_TBL_ENTRY_REG 0x200 + + +/****************************************************************/ +/* Bit definition part */ +/****************************************************************/ + +/* JPEG CNTL Register bit */ +#define S5P_JPEG_ENC_DEC_MODE_MASK (0xfffffffc << 0) +#define S5P_JPEG_DEC_MODE (1 << 0) +#define S5P_JPEG_ENC_MODE (1 << 1) +#define S5P_JPEG_HUF_TBL_EN (1 << 19) +#define S5P_JPEG_HOR_SCALING_SHIFT 20 +#define S5P_JPEG_HOR_SCALING_MASK \ + (3 << S5P_JPEG_HOR_SCALING_SHIFT) +#define S5P_JPEG_HOR_SCALING(x) \ + (((x) & 0x3) << S5P_JPEG_HOR_SCALING_SHIFT) +#define S5P_JPEG_VER_SCALING_SHIFT 22 +#define S5P_JPEG_VER_SCALING_MASK \ + (3 << S5P_JPEG_VER_SCALING_SHIFT) +#define S5P_JPEG_VER_SCALING(x) \ + (((x) & 0x3) << S5P_JPEG_VER_SCALING_SHIFT) +#define S5P_JPEG_SOFT_RESET_HI (1 << 29) + +/* JPEG INT Register bit */ +#define S5P_JPEG_INT_EN_MASK (0x1f << 0) +#define S5P_JPEG_INT_EN_ALL (0x1f << 0) + +/* JPEG IMAGE SIZE Register bit */ +#define S5P_JPEG_X_SIZE_SHIFT 0 +#define S5P_JPEG_X_SIZE_MASK (0xffff << S5P_JPEG_X_SIZE_SHIFT) +#define S5P_JPEG_X_SIZE(x) \ + (((x) & 0xffff) << S5P_JPEG_X_SIZE_SHIFT) +#define S5P_JPEG_Y_SIZE_SHIFT 16 +#define S5P_JPEG_Y_SIZE_MASK (0xffff << S5P_JPEG_Y_SIZE_SHIFT) +#define S5P_JPEG_Y_SIZE(x) \ + (((x) & 0xffff) << S5P_JPEG_Y_SIZE_SHIFT) + +/* JPEG IMAGE FORMAT Register bit */ +#define S5P_JPEG_ENC_IN_FMT_MASK 0xffff0000 +#define S5P_JPEG_ENC_RGB_IMG (1 << 0) +#define S5P_JPEG_RGB_IP_SHIFT 6 +#define S5P_JPEG_RGB_IP_RGB_16BIT_IMG (4 << S5P_JPEG_RGB_IP_SHIFT) +#define S5P_JPEG_ENC_YUV_422_IMG (3 << 0) + +/* JPEG IMAGE FORMAT Register bit */ +#define S5P_JPEG_ENC_IN_FMT_MASK 0xffff0000 +#define S5P_JPEG_DEC_YUV_422_IMG (3 << 0) +#define S5P_JPEG_DEC_YUV_420_IMG (4 << 0) + +#define S5P_JPEG_YUV_422_IP_SHIFT 12 +#define S5P_JPEG_YUV_422_IP_MASK (7 << S5P_JPEG_YUV_422_IP_SHIFT) +#define S5P_JPEG_YUV_422_IP_YUV_422_1P_IMG \ + (4 << S5P_JPEG_YUV_422_IP_SHIFT) + +#define S5P_JPEG_YUV_420_IP_SHIFT 15 +#define S5P_JPEG_YUV_420_IP_MASK (7 << S5P_JPEG_YUV_420_IP_SHIFT) +#define S5P_JPEG_YUV_420_IP_YUV_420_3P_IMG \ + (5 << S5P_JPEG_YUV_420_IP_SHIFT) + +#define S5P_JPEG_ENC_FMT_SHIFT 24 +#define S5P_JPEG_ENC_FMT_MASK (3 << S5P_JPEG_ENC_FMT_SHIFT) +#define S5P_JPEG_ENC_FMT_YUV_444 (1 << S5P_JPEG_ENC_FMT_SHIFT) +#define S5P_JPEG_ENC_FMT_YUV_422 (2 << S5P_JPEG_ENC_FMT_SHIFT) +#define S5P_JPEG_ENC_FMT_YUV_420 (3 << S5P_JPEG_ENC_FMT_SHIFT) + +/* JPEG TBL SEL Register bit */ +#define S5P_JPEG_Q_TBL_COMP1_SHIFT 0 +#define S5P_JPEG_Q_TBL_COMP1_0 (0 << S5P_JPEG_Q_TBL_COMP1_SHIFT) +#define S5P_JPEG_Q_TBL_COMP1_1 (1 << S5P_JPEG_Q_TBL_COMP1_SHIFT) +#define S5P_JPEG_Q_TBL_COMP1_2 (2 << S5P_JPEG_Q_TBL_COMP1_SHIFT) +#define S5P_JPEG_Q_TBL_COMP1_3 (3 << S5P_JPEG_Q_TBL_COMP1_SHIFT) + +#define S5P_JPEG_Q_TBL_COMP2_SHIFT 2 +#define S5P_JPEG_Q_TBL_COMP2_0 (0 << S5P_JPEG_Q_TBL_COMP2_SHIFT) +#define S5P_JPEG_Q_TBL_COMP2_1 (1 << S5P_JPEG_Q_TBL_COMP2_SHIFT) +#define S5P_JPEG_Q_TBL_COMP2_2 (2 << S5P_JPEG_Q_TBL_COMP2_SHIFT) +#define S5P_JPEG_Q_TBL_COMP2_3 (3 << S5P_JPEG_Q_TBL_COMP2_SHIFT) + +#define S5P_JPEG_Q_TBL_COMP3_SHIFT 4 +#define S5P_JPEG_Q_TBL_COMP3_0 (0 << S5P_JPEG_Q_TBL_COMP3_SHIFT) +#define S5P_JPEG_Q_TBL_COMP3_1 (1 << S5P_JPEG_Q_TBL_COMP2_SHIFT) +#define S5P_JPEG_Q_TBL_COMP3_2 (2 << S5P_JPEG_Q_TBL_COMP2_SHIFT) +#define S5P_JPEG_Q_TBL_COMP3_3 (3 << S5P_JPEG_Q_TBL_COMP2_SHIFT) + +#define S5P_JPEG_HUFF_TBL_COMP1_SHIFT 6 +#define S5P_JPEG_HUFF_TBL_COMP1_AC_0_DC_0 \ + (0 << S5P_JPEG_HUFF_TBL_COMP1_SHIFT) +#define S5P_JPEG_HUFF_TBL_COMP1_AC_0_DC_1 \ + (1 << S5P_JPEG_HUFF_TBL_COMP1_SHIFT) +#define S5P_JPEG_HUFF_TBL_COMP1_AC_1_DC_0 \ + (2 << S5P_JPEG_HUFF_TBL_COMP1_SHIFT) +#define S5P_JPEG_HUFF_TBL_COMP1_AC_1_DC_1 \ + (3 << S5P_JPEG_HUFF_TBL_COMP1_SHIFT) + +#define S5P_JPEG_HUFF_TBL_COMP2_SHIFT 8 +#define S5P_JPEG_HUFF_TBL_COMP2_AC_0_DC_0 \ + (0 << S5P_JPEG_HUFF_TBL_COMP2_SHIFT) +#define S5P_JPEG_HUFF_TBL_COMP2_AC_0_DC_1 \ + (1 << S5P_JPEG_HUFF_TBL_COMP2_SHIFT) +#define S5P_JPEG_HUFF_TBL_COMP2_AC_1_DC_0 \ + (2 << S5P_JPEG_HUFF_TBL_COMP2_SHIFT) +#define S5P_JPEG_HUFF_TBL_COMP2_AC_1_DC_1 \ + (3 << S5P_JPEG_HUFF_TBL_COMP2_SHIFT) + +#define S5P_JPEG_HUFF_TBL_COMP3_SHIFT 10 +#define S5P_JPEG_HUFF_TBL_COMP3_AC_0_DC_0 \ + (0 << S5P_JPEG_HUFF_TBL_COMP3_SHIFT) +#define S5P_JPEG_HUFF_TBL_COMP3_AC_0_DC_1 \ + (1 << S5P_JPEG_HUFF_TBL_COMP3_SHIFT) +#define S5P_JPEG_HUFF_TBL_COMP3_AC_1_DC_0 \ + (2 << S5P_JPEG_HUFF_TBL_COMP3_SHIFT) +#define S5P_JPEG_HUFF_TBL_COMP3_AC_1_DC_1 \ + (3 << S5P_JPEG_HUFF_TBL_COMP3_SHIFT) + +#endif /* JPEG_REGS_H_ */ diff --git a/drivers/media/video/s5p-jpeg/jpeg-v2x.c b/drivers/media/video/s5p-jpeg/jpeg-v2x.c new file mode 100644 index 0000000..71bd38b --- /dev/null +++ b/drivers/media/video/s5p-jpeg/jpeg-v2x.c @@ -0,0 +1,129 @@ +/* linux/drivers/media/video/s5p-jpeg/jpeg-v2x.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/gfp.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/string.h> +#include <media/v4l2-mem2mem.h> +#include <media/v4l2-ioctl.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-dma-contig.h> + +#include "jpeg-core.h" +#include "jpeg-hw-v2x.h" + +/* + * ============================================================================ + * mem2mem callbacks + * ============================================================================ + */ + +void s5p_jpeg_irq_execute(void *dev_id) +{ + struct s5p_jpeg *jpeg = dev_id; + struct s5p_jpeg_ctx *curr_ctx; + struct vb2_buffer *src_buf, *dst_buf; + unsigned long payload_size = 0; + enum vb2_buffer_state state = VB2_BUF_STATE_DONE; + + unsigned int int_status; + + curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); + + src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); + dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); + + int_status = jpeg_get_int_status(jpeg->regs); + + if (int_status != 0x2) + state = VB2_BUF_STATE_ERROR; + + v4l2_m2m_buf_done(src_buf, state); + if (curr_ctx->mode == S5P_JPEG_ENCODE && int_status == 0x2) { + payload_size = jpeg_compressed_size(jpeg->regs); + vb2_set_plane_payload(dst_buf, 0, payload_size); + } + v4l2_m2m_buf_done(dst_buf, state); + v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->m2m_ctx); +} + +void s5p_jpeg_execute(void *priv) +{ + struct s5p_jpeg_ctx *ctx = priv; + struct s5p_jpeg *jpeg = ctx->jpeg; + struct vb2_buffer *src_buf, *dst_buf; + unsigned long src_addr, dst_addr; + + src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + + src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); + dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); + + jpeg_reset(jpeg->regs); + jpeg_set_interrupt(jpeg->regs); + + if (ctx->mode == S5P_JPEG_ENCODE) { + jpeg_set_huf_table_enable(jpeg->regs, 1); + jpeg_qtbl(jpeg->regs); + jpeg_htbl_ac(jpeg->regs); + jpeg_htbl_dc(jpeg->regs); + jpeg_set_encode_tbl_select(jpeg->regs, ctx->compr_quality); + jpeg_x_y(jpeg->regs, ctx->out_q.w, ctx->out_q.h); + + if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565) + jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_565); + else + jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_422); + if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV) + jpeg_subsampling_mode(jpeg->regs, + S5P_JPEG_SUBSAMPLING_422); + else + jpeg_subsampling_mode(jpeg->regs, + S5P_JPEG_SUBSAMPLING_420); + + jpeg_enc_imgadr(jpeg->regs, src_addr); + jpeg_jpgadr(jpeg->regs, dst_addr); + jpeg_set_encode_hoff_cnt(jpeg->regs); + } else { + jpeg_set_encode_tbl_select(jpeg->regs, 0); + jpeg_set_dec_scaling(jpeg->regs, 0, 0); + jpeg_jpgadr(jpeg->regs, src_addr); + if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV) { + jpeg_dec_imgadr(jpeg->regs, dst_addr, + S5P_JPEG_RAW_OUT_422, + ctx->out_q.w, ctx->out_q.h); + jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422); + } else { + jpeg_dec_imgadr(jpeg->regs, dst_addr, + S5P_JPEG_RAW_OUT_420, + ctx->out_q.w, ctx->out_q.h); + jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420); + } + jpeg_set_dec_bitstream_size(jpeg->regs, + ctx->out_q.size / 32 + 1); + } + jpeg_proc_mode(jpeg->regs, ctx->mode); +} + +void s5p_jpeg_runtime_resume_execute(struct device *dev) +{ + +} diff --git a/drivers/media/video/s5p-jpeg/jpeg-v3.c b/drivers/media/video/s5p-jpeg/jpeg-v3.c new file mode 100644 index 0000000..41a5038 --- /dev/null +++ b/drivers/media/video/s5p-jpeg/jpeg-v3.c @@ -0,0 +1,340 @@ +/* linux/drivers/media/video/s5p-jpeg/jpeg-v3.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz <andrzej.p@xxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/gfp.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/string.h> +#include <media/v4l2-mem2mem.h> +#include <media/v4l2-ioctl.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-dma-contig.h> + +#include "jpeg-core.h" +#include "jpeg-hw.h" + +static const unsigned char qtbl_luminance[4][64] = { + {/* level 1 - high quality */ + 8, 6, 6, 8, 12, 14, 16, 17, + 6, 6, 6, 8, 10, 13, 12, 15, + 6, 6, 7, 8, 13, 14, 18, 24, + 8, 8, 8, 14, 13, 19, 24, 35, + 12, 10, 13, 13, 20, 26, 34, 39, + 14, 13, 14, 19, 26, 34, 39, 39, + 16, 12, 18, 24, 34, 39, 39, 39, + 17, 15, 24, 35, 39, 39, 39, 39 + }, + {/* level 2 */ + 12, 8, 8, 12, 17, 21, 24, 23, + 8, 9, 9, 11, 15, 19, 18, 23, + 8, 9, 10, 12, 19, 20, 27, 36, + 12, 11, 12, 21, 20, 28, 36, 53, + 17, 15, 19, 20, 30, 39, 51, 59, + 21, 19, 20, 28, 39, 51, 59, 59, + 24, 18, 27, 36, 51, 59, 59, 59, + 23, 23, 36, 53, 59, 59, 59, 59 + }, + {/* level 3 */ + 16, 11, 11, 16, 23, 27, 31, 30, + 11, 12, 12, 15, 20, 23, 23, 30, + 11, 12, 13, 16, 23, 26, 35, 47, + 16, 15, 16, 23, 26, 37, 47, 64, + 23, 20, 23, 26, 39, 51, 64, 64, + 27, 23, 26, 37, 51, 64, 64, 64, + 31, 23, 35, 47, 64, 64, 64, 64, + 30, 30, 47, 64, 64, 64, 64, 64 + }, + {/*level 4 - low quality */ + 20, 16, 25, 39, 50, 46, 62, 68, + 16, 18, 23, 38, 38, 53, 65, 68, + 25, 23, 31, 38, 53, 65, 68, 68, + 39, 38, 38, 53, 65, 68, 68, 68, + 50, 38, 53, 65, 68, 68, 68, 68, + 46, 53, 65, 68, 68, 68, 68, 68, + 62, 65, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68 + } +}; + +static const unsigned char qtbl_chrominance[4][64] = { + {/* level 1 - high quality */ + 9, 8, 9, 11, 14, 17, 19, 24, + 8, 10, 9, 11, 14, 13, 17, 22, + 9, 9, 13, 14, 13, 15, 23, 26, + 11, 11, 14, 14, 15, 20, 26, 33, + 14, 14, 13, 15, 20, 24, 33, 39, + 17, 13, 15, 20, 24, 32, 39, 39, + 19, 17, 23, 26, 33, 39, 39, 39, + 24, 22, 26, 33, 39, 39, 39, 39 + }, + {/* level 2 */ + 13, 11, 13, 16, 20, 20, 29, 37, + 11, 14, 14, 14, 16, 20, 26, 32, + 13, 14, 15, 17, 20, 23, 35, 40, + 16, 14, 17, 21, 23, 30, 40, 50, + 20, 16, 20, 23, 30, 37, 50, 59, + 20, 20, 23, 30, 37, 48, 59, 59, + 29, 26, 35, 40, 50, 59, 59, 59, + 37, 32, 40, 50, 59, 59, 59, 59 + }, + {/* level 3 */ + 17, 15, 17, 21, 20, 26, 38, 48, + 15, 19, 18, 17, 20, 26, 35, 43, + 17, 18, 20, 22, 26, 30, 46, 53, + 21, 17, 22, 28, 30, 39, 53, 64, + 20, 20, 26, 30, 39, 48, 64, 64, + 26, 26, 30, 39, 48, 63, 64, 64, + 38, 35, 46, 53, 64, 64, 64, 64, + 48, 43, 53, 64, 64, 64, 64, 64 + }, + {/*level 4 - low quality */ + 21, 25, 32, 38, 54, 68, 68, 68, + 25, 28, 24, 38, 54, 68, 68, 68, + 32, 24, 32, 43, 66, 68, 68, 68, + 38, 38, 43, 53, 68, 68, 68, 68, + 54, 54, 66, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68 + } +}; + +static const unsigned char hdctbl0[16] = { + 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 +}; + +static const unsigned char hdctblg0[12] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb +}; +static const unsigned char hactbl0[16] = { + 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d +}; +static const unsigned char hactblg0[162] = { + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa +}; + +static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl, + unsigned long tab, int len) +{ + int i; + + for (i = 0; i < len; i++) + writel((unsigned int)qtbl[i], regs + tab + (i * 0x04)); +} + +static inline void jpeg_set_qtbl_lum(void __iomem *regs, int quality) +{ + /* this driver fills quantisation table 0 with data for luma */ + jpeg_set_qtbl(regs, qtbl_luminance[quality], S5P_JPG_QTBL_CONTENT(0), + ARRAY_SIZE(qtbl_luminance[quality])); +} + +static inline void jpeg_set_qtbl_chr(void __iomem *regs, int quality) +{ + /* this driver fills quantisation table 1 with data for chroma */ + jpeg_set_qtbl(regs, qtbl_chrominance[quality], S5P_JPG_QTBL_CONTENT(1), + ARRAY_SIZE(qtbl_chrominance[quality])); +} + +static inline void jpeg_set_htbl(void __iomem *regs, const unsigned char *htbl, + unsigned long tab, int len) +{ + int i; + + for (i = 0; i < len; i++) + writel((unsigned int)htbl[i], regs + tab + (i * 0x04)); +} + +static inline void jpeg_set_hdctbl(void __iomem *regs) +{ + /* this driver fills table 0 for this component */ + jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0), ARRAY_SIZE(hdctbl0)); +} + +static inline void jpeg_set_hdctblg(void __iomem *regs) +{ + /* this driver fills table 0 for this component */ + jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0), ARRAY_SIZE(hdctblg0)); +} + +static inline void jpeg_set_hactbl(void __iomem *regs) +{ + /* this driver fills table 0 for this component */ + jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0), ARRAY_SIZE(hactbl0)); +} + +static inline void jpeg_set_hactblg(void __iomem *regs) +{ + /* this driver fills table 0 for this component */ + jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0), ARRAY_SIZE(hactblg0)); +} + +void s5p_jpeg_irq_execute(void *dev_id) +{ + struct s5p_jpeg *jpeg = dev_id; + struct s5p_jpeg_ctx *curr_ctx; + struct vb2_buffer *src_buf, *dst_buf; + unsigned long payload_size = 0; + enum vb2_buffer_state state = VB2_BUF_STATE_DONE; + bool enc_jpeg_too_large = false; + bool timer_elapsed = false; + bool op_completed = false; + + curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); + + src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); + dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); + + if (curr_ctx->mode == S5P_JPEG_ENCODE) + enc_jpeg_too_large = jpeg_enc_stream_stat(jpeg->regs); + timer_elapsed = jpeg_timer_stat(jpeg->regs); + op_completed = jpeg_result_stat_ok(jpeg->regs); + if (curr_ctx->mode == S5P_JPEG_DECODE) + op_completed = op_completed && jpeg_stream_stat_ok(jpeg->regs); + + if (enc_jpeg_too_large) { + state = VB2_BUF_STATE_ERROR; + jpeg_clear_enc_stream_stat(jpeg->regs); + } else if (timer_elapsed) { + state = VB2_BUF_STATE_ERROR; + jpeg_clear_timer_stat(jpeg->regs); + } else if (!op_completed) { + state = VB2_BUF_STATE_ERROR; + } else { + payload_size = jpeg_compressed_size(jpeg->regs); + } + + v4l2_m2m_buf_done(src_buf, state); + if (curr_ctx->mode == S5P_JPEG_ENCODE) + vb2_set_plane_payload(dst_buf, 0, payload_size); + v4l2_m2m_buf_done(dst_buf, state); + v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->m2m_ctx); + + jpeg_clear_int(jpeg->regs); +} + +void s5p_jpeg_execute(void *priv) +{ + struct s5p_jpeg_ctx *ctx = priv; + struct s5p_jpeg *jpeg = ctx->jpeg; + struct vb2_buffer *src_buf, *dst_buf; + unsigned long src_addr, dst_addr; + + src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); + dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); + + jpeg_reset(jpeg->regs); + jpeg_poweron(jpeg->regs); + jpeg_proc_mode(jpeg->regs, ctx->mode); + if (ctx->mode == S5P_JPEG_ENCODE) { + if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565) + jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_565); + else + jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_422); + if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV) + jpeg_subsampling_mode(jpeg->regs, + S5P_JPEG_SUBSAMPLING_422); + else + jpeg_subsampling_mode(jpeg->regs, + S5P_JPEG_SUBSAMPLING_420); + jpeg_dri(jpeg->regs, 0); + jpeg_x(jpeg->regs, ctx->out_q.w); + jpeg_y(jpeg->regs, ctx->out_q.h); + jpeg_imgadr(jpeg->regs, src_addr); + jpeg_jpgadr(jpeg->regs, dst_addr); + + /* ultimately comes from sizeimage from userspace */ + jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size); + + /* JPEG RGB to YCbCr conversion matrix */ + jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11); + jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12); + jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13); + jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21); + jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22); + jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23); + jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31); + jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32); + jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33); + + /* + * JPEG IP allows storing 4 quantization tables + * We fill table 0 for luma and table 1 for chroma + */ + jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality); + jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality); + /* use table 0 for Y */ + jpeg_qtbl(jpeg->regs, 1, 0); + /* use table 1 for Cb and Cr*/ + jpeg_qtbl(jpeg->regs, 2, 1); + jpeg_qtbl(jpeg->regs, 3, 1); + + /* Y, Cb, Cr use Huffman table 0 */ + jpeg_htbl_ac(jpeg->regs, 1); + jpeg_htbl_dc(jpeg->regs, 1); + jpeg_htbl_ac(jpeg->regs, 2); + jpeg_htbl_dc(jpeg->regs, 2); + jpeg_htbl_ac(jpeg->regs, 3); + jpeg_htbl_dc(jpeg->regs, 3); + } else { + jpeg_rst_int_enable(jpeg->regs, true); + jpeg_data_num_int_enable(jpeg->regs, true); + jpeg_final_mcu_num_int_enable(jpeg->regs, true); + jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422); + jpeg_jpgadr(jpeg->regs, src_addr); + jpeg_imgadr(jpeg->regs, dst_addr); + } + jpeg_start(jpeg->regs); +} + +void s5p_jpeg_runtime_resume_execute(struct device *dev) +{ + struct s5p_jpeg *jpeg = dev_get_drvdata(dev); + /* + * JPEG IP allows storing two Huffman tables for each component + * We fill table 0 for each component + */ + jpeg_set_hdctbl(jpeg->regs); + jpeg_set_hdctblg(jpeg->regs); + jpeg_set_hactbl(jpeg->regs); + jpeg_set_hactblg(jpeg->regs); +} -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html