mirror of
https://github.com/thead-yocto-mirror/vi-kernel
synced 2026-06-21 17:02:34 +02:00
627 lines
20 KiB
C
Executable File
627 lines
20 KiB
C
Executable File
/****************************************************************************
|
|
*
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2020 VeriSilicon Holdings Co., Ltd.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*
|
|
*****************************************************************************
|
|
*
|
|
* The GPL License (GPL)
|
|
*
|
|
* Copyright (c) 2020 VeriSilicon Holdings Co., Ltd.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program;
|
|
*
|
|
*****************************************************************************
|
|
*
|
|
* Note: This software is released under dual MIT and GPL licenses. A
|
|
* recipient may use this file under the terms of either the MIT license or
|
|
* GPL License. If you wish to use only one license not the other, you can
|
|
* indicate your decision by deleting one of the above license notices in your
|
|
* version of this file.
|
|
*
|
|
*****************************************************************************/
|
|
#include "mrv_all_bits.h"
|
|
#include "isp_ioctl.h"
|
|
#include "isp_types.h"
|
|
|
|
#ifdef ISP_MIV1
|
|
|
|
extern MrvAllRegister_t *all_regs;
|
|
|
|
static int getRawBit(u32 type, u32 *bit, u32 *len)
|
|
{
|
|
*len = 16;
|
|
switch (type) {
|
|
case ISP_PICBUF_TYPE_RAW8:
|
|
*bit = 0;
|
|
*len = 8;
|
|
break;
|
|
#if 0 /* normal process, need pass type from engine. */
|
|
case ISP_PICBUF_TYPE_RAW10:
|
|
*bit = 1;
|
|
break;
|
|
case ISP_PICBUF_TYPE_RAW12:
|
|
*bit = 2;
|
|
break;
|
|
case ISP_PICBUF_TYPE_RAW14:
|
|
*bit = 3;
|
|
break;
|
|
case ISP_PICBUF_TYPE_RAW16:
|
|
*bit = 4;
|
|
break;
|
|
#else /* WA */
|
|
case ISP_PICBUF_TYPE_RAW10:
|
|
case ISP_PICBUF_TYPE_RAW12:
|
|
case ISP_PICBUF_TYPE_RAW14:
|
|
case ISP_PICBUF_TYPE_RAW16:
|
|
*bit = 4;
|
|
break;
|
|
#endif
|
|
default:
|
|
pr_err("unsupport raw formt: %d\n", type);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
int isp_ioc_cfg_dma(struct isp_ic_dev *dev, void __user *args)
|
|
{
|
|
return 0;
|
|
}
|
|
int isp_ioc_start_dma_read(struct isp_ic_dev *dev, void __user *args)
|
|
{
|
|
struct isp_dma_context dma;
|
|
u32 mi_dma_ctrl = isp_read_reg(dev, REG_ADDR(mi_dma_ctrl));
|
|
u32 llength = 0, mcm_rd_fmt_bit = 0;
|
|
u32 mi_imsc = 0, mcm_fmt = 0;
|
|
|
|
pr_info("enter %s\n", __func__);
|
|
viv_check_retval(copy_from_user(&dma, args, sizeof(dma)));
|
|
|
|
REG_SET_SLICE(mi_dma_ctrl, MRV_MI_DMA_BURST_LEN_LUM, dma.burst_y);
|
|
REG_SET_SLICE(mi_dma_ctrl, MRV_MI_DMA_BURST_LEN_CHROM, dma.burst_c);
|
|
|
|
isp_write_reg(dev, REG_ADDR(mi_dma_y_pic_start_ad),
|
|
(MRV_MI_DMA_Y_PIC_START_AD_MASK & dma.base));
|
|
getRawBit(dma.type, &mcm_rd_fmt_bit, &llength);
|
|
|
|
llength = dma.width * llength / 8;
|
|
REG_SET_SLICE(mcm_fmt, MCM_RD_RAW_BIT, mcm_rd_fmt_bit);
|
|
isp_write_reg(dev, REG_ADDR(mi_dma_y_pic_width),
|
|
(MRV_MI_DMA_Y_PIC_WIDTH_MASK & dma.width));
|
|
isp_write_reg(dev, REG_ADDR(mi_dma_y_llength),
|
|
(MRV_MI_DMA_Y_LLENGTH_MASK & llength));
|
|
isp_write_reg(dev, REG_ADDR(mi_dma_y_pic_size),
|
|
(MRV_MI_DMA_Y_PIC_SIZE_MASK & (llength * dma.height)));
|
|
isp_write_reg(dev, REG_ADDR(mi_dma_cb_pic_start_ad), 0);
|
|
isp_write_reg(dev, REG_ADDR(mi_dma_cr_pic_start_ad), 0);
|
|
isp_write_reg(dev, REG_ADDR(mi_dma_ctrl), mi_dma_ctrl);
|
|
|
|
isp_write_reg(dev, REG_ADDR(mi_dma_status), 0);
|
|
isp_write_reg(dev, REG_ADDR(mi_dma_y_raw_fmt), mcm_fmt);
|
|
isp_write_reg(dev, REG_ADDR(mi_dma_y_raw_lval),
|
|
(MRV_MI_DMA_Y_LLENGTH_MASK & llength));
|
|
|
|
mi_imsc = isp_read_reg(dev, REG_ADDR(mi_imsc));
|
|
mi_imsc |= MRV_MI_DMA_READY_MASK;
|
|
|
|
isp_write_reg(dev, REG_ADDR(mi_imsc), mi_imsc);
|
|
isp_write_reg(dev, REG_ADDR(mi_dma_start), MRV_MI_DMA_START_MASK);
|
|
return 0;
|
|
}
|
|
|
|
u32 getScaleFactor(u32 src, u32 dst)
|
|
{
|
|
if (dst > src) {
|
|
return ((65536 * (src - 1)) / (dst - 1));
|
|
} else if (dst < src) {
|
|
return ((65536 * (dst - 1)) / (src - 1)) + 1;
|
|
}
|
|
return 65536;
|
|
}
|
|
|
|
int set_scaling(int id, struct isp_ic_dev *dev, bool stabilization)
|
|
{
|
|
u32 addr, ctrl;
|
|
u32 iw, ih, ow, oh;
|
|
u32 inputWidth, inputHeight, outputWidth, outputHeight;
|
|
u32 scale_hy, scale_hcb, scale_hcr, scale_vy, scale_vc;
|
|
struct isp_mi_data_path_context *path = &dev->mi.path[id];
|
|
|
|
if (id == IC_MI_PATH_MAIN) { /* mp */
|
|
addr = REG_ADDR(mrsz_ctrl);
|
|
} else if (id == IC_MI_PATH_SELF) { /* sp */
|
|
addr = REG_ADDR(srsz_ctrl);
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
|
|
inputWidth = path->in_width;
|
|
inputHeight = path->in_height;
|
|
outputWidth = path->out_width;
|
|
outputHeight = path->out_height;
|
|
|
|
if (stabilization) { /* enabled image stabilization. */
|
|
inputWidth = isp_read_reg(dev, REG_ADDR(isp_is_h_size));
|
|
inputHeight = isp_read_reg(dev, REG_ADDR(isp_is_v_size));
|
|
}
|
|
|
|
ctrl = isp_read_reg(dev, addr);
|
|
iw = inputWidth / 2;
|
|
ih = inputHeight;
|
|
ow = outputWidth / 2;
|
|
oh = outputHeight;
|
|
|
|
switch (path->in_mode) {
|
|
case IC_MI_DATAMODE_YUV422:
|
|
oh = outputHeight;
|
|
break;
|
|
case IC_MI_DATAMODE_YUV420:
|
|
oh = outputHeight / 2; /* scale cbcr */
|
|
break;
|
|
default:
|
|
return -EFAULT;
|
|
}
|
|
|
|
REG_SET_SLICE(ctrl, MRV_MRSZ_SCALE_HY_ENABLE,
|
|
inputWidth != outputWidth);
|
|
REG_SET_SLICE(ctrl, MRV_MRSZ_SCALE_VY_ENABLE,
|
|
inputHeight != outputHeight);
|
|
REG_SET_SLICE(ctrl, MRV_MRSZ_SCALE_HY_UP, inputWidth < outputWidth);
|
|
REG_SET_SLICE(ctrl, MRV_MRSZ_SCALE_VY_UP, inputHeight < outputHeight);
|
|
scale_hy = getScaleFactor(inputWidth, outputWidth);
|
|
scale_vy = getScaleFactor(inputHeight, outputHeight);
|
|
REG_SET_SLICE(ctrl, MRV_MRSZ_SCALE_HC_ENABLE, iw != ow);
|
|
REG_SET_SLICE(ctrl, MRV_MRSZ_SCALE_VC_ENABLE, ih != oh);
|
|
REG_SET_SLICE(ctrl, MRV_MRSZ_SCALE_HC_UP, iw < ow);
|
|
REG_SET_SLICE(ctrl, MRV_MRSZ_SCALE_VC_UP, ih < oh);
|
|
scale_hcr = getScaleFactor(iw, ow);
|
|
scale_hcb = getScaleFactor(iw, ow);
|
|
scale_vc = getScaleFactor(ih, oh);
|
|
|
|
REG_SET_SLICE(ctrl, MRV_MRSZ_AUTO_UPD, 1);
|
|
|
|
if (id == IC_MI_PATH_MAIN) {
|
|
isp_write_reg(dev, REG_ADDR(mrsz_scale_vc), scale_vc);
|
|
isp_write_reg(dev, REG_ADDR(mrsz_scale_vy), scale_vy);
|
|
isp_write_reg(dev, REG_ADDR(mrsz_scale_hcr), scale_hcr);
|
|
isp_write_reg(dev, REG_ADDR(mrsz_scale_hcb), scale_hcb);
|
|
isp_write_reg(dev, REG_ADDR(mrsz_scale_hy), scale_hy);
|
|
isp_write_reg(dev, REG_ADDR(mrsz_ctrl),
|
|
ctrl | MRV_MRSZ_CFG_UPD_MASK);
|
|
} else if (id == IC_MI_PATH_SELF) {
|
|
isp_write_reg(dev, REG_ADDR(srsz_scale_vc), scale_vc);
|
|
isp_write_reg(dev, REG_ADDR(srsz_scale_vy), scale_vy);
|
|
isp_write_reg(dev, REG_ADDR(srsz_scale_hcr), scale_hcr);
|
|
isp_write_reg(dev, REG_ADDR(srsz_scale_hcb), scale_hcb);
|
|
isp_write_reg(dev, REG_ADDR(srsz_scale_hy), scale_hy);
|
|
isp_write_reg(dev, REG_ADDR(srsz_ctrl),
|
|
ctrl | MRV_MRSZ_CFG_UPD_MASK);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef ISP_MI_BP
|
|
int isp_bppath_start(struct isp_ic_dev *dev)
|
|
{
|
|
struct isp_mi_context mi = *(&dev->mi);
|
|
u32 bp_ctrl = 0, lval = 0;
|
|
struct isp_mi_data_path_context *path = &mi.path[2];
|
|
u32 mi_imsc = isp_read_reg(dev, REG_ADDR(mi_imsc));
|
|
int i;
|
|
|
|
pr_info("enter %s\n", __func__);
|
|
bp_ctrl = 0;
|
|
lval = path->out_width;
|
|
|
|
if (mi.path[2].enable) {
|
|
bp_ctrl &= ~MRV_MI_BP_WRITE_RAWBIT_MASK;
|
|
|
|
if (path->data_alignMode == ISP_MI_DATA_ALIGN_16BIT_MODE) {
|
|
if ((path->out_mode == IC_MI_DATAMODE_RAW10) ||
|
|
(path->out_mode == IC_MI_DATAMODE_RAW12) ||
|
|
(path->out_mode == IC_MI_DATAMODE_RAW14)) {
|
|
lval = (path->out_width + 3) / 4;
|
|
}
|
|
} else if (path->data_alignMode ==
|
|
ISP_MI_DATA_ALIGN_128BIT_MODE) {
|
|
if ((path->out_mode == IC_MI_DATAMODE_RAW10)
|
|
|| (path->out_mode == IC_MI_DATAMODE_RAW12)
|
|
|| (path->out_mode == IC_MI_DATAMODE_RAW14)) {
|
|
lval = (path->out_width * 2 + 126) / 128;
|
|
}
|
|
} else {
|
|
if (path->out_mode == IC_MI_DATAMODE_RAW10) {
|
|
lval = (path->out_width * 10 + 63) / 64;
|
|
} else if (path->out_mode == IC_MI_DATAMODE_RAW12) {
|
|
lval = (path->out_width * 12 + 63) / 64;
|
|
} else if (path->out_mode == IC_MI_DATAMODE_RAW14) {
|
|
lval = (path->out_width * 14 + 63) / 64;
|
|
} else if (path->out_mode == IC_MI_DATAMODE_RAW16) {
|
|
lval = (path->out_width * 16 + 63) / 64;
|
|
} else {
|
|
lval = (path->out_width * 8 + 63) / 64;
|
|
}
|
|
}
|
|
lval <<= 3;
|
|
REG_SET_SLICE(bp_ctrl, BP_WR_RAW_ALIGNED, path->data_alignMode);
|
|
switch (mi.path[2].out_mode) {
|
|
case (IC_MI_DATAMODE_RAW8):
|
|
REG_SET_SLICE(bp_ctrl, MRV_MI_BP_WRITE_RAWBIT,
|
|
MRV_MI_BP_WRITE_RAWBIT_RAW_8);
|
|
REG_SET_SLICE(bp_ctrl, MRV_MI_BP_WRITE_FORMAT,
|
|
MRV_MI_BP_WRITE_INTERLEAVE_FORMAT);
|
|
break;
|
|
case (IC_MI_DATAMODE_RAW12):
|
|
REG_SET_SLICE(bp_ctrl, BP_WR_BYTE_SWAP, 1);
|
|
REG_SET_SLICE(bp_ctrl, MRV_MI_BP_WRITE_RAWBIT,
|
|
MRV_MI_BP_WRITE_RAWBIT_RAW_12);
|
|
REG_SET_SLICE(bp_ctrl, MRV_MI_BP_WRITE_FORMAT,
|
|
MRV_MI_BP_WRITE_INTERLEAVE_FORMAT);
|
|
break;
|
|
case (IC_MI_DATAMODE_RAW10):
|
|
REG_SET_SLICE(bp_ctrl, BP_WR_BYTE_SWAP, 1);
|
|
REG_SET_SLICE(bp_ctrl, MRV_MI_BP_WRITE_RAWBIT,
|
|
MRV_MI_BP_WRITE_RAWBIT_RAW_10);
|
|
REG_SET_SLICE(bp_ctrl, MRV_MI_BP_WRITE_FORMAT,
|
|
MRV_MI_BP_WRITE_INTERLEAVE_FORMAT);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
isp_write_reg(dev, REG_ADDR(mi_bp_wr_size_init),
|
|
lval * mi.path[2].out_height);
|
|
isp_write_reg(dev, REG_ADDR(mi_bp_pic_width),
|
|
mi.path[2].out_width);
|
|
isp_write_reg(dev, REG_ADDR(mi_bp_wr_llength), lval);
|
|
isp_write_reg(dev, REG_ADDR(mi_bp_pic_height),
|
|
mi.path[2].out_height);
|
|
isp_write_reg(dev, REG_ADDR(mi_bp_pic_size),
|
|
lval * mi.path[2].out_height);
|
|
/* enable frame end irq for bp path */
|
|
mi_imsc |=
|
|
MRV_MI_BP_FRAME_END_MASK | MRV_MI_BP_WRAP_R_MASK |
|
|
MRV_MI_BP_WRAP_GR_MASK | MRV_MI_BP_WRAP_GB_MASK |
|
|
MRV_MI_BP_WRAP_B_MASK;
|
|
}
|
|
if (!dev->rawis.enable) {
|
|
isp_write_reg(dev, REG_ADDR(isp_raw_is_h_size),
|
|
mi.path[2].out_width);
|
|
isp_write_reg(dev, REG_ADDR(isp_raw_is_v_size),
|
|
mi.path[2].out_height);
|
|
isp_write_reg(dev, REG_ADDR(isp_raw_is_ctrl), 0);
|
|
}
|
|
bp_ctrl |= MRV_MI_BP_PATH_ENABLE_MASK;
|
|
isp_write_reg(dev, REG_ADDR(mi_bp_ctrl), bp_ctrl);
|
|
|
|
isp_write_reg(dev, REG_ADDR(mi_imsc), mi_imsc);
|
|
return 0;
|
|
}
|
|
#endif
|
|
int isp_mi_start(struct isp_ic_dev *dev)
|
|
{
|
|
struct isp_mi_context mi = *(&dev->mi);
|
|
u32 mi_init, mi_ctrl, mi_imsc;
|
|
u32 out_stride;
|
|
int i;
|
|
u8 retry = 3;
|
|
|
|
pr_info("enter %s\n", __func__);
|
|
|
|
isp_write_reg(dev, REG_ADDR(mrsz_ctrl), 0);
|
|
isp_write_reg(dev, REG_ADDR(mrsz_ctrl_shd), 0);
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
if (mi.path[i].hscale || mi.path[i].vscale) {
|
|
set_scaling(i, dev, dev->is.enable);
|
|
}
|
|
}
|
|
|
|
mi_init = 0;
|
|
mi_ctrl = 0;
|
|
mi_imsc = 0;
|
|
if (mi.path[0].enable) {
|
|
/* remove update enable bits for offset and base registers */
|
|
mi_init &= ~MRV_MI_MP_OUTPUT_FORMAT_MASK;
|
|
mi_ctrl &= ~MRV_MI_MP_WRITE_FORMAT_MASK;
|
|
|
|
/* config mi_init output format for yuv format */
|
|
if (mi.path[0].out_mode <= IC_MI_DATAMODE_YUV400)
|
|
REG_SET_SLICE(mi_init, MRV_MI_MP_OUTPUT_FORMAT,
|
|
IC_MI_DATAMODE_YUV400 -
|
|
mi.path[0].out_mode);
|
|
switch (mi.path[0].out_mode) {
|
|
case (IC_MI_DATAMODE_RAW8):
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_MP_WRITE_FORMAT,
|
|
MRV_MI_MP_WRITE_FORMAT_RAW_8);
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_RAW_ENABLE, 1);
|
|
REG_SET_SLICE(mi_init, MRV_MI_MP_OUTPUT_FORMAT,
|
|
MRV_MI_MP_OUTPUT_FORMAT_RAW8);
|
|
break;
|
|
case (IC_MI_DATAMODE_RAW12):
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_MP_WRITE_FORMAT,
|
|
MRV_MI_MP_WRITE_FORMAT_RAW_12);
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_RAW_ENABLE, 1);
|
|
REG_SET_SLICE(mi_init, MRV_MI_MP_OUTPUT_FORMAT,
|
|
MRV_MI_MP_OUTPUT_FORMAT_RAW12);
|
|
isp_write_reg(dev, REG_ADDR(mi_output_align_format), 1);
|
|
break;
|
|
case (IC_MI_DATAMODE_RAW10):
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_MP_WRITE_FORMAT,
|
|
MRV_MI_MP_WRITE_FORMAT_RAW_12);
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_RAW_ENABLE, 1);
|
|
REG_SET_SLICE(mi_init, MRV_MI_MP_OUTPUT_FORMAT,
|
|
MRV_MI_MP_OUTPUT_FORMAT_RAW10);
|
|
isp_write_reg(dev, REG_ADDR(mi_output_align_format), 1);
|
|
break;
|
|
case (IC_MI_DATAMODE_JPEG):
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_MP_WRITE_FORMAT,
|
|
MRV_MI_MP_WRITE_FORMAT_PLANAR);
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_JPEG_ENABLE, 1);
|
|
break;
|
|
case (IC_MI_DATAMODE_YUV444):
|
|
case (IC_MI_DATAMODE_YUV422):
|
|
case (IC_MI_DATAMODE_YUV420):
|
|
case (IC_MI_DATAMODE_YUV400):
|
|
if (mi.path[0].data_layout == IC_MI_DATASTORAGE_PLANAR) {
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_MP_WRITE_FORMAT,
|
|
MRV_MI_MP_WRITE_FORMAT_PLANAR);
|
|
} else if (mi.path[0].data_layout ==
|
|
IC_MI_DATASTORAGE_SEMIPLANAR) {
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_MP_WRITE_FORMAT,
|
|
MRV_MI_MP_WRITE_FORMAT_SEMIPLANAR);
|
|
} else if (mi.path[0].data_layout ==
|
|
IC_MI_DATASTORAGE_INTERLEAVED) {
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_MP_WRITE_FORMAT,
|
|
MRV_MI_MP_WRITE_FORMAT_INTERLEAVED);
|
|
} else {
|
|
break;
|
|
}
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_MP_ENABLE, 1);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
out_stride = mi.path[0].data_layout ==
|
|
IC_MI_DATASTORAGE_INTERLEAVED ?
|
|
(mi.path[0].out_width * 2) : (mi.path[0].out_width);
|
|
isp_write_reg(dev, REG_ADDR(mi_mp_y_pic_width), out_stride);
|
|
isp_write_reg(dev, REG_ADDR(mi_mp_y_llength), out_stride);
|
|
isp_write_reg(dev, REG_ADDR(mi_mp_y_pic_height),
|
|
mi.path[0].out_height);
|
|
isp_write_reg(dev, REG_ADDR(mi_mp_y_pic_size),
|
|
out_stride * mi.path[0].out_height);
|
|
|
|
/* workaround to resolve the problem that the mi_mp_y_pic_width can't be written */
|
|
for(i = 0; i < retry; i++) {
|
|
if(isp_read_reg(dev, REG_ADDR(mi_mp_y_pic_width)) != out_stride) {
|
|
isp_write_reg(dev, REG_ADDR(mi_mp_y_pic_width), out_stride);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
if(retry == i) {
|
|
pr_info("%s: update mi_mp_y_pic_width error!\n", __func__);
|
|
}
|
|
|
|
/* enable frame end irq for main path */
|
|
mi_imsc |=
|
|
(MRV_MI_MP_FRAME_END_MASK | MRV_MI_WRAP_MP_Y_MASK |
|
|
MRV_MI_WRAP_MP_CB_MASK | MRV_MI_WRAP_MP_CR_MASK);
|
|
}
|
|
|
|
if (mi.path[1].enable) {
|
|
/* setup mi for self-path */
|
|
mi_ctrl &= ~(MRV_MI_SP_WRITE_FORMAT_MASK);
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_SP_INPUT_FORMAT,
|
|
mi.path[1].in_mode - 1);
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_SP_OUTPUT_FORMAT,
|
|
mi.path[1].out_mode - 1);
|
|
|
|
switch (mi.path[1].out_mode) {
|
|
case (IC_MI_DATAMODE_RGB888):
|
|
case (IC_MI_DATAMODE_RGB666):
|
|
case (IC_MI_DATAMODE_RGB565):
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_SP_WRITE_FORMAT,
|
|
MRV_MI_SP_WRITE_FORMAT_RGB_INTERLEAVED);
|
|
break;
|
|
case (IC_MI_DATAMODE_YUV444):
|
|
case (IC_MI_DATAMODE_YUV400):
|
|
if (mi.path[1].data_layout == IC_MI_DATASTORAGE_PLANAR) {
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_SP_WRITE_FORMAT,
|
|
MRV_MI_SP_WRITE_FORMAT_PLANAR);
|
|
}
|
|
break;
|
|
case (IC_MI_DATAMODE_YUV422):
|
|
switch (mi.path[1].data_layout) {
|
|
case (IC_MI_DATASTORAGE_PLANAR):
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_SP_WRITE_FORMAT,
|
|
MRV_MI_SP_WRITE_FORMAT_PLANAR);
|
|
break;
|
|
case (IC_MI_DATASTORAGE_SEMIPLANAR):
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_SP_WRITE_FORMAT,
|
|
MRV_MI_SP_WRITE_FORMAT_SEMIPLANAR);
|
|
break;
|
|
case (IC_MI_DATASTORAGE_INTERLEAVED):
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_SP_WRITE_FORMAT,
|
|
MRV_MI_SP_WRITE_FORMAT_INTERLEAVED);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case (IC_MI_DATAMODE_YUV420):
|
|
switch (mi.path[1].data_layout) {
|
|
case (IC_MI_DATASTORAGE_PLANAR):
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_SP_WRITE_FORMAT,
|
|
MRV_MI_SP_WRITE_FORMAT_PLANAR);
|
|
break;
|
|
case (IC_MI_DATASTORAGE_SEMIPLANAR):
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_SP_WRITE_FORMAT,
|
|
MRV_MI_SP_WRITE_FORMAT_SEMIPLANAR);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
out_stride = mi.path[1].data_layout ==
|
|
IC_MI_DATASTORAGE_INTERLEAVED ?
|
|
mi.path[1].out_width * 2 : mi.path[1].out_width;
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_SP_ENABLE, 1);
|
|
isp_write_reg(dev, REG_ADDR(mi_sp_y_pic_width), out_stride);
|
|
isp_write_reg(dev, REG_ADDR(mi_sp_y_llength), out_stride);
|
|
isp_write_reg(dev, REG_ADDR(mi_sp_y_pic_height),
|
|
mi.path[1].out_height);
|
|
isp_write_reg(dev, REG_ADDR(mi_sp_y_pic_size),
|
|
out_stride * mi.path[1].out_height);
|
|
/* enable frame end interrupt on self path */
|
|
mi_imsc |=
|
|
(MRV_MI_SP_FRAME_END_MASK | MRV_MI_WRAP_SP_Y_MASK |
|
|
MRV_MI_WRAP_SP_CB_MASK | MRV_MI_WRAP_SP_CR_MASK);
|
|
}
|
|
|
|
#if defined(__KERNEL__) && defined(ENABLE_IRQ)
|
|
for (i = 0; i < MI_PATH_NUM; ++i) {
|
|
dev->mi_buf[i] = NULL;
|
|
dev->mi_buf_shd[i] = NULL;
|
|
}
|
|
if (dev->state)
|
|
*dev->state |= STATE_DRIVER_STARTED;
|
|
#endif
|
|
|
|
mi_ctrl |= (MRV_MI_INIT_BASE_EN_MASK | MRV_MI_INIT_OFFSET_EN_MASK);
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_BURST_LEN_CHROM, mi.burst_len);
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_BURST_LEN_LUM, mi.burst_len);
|
|
isp_write_reg(dev, REG_ADDR(mi_ctrl), mi_ctrl | 0x2000);
|
|
REG_SET_SLICE(mi_init, MRV_MI_MI_CFG_UPD, 1);
|
|
|
|
isp_write_reg(dev, REG_ADDR(mi_imsc), mi_imsc);
|
|
#ifdef ISP_MI_BP
|
|
isp_bppath_start(dev);
|
|
#endif
|
|
isp_write_reg(dev, REG_ADDR(mi_init), mi_init);
|
|
return 0;
|
|
}
|
|
|
|
int isp_mi_stop(struct isp_ic_dev *dev)
|
|
{
|
|
u32 mi_ctrl = 0, mi_init = 0;
|
|
pr_info("enter %s\n", __func__);
|
|
|
|
isp_write_reg(dev, REG_ADDR(mi_imsc), 0);
|
|
|
|
/* disable mi path */
|
|
mi_ctrl = isp_read_reg(dev, REG_ADDR(mi_ctrl));
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_MP_ENABLE, 0);
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_SP_ENABLE, 0);
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_JPEG_ENABLE, 0);
|
|
REG_SET_SLICE(mi_ctrl, MRV_MI_RAW_ENABLE, 0);
|
|
isp_write_reg(dev, REG_ADDR(mi_ctrl), mi_ctrl);
|
|
|
|
mi_init = isp_read_reg(dev, REG_ADDR(mi_init));
|
|
REG_SET_SLICE(mi_init, MRV_MI_MI_CFG_UPD, 1);
|
|
isp_write_reg(dev, REG_ADDR(mi_init), mi_init);
|
|
|
|
#if defined(__KERNEL__) && defined(ENABLE_IRQ)
|
|
if (dev->state)
|
|
*dev->state &= ~STATE_DRIVER_STARTED;
|
|
clean_dma_buffer(dev);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
int isp_set_buffer(struct isp_ic_dev *dev, struct isp_buffer_context *buf)
|
|
{
|
|
u32 addr;
|
|
|
|
if (!dev || !buf) {
|
|
pr_err("NULL pointer %s\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
addr = buf->path == 0 ?
|
|
REG_ADDR(mi_mp_y_base_ad_init) : REG_ADDR(mi_sp_y_base_ad_init);
|
|
isp_write_reg(dev, addr, (buf->addr_y & MRV_MI_MP_Y_BASE_AD_INIT_MASK));
|
|
isp_write_reg(dev, addr + 1 * 4,
|
|
(buf->size_y & MRV_MI_MP_Y_SIZE_INIT_MASK));
|
|
isp_write_reg(dev, addr + 2 * 4, 0);
|
|
isp_write_reg(dev, addr + 5 * 4,
|
|
(buf->addr_cb & MRV_MI_MP_CB_BASE_AD_INIT_MASK));
|
|
isp_write_reg(dev, addr + 6 * 4,
|
|
(buf->size_cb & MRV_MI_MP_CB_SIZE_INIT_MASK));
|
|
isp_write_reg(dev, addr + 7 * 4, 0);
|
|
isp_write_reg(dev, addr + 9 * 4,
|
|
(buf->addr_cr & MRV_MI_MP_CR_BASE_AD_INIT_MASK));
|
|
isp_write_reg(dev, addr + 10 * 4,
|
|
(buf->size_cr & MRV_MI_MP_CR_SIZE_INIT_MASK));
|
|
isp_write_reg(dev, addr + 11 * 4, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int isp_set_bp_buffer(struct isp_ic_dev *dev, struct isp_bp_buffer_context *buf)
|
|
{
|
|
#ifndef ISP_MI_BP
|
|
pr_err("unsupported function: %s", __func__);
|
|
return -EINVAL;
|
|
#else
|
|
isp_write_reg(dev, REG_ADDR(mi_bp_r_base_ad_init),
|
|
(buf->addr_r & BP_R_BASE_AD_INIT_MASK));
|
|
isp_write_reg(dev, REG_ADDR(mi_bp_gr_base_ad_init),
|
|
(buf->addr_gr & BP_GR_BASE_AD_INIT_MASK));
|
|
|
|
isp_write_reg(dev, REG_ADDR(mi_bp_gb_base_ad_init),
|
|
(buf->addr_gb & BP_GB_BASE_AD_INIT_MASK));
|
|
isp_write_reg(dev, REG_ADDR(mi_bp_b_base_ad_init),
|
|
(buf->addr_b & BP_B_BASE_AD_INIT_MASK));
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
u32 isp_read_mi_irq(struct isp_ic_dev * dev)
|
|
{
|
|
return isp_read_reg(dev, REG_ADDR(mi_mis));
|
|
}
|
|
|
|
void isp_reset_mi_irq(struct isp_ic_dev *dev, u32 icr)
|
|
{
|
|
isp_write_reg(dev, REG_ADDR(mi_icr), icr);
|
|
}
|
|
|
|
#endif
|