537 lines
17 KiB
C
Executable File
537 lines
17 KiB
C
Executable File
/*
|
|
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
|
|
* http://www.samsung.com
|
|
*
|
|
* The H/W handling file of Samsung Exynos SMFC Driver
|
|
*
|
|
* 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/kernel.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/delay.h>
|
|
|
|
#include <media/v4l2-ioctl.h>
|
|
#include <media/v4l2-device.h>
|
|
#include <media/v4l2-mem2mem.h>
|
|
#include <media/videobuf2-core.h>
|
|
#include <media/videobuf2-dma-sg.h>
|
|
|
|
#include "smfc.h"
|
|
|
|
void smfc_hwconfigure_reset(struct smfc_dev *smfc)
|
|
{
|
|
u32 cfg = __raw_readl(smfc->reg + REG_MAIN_JPEG_CNTL);
|
|
cfg &= ~((1 << 29) | 3);
|
|
__raw_writel(cfg, smfc->reg + REG_MAIN_JPEG_CNTL);
|
|
__raw_writel(cfg | (1 << 29), smfc->reg + REG_MAIN_JPEG_CNTL);
|
|
}
|
|
|
|
/*
|
|
* Quantization tables in ZIG-ZAG order provided by IOC/IEC 10918-1 K.1 and K.2
|
|
* for YUV420 and YUV422
|
|
*/
|
|
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,
|
|
29, 40, 58, 51, 61, 60, 57, 51,
|
|
56, 55, 64, 72, 92, 78, 64, 68,
|
|
87, 69, 55, 56, 80, 109, 81, 87,
|
|
95, 98, 103, 104, 103, 62, 77, 113,
|
|
121, 112, 100, 120, 92, 101, 103, 99,
|
|
};
|
|
|
|
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,
|
|
99, 99, 99, 99, 99, 99, 99, 99,
|
|
99, 99, 99, 99, 99, 99, 99, 99,
|
|
99, 99, 99, 99, 99, 99, 99, 99,
|
|
99, 99, 99, 99, 99, 99, 99, 99,
|
|
99, 99, 99, 99, 99, 99, 99, 99,
|
|
};
|
|
|
|
/* ITU Luminace Huffman Table */
|
|
static unsigned int ITU_H_TBL_LEN_DC_LUMINANCE[] = {
|
|
0x01050100, 0x01010101, 0x00000001, 0x00000000
|
|
};
|
|
static unsigned int ITU_H_TBL_VAL_DC_LUMINANCE[] = {
|
|
0x03020100, 0x07060504, 0x0b0a0908, 0x00000000
|
|
};
|
|
|
|
/* ITU Chrominace Huffman Table */
|
|
static unsigned int ITU_H_TBL_LEN_DC_CHROMINANCE[] = {
|
|
0x01010300, 0x01010101, 0x00010101, 0x00000000
|
|
};
|
|
static unsigned int ITU_H_TBL_VAL_DC_CHROMINANCE[] = {
|
|
0x03020100, 0x07060504, 0x0b0a0908, 0x00000000
|
|
};
|
|
|
|
/* ITU Luminace Huffman Table */
|
|
static unsigned int ITU_H_TBL_LEN_AC_LUMINANCE[] = {
|
|
0x03010200, 0x03040203, 0x04040505, 0x7d010000
|
|
};
|
|
|
|
static unsigned int ITU_H_TBL_VAL_AC_LUMINANCE[] = {
|
|
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
|
|
};
|
|
|
|
/* ITU Chrominace Huffman Table */
|
|
static u32 ITU_H_TBL_LEN_AC_CHROMINANCE[] = {
|
|
0x02010200, 0x04030404, 0x04040507, 0x77020100
|
|
};
|
|
static u32 ITU_H_TBL_VAL_AC_CHROMINANCE[] = {
|
|
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
|
|
};
|
|
|
|
/* to suppress warning or error message about out-of-array-bound */
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Warray-bounds"
|
|
/* tables and qunatization tables configuration to H/W for compression */
|
|
static inline u32 smfc_calc_quantizers(unsigned int idx, unsigned int factor,
|
|
const unsigned char tbl[])
|
|
{
|
|
u32 val = max(min((tbl[idx] * factor + 50) / 100, 255U), 1U);
|
|
val |= max(min((tbl[idx + 1] * factor + 50) / 100, 255U), 1U) << 8;
|
|
val |= max(min((tbl[idx + 2] * factor + 50) / 100, 255U), 1U) << 16;
|
|
val |= max(min((tbl[idx + 3] * factor + 50) / 100, 255U), 1U) << 24;
|
|
return val;
|
|
}
|
|
#pragma GCC diagnostic pop
|
|
|
|
static void smfc_hwconfigure_qtable(void __iomem *reg, unsigned int factor,
|
|
const u8 table[])
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 0; i < SMFC_MCU_SIZE; i += 4)
|
|
__raw_writel(smfc_calc_quantizers(i, factor, table), reg + i);
|
|
}
|
|
|
|
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;
|
|
|
|
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++) {
|
|
__raw_writel(ITU_H_TBL_LEN_DC_LUMINANCE[i],
|
|
base + REG_HTBL_LUMA_DCLEN + i * sizeof(u32));
|
|
__raw_writel(ITU_H_TBL_VAL_DC_LUMINANCE[i],
|
|
base + REG_HTBL_LUMA_DCVAL + i * sizeof(u32));
|
|
__raw_writel(ITU_H_TBL_LEN_DC_CHROMINANCE[i],
|
|
base + REG_HTBL_CHROMA_DCLEN + i * sizeof(u32));
|
|
__raw_writel(ITU_H_TBL_VAL_DC_CHROMINANCE[i],
|
|
base + REG_HTBL_CHROMA_DCVAL + i * sizeof(u32));
|
|
__raw_writel(ITU_H_TBL_LEN_AC_LUMINANCE[i],
|
|
base + REG_HTBL_LUMA_ACLEN + i * sizeof(u32));
|
|
__raw_writel(ITU_H_TBL_LEN_AC_CHROMINANCE[i],
|
|
base + REG_HTBL_CHROMA_ACLEN + i * sizeof(u32));
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(ITU_H_TBL_VAL_AC_LUMINANCE); i++)
|
|
__raw_writel(ITU_H_TBL_VAL_AC_LUMINANCE[i],
|
|
base + REG_HTBL_LUMA_ACVAL + i * sizeof(u32));
|
|
|
|
for (i = 0; i < ARRAY_SIZE(ITU_H_TBL_VAL_AC_CHROMINANCE); i++)
|
|
__raw_writel(ITU_H_TBL_VAL_AC_CHROMINANCE[i],
|
|
base + REG_HTBL_CHROMA_ACVAL + i * sizeof(u32));
|
|
|
|
__raw_writel(VAL_MAIN_TABLE_SELECT, base + REG_MAIN_TABLE_SELECT);
|
|
__raw_writel(SMFC_DHT_LEN, base + REG_MAIN_DHT_LEN);
|
|
}
|
|
|
|
void smfc_hwconfigure_2nd_tables(struct smfc_ctx *ctx, unsigned int qfactor)
|
|
{
|
|
/* Qunatiazation table 2 and 3 will be used by the secondary image */
|
|
void __iomem *base = ctx->smfc->reg;
|
|
void __iomem *qtblbase = base + REG_QTBL_BASE + SMFC_MCU_SIZE * 2;
|
|
qfactor = (qfactor < 50) ? 5000 / qfactor : 200 - qfactor * 2;
|
|
|
|
smfc_hwconfigure_qtable(qtblbase, qfactor, default_luma_qtbl);
|
|
smfc_hwconfigure_qtable(qtblbase + SMFC_MCU_SIZE,
|
|
qfactor, default_chroma_qtbl);
|
|
/* Huffman table for the secondary image is the same as the main image */
|
|
__raw_writel(VAL_SEC_TABLE_SELECT, base + REG_SEC_TABLE_SELECT);
|
|
__raw_writel(SMFC_DHT_LEN, base + REG_SEC_DHT_LEN);
|
|
}
|
|
|
|
void smfc_hwconfigure_tables_for_decompression(struct smfc_ctx *ctx)
|
|
{
|
|
void __iomem *base = ctx->smfc->reg;
|
|
void __iomem *qtbl_base = ctx->smfc->reg + REG_QTBL_BASE;
|
|
u32 tblsel = ctx->num_components << 16;
|
|
int i;
|
|
|
|
/* Huffman table selector configuration */
|
|
for (i = 0; i < ctx->num_components; i++) {
|
|
u32 val = (ctx->huffman_tables->compsel[i].idx_dc |
|
|
(ctx->huffman_tables->compsel[i].idx_ac << 1)) & 3;
|
|
tblsel |= val << (i * 2 + 4);
|
|
}
|
|
|
|
/* quantization table configuration */
|
|
for (i = 0; i < ctx->num_components; i++) {
|
|
if (ctx->quantizer_tables->compsel[i] != INVALID_QTBLIDX) {
|
|
u8 *table = ctx->quantizer_tables->table[i];
|
|
int j;
|
|
|
|
for (j = 0; j < SMFC_MCU_SIZE; j += 4) {
|
|
u32 quants;
|
|
|
|
quants = table[j + 0] << 0;
|
|
quants |= table[j + 1] << 8;
|
|
quants |= table[j + 2] << 16;
|
|
quants |= table[j + 3] << 24;
|
|
__raw_writel(quants,
|
|
qtbl_base + SMFC_MCU_SIZE * i + j);
|
|
}
|
|
/* quantization table selector */
|
|
tblsel |= ctx->quantizer_tables->compsel[i] << (i * 2);
|
|
}
|
|
}
|
|
|
|
/* Huffman table configuration */
|
|
for (i = 0; i < 4; i++) {
|
|
__raw_writel(ctx->huffman_tables->dc[0].code32[i],
|
|
base + REG_HTBL_LUMA_DCLEN + i * sizeof(u32));
|
|
__raw_writel(ctx->huffman_tables->dc[0].value32[i],
|
|
base + REG_HTBL_LUMA_DCVAL + i * sizeof(u32));
|
|
__raw_writel(ctx->huffman_tables->dc[1].code32[i],
|
|
base + REG_HTBL_CHROMA_DCLEN + i * sizeof(u32));
|
|
__raw_writel(ctx->huffman_tables->dc[1].value32[i],
|
|
base + REG_HTBL_CHROMA_DCVAL + i * sizeof(u32));
|
|
__raw_writel(ctx->huffman_tables->ac[0].code32[i],
|
|
base + REG_HTBL_LUMA_ACLEN + i * sizeof(u32));
|
|
__raw_writel(ctx->huffman_tables->ac[1].code32[i],
|
|
base + REG_HTBL_CHROMA_ACLEN + i * sizeof(u32));
|
|
}
|
|
|
|
for (i = 0; i < (SMFC_NUM_AC_HVAL / 4); i++) {
|
|
__raw_writel(ctx->huffman_tables->ac[0].value32[i],
|
|
base + REG_HTBL_LUMA_ACVAL + i * sizeof(u32));
|
|
__raw_writel(ctx->huffman_tables->ac[1].value32[i],
|
|
base + REG_HTBL_CHROMA_ACVAL + i * sizeof(u32));
|
|
}
|
|
|
|
__raw_writel(tblsel, base + REG_MAIN_TABLE_SELECT);
|
|
}
|
|
|
|
static void smfc_hwconfigure_image_base(struct smfc_ctx *ctx,
|
|
struct vb2_buffer *vb2buf,
|
|
bool thumbnail)
|
|
{
|
|
dma_addr_t addr;
|
|
unsigned int i;
|
|
unsigned int num_buffers = ctx->img_fmt->num_buffers;
|
|
bool multiplane = (num_buffers == ctx->img_fmt->num_planes);
|
|
u32 off = thumbnail ? REG_SEC_IMAGE_BASE : REG_MAIN_IMAGE_BASE;
|
|
|
|
if (multiplane) {
|
|
/* Note that this includes a single-plane format such as YUYV */
|
|
for (i = 0; i < num_buffers; i++) {
|
|
addr = vb2_dma_sg_plane_dma_addr(vb2buf, i);
|
|
__raw_writel((u32)addr,
|
|
ctx->smfc->reg + REG_IMAGE_BASE(off, i));
|
|
}
|
|
} else {
|
|
u32 width = thumbnail ? ctx->thumb_width : ctx->width;
|
|
u32 height = thumbnail ? ctx->thumb_height : ctx->height;
|
|
addr = vb2_dma_sg_plane_dma_addr(vb2buf, thumbnail ? 1 : 0);
|
|
|
|
for (i = 0; i < ctx->img_fmt->num_planes; i++) {
|
|
__raw_writel((u32)addr,
|
|
ctx->smfc->reg + REG_IMAGE_BASE(off, i));
|
|
addr += (width * height * ctx->img_fmt->bpp_pix[i]) / 8;
|
|
}
|
|
}
|
|
}
|
|
|
|
static u32 smfc_hwconfigure_jpeg_base(struct smfc_ctx *ctx,
|
|
struct vb2_buffer *vb2buf,
|
|
u32 offset, bool thumbnail)
|
|
{
|
|
dma_addr_t addr;
|
|
u32 off = thumbnail ? REG_SEC_JPEG_BASE : REG_MAIN_JPEG_BASE;
|
|
|
|
addr = vb2_dma_sg_plane_dma_addr(vb2buf, thumbnail ? 1 : 0);
|
|
addr += offset;
|
|
__raw_writel((u32)addr, ctx->smfc->reg + off);
|
|
return (u32)addr;
|
|
}
|
|
|
|
/* [hfactor - 1][vfactor - 1]: 444, 422V, 422, 420 */
|
|
static u32 smfc_get_jpeg_format(unsigned int hfactor, unsigned int vfactor)
|
|
{
|
|
switch ((hfactor << 4) | vfactor) {
|
|
case 0x00: return 0 << 24;
|
|
case 0x11: return 1 << 24;
|
|
case 0x21: return 2 << 24;
|
|
case 0x22: return 3 << 24;
|
|
case 0x12: return 4 << 24;
|
|
case 0x41: return 5 << 24;
|
|
}
|
|
|
|
return 2 << 24; /* default: YUV422 */
|
|
}
|
|
|
|
void smfc_hwconfigure_2nd_image(struct smfc_ctx *ctx, bool hwfc_enabled)
|
|
{
|
|
struct vb2_buffer *vb2buf_img, *vb2buf_jpg;
|
|
u32 format;
|
|
|
|
if (!(ctx->flags & SMFC_CTX_COMPRESS))
|
|
return;
|
|
|
|
__raw_writel(ctx->thumb_width | (ctx->thumb_height << 16),
|
|
ctx->smfc->reg + REG_SEC_IMAGE_SIZE);
|
|
|
|
vb2buf_img = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
|
|
vb2buf_jpg = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
|
|
|
|
smfc_hwconfigure_image_base(ctx, vb2buf_img, true);
|
|
/*
|
|
* secondary image stream base is not required because there is no
|
|
* MAX_COMPRESSED_SIZE register for the secondary image
|
|
*/
|
|
smfc_hwconfigure_jpeg_base(ctx, vb2buf_jpg, 0, true);
|
|
|
|
format = ctx->img_fmt->regcfg;
|
|
/*
|
|
* Chroma subsampling is always 1/2 for both of horizontal and vertical
|
|
* directions to reduce the compressed size of the secondary image.
|
|
* If HWFC is enabled, the chroma subsampling is not allowed.
|
|
*/
|
|
if (hwfc_enabled)
|
|
format |= smfc_get_jpeg_format(ctx->img_fmt->chroma_hfactor,
|
|
ctx->img_fmt->chroma_vfactor);
|
|
else
|
|
format |= smfc_get_jpeg_format(2, 2);
|
|
|
|
__raw_writel(format, ctx->smfc->reg + REG_SEC_IMAGE_FORMAT);
|
|
}
|
|
|
|
void smfc_hwconfigure_image(struct smfc_ctx *ctx,
|
|
unsigned int hfactor, unsigned int vfactor)
|
|
{
|
|
struct vb2_v4l2_buffer *vb2buf_img, *vb2buf_jpg;
|
|
u32 stream_address;
|
|
u32 format = ctx->img_fmt->regcfg;
|
|
unsigned char num_plane = ctx->img_fmt->num_planes;
|
|
u32 burstlen = 1 << ctx->smfc->devdata->burstlenth_bits;
|
|
unsigned int i;
|
|
|
|
if (!(ctx->flags & SMFC_CTX_COMPRESS)) {
|
|
__raw_writel(ctx->width | (ctx->height << 16),
|
|
ctx->smfc->reg + REG_MAIN_IMAGE_SIZE);
|
|
|
|
vb2buf_img = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
|
|
vb2buf_jpg = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
|
|
format |= smfc_get_jpeg_format(hfactor, vfactor);
|
|
} else {
|
|
__raw_writel(ctx->crop.width | (ctx->crop.height << 16),
|
|
ctx->smfc->reg + REG_MAIN_IMAGE_SIZE);
|
|
|
|
for (i = 0; i < num_plane; i++) {
|
|
__raw_writel(ctx->crop.po[i],
|
|
ctx->smfc->reg + REG_MAIN_IMAGE_PO_PLANE(i));
|
|
__raw_writel(ctx->crop.so[i],
|
|
ctx->smfc->reg + REG_MAIN_IMAGE_SO_PLANE(i));
|
|
}
|
|
|
|
vb2buf_img = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
|
|
vb2buf_jpg = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
|
|
/*
|
|
* H/W JPEG does not allow upscaling of chroma components
|
|
* during compression
|
|
*/
|
|
format |= smfc_get_jpeg_format(
|
|
max_t(unsigned int, hfactor,
|
|
ctx->img_fmt->chroma_hfactor),
|
|
max_t(unsigned int, vfactor,
|
|
ctx->img_fmt->chroma_vfactor));
|
|
}
|
|
|
|
smfc_hwconfigure_image_base(ctx, &vb2buf_img->vb2_buf, false);
|
|
__raw_writel(format, ctx->smfc->reg + REG_MAIN_IMAGE_FORMAT);
|
|
|
|
stream_address = smfc_hwconfigure_jpeg_base(ctx, &vb2buf_jpg->vb2_buf,
|
|
ctx->offset_of_sos, false);
|
|
if (!(ctx->flags & SMFC_CTX_COMPRESS)) {
|
|
u32 streamsize = (u32)vb2_plane_size(&vb2buf_jpg->vb2_buf, 0);
|
|
|
|
streamsize -= ctx->offset_of_sos;
|
|
streamsize += stream_address & SMFC_ADDR_ALIGN_MASK(burstlen);
|
|
streamsize = ALIGN(streamsize, burstlen);
|
|
streamsize >>= ctx->smfc->devdata->burstlenth_bits;
|
|
__raw_writel(streamsize, ctx->smfc->reg + REG_MAIN_STREAM_SIZE);
|
|
}
|
|
}
|
|
|
|
void smfc_hwconfigure_start(struct smfc_ctx *ctx,
|
|
unsigned int rst_int, bool hwfc_en)
|
|
{
|
|
u32 cfg;
|
|
void __iomem *base = ctx->smfc->reg;
|
|
|
|
if (smfc_is_capable(ctx->smfc, V4L2_CAP_EXYNOS_JPEG_B2B_COMPRESSION))
|
|
__raw_writel(!(ctx->flags & SMFC_CTX_B2B_COMPRESS) ? 0 : 1,
|
|
base + REG_SEC_JPEG_CNTL);
|
|
|
|
/* configure "Error max compressed size" interrupt */
|
|
cfg = __raw_readl(base + REG_INT_EN);
|
|
if (hwfc_en) {
|
|
/*
|
|
* Timer interrupt should be disabled if HWFC is enabled.
|
|
* Instead OTF_EMU_HURRY_THRESHOLD interrupt is used for HWFC
|
|
* that is asserted when the synchronization between SMFC and
|
|
* MC-Scaler is broken.
|
|
*/
|
|
cfg &= ~(1 << 5);
|
|
cfg |= 1 << 12;
|
|
}
|
|
__raw_writel(cfg | (1 << 11), base + REG_INT_EN);
|
|
|
|
cfg = __raw_readl(base + REG_MAIN_JPEG_CNTL) & ~JPEG_CNTL_CODECON_MASK;
|
|
cfg |= !(ctx->flags & SMFC_CTX_COMPRESS) ?
|
|
JPEG_CNTL_CODECON_DECOMPRESS : JPEG_CNTL_CODECON_COMPRESS;
|
|
cfg |= 1 << 19; /* update huffman table from SFR */
|
|
cfg |= 1 << JPEG_CNTL_INT_EN_SHIFT; /* enable global interrupt */
|
|
cfg |= 1 << 29; /* Release reset */
|
|
if (hwfc_en) /* Enable OTF mode (default: emulation) */
|
|
cfg |= 1 << JPEG_CNTL_HWFC_EN_SHIFT;
|
|
if (rst_int != 0)
|
|
cfg |= (rst_int << 3) | (1 << 2);
|
|
if (!!(ctx->flags & SMFC_CTX_B2B_COMPRESS))
|
|
cfg |= 1 << JPEG_CNTL_BTB_EN_SHIFT; /* back-to-back enable */
|
|
|
|
writel(cfg, base + REG_MAIN_JPEG_CNTL);
|
|
}
|
|
|
|
bool smfc_hwstatus_okay(struct smfc_dev *smfc, struct smfc_ctx *ctx)
|
|
{
|
|
u32 val, reg;
|
|
u32 val2 = 0;
|
|
|
|
/* Disable global interrupt */
|
|
reg = __raw_readl(smfc->reg + REG_MAIN_JPEG_CNTL);
|
|
reg ^= 1 << JPEG_CNTL_INT_EN_SHIFT;
|
|
__raw_writel(reg, smfc->reg + REG_MAIN_JPEG_CNTL);
|
|
|
|
val = __raw_readl(smfc->reg + REG_MAIN_INT_STATUS);
|
|
if (smfc_is_capable(smfc, V4L2_CAP_EXYNOS_JPEG_B2B_COMPRESSION))
|
|
val2 = __raw_readl(smfc->reg + REG_SEC_INT_STATUS);
|
|
|
|
if (!val && !val2) {
|
|
dev_err(smfc->dev, "Interrupt with no state change\n");
|
|
return false;
|
|
}
|
|
|
|
if ((val & ~2)) {
|
|
dev_err(smfc->dev, "Error main interrupt %#010x.\n", val);
|
|
return false;
|
|
}
|
|
|
|
if ((val2 & ~2)) {
|
|
dev_err(smfc->dev, "Error secondary interrupt %#010x.\n", val);
|
|
return false;
|
|
}
|
|
|
|
if (ctx && !!(ctx->flags & SMFC_CTX_B2B_COMPRESS) && !val2) {
|
|
dev_err(smfc->dev, "Secondary image is not completed\n");
|
|
return false;
|
|
}
|
|
|
|
/* reset codec state to compression/decompression disabled */
|
|
reg = __raw_readl(smfc->reg + REG_MAIN_JPEG_CNTL);
|
|
reg &= ~JPEG_CNTL_RESET_MASK,
|
|
__raw_writel(reg, smfc->reg + REG_MAIN_JPEG_CNTL);
|
|
|
|
return true;
|
|
}
|
|
|
|
void smfc_dump_registers(struct smfc_dev *smfc)
|
|
{
|
|
u32 val;
|
|
|
|
/* Register dump based on Istor */
|
|
pr_info("DUMPING REGISTERS OF H/W JPEG...\n");
|
|
pr_info("------------------------------------------------\n");
|
|
/* JPEG_CNTL ~ FIFO_STATUS */
|
|
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 4,
|
|
smfc->reg + 0x000, 0xD4, false);
|
|
/* Reading quantization tables */
|
|
val = __raw_readl(smfc->reg + REG_MAIN_TABLE_SELECT);
|
|
__raw_writel(val | SMFC_TABLE_READ_REQ_MASK,
|
|
smfc->reg + REG_MAIN_TABLE_SELECT);
|
|
for (val = 0; val < 512; val++) {
|
|
if (!!(__raw_readl(smfc->reg + REG_MAIN_TABLE_SELECT)
|
|
& SMFC_TABLE_READ_OK_MASK))
|
|
break;
|
|
cpu_relax();
|
|
}
|
|
|
|
if ((val == 512) &&
|
|
!(__raw_readl(smfc->reg + REG_MAIN_TABLE_SELECT)
|
|
& SMFC_TABLE_READ_OK_MASK)) {
|
|
pr_info("** FAILED TO READ HUFFMAN and QUANTIZER TABLES **\n");
|
|
return;
|
|
}
|
|
|
|
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 4,
|
|
smfc->reg + 0x100, 0x2C0, false);
|
|
}
|