linux/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c
Andrzej Pietrasiewicz 6c96dbbc2a [media] s5p-jpeg: add support for 5433
JPEG IP found in Exynos5433 is similar to what is in Exynos4, but
there are some subtle differences which this patch takes into account.

The most important difference is in what is processed by the JPEG IP and
what has to be provided to it. In case of 5433 the IP does not parse
Huffman and quantisation tables, so this has to be performed with the CPU
and the majority of the code in this patch does that.

A small but important difference is in what address is passed to the JPEG
IP. In case of 5433 it is the SOS (start of scan) position, which is
natural, because the headers must be parsed elsewhere.

There is also a difference in how the hardware is put to work in
device_run.

Data structures are extended as appropriate to accommodate the above
changes.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Reviewed-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-10-01 08:40:04 -03:00

329 lines
8.2 KiB
C

/* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* Author: Jacek Anaszewski <j.anaszewski@samsung.com>
*
* Register interface file for JPEG driver on Exynos4x12.
*
* 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/io.h>
#include <linux/delay.h>
#include "jpeg-core.h"
#include "jpeg-hw-exynos4.h"
#include "jpeg-regs.h"
void exynos4_jpeg_sw_reset(void __iomem *base)
{
unsigned int reg;
reg = readl(base + EXYNOS4_JPEG_CNTL_REG);
writel(reg & ~EXYNOS4_SOFT_RESET_HI, base + EXYNOS4_JPEG_CNTL_REG);
udelay(100);
writel(reg | EXYNOS4_SOFT_RESET_HI, base + EXYNOS4_JPEG_CNTL_REG);
}
void exynos4_jpeg_set_enc_dec_mode(void __iomem *base, unsigned int mode)
{
unsigned int reg;
reg = readl(base + EXYNOS4_JPEG_CNTL_REG);
/* set exynos4_jpeg mod register */
if (mode == S5P_JPEG_DECODE) {
writel((reg & EXYNOS4_ENC_DEC_MODE_MASK) |
EXYNOS4_DEC_MODE,
base + EXYNOS4_JPEG_CNTL_REG);
} else {/* encode */
writel((reg & EXYNOS4_ENC_DEC_MODE_MASK) |
EXYNOS4_ENC_MODE,
base + EXYNOS4_JPEG_CNTL_REG);
}
}
void __exynos4_jpeg_set_img_fmt(void __iomem *base, unsigned int img_fmt,
unsigned int version)
{
unsigned int reg;
unsigned int exynos4_swap_chroma_cbcr;
unsigned int exynos4_swap_chroma_crcb;
if (version == SJPEG_EXYNOS4) {
exynos4_swap_chroma_cbcr = EXYNOS4_SWAP_CHROMA_CBCR;
exynos4_swap_chroma_crcb = EXYNOS4_SWAP_CHROMA_CRCB;
} else {
exynos4_swap_chroma_cbcr = EXYNOS5433_SWAP_CHROMA_CBCR;
exynos4_swap_chroma_crcb = EXYNOS5433_SWAP_CHROMA_CRCB;
}
reg = readl(base + EXYNOS4_IMG_FMT_REG) &
EXYNOS4_ENC_IN_FMT_MASK; /* clear except enc format */
switch (img_fmt) {
case V4L2_PIX_FMT_GREY:
reg = reg | EXYNOS4_ENC_GRAY_IMG | EXYNOS4_GRAY_IMG_IP;
break;
case V4L2_PIX_FMT_RGB32:
reg = reg | EXYNOS4_ENC_RGB_IMG |
EXYNOS4_RGB_IP_RGB_32BIT_IMG;
break;
case V4L2_PIX_FMT_RGB565:
reg = reg | EXYNOS4_ENC_RGB_IMG |
EXYNOS4_RGB_IP_RGB_16BIT_IMG;
break;
case V4L2_PIX_FMT_NV24:
reg = reg | EXYNOS4_ENC_YUV_444_IMG |
EXYNOS4_YUV_444_IP_YUV_444_2P_IMG |
exynos4_swap_chroma_cbcr;
break;
case V4L2_PIX_FMT_NV42:
reg = reg | EXYNOS4_ENC_YUV_444_IMG |
EXYNOS4_YUV_444_IP_YUV_444_2P_IMG |
exynos4_swap_chroma_crcb;
break;
case V4L2_PIX_FMT_YUYV:
reg = reg | EXYNOS4_DEC_YUV_422_IMG |
EXYNOS4_YUV_422_IP_YUV_422_1P_IMG |
exynos4_swap_chroma_cbcr;
break;
case V4L2_PIX_FMT_YVYU:
reg = reg | EXYNOS4_DEC_YUV_422_IMG |
EXYNOS4_YUV_422_IP_YUV_422_1P_IMG |
exynos4_swap_chroma_crcb;
break;
case V4L2_PIX_FMT_NV16:
reg = reg | EXYNOS4_DEC_YUV_422_IMG |
EXYNOS4_YUV_422_IP_YUV_422_2P_IMG |
exynos4_swap_chroma_cbcr;
break;
case V4L2_PIX_FMT_NV61:
reg = reg | EXYNOS4_DEC_YUV_422_IMG |
EXYNOS4_YUV_422_IP_YUV_422_2P_IMG |
exynos4_swap_chroma_crcb;
break;
case V4L2_PIX_FMT_NV12:
reg = reg | EXYNOS4_DEC_YUV_420_IMG |
EXYNOS4_YUV_420_IP_YUV_420_2P_IMG |
exynos4_swap_chroma_cbcr;
break;
case V4L2_PIX_FMT_NV21:
reg = reg | EXYNOS4_DEC_YUV_420_IMG |
EXYNOS4_YUV_420_IP_YUV_420_2P_IMG |
exynos4_swap_chroma_crcb;
break;
case V4L2_PIX_FMT_YUV420:
reg = reg | EXYNOS4_DEC_YUV_420_IMG |
EXYNOS4_YUV_420_IP_YUV_420_3P_IMG |
exynos4_swap_chroma_cbcr;
break;
default:
break;
}
writel(reg, base + EXYNOS4_IMG_FMT_REG);
}
void __exynos4_jpeg_set_enc_out_fmt(void __iomem *base, unsigned int out_fmt,
unsigned int version)
{
unsigned int reg;
reg = readl(base + EXYNOS4_IMG_FMT_REG) &
~(version == SJPEG_EXYNOS4 ? EXYNOS4_ENC_FMT_MASK :
EXYNOS5433_ENC_FMT_MASK); /* clear enc format */
switch (out_fmt) {
case V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY:
reg = reg | EXYNOS4_ENC_FMT_GRAY;
break;
case V4L2_JPEG_CHROMA_SUBSAMPLING_444:
reg = reg | EXYNOS4_ENC_FMT_YUV_444;
break;
case V4L2_JPEG_CHROMA_SUBSAMPLING_422:
reg = reg | EXYNOS4_ENC_FMT_YUV_422;
break;
case V4L2_JPEG_CHROMA_SUBSAMPLING_420:
reg = reg | EXYNOS4_ENC_FMT_YUV_420;
break;
default:
break;
}
writel(reg, base + EXYNOS4_IMG_FMT_REG);
}
void exynos4_jpeg_set_interrupt(void __iomem *base, unsigned int version)
{
unsigned int reg;
if (version == SJPEG_EXYNOS4) {
reg = readl(base + EXYNOS4_INT_EN_REG) & ~EXYNOS4_INT_EN_MASK;
writel(reg | EXYNOS4_INT_EN_ALL, base + EXYNOS4_INT_EN_REG);
} else {
reg = readl(base + EXYNOS4_INT_EN_REG) &
~EXYNOS5433_INT_EN_MASK;
writel(reg | EXYNOS5433_INT_EN_ALL, base + EXYNOS4_INT_EN_REG);
}
}
unsigned int exynos4_jpeg_get_int_status(void __iomem *base)
{
unsigned int int_status;
int_status = readl(base + EXYNOS4_INT_STATUS_REG);
return int_status;
}
unsigned int exynos4_jpeg_get_fifo_status(void __iomem *base)
{
unsigned int fifo_status;
fifo_status = readl(base + EXYNOS4_FIFO_STATUS_REG);
return fifo_status;
}
void exynos4_jpeg_set_huf_table_enable(void __iomem *base, int value)
{
unsigned int reg;
reg = readl(base + EXYNOS4_JPEG_CNTL_REG) & ~EXYNOS4_HUF_TBL_EN;
if (value == 1)
writel(reg | EXYNOS4_HUF_TBL_EN,
base + EXYNOS4_JPEG_CNTL_REG);
else
writel(reg & ~EXYNOS4_HUF_TBL_EN,
base + EXYNOS4_JPEG_CNTL_REG);
}
void exynos4_jpeg_set_sys_int_enable(void __iomem *base, int value)
{
unsigned int reg;
reg = readl(base + EXYNOS4_JPEG_CNTL_REG) & ~(EXYNOS4_SYS_INT_EN);
if (value == 1)
writel(reg | EXYNOS4_SYS_INT_EN, base + EXYNOS4_JPEG_CNTL_REG);
else
writel(reg & ~EXYNOS4_SYS_INT_EN, base + EXYNOS4_JPEG_CNTL_REG);
}
void exynos4_jpeg_set_stream_buf_address(void __iomem *base,
unsigned int address)
{
writel(address, base + EXYNOS4_OUT_MEM_BASE_REG);
}
void exynos4_jpeg_set_stream_size(void __iomem *base,
unsigned int x_value, unsigned int y_value)
{
writel(0x0, base + EXYNOS4_JPEG_IMG_SIZE_REG); /* clear */
writel(EXYNOS4_X_SIZE(x_value) | EXYNOS4_Y_SIZE(y_value),
base + EXYNOS4_JPEG_IMG_SIZE_REG);
}
void exynos4_jpeg_set_frame_buf_address(void __iomem *base,
struct s5p_jpeg_addr *exynos4_jpeg_addr)
{
writel(exynos4_jpeg_addr->y, base + EXYNOS4_IMG_BA_PLANE_1_REG);
writel(exynos4_jpeg_addr->cb, base + EXYNOS4_IMG_BA_PLANE_2_REG);
writel(exynos4_jpeg_addr->cr, base + EXYNOS4_IMG_BA_PLANE_3_REG);
}
void exynos4_jpeg_set_encode_tbl_select(void __iomem *base,
enum exynos4_jpeg_img_quality_level level)
{
unsigned int reg;
reg = EXYNOS4_Q_TBL_COMP1_0 | EXYNOS4_Q_TBL_COMP2_1 |
EXYNOS4_Q_TBL_COMP3_1 |
EXYNOS4_HUFF_TBL_COMP1_AC_0_DC_1 |
EXYNOS4_HUFF_TBL_COMP2_AC_0_DC_0 |
EXYNOS4_HUFF_TBL_COMP3_AC_1_DC_1;
writel(reg, base + EXYNOS4_TBL_SEL_REG);
}
void exynos4_jpeg_set_dec_components(void __iomem *base, int n)
{
unsigned int reg;
reg = readl(base + EXYNOS4_TBL_SEL_REG);
reg |= EXYNOS4_NF(n);
writel(reg, base + EXYNOS4_TBL_SEL_REG);
}
void exynos4_jpeg_select_dec_q_tbl(void __iomem *base, char c, char x)
{
unsigned int reg;
reg = readl(base + EXYNOS4_TBL_SEL_REG);
reg |= EXYNOS4_Q_TBL_COMP(c, x);
writel(reg, base + EXYNOS4_TBL_SEL_REG);
}
void exynos4_jpeg_select_dec_h_tbl(void __iomem *base, char c, char x)
{
unsigned int reg;
reg = readl(base + EXYNOS4_TBL_SEL_REG);
reg |= EXYNOS4_HUFF_TBL_COMP(c, x);
writel(reg, base + EXYNOS4_TBL_SEL_REG);
}
void exynos4_jpeg_set_encode_hoff_cnt(void __iomem *base, unsigned int fmt)
{
if (fmt == V4L2_PIX_FMT_GREY)
writel(0xd2, base + EXYNOS4_HUFF_CNT_REG);
else
writel(0x1a2, base + EXYNOS4_HUFF_CNT_REG);
}
unsigned int exynos4_jpeg_get_stream_size(void __iomem *base)
{
unsigned int size;
size = readl(base + EXYNOS4_BITSTREAM_SIZE_REG);
return size;
}
void exynos4_jpeg_set_dec_bitstream_size(void __iomem *base, unsigned int size)
{
writel(size, base + EXYNOS4_BITSTREAM_SIZE_REG);
}
void exynos4_jpeg_get_frame_size(void __iomem *base,
unsigned int *width, unsigned int *height)
{
*width = (readl(base + EXYNOS4_DECODE_XY_SIZE_REG) &
EXYNOS4_DECODED_SIZE_MASK);
*height = (readl(base + EXYNOS4_DECODE_XY_SIZE_REG) >> 16) &
EXYNOS4_DECODED_SIZE_MASK;
}
unsigned int exynos4_jpeg_get_frame_fmt(void __iomem *base)
{
return readl(base + EXYNOS4_DECODE_IMG_FMT_REG) &
EXYNOS4_JPEG_DECODED_IMG_FMT_MASK;
}
void exynos4_jpeg_set_timer_count(void __iomem *base, unsigned int size)
{
writel(size, base + EXYNOS4_INT_TIMER_COUNT_REG);
}