media: rockchip: vicap support to get sensor effect exp info

Signed-off-by: Zefa Chen <zefa.chen@rock-chips.com>
Change-Id: Iaa67bf235437e1a4e42bee87e78352496ba7f086
This commit is contained in:
Zefa Chen
2024-10-25 11:36:26 +08:00
committed by Tao Huang
parent 10f2e76f0c
commit 09610469c5
3 changed files with 434 additions and 3 deletions

View File

@@ -25,6 +25,7 @@
#include <linux/fdtable.h>
#include <linux/mm.h>
#include <clocksource/arm_arch_timer.h>
#include <linux/kfifo.h>
#include "dev.h"
#include "mipi-csi2.h"
@@ -6479,6 +6480,15 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream,
if (can_reset && hw_dev->dummy_buf.vaddr)
rkcif_destroy_dummy_buf(stream);
stream->rounding_bit = 0;
if (stream->id == RKCIF_STREAM_MIPI_ID0 && dev->is_support_get_exp) {
kfifo_free(&stream->exp_kfifo);
kfifo_free(&stream->gain_kfifo);
kfifo_free(&stream->vts_kfifo);
kfifo_free(&stream->dcg_kfifo);
}
}
if (mode == RKCIF_STREAM_MODE_CAPTURE) {
tasklet_disable(&stream->vb_done_tasklet);
@@ -7870,6 +7880,34 @@ int rkcif_do_start_stream(struct rkcif_stream *stream, enum rkcif_stream_mode mo
else
stream->skip_frame = 0;
stream->cur_skip_frame = stream->skip_frame;
if (stream->id == RKCIF_STREAM_MIPI_ID0 && dev->is_support_get_exp) {
ret = kfifo_alloc(&stream->exp_kfifo,
sizeof(struct rkcif_sensor_exp) * RKCIF_EXP_NUM_MAX, GFP_KERNEL);
if (ret < 0)
goto disable_tasklet;
ret = kfifo_alloc(&stream->gain_kfifo,
sizeof(struct rkcif_sensor_gain) * RKCIF_EXP_NUM_MAX, GFP_KERNEL);
if (ret < 0)
goto disable_tasklet;
ret = kfifo_alloc(&stream->vts_kfifo,
sizeof(struct rkcif_sensor_vts) * RKCIF_EXP_NUM_MAX, GFP_KERNEL);
if (ret < 0)
goto disable_tasklet;
ret = kfifo_alloc(&stream->dcg_kfifo,
sizeof(struct rkcif_sensor_dcg) * RKCIF_EXP_NUM_MAX, GFP_KERNEL);
if (ret < 0)
goto disable_tasklet;
ret = v4l2_subdev_call(terminal_sensor->sd,
core, ioctl,
RKMODULE_GET_EXP_DELAY,
&stream->exp_delay);
if (ret) {
stream->exp_delay.exp_delay = 2;
stream->exp_delay.gain_delay = 2;
stream->exp_delay.vts_delay = 2;
stream->exp_delay.dcg_delay = 1;
}
}
}
if (dev->chip_id >= CHIP_RK1808_CIF) {
if (dev->active_sensor &&
@@ -8300,6 +8338,7 @@ void rkcif_stream_init(struct rkcif_device *dev, u32 id)
stream->is_m_online_fb_res = false;
stream->is_fb_first_frame = true;
stream->frame_idx = 0;
memset(&stream->sensor_exp_info, 0, sizeof(stream->sensor_exp_info));
}
static int rkcif_sensor_set_power(struct rkcif_stream *stream, int on)
@@ -9440,6 +9479,12 @@ static long rkcif_ioctl_default(struct file *file, void *fh,
v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, "flip delay_ms %d\n", delay_ms);
mutex_unlock(&dev->stream_lock);
break;
case RKCIF_CMD_SUPPORT_GET_EXP:
if (*(int *)arg)
dev->is_support_get_exp = true;
else
dev->is_support_get_exp = false;
break;
default:
return -EINVAL;
}
@@ -12532,6 +12577,313 @@ static void rkcif_check_vblank_value(struct rkcif_device *dev)
v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, "vblank time %u us\n", vblank_us);
}
static void rkcif_add_sensor_exp_to_kfifo(struct rkcif_stream *stream)
{
struct rkcif_sensor_exp sensor_exp;
struct rkcif_sensor_gain sensor_gain;
struct rkcif_sensor_vts sensor_vts;
struct rkcif_sensor_dcg sensor_dcg;
struct rkmodule_exp_info sensor_exp_info = {0};
int i = 0;
int ret = 0;
int j = 0;
int idx_max = 0;
if (!stream->cifdev->is_support_get_exp)
return;
if (stream->cifdev->hdr.hdr_mode == HDR_X2)
idx_max = 2;
else if (stream->cifdev->hdr.hdr_mode == HDR_X3)
idx_max = 3;
else
idx_max = 1;
ret = v4l2_subdev_call(stream->cifdev->terminal_sensor.sd,
core, ioctl,
RKMODULE_GET_EXP_INFO,
&sensor_exp_info);
if (!ret)
stream->sensor_exp_info = sensor_exp_info;
if (stream->frame_idx == 0) {
for (i = 0; i < stream->exp_delay.exp_delay; i++) {
sensor_exp.sequence = i;
for (j = 0; j < idx_max; j++)
sensor_exp.exp[j] = stream->sensor_exp_info.exp[j];
kfifo_in(&stream->exp_kfifo, &sensor_exp, sizeof(sensor_exp));
}
for (i = 0; i < stream->exp_delay.gain_delay; i++) {
sensor_gain.sequence = i;
for (j = 0; j < idx_max; j++)
sensor_gain.gain[j] = stream->sensor_exp_info.gain[j];
kfifo_in(&stream->gain_kfifo, &sensor_gain, sizeof(sensor_gain));
}
for (i = 0; i < stream->exp_delay.vts_delay; i++) {
sensor_vts.sequence = i;
sensor_vts.vts = stream->sensor_exp_info.vts;
kfifo_in(&stream->vts_kfifo, &sensor_vts, sizeof(sensor_vts));
}
if (sensor_exp_info.dcg_used) {
for (i = 0; i < stream->exp_delay.dcg_delay; i++) {
sensor_dcg.sequence = i;
for (j = 0; j < idx_max; j++)
sensor_dcg.dcg[j] = stream->sensor_exp_info.dcg_val[j];
kfifo_in(&stream->dcg_kfifo, &sensor_dcg, sizeof(sensor_dcg));
}
}
} else {
if (kfifo_is_full(&stream->exp_kfifo)) {
ret = kfifo_out(&stream->exp_kfifo, &sensor_exp, sizeof(sensor_exp));
if (!ret)
v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev,
"stream[%d] seq %d, exp %u %u %u\n",
stream->id, sensor_exp.sequence,
sensor_exp.exp[0],
sensor_exp.exp[1],
sensor_exp.exp[2]);
}
sensor_exp.sequence = stream->frame_idx + stream->exp_delay.exp_delay - 1;
for (j = 0; j < idx_max; j++)
sensor_exp.exp[j] = stream->sensor_exp_info.exp[j];
kfifo_in(&stream->exp_kfifo, &sensor_exp, sizeof(sensor_exp));
if (kfifo_is_full(&stream->gain_kfifo)) {
ret = kfifo_out(&stream->gain_kfifo, &sensor_gain, sizeof(sensor_gain));
if (!ret)
v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev,
"stream[%d] seq %d, gain %u %u %u\n",
stream->id, sensor_gain.sequence,
sensor_gain.gain[0],
sensor_gain.gain[1],
sensor_gain.gain[2]);
}
sensor_gain.sequence = stream->frame_idx + stream->exp_delay.gain_delay - 1;
for (j = 0; j < idx_max; j++)
sensor_gain.gain[j] = stream->sensor_exp_info.gain[j];
kfifo_in(&stream->gain_kfifo, &sensor_gain, sizeof(sensor_gain));
if (kfifo_is_full(&stream->vts_kfifo)) {
ret = kfifo_out(&stream->vts_kfifo, &sensor_vts, sizeof(sensor_vts));
if (!ret)
v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev,
"stream[%d] seq %d, vts %u\n",
stream->id, sensor_vts.sequence, sensor_vts.vts);
}
sensor_vts.sequence = stream->frame_idx + stream->exp_delay.vts_delay - 1;
sensor_vts.vts = stream->sensor_exp_info.vts;
kfifo_in(&stream->vts_kfifo, &sensor_vts, sizeof(sensor_vts));
if (sensor_exp_info.dcg_used) {
if (kfifo_is_full(&stream->dcg_kfifo)) {
ret = kfifo_out(&stream->dcg_kfifo, &sensor_dcg, sizeof(sensor_dcg));
if (!ret)
v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev,
"stream[%d] seq %d, dcg %u %u %u\n",
stream->id, sensor_dcg.sequence,
sensor_dcg.dcg[0],
sensor_dcg.dcg[1],
sensor_dcg.dcg[2]);
}
sensor_dcg.sequence = stream->frame_idx + stream->exp_delay.dcg_delay - 1;
for (j = 0; j < idx_max; j++)
sensor_dcg.dcg[j] = stream->sensor_exp_info.dcg_val[j];
kfifo_in(&stream->dcg_kfifo, &sensor_dcg, sizeof(sensor_dcg));
}
}
}
static int rkcif_get_sof_and_exp_info(struct rkcif_device *cif_dev,
struct rkisp_vicap_sof *sof_info)
{
struct rkcif_stream *stream = &cif_dev->stream[0];
struct rkcif_sensor_exp sensor_exp = {0};
struct rkcif_sensor_gain sensor_gain = {0};
struct rkcif_sensor_vts sensor_vts = {0};
struct rkcif_sensor_dcg sensor_dcg = {0};
int ret = 0;
int i = 0;
int j = 0;
int idx_max = 0;
sof_info->timestamp = stream->readout.fs_timestamp;
sof_info->sequence = stream->frame_idx;
if (!cif_dev->is_support_get_exp)
return 0;
if (cif_dev->hdr.hdr_mode == HDR_X2)
idx_max = 2;
else if (cif_dev->hdr.hdr_mode == HDR_X3)
idx_max = 3;
else
idx_max = 1;
if (!kfifo_is_empty(&stream->exp_kfifo)) {
ret = kfifo_out(&stream->exp_kfifo, &sensor_exp, sizeof(sensor_exp));
if (ret == sizeof(sensor_exp)) {
v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev,
"stream[%d] seq %d, exp %u %u %u\n",
stream->id, sensor_exp.sequence,
sensor_exp.exp[0],
sensor_exp.exp[1],
sensor_exp.exp[2]);
}
}
if (!kfifo_is_empty(&stream->gain_kfifo)) {
ret = kfifo_out(&stream->gain_kfifo, &sensor_gain, sizeof(sensor_gain));
if (ret == sizeof(sensor_gain))
v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev,
"stream[%d] seq %d, gain %u %u %u\n",
stream->id, sensor_gain.sequence,
sensor_gain.gain[0],
sensor_gain.gain[1],
sensor_gain.gain[2]);
else
return ret;
}
if (sensor_exp.sequence > sensor_gain.sequence) {
for (i = 0; i < RKCIF_EXP_NUM_MAX; i++) {
if (!kfifo_is_empty(&stream->gain_kfifo)) {
ret = kfifo_out(&stream->gain_kfifo, &sensor_gain, sizeof(sensor_gain));
if (ret == sizeof(sensor_gain))
v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev,
"stream[%d] seq %d, gain %u %u %u\n",
stream->id, sensor_gain.sequence,
sensor_gain.gain[0],
sensor_gain.gain[1],
sensor_gain.gain[2]);
else
return ret;
if (sensor_gain.sequence == sensor_exp.sequence)
break;
else if (sensor_gain.sequence > sensor_exp.sequence)
return -EINVAL;
}
}
if (i == RKCIF_EXP_NUM_MAX)
return -EINVAL;
} else if (sensor_exp.sequence < sensor_gain.sequence) {
for (i = 0; i < RKCIF_EXP_NUM_MAX; i++) {
if (!kfifo_is_empty(&stream->exp_kfifo)) {
ret = kfifo_out(&stream->exp_kfifo, &sensor_exp, sizeof(sensor_exp));
if (ret == sizeof(sensor_exp))
v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev,
"stream[%d] seq %d, exp %u %u %u\n",
stream->id, sensor_exp.sequence,
sensor_exp.exp[0],
sensor_exp.exp[1],
sensor_exp.exp[2]);
else
return ret;
if (sensor_exp.sequence == sensor_gain.sequence)
break;
else if (sensor_exp.sequence > sensor_gain.sequence)
return -EINVAL;
}
}
if (i == RKCIF_EXP_NUM_MAX)
return -EINVAL;
}
if (!kfifo_is_empty(&stream->vts_kfifo)) {
ret = kfifo_out(&stream->vts_kfifo, &sensor_vts, sizeof(sensor_vts));
if (ret == sizeof(sensor_vts))
v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev,
"stream[%d] seq %d, vts %u\n",
stream->id, sensor_vts.sequence, sensor_vts.vts);
else
return ret;
}
if (sensor_exp.sequence > sensor_vts.sequence) {
for (i = 0; i < RKCIF_EXP_NUM_MAX; i++) {
if (!kfifo_is_empty(&stream->vts_kfifo)) {
ret = kfifo_out(&stream->vts_kfifo, &sensor_vts, sizeof(sensor_vts));
if (ret == sizeof(sensor_vts))
v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev,
"stream[%d] seq %d, vts %u\n",
stream->id, sensor_vts.sequence, sensor_vts.vts);
else
return ret;
if (sensor_vts.sequence == sensor_exp.sequence)
break;
else if (sensor_vts.sequence > sensor_exp.sequence)
return -EINVAL;
}
}
if (i == RKCIF_EXP_NUM_MAX)
return -EINVAL;
} else if (sensor_exp.sequence < sensor_vts.sequence) {
return -EINVAL;
}
if (stream->sensor_exp_info.dcg_used) {
if (!kfifo_is_empty(&stream->dcg_kfifo)) {
ret = kfifo_out(&stream->dcg_kfifo, &sensor_dcg, sizeof(sensor_dcg));
if (ret == sizeof(sensor_dcg))
v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev,
"stream[%d] seq %d, dcg %u %u %u\n",
stream->id, sensor_dcg.sequence,
sensor_dcg.dcg[0],
sensor_dcg.dcg[1],
sensor_dcg.dcg[2]);
else
return ret;
}
if (sensor_exp.sequence > sensor_dcg.sequence) {
for (i = 0; i < RKCIF_EXP_NUM_MAX; i++) {
if (!kfifo_is_empty(&stream->dcg_kfifo)) {
ret = kfifo_out(&stream->dcg_kfifo, &sensor_dcg, sizeof(sensor_dcg));
if (ret == sizeof(sensor_dcg))
v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev,
"stream[%d] seq %d, dcg %u %u %u\n",
stream->id, sensor_dcg.sequence,
sensor_dcg.dcg[0],
sensor_dcg.dcg[1],
sensor_dcg.dcg[2]);
else
return ret;
if (sensor_dcg.sequence == sensor_exp.sequence)
break;
else if (sensor_dcg.sequence > sensor_exp.sequence)
return -EINVAL;
}
}
if (i == RKCIF_EXP_NUM_MAX)
return -EINVAL;
} else if (sensor_exp.sequence < sensor_dcg.sequence) {
return -EINVAL;
}
sof_info->dcg_used = 1;
sof_info->dcg_ratio = stream->sensor_exp_info.dcg_ratio;
for (j = 0; j < idx_max; j++)
sof_info->dcg_val[j] = sensor_dcg.dcg[j];
} else {
sof_info->dcg_used = 0;
}
sof_info->sequence = sensor_exp.sequence;
for (j = 0; j < idx_max; j++) {
sof_info->exp[j] = sensor_exp.exp[j];
sof_info->gain[j] = sensor_gain.gain[j];
}
sof_info->vts = sensor_vts.vts;
sof_info->hts = stream->sensor_exp_info.hts;
sof_info->pclk = stream->sensor_exp_info.pclk;
sof_info->gain_mode = stream->sensor_exp_info.gain_mode;
sof_info->is_exp_active = true;
v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev,
"seq %d, exp %u %u %u, gain %u %u %u, dcg %u %u %u, vts %u\n",
sof_info->sequence,
sof_info->exp[0],
sof_info->exp[1],
sof_info->exp[2],
sof_info->gain[0],
sof_info->gain[1],
sof_info->gain[2],
sof_info->dcg_val[0],
sof_info->dcg_val[1],
sof_info->dcg_val[2],
sof_info->vts);
return 0;
}
static void rkcif_toisp_check_stop_status(struct sditf_priv *priv,
unsigned int intstat_glb,
int index)
@@ -12826,15 +13178,28 @@ static void rkcif_deal_sof(struct rkcif_device *cif_dev)
unsigned long flags;
int i = 0;
int ret = 0;
struct v4l2_subdev *sd = NULL;
struct rkisp_vicap_sof sof = {0};
spin_lock_irqsave(&detect_stream->fps_lock, flags);
detect_stream->readout.fs_timestamp = rkcif_time_get_ns(cif_dev);
spin_unlock_irqrestore(&detect_stream->fps_lock, flags);
if (cif_dev->chip_id >= CHIP_RK3576_CIF) {
rkcif_add_sensor_exp_to_kfifo(&cif_dev->stream[0]);
sd = get_rkisp_sd(cif_dev->sditf[0]);
if (sd) {
rkcif_get_sof_and_exp_info(cif_dev, &sof);
v4l2_subdev_call(sd, core, ioctl,
RKISP_VICAP_CMD_SOF, &sof);
}
}
if (cif_dev->chip_id >= CHIP_RK3576_CIF && (!detect_stream->dma_en))
return;
if (cif_dev->chip_id < CHIP_RK3588_CIF)
detect_stream->fs_cnt_in_single_frame++;
spin_lock_irqsave(&detect_stream->fps_lock, flags);
detect_stream->readout.fs_timestamp = rkcif_time_get_ns(cif_dev);
spin_unlock_irqrestore(&detect_stream->fps_lock, flags);
if (cif_dev->sync_cfg.type != NO_SYNC_MODE &&
cif_dev->sync_cfg.type != SOFT_SYNC_MODE) {

View File

@@ -1004,6 +1004,41 @@ static ssize_t rkcif_store_reg_dbg(struct device *dev,
static DEVICE_ATTR(reg_dbg, 0600,
rkcif_show_reg_dbg, rkcif_store_reg_dbg);
static ssize_t rkcif_show_get_exp_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev);
int ret;
ret = snprintf(buf, PAGE_SIZE, "%d\n",
cif_dev->is_support_get_exp);
return ret;
}
static ssize_t rkcif_store_get_exp_mode(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev);
int val = 0;
int ret = 0;
ret = kstrtoint(buf, 0, &val);
if (!ret) {
if (val)
cif_dev->is_support_get_exp = true;
else
cif_dev->is_support_get_exp = false;
} else {
dev_info(cif_dev->dev, "set get_exp mode failed\n");
}
return len;
}
static DEVICE_ATTR(is_support_get_exp, 0600,
rkcif_show_get_exp_mode, rkcif_store_get_exp_mode);
static struct attribute *dev_attrs[] = {
&dev_attr_compact_test.attr,
&dev_attr_wait_line.attr,
@@ -1023,6 +1058,7 @@ static struct attribute *dev_attrs[] = {
&dev_attr_use_hw_interlace.attr,
&dev_attr_low_latency.attr,
&dev_attr_reg_dbg.attr,
&dev_attr_is_support_get_exp.attr,
NULL,
};
@@ -2825,6 +2861,7 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int
cif_dev->is_in_flip = false;
cif_dev->sw_reg = devm_kzalloc(cif_dev->dev, RKCIF_REG_MAX, GFP_KERNEL);
cif_dev->reg_dbg = 0;
cif_dev->is_support_get_exp = false;
cif_dev->resume_mode = 0;
memset(&cif_dev->channels[0].capture_info, 0, sizeof(cif_dev->channels[0].capture_info));

View File

@@ -90,6 +90,8 @@
#define RDBK_M 1
#define RDBK_S 2
#define RKCIF_EXP_NUM_MAX (8)
/*
* for distinguishing cropping from senosr or usr
*/
@@ -524,6 +526,26 @@ struct rkcif_fence {
int fence_fd;
};
struct rkcif_sensor_exp {
int sequence;
u32 exp[3];
};
struct rkcif_sensor_gain {
int sequence;
u32 gain[3];
};
struct rkcif_sensor_vts {
int sequence;
u32 vts;
};
struct rkcif_sensor_dcg {
int sequence;
u32 dcg[3];
};
/*
* struct rkcif_stream - Stream states TODO
*
@@ -615,6 +637,12 @@ struct rkcif_stream {
struct list_head done_fence_list_head;
spinlock_t fence_lock;
u32 rounding_bit;
struct kfifo exp_kfifo;
struct kfifo gain_kfifo;
struct kfifo vts_kfifo;
struct kfifo dcg_kfifo;
struct rkmodule_exp_delay exp_delay;
struct rkmodule_exp_info sensor_exp_info;
bool stopping;
bool crop_enable;
bool crop_dyn_en;
@@ -996,6 +1024,7 @@ struct rkcif_device {
bool is_camera_over_bridge;
bool is_thunderboot_start;
bool is_in_flip;
bool is_support_get_exp;
int rdbk_debug;
struct rkcif_sync_cfg sync_cfg;
int sditf_cnt;