1754 lines
51 KiB
C
1754 lines
51 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */
|
|
|
|
#include <linux/clk.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/pm_runtime.h>
|
|
#include <linux/slab.h>
|
|
#include <media/v4l2-common.h>
|
|
#include <media/v4l2-event.h>
|
|
#include <media/v4l2-fh.h>
|
|
#include <media/v4l2-ioctl.h>
|
|
#include <media/v4l2-mc.h>
|
|
#include <media/v4l2-subdev.h>
|
|
#include <media/videobuf2-dma-contig.h>
|
|
#include <media/videobuf2-dma-sg.h>
|
|
#include <linux/rk-isp1-config.h>
|
|
#include <uapi/linux/rk-video-format.h>
|
|
|
|
#include "dev.h"
|
|
#include "regs.h"
|
|
|
|
|
|
/*
|
|
* DDR->| |->MB------->DDR
|
|
* |->TNR->DDR->NR->SHARP->DDR->FEC->|->SCL0----->DDR
|
|
* ISP->| |->SCL1----->DDR
|
|
* |->SCL2----->DDR
|
|
*/
|
|
|
|
static void rkispp_module_work_event(struct rkispp_device *dev,
|
|
void *buf_rd, void *buf_wr,
|
|
u32 module, bool is_isr);
|
|
|
|
static void set_y_addr(struct rkispp_stream *stream, u32 val)
|
|
{
|
|
rkispp_write(stream->isppdev, stream->config->reg.cur_y_base, val);
|
|
}
|
|
|
|
static void set_uv_addr(struct rkispp_stream *stream, u32 val)
|
|
{
|
|
rkispp_write(stream->isppdev, stream->config->reg.cur_uv_base, val);
|
|
}
|
|
|
|
static enum hrtimer_restart rkispp_frame_done_early(struct hrtimer *timer)
|
|
{
|
|
struct rkispp_stream_vdev *vdev =
|
|
container_of(timer, struct rkispp_stream_vdev, frame_qst);
|
|
struct rkispp_stream *stream = &vdev->stream[0];
|
|
struct rkispp_device *dev = stream->isppdev;
|
|
void __iomem *base = dev->hw_dev->base_addr;
|
|
bool is_fec_en = (vdev->module_ens & ISPP_MODULE_FEC);
|
|
enum hrtimer_restart ret = HRTIMER_NORESTART;
|
|
u32 threshold = vdev->wait_line / 128;
|
|
u32 tile, tile_mask, working, work_mask;
|
|
u32 i, seq, ycnt, shift, time, max_time;
|
|
u64 t, ns = ktime_get_ns();
|
|
|
|
working = readl(base + RKISPP_CTRL_SYS_STATUS);
|
|
tile = readl(base + RKISPP_CTRL_SYS_CTL_STA0);
|
|
if (is_fec_en) {
|
|
shift = 16;
|
|
work_mask = FEC_WORKING;
|
|
tile_mask = FEC_TILE_LINE_CNT_MASK;
|
|
t = vdev->fec.dbg.timestamp;
|
|
seq = vdev->fec.dbg.id;
|
|
max_time = 6000000;
|
|
} else {
|
|
shift = 8;
|
|
work_mask = NR_WORKING;
|
|
tile_mask = NR_TILE_LINE_CNT_MASK;
|
|
t = vdev->nr.dbg.timestamp;
|
|
seq = vdev->nr.dbg.id;
|
|
max_time = 2000000;
|
|
}
|
|
working &= work_mask;
|
|
tile &= tile_mask;
|
|
ycnt = tile >> shift;
|
|
time = (u32)(ns - t);
|
|
if (dev->ispp_sdev.state == ISPP_STOP) {
|
|
vdev->is_done_early = false;
|
|
goto end;
|
|
} else if (working && ycnt < threshold) {
|
|
if (!ycnt)
|
|
ns = max_time;
|
|
else
|
|
ns = time * (threshold - ycnt) / ycnt + 100 * 1000;
|
|
if (ns > max_time)
|
|
ns = max_time;
|
|
hrtimer_forward(timer, timer->base->get_time(), ns_to_ktime(ns));
|
|
ret = HRTIMER_RESTART;
|
|
} else {
|
|
v4l2_dbg(3, rkispp_debug, &stream->isppdev->v4l2_dev,
|
|
"%s seq:%d line:%d ycnt:%d time:%dus\n",
|
|
__func__, seq, vdev->wait_line, ycnt * 128, time / 1000);
|
|
for (i = 0; i < dev->stream_max; i++) {
|
|
stream = &vdev->stream[i];
|
|
if (!stream->streaming || !stream->is_cfg || stream->stopping)
|
|
continue;
|
|
rkispp_frame_end(stream, FRAME_WORK);
|
|
}
|
|
}
|
|
end:
|
|
return ret;
|
|
}
|
|
|
|
static void update_mi(struct rkispp_stream *stream)
|
|
{
|
|
struct rkispp_device *dev = stream->isppdev;
|
|
struct rkispp_dummy_buffer *dummy_buf;
|
|
u32 val;
|
|
|
|
if (stream->curr_buf) {
|
|
val = stream->curr_buf->buff_addr[RKISPP_PLANE_Y];
|
|
set_y_addr(stream, val);
|
|
val = stream->curr_buf->buff_addr[RKISPP_PLANE_UV];
|
|
set_uv_addr(stream, val);
|
|
}
|
|
|
|
if (stream->type == STREAM_OUTPUT && !stream->curr_buf) {
|
|
dummy_buf = &dev->hw_dev->dummy_buf;
|
|
set_y_addr(stream, dummy_buf->dma_addr);
|
|
set_uv_addr(stream, dummy_buf->dma_addr);
|
|
}
|
|
|
|
v4l2_dbg(2, rkispp_debug, &stream->isppdev->v4l2_dev,
|
|
"%s stream:%d Y:0x%x UV:0x%x\n",
|
|
__func__, stream->id,
|
|
rkispp_read(dev, stream->config->reg.cur_y_base),
|
|
rkispp_read(dev, stream->config->reg.cur_uv_base));
|
|
}
|
|
|
|
static bool is_en_done_early(struct rkispp_device *dev)
|
|
{
|
|
u32 height = dev->ispp_sdev.out_fmt.height;
|
|
u32 line = dev->stream_vdev.wait_line;
|
|
bool en = false;
|
|
|
|
if (line) {
|
|
if (line > height - 128)
|
|
dev->stream_vdev.wait_line = height - 128;
|
|
en = true;
|
|
v4l2_dbg(1, rkispp_debug, &dev->v4l2_dev,
|
|
"wait %d line to wake up frame\n", line);
|
|
}
|
|
|
|
return en;
|
|
}
|
|
|
|
static void tnr_free_buf(struct rkispp_device *dev)
|
|
{
|
|
struct rkispp_stream_vdev *vdev = &dev->stream_vdev;
|
|
struct rkisp_ispp_buf *dbufs;
|
|
struct list_head *list;
|
|
int i;
|
|
|
|
list = &vdev->tnr.list_rd;
|
|
if (vdev->tnr.cur_rd) {
|
|
list_add_tail(&vdev->tnr.cur_rd->list, list);
|
|
if (vdev->tnr.nxt_rd == vdev->tnr.cur_rd)
|
|
vdev->tnr.nxt_rd = NULL;
|
|
vdev->tnr.cur_rd = NULL;
|
|
}
|
|
if (vdev->tnr.nxt_rd) {
|
|
list_add_tail(&vdev->tnr.nxt_rd->list, list);
|
|
vdev->tnr.nxt_rd = NULL;
|
|
}
|
|
while (!list_empty(list)) {
|
|
dbufs = get_list_buf(list, true);
|
|
v4l2_subdev_call(dev->ispp_sdev.remote_sd,
|
|
video, s_rx_buffer, dbufs, NULL);
|
|
}
|
|
|
|
list = &vdev->tnr.list_wr;
|
|
if (vdev->tnr.cur_wr) {
|
|
list_add_tail(&vdev->tnr.cur_wr->list, list);
|
|
vdev->tnr.cur_wr = NULL;
|
|
}
|
|
while (!list_empty(list)) {
|
|
dbufs = get_list_buf(list, true);
|
|
kfree(dbufs);
|
|
}
|
|
list = &vdev->tnr.list_rpt;
|
|
while (!list_empty(list)) {
|
|
dbufs = get_list_buf(list, true);
|
|
kfree(dbufs);
|
|
}
|
|
|
|
for (i = 0; i < sizeof(vdev->tnr.buf) /
|
|
sizeof(struct rkispp_dummy_buffer); i++)
|
|
rkispp_free_buffer(dev, &vdev->tnr.buf.iir + i);
|
|
|
|
vdev->tnr.is_buf_init = false;
|
|
vdev->tnr.is_trigger = false;
|
|
}
|
|
|
|
static int tnr_init_buf(struct rkispp_device *dev,
|
|
u32 pic_size, u32 gain_size)
|
|
{
|
|
struct rkispp_stream_vdev *vdev = &dev->stream_vdev;
|
|
struct rkisp_ispp_buf *dbufs;
|
|
struct rkispp_dummy_buffer *buf;
|
|
int i, j, ret, cnt = RKISPP_BUF_MAX;
|
|
u32 buf_idx = 0;
|
|
|
|
if (dev->inp == INP_ISP && dev->isp_mode & ISP_ISPP_QUICK)
|
|
cnt = 1;
|
|
for (i = 0; i < cnt; i++) {
|
|
dbufs = kzalloc(sizeof(*dbufs), GFP_KERNEL);
|
|
if (!dbufs) {
|
|
ret = -ENOMEM;
|
|
goto err;
|
|
}
|
|
dbufs->is_isp = false;
|
|
for (j = 0; j < GROUP_BUF_MAX; j++) {
|
|
buf = &vdev->tnr.buf.wr[i][j];
|
|
buf->is_need_dbuf = true;
|
|
buf->is_need_dmafd = false;
|
|
buf->is_need_vaddr = true;
|
|
buf->size = !j ? pic_size : PAGE_ALIGN(gain_size);
|
|
buf->index = buf_idx++;
|
|
ret = rkispp_allow_buffer(dev, buf);
|
|
if (ret) {
|
|
kfree(dbufs);
|
|
goto err;
|
|
}
|
|
dbufs->dbuf[j] = buf->dbuf;
|
|
dbufs->didx[j] = buf->index;
|
|
}
|
|
list_add_tail(&dbufs->list, &vdev->tnr.list_wr);
|
|
}
|
|
|
|
if (dev->inp == INP_ISP && dev->isp_mode & ISP_ISPP_QUICK) {
|
|
buf = &vdev->tnr.buf.iir;
|
|
buf->size = pic_size;
|
|
ret = rkispp_allow_buffer(dev, buf);
|
|
if (ret < 0)
|
|
goto err;
|
|
}
|
|
|
|
buf = &vdev->tnr.buf.gain_kg;
|
|
buf->is_need_vaddr = true;
|
|
buf->is_need_dbuf = true;
|
|
buf->is_need_dmafd = false;
|
|
buf->size = PAGE_ALIGN(gain_size * 4);
|
|
buf->index = buf_idx++;
|
|
ret = rkispp_allow_buffer(dev, buf);
|
|
if (ret < 0)
|
|
goto err;
|
|
|
|
vdev->tnr.is_buf_init = true;
|
|
return 0;
|
|
err:
|
|
tnr_free_buf(dev);
|
|
v4l2_err(&dev->v4l2_dev, "%s failed\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
static int config_tnr(struct rkispp_device *dev)
|
|
{
|
|
struct rkispp_hw_dev *hw = dev->hw_dev;
|
|
struct rkispp_stream_vdev *vdev;
|
|
struct rkispp_stream *stream = NULL;
|
|
int ret, mult = 1;
|
|
u32 width, height, fmt;
|
|
u32 pic_size, gain_size;
|
|
u32 addr_offs, w, h, val;
|
|
u32 max_w, max_h;
|
|
|
|
vdev = &dev->stream_vdev;
|
|
vdev->tnr.is_end = true;
|
|
vdev->tnr.is_3to1 =
|
|
((vdev->module_ens & ISPP_MODULE_TNR_3TO1) ==
|
|
ISPP_MODULE_TNR_3TO1);
|
|
if (!(vdev->module_ens & ISPP_MODULE_TNR))
|
|
return 0;
|
|
|
|
if (dev->inp == INP_DDR) {
|
|
vdev->tnr.is_3to1 = false;
|
|
stream = &vdev->stream[STREAM_II];
|
|
fmt = stream->out_cap_fmt.wr_fmt;
|
|
} else {
|
|
fmt = dev->isp_mode & (FMT_YUV422 | FMT_FBC);
|
|
}
|
|
|
|
width = dev->ispp_sdev.in_fmt.width;
|
|
height = dev->ispp_sdev.in_fmt.height;
|
|
max_w = hw->max_in.w ? hw->max_in.w : width;
|
|
max_h = hw->max_in.h ? hw->max_in.h : height;
|
|
w = (fmt & FMT_FBC) ? ALIGN(max_w, 16) : max_w;
|
|
h = (fmt & FMT_FBC) ? ALIGN(max_h, 16) : max_h;
|
|
addr_offs = (fmt & FMT_FBC) ? w * h >> 4 : w * h;
|
|
pic_size = (fmt & FMT_YUV422) ? w * h * 2 : w * h * 3 >> 1;
|
|
vdev->tnr.uv_offset = addr_offs;
|
|
if (fmt & FMT_FBC)
|
|
pic_size += w * h >> 4;
|
|
|
|
gain_size = ALIGN(width, 64) * ALIGN(height, 128) >> 4;
|
|
if (fmt & FMT_YUYV)
|
|
mult = 2;
|
|
|
|
if (vdev->module_ens & (ISPP_MODULE_NR | ISPP_MODULE_SHP)) {
|
|
ret = tnr_init_buf(dev, pic_size, gain_size);
|
|
if (ret)
|
|
return ret;
|
|
if (dev->inp == INP_ISP &&
|
|
dev->isp_mode & ISP_ISPP_QUICK) {
|
|
rkispp_set_bits(dev, RKISPP_CTRL_QUICK,
|
|
GLB_QUICK_MODE_MASK,
|
|
GLB_QUICK_MODE(0));
|
|
|
|
val = hw->pool[0].dma[GROUP_BUF_PIC];
|
|
rkispp_write(dev, RKISPP_TNR_CUR_Y_BASE, val);
|
|
rkispp_write(dev, RKISPP_TNR_CUR_UV_BASE, val + addr_offs);
|
|
|
|
val = hw->pool[0].dma[GROUP_BUF_GAIN];
|
|
rkispp_write(dev, RKISPP_TNR_GAIN_CUR_Y_BASE, val);
|
|
|
|
if (vdev->tnr.is_3to1) {
|
|
val = hw->pool[1].dma[GROUP_BUF_PIC];
|
|
rkispp_write(dev, RKISPP_TNR_NXT_Y_BASE, val);
|
|
rkispp_write(dev, RKISPP_TNR_NXT_UV_BASE, val + addr_offs);
|
|
val = hw->pool[1].dma[GROUP_BUF_GAIN];
|
|
rkispp_write(dev, RKISPP_TNR_GAIN_NXT_Y_BASE, val);
|
|
}
|
|
}
|
|
|
|
val = vdev->tnr.buf.gain_kg.dma_addr;
|
|
rkispp_write(dev, RKISPP_TNR_GAIN_KG_Y_BASE, val);
|
|
|
|
val = vdev->tnr.buf.wr[0][GROUP_BUF_PIC].dma_addr;
|
|
rkispp_write(dev, RKISPP_TNR_WR_Y_BASE, val);
|
|
rkispp_write(dev, RKISPP_TNR_WR_UV_BASE, val + addr_offs);
|
|
if (vdev->tnr.buf.iir.mem_priv)
|
|
val = vdev->tnr.buf.iir.dma_addr;
|
|
rkispp_write(dev, RKISPP_TNR_IIR_Y_BASE, val);
|
|
rkispp_write(dev, RKISPP_TNR_IIR_UV_BASE, val + addr_offs);
|
|
|
|
val = vdev->tnr.buf.wr[0][GROUP_BUF_GAIN].dma_addr;
|
|
rkispp_write(dev, RKISPP_TNR_GAIN_WR_Y_BASE, val);
|
|
|
|
rkispp_write(dev, RKISPP_TNR_WR_VIR_STRIDE, ALIGN(width * mult, 16) >> 2);
|
|
rkispp_set_bits(dev, RKISPP_TNR_CTRL, FMT_WR_MASK, fmt << 4 | SW_TNR_1ST_FRM);
|
|
}
|
|
|
|
if (stream) {
|
|
stream->config->frame_end_id = TNR_INT;
|
|
stream->config->reg.cur_y_base = RKISPP_TNR_CUR_Y_BASE;
|
|
stream->config->reg.cur_uv_base = RKISPP_TNR_CUR_UV_BASE;
|
|
stream->config->reg.cur_y_base_shd = RKISPP_TNR_CUR_Y_BASE_SHD;
|
|
stream->config->reg.cur_uv_base_shd = RKISPP_TNR_CUR_UV_BASE_SHD;
|
|
}
|
|
|
|
rkispp_set_bits(dev, RKISPP_TNR_CTRL, FMT_RD_MASK, fmt);
|
|
if (fmt & FMT_FBC) {
|
|
rkispp_write(dev, RKISPP_TNR_CUR_VIR_STRIDE, 0);
|
|
rkispp_write(dev, RKISPP_TNR_IIR_VIR_STRIDE, 0);
|
|
rkispp_write(dev, RKISPP_TNR_NXT_VIR_STRIDE, 0);
|
|
} else {
|
|
rkispp_write(dev, RKISPP_TNR_CUR_VIR_STRIDE, ALIGN(width * mult, 16) >> 2);
|
|
rkispp_write(dev, RKISPP_TNR_IIR_VIR_STRIDE, ALIGN(width * mult, 16) >> 2);
|
|
rkispp_write(dev, RKISPP_TNR_NXT_VIR_STRIDE, ALIGN(width * mult, 16) >> 2);
|
|
}
|
|
rkispp_set_bits(dev, RKISPP_TNR_CORE_CTRL, SW_TNR_MODE,
|
|
vdev->tnr.is_3to1 ? SW_TNR_MODE : 0);
|
|
rkispp_write(dev, RKISPP_TNR_GAIN_CUR_VIR_STRIDE, ALIGN(width, 64) >> 4);
|
|
rkispp_write(dev, RKISPP_TNR_GAIN_NXT_VIR_STRIDE, ALIGN(width, 64) >> 4);
|
|
rkispp_write(dev, RKISPP_TNR_GAIN_KG_VIR_STRIDE, ALIGN(width, 16) * 6);
|
|
rkispp_write(dev, RKISPP_TNR_GAIN_WR_VIR_STRIDE, ALIGN(width, 64) >> 4);
|
|
rkispp_write(dev, RKISPP_CTRL_TNR_SIZE, height << 16 | width);
|
|
|
|
if (vdev->monitor.is_en) {
|
|
init_completion(&vdev->monitor.tnr.cmpl);
|
|
schedule_work(&vdev->monitor.tnr.work);
|
|
}
|
|
v4l2_dbg(1, rkispp_debug, &dev->v4l2_dev,
|
|
"%s size:%dx%d ctrl:0x%x core_ctrl:0x%x\n",
|
|
__func__, width, height,
|
|
rkispp_read(dev, RKISPP_TNR_CTRL),
|
|
rkispp_read(dev, RKISPP_TNR_CORE_CTRL));
|
|
return 0;
|
|
}
|
|
|
|
static void nr_free_buf(struct rkispp_device *dev)
|
|
{
|
|
struct rkispp_stream_vdev *vdev = &dev->stream_vdev;
|
|
struct rkisp_ispp_buf *dbufs;
|
|
struct list_head *list;
|
|
int i;
|
|
|
|
list = &vdev->nr.list_rd;
|
|
if (vdev->nr.cur_rd) {
|
|
list_add_tail(&vdev->nr.cur_rd->list, list);
|
|
vdev->nr.cur_rd = NULL;
|
|
}
|
|
while (!list_empty(list)) {
|
|
dbufs = get_list_buf(list, true);
|
|
if (dbufs->is_isp)
|
|
v4l2_subdev_call(dev->ispp_sdev.remote_sd,
|
|
video, s_rx_buffer, dbufs, NULL);
|
|
else
|
|
kfree(dbufs);
|
|
}
|
|
|
|
list = &vdev->nr.list_wr;
|
|
if (vdev->nr.cur_wr)
|
|
vdev->nr.cur_wr = NULL;
|
|
while (!list_empty(list))
|
|
get_list_buf(list, false);
|
|
list = &vdev->nr.list_rpt;
|
|
while (!list_empty(list))
|
|
get_list_buf(list, false);
|
|
|
|
for (i = 0; i < sizeof(vdev->nr.buf) /
|
|
sizeof(struct rkispp_dummy_buffer); i++)
|
|
rkispp_free_buffer(dev, &vdev->nr.buf.tmp_yuv + i);
|
|
|
|
vdev->nr.is_buf_init = false;
|
|
}
|
|
|
|
static int nr_init_buf(struct rkispp_device *dev, u32 size)
|
|
{
|
|
struct rkispp_stream_vdev *vdev = &dev->stream_vdev;
|
|
struct rkispp_dummy_buffer *buf;
|
|
int i, ret, cnt;
|
|
|
|
switch (vdev->module_ens & ISPP_MODULE_FEC_ST) {
|
|
case ISPP_MODULE_FEC_ST:
|
|
cnt = RKISPP_FEC_BUF_MAX;
|
|
break;
|
|
case ISPP_MODULE_FEC:
|
|
cnt = RKISPP_BUF_MAX;
|
|
break;
|
|
default:
|
|
cnt = 0;
|
|
}
|
|
|
|
for (i = 0; i < cnt; i++) {
|
|
buf = &vdev->nr.buf.wr[i];
|
|
buf->size = size;
|
|
buf->index = i;
|
|
buf->is_need_dbuf = true;
|
|
buf->is_need_vaddr = true;
|
|
buf->is_need_dmafd = false;
|
|
ret = rkispp_allow_buffer(dev, buf);
|
|
if (ret)
|
|
goto err;
|
|
list_add_tail(&buf->list, &vdev->nr.list_wr);
|
|
}
|
|
|
|
buf = &vdev->nr.buf.tmp_yuv;
|
|
cnt = DIV_ROUND_UP(dev->ispp_sdev.in_fmt.width, 32);
|
|
buf->size = PAGE_ALIGN(cnt * 42 * 32);
|
|
ret = rkispp_allow_buffer(dev, buf);
|
|
if (ret)
|
|
goto err;
|
|
|
|
vdev->nr.is_buf_init = true;
|
|
return 0;
|
|
err:
|
|
nr_free_buf(dev);
|
|
v4l2_err(&dev->v4l2_dev, "%s failed\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
static int config_nr_shp(struct rkispp_device *dev)
|
|
{
|
|
struct rkispp_hw_dev *hw = dev->hw_dev;
|
|
struct rkispp_stream_vdev *vdev;
|
|
struct rkispp_stream *stream = NULL;
|
|
u32 width, height, fmt;
|
|
u32 pic_size, addr_offs;
|
|
u32 w, h, val;
|
|
u32 max_w, max_h;
|
|
int ret, mult = 1;
|
|
|
|
vdev = &dev->stream_vdev;
|
|
vdev->nr.is_end = true;
|
|
if (!(vdev->module_ens & (ISPP_MODULE_NR | ISPP_MODULE_SHP)))
|
|
return 0;
|
|
|
|
vdev->is_done_early = is_en_done_early(dev);
|
|
|
|
if (dev->inp == INP_DDR) {
|
|
stream = &vdev->stream[STREAM_II];
|
|
fmt = stream->out_cap_fmt.wr_fmt;
|
|
} else {
|
|
fmt = dev->isp_mode & (FMT_YUV422 | FMT_FBC);
|
|
}
|
|
|
|
width = dev->ispp_sdev.in_fmt.width;
|
|
height = dev->ispp_sdev.in_fmt.height;
|
|
w = width;
|
|
h = height;
|
|
max_w = hw->max_in.w ? hw->max_in.w : w;
|
|
max_h = hw->max_in.h ? hw->max_in.h : h;
|
|
if (fmt & FMT_FBC) {
|
|
max_w = ALIGN(max_w, 16);
|
|
max_h = ALIGN(max_h, 16);
|
|
w = ALIGN(w, 16);
|
|
h = ALIGN(h, 16);
|
|
}
|
|
addr_offs = (fmt & FMT_FBC) ? max_w * max_h >> 4 : max_w * max_h;
|
|
pic_size = (fmt & FMT_YUV422) ? w * h * 2 : w * h * 3 >> 1;
|
|
vdev->nr.uv_offset = addr_offs;
|
|
|
|
if (fmt & FMT_YUYV)
|
|
mult = 2;
|
|
|
|
ret = nr_init_buf(dev, pic_size);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if (vdev->module_ens & ISPP_MODULE_TNR) {
|
|
rkispp_write(dev, RKISPP_NR_ADDR_BASE_Y,
|
|
rkispp_read(dev, RKISPP_TNR_WR_Y_BASE));
|
|
rkispp_write(dev, RKISPP_NR_ADDR_BASE_UV,
|
|
rkispp_read(dev, RKISPP_TNR_WR_UV_BASE));
|
|
rkispp_write(dev, RKISPP_NR_ADDR_BASE_GAIN,
|
|
rkispp_read(dev, RKISPP_TNR_GAIN_WR_Y_BASE));
|
|
rkispp_set_bits(dev, RKISPP_CTRL_QUICK, 0, GLB_NR_SD32_TNR);
|
|
} else {
|
|
/* tnr need to set same format with nr in the fbc mode */
|
|
rkispp_set_bits(dev, RKISPP_TNR_CTRL, FMT_RD_MASK, fmt);
|
|
rkispp_write(dev, RKISPP_CTRL_TNR_SIZE, height << 16 | width);
|
|
if (dev->inp == INP_ISP) {
|
|
if (dev->isp_mode & ISP_ISPP_QUICK)
|
|
rkispp_set_bits(dev, RKISPP_CTRL_QUICK,
|
|
GLB_QUICK_MODE_MASK,
|
|
GLB_QUICK_MODE(2));
|
|
else
|
|
rkispp_set_bits(dev, RKISPP_NR_UVNR_CTRL_PARA,
|
|
0, SW_UVNR_SD32_SELF_EN);
|
|
|
|
val = hw->pool[0].dma[GROUP_BUF_PIC];
|
|
rkispp_write(dev, RKISPP_NR_ADDR_BASE_Y, val);
|
|
rkispp_write(dev, RKISPP_NR_ADDR_BASE_UV, val + addr_offs);
|
|
val = hw->pool[0].dma[GROUP_BUF_GAIN];
|
|
rkispp_write(dev, RKISPP_NR_ADDR_BASE_GAIN, val);
|
|
rkispp_clear_bits(dev, RKISPP_CTRL_QUICK, GLB_NR_SD32_TNR);
|
|
} else if (stream) {
|
|
stream->config->frame_end_id = NR_INT;
|
|
stream->config->reg.cur_y_base = RKISPP_NR_ADDR_BASE_Y;
|
|
stream->config->reg.cur_uv_base = RKISPP_NR_ADDR_BASE_UV;
|
|
stream->config->reg.cur_y_base_shd = RKISPP_NR_ADDR_BASE_Y_SHD;
|
|
stream->config->reg.cur_uv_base_shd = RKISPP_NR_ADDR_BASE_UV_SHD;
|
|
}
|
|
}
|
|
|
|
rkispp_clear_bits(dev, RKISPP_CTRL_QUICK, GLB_FEC2SCL_EN);
|
|
if (vdev->module_ens & ISPP_MODULE_FEC) {
|
|
addr_offs = width * height;
|
|
vdev->fec.uv_offset = addr_offs;
|
|
val = vdev->nr.buf.wr[0].dma_addr;
|
|
rkispp_write(dev, RKISPP_SHARP_WR_Y_BASE, val);
|
|
rkispp_write(dev, RKISPP_SHARP_WR_UV_BASE, val + addr_offs);
|
|
rkispp_write(dev, RKISPP_SHARP_WR_VIR_STRIDE, ALIGN(width * mult, 16) >> 2);
|
|
rkispp_set_bits(dev, RKISPP_SHARP_CTRL, SW_SHP_WR_FORMAT_MASK, fmt & (~FMT_FBC));
|
|
|
|
rkispp_write(dev, RKISPP_FEC_RD_Y_BASE, val);
|
|
rkispp_write(dev, RKISPP_FEC_RD_UV_BASE, val + addr_offs);
|
|
} else {
|
|
stream = &vdev->stream[STREAM_MB];
|
|
if (!stream->streaming) {
|
|
val = hw->dummy_buf.dma_addr;
|
|
rkispp_write(dev, RKISPP_SHARP_WR_Y_BASE, val);
|
|
rkispp_write(dev, RKISPP_SHARP_WR_UV_BASE, val);
|
|
rkispp_write(dev, RKISPP_SHARP_WR_VIR_STRIDE, ALIGN(width * mult, 16) >> 2);
|
|
if (dev->inp == INP_ISP)
|
|
rkispp_set_bits(dev, RKISPP_SHARP_CTRL,
|
|
SW_SHP_WR_FORMAT_MASK, FMT_FBC);
|
|
}
|
|
}
|
|
|
|
val = vdev->nr.buf.tmp_yuv.dma_addr;
|
|
rkispp_write(dev, RKISPP_SHARP_TMP_YUV_BASE, val);
|
|
|
|
/* fix to use new nr algorithm */
|
|
rkispp_set_bits(dev, RKISPP_NR_CTRL, NR_NEW_ALGO, NR_NEW_ALGO);
|
|
rkispp_set_bits(dev, RKISPP_NR_CTRL, FMT_RD_MASK, fmt);
|
|
if (fmt & FMT_FBC) {
|
|
rkispp_write(dev, RKISPP_NR_VIR_STRIDE, 0);
|
|
rkispp_write(dev, RKISPP_FBC_VIR_HEIGHT, max_h);
|
|
} else {
|
|
rkispp_write(dev, RKISPP_NR_VIR_STRIDE, ALIGN(width * mult, 16) >> 2);
|
|
}
|
|
rkispp_write(dev, RKISPP_NR_VIR_STRIDE_GAIN, ALIGN(width, 64) >> 4);
|
|
rkispp_write(dev, RKISPP_CTRL_SIZE, height << 16 | width);
|
|
|
|
if (vdev->monitor.is_en) {
|
|
init_completion(&vdev->monitor.nr.cmpl);
|
|
schedule_work(&vdev->monitor.nr.work);
|
|
}
|
|
v4l2_dbg(1, rkispp_debug, &dev->v4l2_dev,
|
|
"%s size:%dx%d\n"
|
|
"nr ctrl:0x%x ctrl_para:0x%x\n"
|
|
"shp ctrl:0x%x core_ctrl:0x%x\n",
|
|
__func__, width, height,
|
|
rkispp_read(dev, RKISPP_NR_CTRL),
|
|
rkispp_read(dev, RKISPP_NR_UVNR_CTRL_PARA),
|
|
rkispp_read(dev, RKISPP_SHARP_CTRL),
|
|
rkispp_read(dev, RKISPP_SHARP_CORE_CTRL));
|
|
return 0;
|
|
}
|
|
|
|
static void fec_free_buf(struct rkispp_device *dev)
|
|
{
|
|
struct rkispp_stream_vdev *vdev = &dev->stream_vdev;
|
|
struct list_head *list = &vdev->fec.list_rd;
|
|
|
|
if (vdev->fec.cur_rd)
|
|
vdev->fec.cur_rd = NULL;
|
|
while (!list_empty(list))
|
|
get_list_buf(list, false);
|
|
}
|
|
|
|
static int config_fec(struct rkispp_device *dev)
|
|
{
|
|
struct rkispp_stream_vdev *vdev;
|
|
struct rkispp_stream *stream = NULL;
|
|
u32 in_width, in_height, fmt, mult = 1;
|
|
u32 out_width, out_height;
|
|
|
|
vdev = &dev->stream_vdev;
|
|
vdev->fec.is_end = true;
|
|
if (!(vdev->module_ens & ISPP_MODULE_FEC))
|
|
return 0;
|
|
|
|
if (dev->inp == INP_DDR) {
|
|
stream = &vdev->stream[STREAM_II];
|
|
fmt = stream->out_cap_fmt.wr_fmt;
|
|
} else {
|
|
fmt = dev->isp_mode & FMT_YUV422;
|
|
}
|
|
|
|
in_width = dev->ispp_sdev.in_fmt.width;
|
|
in_height = dev->ispp_sdev.in_fmt.height;
|
|
out_width = dev->ispp_sdev.out_fmt.width;
|
|
out_height = dev->ispp_sdev.out_fmt.height;
|
|
|
|
if (vdev->module_ens & (ISPP_MODULE_NR | ISPP_MODULE_SHP)) {
|
|
rkispp_write(dev, RKISPP_FEC_RD_Y_BASE,
|
|
rkispp_read(dev, RKISPP_SHARP_WR_Y_BASE));
|
|
rkispp_write(dev, RKISPP_FEC_RD_UV_BASE,
|
|
rkispp_read(dev, RKISPP_SHARP_WR_UV_BASE));
|
|
} else if (stream) {
|
|
stream->config->frame_end_id = FEC_INT;
|
|
stream->config->reg.cur_y_base = RKISPP_FEC_RD_Y_BASE;
|
|
stream->config->reg.cur_uv_base = RKISPP_FEC_RD_UV_BASE;
|
|
stream->config->reg.cur_y_base_shd = RKISPP_FEC_RD_Y_BASE_SHD;
|
|
stream->config->reg.cur_uv_base_shd = RKISPP_FEC_RD_UV_BASE_SHD;
|
|
}
|
|
|
|
if (fmt & FMT_YUYV)
|
|
mult = 2;
|
|
rkispp_set_bits(dev, RKISPP_FEC_CTRL, FMT_RD_MASK, fmt);
|
|
rkispp_write(dev, RKISPP_FEC_RD_VIR_STRIDE, ALIGN(in_width * mult, 16) >> 2);
|
|
rkispp_write(dev, RKISPP_FEC_PIC_SIZE, out_height << 16 | out_width);
|
|
rkispp_set_bits(dev, RKISPP_CTRL_QUICK, 0, GLB_FEC2SCL_EN);
|
|
|
|
if (vdev->monitor.is_en) {
|
|
init_completion(&vdev->monitor.fec.cmpl);
|
|
schedule_work(&vdev->monitor.fec.work);
|
|
}
|
|
v4l2_dbg(1, rkispp_debug, &dev->v4l2_dev,
|
|
"%s size:%dx%d->%dx%d ctrl:0x%x core_ctrl:0x%x\n",
|
|
__func__, in_width, in_height, out_width, out_height,
|
|
rkispp_read(dev, RKISPP_FEC_CTRL),
|
|
rkispp_read(dev, RKISPP_FEC_CORE_CTRL));
|
|
return 0;
|
|
}
|
|
|
|
static int config_modules(struct rkispp_device *dev)
|
|
{
|
|
struct rkispp_params_vdev *params_vdev;
|
|
int ret;
|
|
|
|
v4l2_dbg(1, rkispp_debug, &dev->v4l2_dev,
|
|
"stream module ens:0x%x\n", dev->stream_vdev.module_ens);
|
|
dev->stream_vdev.monitor.monitoring_module = 0;
|
|
dev->stream_vdev.monitor.restart_module = 0;
|
|
dev->stream_vdev.monitor.is_restart = false;
|
|
dev->stream_vdev.monitor.retry = 0;
|
|
dev->stream_vdev.monitor.is_en = rkispp_monitor;
|
|
init_completion(&dev->stream_vdev.monitor.cmpl);
|
|
|
|
ret = config_tnr(dev);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
ret = config_nr_shp(dev);
|
|
if (ret < 0)
|
|
goto free_tnr;
|
|
|
|
ret = config_fec(dev);
|
|
if (ret < 0)
|
|
goto free_nr;
|
|
|
|
/* config default params */
|
|
params_vdev = &dev->params_vdev[PARAM_VDEV_TNR];
|
|
params_vdev->params_ops->rkispp_params_cfg(params_vdev, 0);
|
|
params_vdev = &dev->params_vdev[PARAM_VDEV_NR];
|
|
params_vdev->params_ops->rkispp_params_cfg(params_vdev, 0);
|
|
params_vdev = &dev->params_vdev[PARAM_VDEV_FEC];
|
|
params_vdev->params_ops->rkispp_params_cfg(params_vdev, 0);
|
|
return 0;
|
|
free_nr:
|
|
nr_free_buf(dev);
|
|
free_tnr:
|
|
tnr_free_buf(dev);
|
|
return ret;
|
|
}
|
|
|
|
static void rkispp_destroy_buf(struct rkispp_stream *stream)
|
|
{
|
|
struct rkispp_device *dev = stream->isppdev;
|
|
struct rkispp_stream_vdev *vdev = &dev->stream_vdev;
|
|
|
|
if (atomic_read(&vdev->refcnt) == 1) {
|
|
vdev->irq_ends = 0;
|
|
tnr_free_buf(dev);
|
|
nr_free_buf(dev);
|
|
fec_free_buf(dev);
|
|
rkispp_event_handle(dev, CMD_FREE_POOL, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
static void nr_work_event(struct rkispp_device *dev,
|
|
struct rkisp_ispp_buf *buf_rd,
|
|
struct rkispp_dummy_buffer *buf_wr,
|
|
bool is_isr)
|
|
{
|
|
struct rkispp_params_vdev *params_vdev = &dev->params_vdev[PARAM_VDEV_NR];
|
|
struct rkispp_stream_vdev *vdev = &dev->stream_vdev;
|
|
struct rkispp_stream *stream = &vdev->stream[STREAM_II];
|
|
struct rkispp_monitor *monitor = &vdev->monitor;
|
|
void __iomem *base = dev->hw_dev->base_addr;
|
|
struct rkispp_dummy_buffer *buf_to_fec = NULL;
|
|
struct rkispp_dummy_buffer *dummy;
|
|
struct rkispp_buffer *inbuf;
|
|
struct v4l2_subdev *sd = NULL;
|
|
struct list_head *list;
|
|
struct dma_buf *dbuf;
|
|
unsigned long lock_flags = 0, lock_flags1 = 0;
|
|
bool is_start = false, is_quick = false, is_fec_event = false;
|
|
bool is_fec_en = (vdev->module_ens & ISPP_MODULE_FEC);
|
|
struct rkisp_ispp_reg *reg_buf = NULL;
|
|
u32 val;
|
|
|
|
if (!(vdev->module_ens & (ISPP_MODULE_NR | ISPP_MODULE_SHP)))
|
|
return;
|
|
|
|
if (dev->inp == INP_ISP) {
|
|
if (dev->isp_mode & ISP_ISPP_QUICK)
|
|
is_quick = true;
|
|
else
|
|
sd = dev->ispp_sdev.remote_sd;
|
|
}
|
|
|
|
spin_lock_irqsave(&vdev->nr.buf_lock, lock_flags);
|
|
|
|
/* event from nr frame end */
|
|
if (!buf_rd && !buf_wr && is_isr) {
|
|
vdev->nr.is_end = true;
|
|
is_fec_event = true;
|
|
if (vdev->nr.cur_rd) {
|
|
/* nr read buf return to isp or tnr */
|
|
if (vdev->nr.cur_rd->is_isp && sd) {
|
|
v4l2_subdev_call(sd, video, s_rx_buffer, vdev->nr.cur_rd, NULL);
|
|
} else if (!vdev->nr.cur_rd->priv) {
|
|
rkispp_module_work_event(dev, NULL, vdev->nr.cur_rd,
|
|
ISPP_MODULE_TNR, is_isr);
|
|
} else if (stream->streaming && vdev->nr.cur_rd->priv) {
|
|
inbuf = vdev->nr.cur_rd->priv;
|
|
vb2_buffer_done(&inbuf->vb.vb2_buf, VB2_BUF_STATE_DONE);
|
|
}
|
|
vdev->nr.cur_rd = NULL;
|
|
}
|
|
|
|
if (vdev->nr.cur_wr) {
|
|
/* nr write buf to fec */
|
|
buf_to_fec = vdev->nr.cur_wr;
|
|
vdev->nr.cur_wr = NULL;
|
|
|
|
if (vdev->is_done_early && !dev->hw_dev->is_first)
|
|
buf_to_fec = NULL;
|
|
}
|
|
}
|
|
|
|
if (!vdev->fec.is_end) {
|
|
if (buf_rd)
|
|
list_add_tail(&buf_rd->list, &vdev->nr.list_rd);
|
|
goto end;
|
|
}
|
|
|
|
spin_lock_irqsave(&monitor->lock, lock_flags1);
|
|
if (monitor->is_restart) {
|
|
if (buf_rd)
|
|
list_add_tail(&buf_rd->list, &vdev->nr.list_rd);
|
|
if (buf_wr)
|
|
list_add_tail(&buf_wr->list, &vdev->nr.list_wr);
|
|
goto restart_unlock;
|
|
}
|
|
|
|
list = &vdev->nr.list_rd;
|
|
if (buf_rd && vdev->nr.is_end && list_empty(list)) {
|
|
/* nr read buf from isp or tnr */
|
|
vdev->nr.cur_rd = buf_rd;
|
|
} else if (vdev->nr.is_end && !list_empty(list)) {
|
|
/* nr read buf from list
|
|
* nr processing slow than isp or tnr
|
|
* new read buf from isp or tnr into list
|
|
*/
|
|
vdev->nr.cur_rd = get_list_buf(list, true);
|
|
if (buf_rd)
|
|
list_add_tail(&buf_rd->list, list);
|
|
} else if (!vdev->nr.is_end && buf_rd) {
|
|
/* nr no idle
|
|
* new read buf from isp or tnr into list
|
|
*/
|
|
list_add_tail(&buf_rd->list, list);
|
|
}
|
|
|
|
list = &vdev->nr.list_wr;
|
|
if (vdev->nr.is_end && !vdev->nr.cur_wr) {
|
|
/* nr idle, get new write buf */
|
|
vdev->nr.cur_wr = buf_wr ? buf_wr :
|
|
get_list_buf(list, false);
|
|
} else if (buf_wr) {
|
|
/* tnr no idle, write buf from nr into list */
|
|
list_add_tail(&buf_wr->list, list);
|
|
}
|
|
|
|
if (vdev->nr.cur_rd && vdev->nr.is_end) {
|
|
if (vdev->nr.cur_rd->priv) {
|
|
inbuf = vdev->nr.cur_rd->priv;
|
|
val = inbuf->buff_addr[RKISPP_PLANE_Y];
|
|
rkispp_write(dev, RKISPP_NR_ADDR_BASE_Y, val);
|
|
val = inbuf->buff_addr[RKISPP_PLANE_UV];
|
|
rkispp_write(dev, RKISPP_NR_ADDR_BASE_UV, val);
|
|
} else if (!vdev->nr.cur_rd->is_isp) {
|
|
u32 size = sizeof(vdev->tnr.buf) / sizeof(*dummy);
|
|
|
|
dbuf = vdev->nr.cur_rd->dbuf[GROUP_BUF_PIC];
|
|
dummy = dbuf_to_dummy(dbuf, &vdev->tnr.buf.iir, size);
|
|
val = dummy->dma_addr;
|
|
rkispp_write(dev, RKISPP_NR_ADDR_BASE_Y, val);
|
|
val += vdev->nr.uv_offset;
|
|
rkispp_write(dev, RKISPP_NR_ADDR_BASE_UV, val);
|
|
|
|
dbuf = vdev->nr.cur_rd->dbuf[GROUP_BUF_GAIN];
|
|
dummy = dbuf_to_dummy(dbuf, &vdev->tnr.buf.iir, size);
|
|
val = dummy->dma_addr;
|
|
rkispp_write(dev, RKISPP_NR_ADDR_BASE_GAIN, val);
|
|
} else {
|
|
struct rkispp_isp_buf_pool *buf;
|
|
|
|
buf = get_pool_buf(dev, vdev->nr.cur_rd);
|
|
val = buf->dma[GROUP_BUF_PIC];
|
|
rkispp_write(dev, RKISPP_NR_ADDR_BASE_Y, val);
|
|
val += vdev->nr.uv_offset;
|
|
rkispp_write(dev, RKISPP_NR_ADDR_BASE_UV, val);
|
|
|
|
val = buf->dma[GROUP_BUF_GAIN];
|
|
rkispp_write(dev, RKISPP_NR_ADDR_BASE_GAIN, val);
|
|
}
|
|
is_start = true;
|
|
}
|
|
|
|
if (vdev->nr.is_end && is_quick)
|
|
is_start = true;
|
|
|
|
if (vdev->nr.cur_wr && is_start) {
|
|
dummy = vdev->nr.cur_wr;
|
|
val = dummy->dma_addr;
|
|
rkispp_write(dev, RKISPP_SHARP_WR_Y_BASE, val);
|
|
val += vdev->fec.uv_offset;
|
|
rkispp_write(dev, RKISPP_SHARP_WR_UV_BASE, val);
|
|
}
|
|
|
|
if (is_start) {
|
|
u32 seq = 0;
|
|
u64 timestamp = 0;
|
|
|
|
if (vdev->nr.cur_rd) {
|
|
seq = vdev->nr.cur_rd->frame_id;
|
|
timestamp = vdev->nr.cur_rd->frame_timestamp;
|
|
if (vdev->nr.cur_wr) {
|
|
vdev->nr.cur_wr->id = seq;
|
|
vdev->nr.cur_wr->timestamp = timestamp;
|
|
} else {
|
|
vdev->nr.buf.wr[0].id = seq;
|
|
vdev->nr.buf.wr[0].timestamp = timestamp;
|
|
}
|
|
if (!is_fec_en && !is_quick) {
|
|
dev->ispp_sdev.frame_timestamp = timestamp;
|
|
dev->ispp_sdev.frm_sync_seq = seq;
|
|
}
|
|
dev->stats_vdev[STATS_VDEV_NR].frame_id = seq;
|
|
params_vdev->params_ops->rkispp_params_cfg(params_vdev, seq);
|
|
}
|
|
|
|
/* check MB config and output buf beforce start, when MB connect to SHARP
|
|
* MB update by OTHER_FORCE_UPD
|
|
*/
|
|
stream = &vdev->stream[STREAM_MB];
|
|
if (!is_fec_en && stream->streaming) {
|
|
if (!stream->is_cfg) {
|
|
secure_config_mb(stream);
|
|
} else if (!stream->curr_buf) {
|
|
get_stream_buf(stream);
|
|
if (stream->curr_buf)
|
|
vdev->stream_ops->update_mi(stream);
|
|
}
|
|
}
|
|
|
|
/* check SCL output buf beforce start
|
|
* SCL update by OTHER_FORCE_UPD
|
|
*/
|
|
for (val = STREAM_S0; val <= STREAM_S2; val++) {
|
|
stream = &vdev->stream[val];
|
|
if (!stream->streaming || !stream->is_cfg || stream->curr_buf)
|
|
continue;
|
|
get_stream_buf(stream);
|
|
if (stream->curr_buf) {
|
|
vdev->stream_ops->update_mi(stream);
|
|
rkispp_set_bits(dev, stream->config->reg.ctrl, 0, SW_SCL_ENABLE);
|
|
} else {
|
|
rkispp_clear_bits(dev, stream->config->reg.ctrl, SW_SCL_ENABLE);
|
|
}
|
|
}
|
|
|
|
if (!dev->hw_dev->is_single) {
|
|
if (vdev->nr.cur_rd &&
|
|
(vdev->nr.cur_rd->is_isp || vdev->nr.cur_rd->priv)) {
|
|
rkispp_update_regs(dev, RKISPP_CTRL, RKISPP_TNR_CTRL);
|
|
writel(TNR_FORCE_UPD, base + RKISPP_CTRL_UPDATE);
|
|
}
|
|
rkispp_update_regs(dev, RKISPP_NR, RKISPP_ORB_MAX_FEATURE);
|
|
}
|
|
|
|
writel(OTHER_FORCE_UPD, base + RKISPP_CTRL_UPDATE);
|
|
|
|
val = readl(base + RKISPP_SHARP_CORE_CTRL);
|
|
if (!(val & SW_SHP_EN) && !is_fec_en && !stream->streaming)
|
|
writel(val | SW_SHP_DMA_DIS, base + RKISPP_SHARP_CORE_CTRL);
|
|
else if (val & SW_SHP_EN)
|
|
writel(val & ~SW_SHP_DMA_DIS, base + RKISPP_SHARP_CORE_CTRL);
|
|
|
|
v4l2_dbg(3, rkispp_debug, &dev->v4l2_dev,
|
|
"NR start seq:%d | Y_SHD rd:0x%x wr:0x%x\n",
|
|
seq, readl(base + RKISPP_NR_ADDR_BASE_Y_SHD),
|
|
readl(base + RKISPP_SHARP_WR_Y_BASE_SHD));
|
|
|
|
for (val = STREAM_S0; val <= STREAM_S2 && !is_fec_en; val++) {
|
|
stream = &vdev->stream[val];
|
|
/* check scale stream stop state */
|
|
if (stream->streaming && stream->stopping) {
|
|
if (stream->ops->is_stopped(stream)) {
|
|
stream->stopping = false;
|
|
stream->streaming = false;
|
|
wake_up(&stream->done);
|
|
} else {
|
|
stream->ops->stop(stream);
|
|
}
|
|
}
|
|
}
|
|
|
|
vdev->nr.dbg.id = seq;
|
|
vdev->nr.dbg.timestamp = ktime_get_ns();
|
|
if (monitor->is_en) {
|
|
monitor->nr.time = vdev->nr.dbg.interval / 1000 / 1000;
|
|
monitor->monitoring_module |= MONITOR_NR;
|
|
monitor->nr.is_err = false;
|
|
if (!completion_done(&monitor->nr.cmpl))
|
|
complete(&monitor->nr.cmpl);
|
|
}
|
|
|
|
if (rkispp_is_reg_withstream_global())
|
|
rkispp_find_regbuf_by_id(dev, ®_buf, dev->dev_id, seq);
|
|
if (reg_buf && (rkispp_debug_reg & ISPP_MODULE_NR)) {
|
|
u32 offset, size;
|
|
|
|
offset = reg_buf->reg_size;
|
|
size = 4 + RKISPP_NR_BUFFER_READY - RKISPP_NR_CTRL;
|
|
reg_buf->ispp_size[ISPP_ID_NR] = size;
|
|
reg_buf->ispp_offset[ISPP_ID_NR] = offset;
|
|
memcpy_fromio(®_buf->reg[offset], base + RKISPP_NR_CTRL, size);
|
|
|
|
offset += size;
|
|
reg_buf->reg_size = offset;
|
|
}
|
|
if (reg_buf && (rkispp_debug_reg & ISPP_MODULE_SHP)) {
|
|
u32 offset, size;
|
|
|
|
offset = reg_buf->reg_size;
|
|
size = 4 + RKISPP_SHARP_GRAD_RATIO - RKISPP_SHARP_CTRL;
|
|
reg_buf->ispp_size[ISPP_ID_SHP] = size;
|
|
reg_buf->ispp_offset[ISPP_ID_SHP] = offset;
|
|
memcpy_fromio(®_buf->reg[offset], base + RKISPP_SHARP_CTRL, size);
|
|
|
|
offset += size;
|
|
reg_buf->reg_size = offset;
|
|
}
|
|
if (reg_buf && (rkispp_debug_reg & ISPP_MODULE_ORB)) {
|
|
u32 offset, size;
|
|
|
|
offset = reg_buf->reg_size;
|
|
size = 4 + RKISPP_ORB_MAX_FEATURE - RKISPP_ORB_WR_BASE;
|
|
reg_buf->ispp_size[ISPP_ID_ORB] = size;
|
|
reg_buf->ispp_offset[ISPP_ID_ORB] = offset;
|
|
memcpy_fromio(®_buf->reg[offset], base + RKISPP_ORB_WR_BASE, size);
|
|
|
|
offset += size;
|
|
reg_buf->reg_size = offset;
|
|
}
|
|
|
|
if (!is_quick && !dev->hw_dev->is_shutdown) {
|
|
writel(NR_SHP_ST, base + RKISPP_CTRL_STRT);
|
|
|
|
if (!is_fec_en && vdev->is_done_early)
|
|
hrtimer_start(&vdev->frame_qst,
|
|
ns_to_ktime(1000000),
|
|
HRTIMER_MODE_REL);
|
|
}
|
|
vdev->nr.is_end = false;
|
|
}
|
|
restart_unlock:
|
|
spin_unlock_irqrestore(&monitor->lock, lock_flags1);
|
|
end:
|
|
/* nr_shp->fec->scl
|
|
* fec start working should after nr
|
|
* for scl will update by OTHER_FORCE_UPD
|
|
*/
|
|
if (buf_to_fec) {
|
|
if ((vdev->module_ens & ISPP_MODULE_FEC_ST) == ISPP_MODULE_FEC_ST) {
|
|
rkispp_finish_buffer(dev, buf_to_fec);
|
|
list_add_tail(&buf_to_fec->list, &dev->stream_vdev.nr.list_rpt);
|
|
buf_to_fec = NULL;
|
|
}
|
|
rkispp_module_work_event(dev, buf_to_fec, NULL, ISPP_MODULE_FEC, false);
|
|
} else if (!list_empty(&vdev->fec.list_rd) && is_fec_event) {
|
|
rkispp_module_work_event(dev, NULL, NULL, ISPP_MODULE_FEC, false);
|
|
}
|
|
spin_unlock_irqrestore(&vdev->nr.buf_lock, lock_flags);
|
|
|
|
if (is_fec_en && vdev->is_done_early &&
|
|
is_start && !dev->hw_dev->is_first &&
|
|
(vdev->module_ens & ISPP_MODULE_FEC_ST) != ISPP_MODULE_FEC_ST)
|
|
hrtimer_start(&vdev->fec_qst,
|
|
ns_to_ktime(1000000),
|
|
HRTIMER_MODE_REL);
|
|
}
|
|
|
|
static void tnr_work_event(struct rkispp_device *dev,
|
|
struct rkisp_ispp_buf *buf_rd,
|
|
struct rkisp_ispp_buf *buf_wr,
|
|
bool is_isr)
|
|
{
|
|
struct rkispp_params_vdev *params_vdev = &dev->params_vdev[PARAM_VDEV_TNR];
|
|
struct rkispp_stream_vdev *vdev = &dev->stream_vdev;
|
|
struct rkispp_stream *stream = &vdev->stream[STREAM_II];
|
|
struct rkispp_monitor *monitor = &vdev->monitor;
|
|
void __iomem *base = dev->hw_dev->base_addr;
|
|
struct rkispp_dummy_buffer *dummy;
|
|
struct rkispp_buffer *inbuf;
|
|
struct v4l2_subdev *sd = NULL;
|
|
struct list_head *list;
|
|
struct dma_buf *dbuf;
|
|
unsigned long lock_flags = 0, lock_flags1 = 0;
|
|
u32 val, size = sizeof(vdev->tnr.buf) / sizeof(*dummy);
|
|
bool is_en, is_3to1 = vdev->tnr.is_3to1, is_start = false;
|
|
struct rkisp_ispp_reg *reg_buf = NULL;
|
|
|
|
if (!(vdev->module_ens & ISPP_MODULE_TNR) ||
|
|
(dev->inp == INP_ISP && dev->isp_mode & ISP_ISPP_QUICK))
|
|
return;
|
|
|
|
if (dev->inp == INP_ISP)
|
|
sd = dev->ispp_sdev.remote_sd;
|
|
|
|
if (buf_rd)
|
|
params_vdev->params_ops->rkispp_params_cfg(params_vdev, buf_rd->frame_id);
|
|
|
|
is_en = rkispp_read(dev, RKISPP_TNR_CORE_CTRL) & SW_TNR_EN;
|
|
|
|
spin_lock_irqsave(&vdev->tnr.buf_lock, lock_flags);
|
|
|
|
/* event from tnr frame end */
|
|
if (!buf_rd && !buf_wr && is_isr) {
|
|
vdev->tnr.is_end = true;
|
|
|
|
if (vdev->tnr.cur_rd) {
|
|
/* tnr read buf return to isp */
|
|
if (sd) {
|
|
v4l2_subdev_call(sd, video, s_rx_buffer, vdev->tnr.cur_rd, NULL);
|
|
} else if (stream->streaming && vdev->tnr.cur_rd->priv) {
|
|
inbuf = vdev->tnr.cur_rd->priv;
|
|
vb2_buffer_done(&inbuf->vb.vb2_buf, VB2_BUF_STATE_DONE);
|
|
}
|
|
if (vdev->tnr.cur_rd == vdev->tnr.nxt_rd)
|
|
vdev->tnr.nxt_rd = NULL;
|
|
vdev->tnr.cur_rd = NULL;
|
|
}
|
|
|
|
if (vdev->tnr.cur_wr) {
|
|
if (!vdev->tnr.cur_wr->is_move_judge || !vdev->tnr.is_trigger) {
|
|
/* tnr write buf to nr */
|
|
rkispp_module_work_event(dev, vdev->tnr.cur_wr, NULL,
|
|
ISPP_MODULE_NR, is_isr);
|
|
} else {
|
|
dbuf = vdev->tnr.cur_wr->dbuf[GROUP_BUF_GAIN];
|
|
dummy = dbuf_to_dummy(dbuf, &vdev->tnr.buf.iir, size);
|
|
rkispp_finish_buffer(dev, dummy);
|
|
rkispp_finish_buffer(dev, &vdev->tnr.buf.gain_kg);
|
|
list_add_tail(&vdev->tnr.cur_wr->list, &vdev->tnr.list_rpt);
|
|
}
|
|
vdev->tnr.cur_wr = NULL;
|
|
}
|
|
}
|
|
|
|
if (!is_en) {
|
|
if (buf_wr)
|
|
list_add_tail(&buf_wr->list, &vdev->tnr.list_wr);
|
|
|
|
if (vdev->tnr.nxt_rd) {
|
|
if (sd) {
|
|
v4l2_subdev_call(sd, video, s_rx_buffer,
|
|
vdev->tnr.nxt_rd, NULL);
|
|
} else if (stream->streaming && vdev->tnr.nxt_rd->priv) {
|
|
inbuf = vdev->tnr.nxt_rd->priv;
|
|
vb2_buffer_done(&inbuf->vb.vb2_buf, VB2_BUF_STATE_DONE);
|
|
}
|
|
vdev->tnr.nxt_rd = NULL;
|
|
}
|
|
list = &vdev->tnr.list_rd;
|
|
while (!list_empty(list)) {
|
|
struct rkisp_ispp_buf *buf = get_list_buf(list, true);
|
|
|
|
rkispp_module_work_event(dev, buf, NULL,
|
|
ISPP_MODULE_NR, is_isr);
|
|
}
|
|
if (buf_rd)
|
|
rkispp_module_work_event(dev, buf_rd, NULL,
|
|
ISPP_MODULE_NR, is_isr);
|
|
goto end;
|
|
}
|
|
|
|
spin_lock_irqsave(&monitor->lock, lock_flags1);
|
|
if (monitor->is_restart) {
|
|
if (buf_rd)
|
|
list_add_tail(&buf_rd->list, &vdev->tnr.list_rd);
|
|
if (buf_wr)
|
|
list_add_tail(&buf_wr->list, &vdev->tnr.list_wr);
|
|
goto restart_unlock;
|
|
}
|
|
|
|
list = &vdev->tnr.list_rd;
|
|
if (buf_rd && vdev->tnr.is_end && list_empty(list)) {
|
|
/* tnr read buf from isp */
|
|
vdev->tnr.cur_rd = vdev->tnr.nxt_rd;
|
|
vdev->tnr.nxt_rd = buf_rd;
|
|
/* first buf for 3to1 using twice */
|
|
if (!is_3to1 ||
|
|
(rkispp_read(dev, RKISPP_TNR_CTRL) & SW_TNR_1ST_FRM))
|
|
vdev->tnr.cur_rd = vdev->tnr.nxt_rd;
|
|
} else if (vdev->tnr.is_end && !list_empty(list)) {
|
|
/* tnr read buf from list
|
|
* tnr processing slow than isp
|
|
* new read buf from isp into list
|
|
*/
|
|
vdev->tnr.cur_rd = vdev->tnr.nxt_rd;
|
|
vdev->tnr.nxt_rd = get_list_buf(list, true);
|
|
if (!is_3to1)
|
|
vdev->tnr.cur_rd = vdev->tnr.nxt_rd;
|
|
|
|
if (buf_rd)
|
|
list_add_tail(&buf_rd->list, list);
|
|
} else if (!vdev->tnr.is_end && buf_rd) {
|
|
/* tnr no idle
|
|
* new read buf from isp into list
|
|
*/
|
|
list_add_tail(&buf_rd->list, list);
|
|
}
|
|
|
|
list = &vdev->tnr.list_wr;
|
|
if (vdev->tnr.is_end && !vdev->tnr.cur_wr) {
|
|
/* tnr idle, get new write buf */
|
|
vdev->tnr.cur_wr =
|
|
buf_wr ? buf_wr : get_list_buf(list, true);
|
|
} else if (buf_wr) {
|
|
/* tnr no idle, write buf from nr into list */
|
|
list_add_tail(&buf_wr->list, list);
|
|
}
|
|
|
|
if (vdev->tnr.cur_rd && vdev->tnr.nxt_rd && vdev->tnr.is_end) {
|
|
if (vdev->tnr.cur_rd->priv) {
|
|
inbuf = vdev->tnr.cur_rd->priv;
|
|
val = inbuf->buff_addr[RKISPP_PLANE_Y];
|
|
rkispp_write(dev, RKISPP_TNR_CUR_Y_BASE, val);
|
|
val = inbuf->buff_addr[RKISPP_PLANE_UV];
|
|
rkispp_write(dev, RKISPP_TNR_CUR_UV_BASE, val);
|
|
} else {
|
|
struct rkispp_isp_buf_pool *buf;
|
|
|
|
buf = get_pool_buf(dev, vdev->tnr.cur_rd);
|
|
val = buf->dma[GROUP_BUF_PIC];
|
|
rkispp_write(dev, RKISPP_TNR_CUR_Y_BASE, val);
|
|
val += vdev->tnr.uv_offset;
|
|
rkispp_write(dev, RKISPP_TNR_CUR_UV_BASE, val);
|
|
|
|
val = buf->dma[GROUP_BUF_GAIN];
|
|
rkispp_write(dev, RKISPP_TNR_GAIN_CUR_Y_BASE, val);
|
|
if (is_3to1) {
|
|
buf = get_pool_buf(dev, vdev->tnr.nxt_rd);
|
|
val = buf->dma[GROUP_BUF_PIC];
|
|
rkispp_write(dev, RKISPP_TNR_NXT_Y_BASE, val);
|
|
val += vdev->tnr.uv_offset;
|
|
rkispp_write(dev, RKISPP_TNR_NXT_UV_BASE, val);
|
|
|
|
val = buf->dma[GROUP_BUF_GAIN];
|
|
rkispp_write(dev, RKISPP_TNR_GAIN_NXT_Y_BASE, val);
|
|
|
|
if (rkispp_read(dev, RKISPP_TNR_CTRL) & SW_TNR_1ST_FRM)
|
|
vdev->tnr.cur_rd = NULL;
|
|
}
|
|
}
|
|
is_start = true;
|
|
}
|
|
|
|
if (vdev->tnr.cur_wr && is_start) {
|
|
dbuf = vdev->tnr.cur_wr->dbuf[GROUP_BUF_PIC];
|
|
dummy = dbuf_to_dummy(dbuf, &vdev->tnr.buf.iir, size);
|
|
val = dummy->dma_addr;
|
|
rkispp_write(dev, RKISPP_TNR_WR_Y_BASE, val);
|
|
val += vdev->tnr.uv_offset;
|
|
rkispp_write(dev, RKISPP_TNR_WR_UV_BASE, val);
|
|
|
|
dbuf = vdev->tnr.cur_wr->dbuf[GROUP_BUF_GAIN];
|
|
dummy = dbuf_to_dummy(dbuf, &vdev->tnr.buf.iir, size);
|
|
val = dummy->dma_addr;
|
|
rkispp_write(dev, RKISPP_TNR_GAIN_WR_Y_BASE, val);
|
|
}
|
|
|
|
if (is_start) {
|
|
u32 seq = 0;
|
|
|
|
if (vdev->tnr.nxt_rd) {
|
|
seq = vdev->tnr.nxt_rd->frame_id;
|
|
if (vdev->tnr.cur_wr) {
|
|
vdev->tnr.cur_wr->frame_id = seq;
|
|
vdev->tnr.cur_wr->frame_timestamp =
|
|
vdev->tnr.nxt_rd->frame_timestamp;
|
|
vdev->tnr.cur_wr->is_move_judge =
|
|
vdev->tnr.nxt_rd->is_move_judge;
|
|
}
|
|
dev->stats_vdev[STATS_VDEV_TNR].frame_id = seq;
|
|
}
|
|
|
|
if (!dev->hw_dev->is_single)
|
|
rkispp_update_regs(dev, RKISPP_CTRL, RKISPP_TNR_CORE_WEIGHT);
|
|
writel(TNR_FORCE_UPD, base + RKISPP_CTRL_UPDATE);
|
|
|
|
v4l2_dbg(3, rkispp_debug, &dev->v4l2_dev,
|
|
"TNR start seq:%d | Y_SHD nxt:0x%x cur:0x%x iir:0x%x wr:0x%x\n",
|
|
seq, readl(base + RKISPP_TNR_NXT_Y_BASE_SHD),
|
|
readl(base + RKISPP_TNR_CUR_Y_BASE_SHD),
|
|
readl(base + RKISPP_TNR_IIR_Y_BASE_SHD),
|
|
readl(base + RKISPP_TNR_WR_Y_BASE_SHD));
|
|
|
|
/* iir using previous tnr write frame */
|
|
rkispp_write(dev, RKISPP_TNR_IIR_Y_BASE,
|
|
rkispp_read(dev, RKISPP_TNR_WR_Y_BASE));
|
|
rkispp_write(dev, RKISPP_TNR_IIR_UV_BASE,
|
|
rkispp_read(dev, RKISPP_TNR_WR_UV_BASE));
|
|
|
|
rkispp_prepare_buffer(dev, &vdev->tnr.buf.gain_kg);
|
|
|
|
vdev->tnr.dbg.id = seq;
|
|
vdev->tnr.dbg.timestamp = ktime_get_ns();
|
|
if (monitor->is_en) {
|
|
monitor->tnr.time = vdev->tnr.dbg.interval / 1000 / 1000;
|
|
monitor->monitoring_module |= MONITOR_TNR;
|
|
monitor->tnr.is_err = false;
|
|
if (!completion_done(&monitor->tnr.cmpl))
|
|
complete(&monitor->tnr.cmpl);
|
|
}
|
|
|
|
if (rkispp_is_reg_withstream_global())
|
|
rkispp_find_regbuf_by_id(dev, ®_buf, dev->dev_id, seq);
|
|
if (reg_buf && (rkispp_debug_reg & ISPP_MODULE_TNR)) {
|
|
u32 offset, size;
|
|
|
|
offset = reg_buf->reg_size;
|
|
size = 4 + RKISPP_TNR_STATE - RKISPP_TNR_CTRL;
|
|
reg_buf->ispp_size[ISPP_ID_TNR] = size;
|
|
reg_buf->ispp_offset[ISPP_ID_TNR] = offset;
|
|
memcpy_fromio(®_buf->reg[offset], base + RKISPP_TNR_CTRL, size);
|
|
|
|
offset += size;
|
|
reg_buf->reg_size = offset;
|
|
}
|
|
|
|
if (!dev->hw_dev->is_shutdown)
|
|
writel(TNR_ST, base + RKISPP_CTRL_STRT);
|
|
vdev->tnr.is_end = false;
|
|
}
|
|
|
|
restart_unlock:
|
|
spin_unlock_irqrestore(&monitor->lock, lock_flags1);
|
|
end:
|
|
spin_unlock_irqrestore(&vdev->tnr.buf_lock, lock_flags);
|
|
}
|
|
|
|
static void fec_work_event(struct rkispp_device *dev,
|
|
void *buff_rd,
|
|
bool is_isr, bool is_quick)
|
|
{
|
|
struct rkispp_params_vdev *params_vdev = &dev->params_vdev[PARAM_VDEV_FEC];
|
|
struct rkispp_stream_vdev *vdev = &dev->stream_vdev;
|
|
struct rkispp_monitor *monitor = &vdev->monitor;
|
|
struct list_head *list = &vdev->fec.list_rd;
|
|
void __iomem *base = dev->hw_dev->base_addr;
|
|
struct rkispp_dummy_buffer *dummy;
|
|
struct rkispp_stream *stream;
|
|
unsigned long lock_flags = 0, lock_flags1 = 0;
|
|
bool is_start = false;
|
|
struct rkisp_ispp_reg *reg_buf = NULL;
|
|
u32 val;
|
|
struct rkispp_dummy_buffer *buf_rd = buff_rd;
|
|
|
|
if (!(vdev->module_ens & ISPP_MODULE_FEC))
|
|
return;
|
|
|
|
spin_lock_irqsave(&vdev->fec.buf_lock, lock_flags);
|
|
|
|
/* event from fec frame end */
|
|
if (!buf_rd && is_isr) {
|
|
vdev->fec.is_end = true;
|
|
|
|
if (vdev->fec.dummy_cur_rd || vdev->is_done_early)
|
|
rkispp_module_work_event(dev, NULL, vdev->fec.dummy_cur_rd,
|
|
ISPP_MODULE_NR, false);
|
|
vdev->fec.dummy_cur_rd = NULL;
|
|
}
|
|
|
|
spin_lock_irqsave(&monitor->lock, lock_flags1);
|
|
if (monitor->is_restart && buf_rd) {
|
|
list_add_tail(&buf_rd->list, list);
|
|
goto restart_unlock;
|
|
}
|
|
|
|
if (buf_rd && vdev->fec.is_end && list_empty(list)) {
|
|
/* fec read buf from nr */
|
|
vdev->fec.dummy_cur_rd = buf_rd;
|
|
} else if (vdev->fec.is_end && !list_empty(list)) {
|
|
/* fec read buf from list
|
|
* fec processing slow than nr
|
|
* new read buf from nr into list
|
|
*/
|
|
vdev->fec.dummy_cur_rd = get_list_buf(list, false);
|
|
if (buf_rd)
|
|
list_add_tail(&buf_rd->list, list);
|
|
} else if (!vdev->fec.is_end && buf_rd) {
|
|
/* fec no idle
|
|
* new read buf from nr into list
|
|
*/
|
|
list_add_tail(&buf_rd->list, list);
|
|
}
|
|
|
|
if (vdev->fec.dummy_cur_rd && vdev->fec.is_end) {
|
|
dummy = vdev->fec.dummy_cur_rd;
|
|
val = dummy->dma_addr;
|
|
rkispp_write(dev, RKISPP_FEC_RD_Y_BASE, val);
|
|
val += vdev->fec.uv_offset;
|
|
rkispp_write(dev, RKISPP_FEC_RD_UV_BASE, val);
|
|
is_start = true;
|
|
}
|
|
|
|
if (is_start || is_quick) {
|
|
u32 seq = 0;
|
|
|
|
if (vdev->fec.dummy_cur_rd) {
|
|
seq = vdev->fec.dummy_cur_rd->id;
|
|
dev->ispp_sdev.frame_timestamp =
|
|
vdev->fec.dummy_cur_rd->timestamp;
|
|
dev->ispp_sdev.frm_sync_seq = seq;
|
|
params_vdev->params_ops->rkispp_params_cfg(params_vdev, seq);
|
|
} else {
|
|
seq = vdev->nr.buf.wr[0].id;
|
|
dev->ispp_sdev.frame_timestamp =
|
|
vdev->nr.buf.wr[0].timestamp;
|
|
dev->ispp_sdev.frm_sync_seq = seq;
|
|
}
|
|
|
|
/* check MB config and output buf beforce start, when MB connect to FEC
|
|
* MB update by FEC_FORCE_UPD
|
|
*/
|
|
stream = &vdev->stream[STREAM_MB];
|
|
if (stream->streaming) {
|
|
if (!stream->is_cfg) {
|
|
secure_config_mb(stream);
|
|
} else if (!stream->curr_buf) {
|
|
get_stream_buf(stream);
|
|
if (stream->curr_buf)
|
|
update_mi(stream);
|
|
}
|
|
}
|
|
|
|
if (!dev->hw_dev->is_single) {
|
|
rkispp_update_regs(dev, RKISPP_FEC, RKISPP_FEC_CROP);
|
|
rkispp_update_regs(dev, RKISPP_SCL0, RKISPP_SCL2_FACTOR);
|
|
}
|
|
|
|
writel(FEC_FORCE_UPD, base + RKISPP_CTRL_UPDATE);
|
|
if (vdev->nr.is_end) {
|
|
if (!dev->hw_dev->is_single)
|
|
rkispp_update_regs(dev, RKISPP_SCL0_CTRL, RKISPP_SCL2_FACTOR);
|
|
writel(OTHER_FORCE_UPD, base + RKISPP_CTRL_UPDATE);
|
|
/* check scale stream stop state */
|
|
for (val = STREAM_S0; val <= STREAM_S2; val++) {
|
|
stream = &vdev->stream[val];
|
|
if (stream->streaming && stream->stopping) {
|
|
if (stream->ops->is_stopped(stream)) {
|
|
stream->stopping = false;
|
|
stream->streaming = false;
|
|
wake_up(&stream->done);
|
|
} else {
|
|
stream->ops->stop(stream);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
v4l2_dbg(3, rkispp_debug, &dev->v4l2_dev,
|
|
"FEC start seq:%d | Y_SHD rd:0x%x\n"
|
|
"\txint:0x%x xfra:0x%x yint:0x%x yfra:0x%x\n",
|
|
seq, readl(base + RKISPP_FEC_RD_Y_BASE_SHD),
|
|
readl(base + RKISPP_FEC_MESH_XINT_BASE_SHD),
|
|
readl(base + RKISPP_FEC_MESH_XFRA_BASE_SHD),
|
|
readl(base + RKISPP_FEC_MESH_YINT_BASE_SHD),
|
|
readl(base + RKISPP_FEC_MESH_YFRA_BASE_SHD));
|
|
|
|
vdev->fec.dbg.id = seq;
|
|
vdev->fec.dbg.timestamp = ktime_get_ns();
|
|
if (monitor->is_en) {
|
|
monitor->fec.time = vdev->fec.dbg.interval / 1000 / 1000;
|
|
monitor->monitoring_module |= MONITOR_FEC;
|
|
if (!completion_done(&monitor->fec.cmpl))
|
|
complete(&monitor->fec.cmpl);
|
|
}
|
|
|
|
if (rkispp_is_reg_withstream_global())
|
|
rkispp_find_regbuf_by_id(dev, ®_buf, dev->dev_id, seq);
|
|
if (reg_buf && (rkispp_debug_reg & ISPP_MODULE_FEC)) {
|
|
u32 offset, size;
|
|
|
|
offset = reg_buf->reg_size;
|
|
size = 4 + RKISPP_FEC_CROP - RKISPP_FEC_CTRL;
|
|
reg_buf->ispp_size[ISPP_ID_FEC] = size;
|
|
reg_buf->ispp_offset[ISPP_ID_FEC] = offset;
|
|
memcpy_fromio(®_buf->reg[offset], base + RKISPP_FEC_CTRL, size);
|
|
|
|
offset += size;
|
|
reg_buf->reg_size = offset;
|
|
}
|
|
|
|
if (!dev->hw_dev->is_shutdown) {
|
|
writel(FEC_ST, base + RKISPP_CTRL_STRT);
|
|
|
|
if (vdev->is_done_early)
|
|
hrtimer_start(&vdev->frame_qst,
|
|
ns_to_ktime(5000000),
|
|
HRTIMER_MODE_REL);
|
|
}
|
|
vdev->fec.is_end = false;
|
|
}
|
|
restart_unlock:
|
|
spin_unlock_irqrestore(&monitor->lock, lock_flags1);
|
|
spin_unlock_irqrestore(&vdev->fec.buf_lock, lock_flags);
|
|
}
|
|
|
|
|
|
void rkispp_set_trigger_mode(struct rkispp_device *dev,
|
|
struct rkispp_trigger_mode *mode)
|
|
{
|
|
struct rkispp_stream_vdev *vdev = &dev->stream_vdev;
|
|
|
|
if (mode->module & ISPP_MODULE_TNR)
|
|
vdev->tnr.is_trigger = mode->on;
|
|
}
|
|
|
|
int rkispp_get_tnrbuf_fd(struct rkispp_device *dev, struct rkispp_buf_idxfd *idxfd)
|
|
{
|
|
struct rkispp_stream_vdev *vdev = &dev->stream_vdev;
|
|
struct rkisp_ispp_buf *dbufs;
|
|
struct rkispp_dummy_buffer *buf;
|
|
unsigned long lock_flags = 0;
|
|
int j, buf_idx, ret = 0;
|
|
|
|
spin_lock_irqsave(&vdev->tnr.buf_lock, lock_flags);
|
|
if (!vdev->tnr.is_buf_init) {
|
|
spin_unlock_irqrestore(&vdev->tnr.buf_lock, lock_flags);
|
|
ret = -EAGAIN;
|
|
return ret;
|
|
}
|
|
spin_unlock_irqrestore(&vdev->tnr.buf_lock, lock_flags);
|
|
|
|
buf_idx = 0;
|
|
list_for_each_entry(dbufs, &vdev->tnr.list_wr, list) {
|
|
for (j = 0; j < GROUP_BUF_MAX; j++) {
|
|
dbufs->dfd[j] = dma_buf_fd(dbufs->dbuf[j], O_CLOEXEC);
|
|
get_dma_buf(dbufs->dbuf[j]);
|
|
idxfd->index[buf_idx] = dbufs->didx[j];
|
|
idxfd->dmafd[buf_idx] = dbufs->dfd[j];
|
|
buf_idx++;
|
|
}
|
|
}
|
|
|
|
list_for_each_entry(dbufs, &vdev->tnr.list_rpt, list) {
|
|
for (j = 0; j < GROUP_BUF_MAX; j++) {
|
|
dbufs->dfd[j] = dma_buf_fd(dbufs->dbuf[j], O_CLOEXEC);
|
|
get_dma_buf(dbufs->dbuf[j]);
|
|
idxfd->index[buf_idx] = dbufs->didx[j];
|
|
idxfd->dmafd[buf_idx] = dbufs->dfd[j];
|
|
buf_idx++;
|
|
}
|
|
}
|
|
|
|
if (vdev->tnr.cur_wr) {
|
|
for (j = 0; j < GROUP_BUF_MAX; j++) {
|
|
vdev->tnr.cur_wr->dfd[j] = dma_buf_fd(vdev->tnr.cur_wr->dbuf[j], O_CLOEXEC);
|
|
get_dma_buf(vdev->tnr.cur_wr->dbuf[j]);
|
|
idxfd->index[buf_idx] = vdev->tnr.cur_wr->didx[j];
|
|
idxfd->dmafd[buf_idx] = vdev->tnr.cur_wr->dfd[j];
|
|
buf_idx++;
|
|
}
|
|
}
|
|
|
|
buf = &vdev->tnr.buf.gain_kg;
|
|
buf->dma_fd = dma_buf_fd(buf->dbuf, O_CLOEXEC);
|
|
get_dma_buf(buf->dbuf);
|
|
idxfd->index[buf_idx] = buf->index;
|
|
idxfd->dmafd[buf_idx] = buf->dma_fd;
|
|
buf_idx++;
|
|
|
|
idxfd->buf_num = buf_idx;
|
|
|
|
return ret;
|
|
}
|
|
|
|
int rkispp_get_nrbuf_fd(struct rkispp_device *dev, struct rkispp_buf_idxfd *idxfd)
|
|
{
|
|
struct rkispp_stream_vdev *vdev = &dev->stream_vdev;
|
|
struct rkispp_dummy_buffer *buf;
|
|
unsigned long lock_flags = 0;
|
|
int i, ret = 0;
|
|
|
|
spin_lock_irqsave(&vdev->nr.buf_lock, lock_flags);
|
|
if (!vdev->nr.is_buf_init) {
|
|
spin_unlock_irqrestore(&vdev->nr.buf_lock, lock_flags);
|
|
ret = -EAGAIN;
|
|
return ret;
|
|
}
|
|
spin_unlock_irqrestore(&vdev->nr.buf_lock, lock_flags);
|
|
|
|
for (i = 0; i < RKISPP_FEC_BUF_MAX; i++) {
|
|
buf = &vdev->nr.buf.wr[i];
|
|
if (!buf->dbuf)
|
|
break;
|
|
buf->dma_fd = dma_buf_fd(buf->dbuf, O_CLOEXEC);
|
|
get_dma_buf(buf->dbuf);
|
|
idxfd->index[i] = i;
|
|
idxfd->dmafd[i] = buf->dma_fd;
|
|
}
|
|
idxfd->buf_num = i;
|
|
return ret;
|
|
}
|
|
|
|
static void rkispp_module_work_event(struct rkispp_device *dev,
|
|
void *buf_rd, void *buf_wr,
|
|
u32 module, bool is_isr)
|
|
{
|
|
struct rkispp_stream_vdev *vdev = &dev->stream_vdev;
|
|
bool is_fec_en = !!(vdev->module_ens & ISPP_MODULE_FEC);
|
|
bool is_single = dev->hw_dev->is_single;
|
|
//bool is_early = vdev->is_done_early;
|
|
|
|
if (dev->hw_dev->is_shutdown)
|
|
return;
|
|
|
|
if (dev->ispp_sdev.state != ISPP_STOP) {
|
|
if (module & ISPP_MODULE_TNR)
|
|
tnr_work_event(dev, buf_rd, buf_wr, is_isr);
|
|
else if (module & ISPP_MODULE_NR)
|
|
nr_work_event(dev, buf_rd, buf_wr, is_isr);
|
|
else
|
|
fec_work_event(dev, buf_rd, is_isr, false);
|
|
}
|
|
|
|
/*
|
|
* ispp frame done to do next conditions
|
|
* mulit dev: cur frame (tnr->nr->fec) done for next frame
|
|
* 1.single dev: fec async with tnr, and sync with nr:
|
|
* { f0 }
|
|
* tnr->nr->fec->|
|
|
* |->tnr->nr->fec
|
|
* { f1 }
|
|
* 2.single dev and early mode:
|
|
* { f0 } { f1 } { f2 }
|
|
* tnr->nr->tnr->nr->tnr->nr
|
|
* |->fec->||->fec->|
|
|
* { f0 }{ f1 }
|
|
* 3.single fec
|
|
*
|
|
*/
|
|
if (is_isr && !buf_rd && !buf_wr &&
|
|
((!is_fec_en && module == ISPP_MODULE_NR) ||
|
|
(is_fec_en &&
|
|
((module == ISPP_MODULE_NR && (is_single || vdev->fec.is_end)) ||
|
|
(module == ISPP_MODULE_FEC && !is_single && vdev->fec.is_end))))) {
|
|
dev->stream_vdev.monitor.retry = 0;
|
|
rkispp_soft_reset(dev->hw_dev);
|
|
rkispp_event_handle(dev, CMD_QUEUE_DMABUF, NULL);
|
|
}
|
|
|
|
if (dev->ispp_sdev.state == ISPP_STOP) {
|
|
if ((module & (ISPP_MODULE_TNR | ISPP_MODULE_NR)) && buf_rd) {
|
|
struct rkisp_ispp_buf *buf = buf_rd;
|
|
|
|
if (buf->is_isp)
|
|
v4l2_subdev_call(dev->ispp_sdev.remote_sd,
|
|
video, s_rx_buffer, buf, NULL);
|
|
}
|
|
if (!dev->hw_dev->is_idle)
|
|
dev->hw_dev->is_idle = true;
|
|
}
|
|
}
|
|
|
|
static int start_isp(struct rkispp_device *dev)
|
|
{
|
|
struct rkispp_subdev *ispp_sdev = &dev->ispp_sdev;
|
|
struct rkispp_stream_vdev *vdev = &dev->stream_vdev;
|
|
struct rkispp_stream *stream;
|
|
struct rkisp_ispp_mode mode;
|
|
int i, ret;
|
|
|
|
if (dev->inp != INP_ISP || ispp_sdev->state)
|
|
return 0;
|
|
|
|
if (dev->stream_sync) {
|
|
/* output stream enable then start isp */
|
|
for (i = STREAM_MB; i <= STREAM_S2; i++) {
|
|
stream = &vdev->stream[i];
|
|
if (stream->linked && !stream->streaming)
|
|
return 0;
|
|
}
|
|
} else if (atomic_read(&vdev->refcnt) > 1) {
|
|
return 0;
|
|
}
|
|
|
|
rkispp_start_3a_run(dev);
|
|
|
|
mutex_lock(&dev->hw_dev->dev_lock);
|
|
|
|
mode.work_mode = dev->isp_mode;
|
|
mode.buf_num = ((vdev->module_ens & ISPP_MODULE_TNR_3TO1) ==
|
|
ISPP_MODULE_TNR_3TO1) ? 2 : 1;
|
|
mode.buf_num += RKISP_BUF_MAX + 2 * (dev->hw_dev->dev_num - 1);
|
|
ret = v4l2_subdev_call(ispp_sdev->remote_sd, core, ioctl,
|
|
RKISP_ISPP_CMD_SET_MODE, &mode);
|
|
if (ret)
|
|
goto err;
|
|
|
|
ret = config_modules(dev);
|
|
if (ret) {
|
|
rkispp_event_handle(dev, CMD_FREE_POOL, NULL);
|
|
mode.work_mode = ISP_ISPP_INIT_FAIL;
|
|
v4l2_subdev_call(ispp_sdev->remote_sd, core, ioctl,
|
|
RKISP_ISPP_CMD_SET_MODE, &mode);
|
|
goto err;
|
|
}
|
|
if (dev->hw_dev->is_single)
|
|
writel(ALL_FORCE_UPD, dev->hw_dev->base_addr + RKISPP_CTRL_UPDATE);
|
|
for (i = STREAM_MB; i <= STREAM_S2; i++) {
|
|
stream = &vdev->stream[i];
|
|
if (stream->streaming)
|
|
stream->is_upd = true;
|
|
}
|
|
if (dev->isp_mode & ISP_ISPP_QUICK)
|
|
rkispp_set_bits(dev, RKISPP_CTRL_QUICK, 0, GLB_QUICK_EN);
|
|
|
|
dev->isr_cnt = 0;
|
|
dev->isr_err_cnt = 0;
|
|
ret = v4l2_subdev_call(&ispp_sdev->sd, video, s_stream, true);
|
|
err:
|
|
mutex_unlock(&dev->hw_dev->dev_lock);
|
|
return ret;
|
|
}
|
|
|
|
static void check_to_force_update(struct rkispp_device *dev, u32 mis_val)
|
|
{
|
|
struct rkispp_stream_vdev *vdev = &dev->stream_vdev;
|
|
struct rkispp_stream *stream;
|
|
u32 i, mask = NR_INT | SHP_INT;
|
|
bool is_fec_en = (vdev->module_ens & ISPP_MODULE_FEC);
|
|
|
|
if (mis_val & TNR_INT)
|
|
rkispp_module_work_event(dev, NULL, NULL,
|
|
ISPP_MODULE_TNR, true);
|
|
if (mis_val & FEC_INT)
|
|
rkispp_module_work_event(dev, NULL, NULL,
|
|
ISPP_MODULE_FEC, true);
|
|
|
|
/* wait nr_shp/fec/scl idle */
|
|
for (i = STREAM_S0; i <= STREAM_S2; i++) {
|
|
stream = &vdev->stream[i];
|
|
if (stream->is_upd && !is_fec_en &&
|
|
rkispp_read(dev, stream->config->reg.ctrl) & SW_SCL_ENABLE)
|
|
mask |= stream->config->frame_end_id;
|
|
}
|
|
|
|
vdev->irq_ends |= (mis_val & mask);
|
|
v4l2_dbg(3, rkispp_debug, &dev->v4l2_dev,
|
|
"irq_ends:0x%x mask:0x%x\n",
|
|
vdev->irq_ends, mask);
|
|
if (vdev->irq_ends != mask)
|
|
return;
|
|
vdev->irq_ends = 0;
|
|
rkispp_module_work_event(dev, NULL, NULL,
|
|
ISPP_MODULE_NR, true);
|
|
|
|
for (i = STREAM_MB; i <= STREAM_S2; i++) {
|
|
stream = &vdev->stream[i];
|
|
if (stream->streaming)
|
|
stream->is_upd = true;
|
|
}
|
|
}
|
|
|
|
static struct rkispp_stream_ops rkispp_stream_ops = {
|
|
.config_modules = config_modules,
|
|
.destroy_buf = rkispp_destroy_buf,
|
|
.fec_work_event = fec_work_event,
|
|
.start_isp = start_isp,
|
|
.check_to_force_update = check_to_force_update,
|
|
.update_mi = update_mi,
|
|
.rkispp_frame_done_early = rkispp_frame_done_early,
|
|
.rkispp_module_work_event = rkispp_module_work_event,
|
|
};
|
|
|
|
void rkispp_stream_init_ops_v10(struct rkispp_stream_vdev *stream_vdev)
|
|
{
|
|
stream_vdev->stream_ops = &rkispp_stream_ops;
|
|
}
|