alistair23-linux/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c
Tony K Nadackal 787d862091 media: s5p-jpeg: Clear JPEG_CODEC_ON bits in sw reset function
Bits EXYNOS4_DEC_MODE and EXYNOS4_ENC_MODE do not get cleared
on software reset. These bits need to be cleared explicitly.

Even though the bits in question are already cleared in interrupt
service routine, the reset should also clear them in case when
e.g. bootloader uses the codec and leaves it in a bad state.

[Updated commit message]

Signed-off-by: Tony K Nadackal <tony.kn@samsung.com>
Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
2017-08-20 08:01:45 -04:00

325 lines
8.3 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_DEC_MODE | EXYNOS4_ENC_MODE),
base + EXYNOS4_JPEG_CNTL_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 if (mode == S5P_JPEG_ENCODE) {/* encode */
writel((reg & EXYNOS4_ENC_DEC_MODE_MASK) |
EXYNOS4_ENC_MODE,
base + EXYNOS4_JPEG_CNTL_REG);
} else { /* disable both */
writel(reg & EXYNOS4_ENC_DEC_MODE_MASK,
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)
{
return readl(base + EXYNOS4_INT_STATUS_REG);
}
unsigned int exynos4_jpeg_get_fifo_status(void __iomem *base)
{
return readl(base + EXYNOS4_FIFO_STATUS_REG);
}
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)
{
return readl(base + EXYNOS4_BITSTREAM_SIZE_REG);
}
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);
}