media: rockchip: cif: add proc interface

Signed-off-by: Allon Huang <allon.huang@rock-chips.com>
Change-Id: Ifd8a5195ba7e5446a71c1d3f03e0ba2961ba49d5
This commit is contained in:
Allon Huang
2020-09-10 21:50:58 +08:00
parent 5405181b7d
commit 8e99dadcf8
11 changed files with 575 additions and 18 deletions

View File

@@ -5,4 +5,5 @@ video_rkcif-objs += dev.o \
mipi-csi2.o \
cif-luma.o \
hw.o \
subdev-itf.o
subdev-itf.o \
procfs.o

View File

@@ -1939,6 +1939,9 @@ static void rkcif_sync_crop_info(struct rkcif_stream *stream)
stream->crop[CROP_SRC_SENSOR] = input_sel.r;
stream->crop_enable = true;
stream->crop_mask |= CROP_SRC_SENSOR_MASK;
dev->terminal_sensor.selection = input_sel;
} else {
dev->terminal_sensor.selection.r = dev->terminal_sensor.raw_rect;
}
}
@@ -1966,7 +1969,7 @@ static void rkcif_sync_crop_info(struct rkcif_stream *stream)
static int rkcif_stream_start(struct rkcif_stream *stream)
{
u32 val, mbus_flags, href_pol, vsync_pol,
xfer_mode = 0, yc_swap = 0, skip_top = 0,
xfer_mode = 0, yc_swap = 0,
inputmode = 0, mipimode = 0, workmode = 0;
struct rkcif_device *dev = stream->cifdev;
struct rkcif_sensor_info *sensor_info;
@@ -2025,10 +2028,23 @@ static int rkcif_stream_start(struct rkcif_stream *stream)
rkcif_write_register(dev, CIF_REG_DVP_SET_SIZE,
stream->pixm.width | (stream->pixm.height << 16));
v4l2_subdev_call(sensor_info->sd, sensor, g_skip_top_lines, &skip_top);
if (stream->crop_enable) {
dev->channels[stream->id].crop_en = 1;
dev->channels[stream->id].crop_st_x = stream->crop[CROP_SRC_ACT].left;
dev->channels[stream->id].crop_st_y = stream->crop[CROP_SRC_ACT].top;
dev->channels[stream->id].width = stream->crop[CROP_SRC_ACT].width;
dev->channels[stream->id].height = stream->crop[CROP_SRC_ACT].height;
} else {
dev->channels[stream->id].crop_st_y = 0;
dev->channels[stream->id].crop_st_x = 0;
dev->channels[stream->id].width = stream->pixm.width;
dev->channels[stream->id].height = stream->pixm.height;
dev->channels[stream->id].crop_en = 0;
}
/* TODO: set crop properly */
rkcif_write_register(dev, CIF_REG_DVP_CROP, skip_top << CIF_CROP_Y_SHIFT);
rkcif_write_register(dev, CIF_REG_DVP_CROP,
dev->channels[stream->id].crop_st_y << CIF_CROP_Y_SHIFT |
dev->channels[stream->id].crop_st_x);
rkcif_write_register(dev, CIF_REG_DVP_FRAME_STATUS, FRAME_STAT_CLS);
rkcif_write_register(dev, CIF_REG_DVP_INTSTAT, INTSTAT_CLS);
rkcif_write_register(dev, CIF_REG_DVP_SCL_CTRL, rkcif_scl_ctl(stream));
@@ -2043,7 +2059,7 @@ static int rkcif_stream_start(struct rkcif_stream *stream)
RKCIF_YUV_ADDR_STATE_INIT);
rkcif_write_register(dev, CIF_REG_DVP_INTEN,
FRAME_END_EN | PST_INF_FRAME_END);
FRAME_END_EN | PST_INF_FRAME_END | INTSTAT_ERR);
if (dev->workmode == RKCIF_WORKMODE_ONEFRAME)
workmode = MODE_ONEFRAME;
@@ -2336,6 +2352,8 @@ static void rkcif_set_fmt(struct rkcif_stream *stream,
dev->hdr.mode = hdr_cfg.hdr_mode;
else
dev->hdr.mode = NO_HDR;
dev->terminal_sensor.raw_rect = input_rect;
}
/* CIF has not scale function,
@@ -2434,6 +2452,7 @@ void rkcif_stream_init(struct rkcif_device *dev, u32 id)
INIT_LIST_HEAD(&stream->buf_head);
spin_lock_init(&stream->vbq_lock);
spin_lock_init(&stream->fps_lock);
stream->state = RKCIF_STATE_READY;
init_waitqueue_head(&stream->wq_stopped);
@@ -3256,6 +3275,29 @@ int rkcif_update_sensor_info(struct rkcif_stream *stream)
terminal_sensor = &stream->cifdev->terminal_sensor;
get_remote_terminal_sensor(stream, &terminal_sensor->sd);
if (terminal_sensor->sd) {
ret = v4l2_subdev_call(terminal_sensor->sd, video, g_mbus_config,
&terminal_sensor->mbus);
if (ret && ret != -ENOIOCTLCMD)
return ret;
}
switch (terminal_sensor->mbus.flags & V4L2_MBUS_CSI2_LANES) {
case V4L2_MBUS_CSI2_1_LANE:
terminal_sensor->lanes = 1;
break;
case V4L2_MBUS_CSI2_2_LANE:
terminal_sensor->lanes = 2;
break;
case V4L2_MBUS_CSI2_3_LANE:
terminal_sensor->lanes = 3;
break;
case V4L2_MBUS_CSI2_4_LANE:
terminal_sensor->lanes = 4;
break;
default:
return -EINVAL;
}
return ret;
}
@@ -3639,6 +3681,7 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
rkcif_write_register(cif_dev, CIF_REG_MIPI_LVDS_INTSTAT, intstat);
if (intstat & CSI_FIFO_OVERFLOW) {
cif_dev->irq_stats.csi_overflow_cnt++;
v4l2_err(&cif_dev->v4l2_dev,
"ERROR: csi fifo overflow, intstat:0x%x, lastline:%d!!\n",
intstat, lastline);
@@ -3646,6 +3689,7 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
}
if (intstat & CSI_BANDWIDTH_LACK) {
cif_dev->irq_stats.csi_bwidth_lack_cnt++;
v4l2_err(&cif_dev->v4l2_dev,
"ERROR: csi bandwidth lack, intstat:0x%x!!\n",
intstat);
@@ -3653,6 +3697,7 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
}
if (intstat & CSI_ALL_ERROR_INTEN) {
cif_dev->irq_stats.all_err_cnt++;
v4l2_err(&cif_dev->v4l2_dev,
"ERROR: CSI_ALL_ERROR_INTEN:0x%x!!\n", intstat);
return;
@@ -3677,6 +3722,8 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
if (mipi_id < 0)
return;
cif_dev->irq_stats.all_frm_end_cnt++;
for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) {
mipi_id = rkcif_csi_g_mipi_id(&cif_dev->v4l2_dev,
intstat);
@@ -3733,6 +3780,12 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
vb_done = &active_buf->vb;
vb_done->vb2_buf.timestamp = ktime_get_ns();
vb_done->sequence = stream->frame_idx;
spin_lock(&stream->fps_lock);
if (stream->frame_phase & CIF_CSI_FRAME0_READY)
stream->fps_stats.frm0_timestamp = vb_done->vb2_buf.timestamp;
else if (stream->frame_phase & CIF_CSI_FRAME1_READY)
stream->fps_stats.frm1_timestamp = vb_done->vb2_buf.timestamp;
spin_unlock(&stream->fps_lock);
}
if (cif_dev->hdr.mode == NO_HDR) {
@@ -3793,6 +3846,32 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
stream = &cif_dev->stream[RKCIF_STREAM_CIF];
if (intstat & BUS_ERR) {
cif_dev->irq_stats.dvp_bus_err_cnt++;
v4l2_info(&cif_dev->v4l2_dev, "dvp bus err\n");
}
if (intstat & DVP_ALL_OVERFLOW) {
cif_dev->irq_stats.dvp_overflow_cnt++;
v4l2_info(&cif_dev->v4l2_dev, "dvp overflow err\n");
}
if (intstat & LINE_ERR) {
cif_dev->irq_stats.dvp_line_err_cnt++;
v4l2_info(&cif_dev->v4l2_dev, "dvp line err\n");
}
if (intstat & PIX_ERR) {
cif_dev->irq_stats.dvp_pix_err_cnt++;
v4l2_info(&cif_dev->v4l2_dev, "dvp pix err\n");
}
if (intstat & INTSTAT_ERR) {
cif_dev->irq_stats.all_err_cnt++;
v4l2_err(&cif_dev->v4l2_dev,
"ERROR: DVP_ALL_ERROR_INTEN:0x%x!!\n", intstat);
}
/* There are two irqs enabled:
* - PST_INF_FRAME_END: cif FIFO is ready,
* this is prior to FRAME_END
@@ -3815,6 +3894,8 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
rkcif_write_register(cif_dev, CIF_REG_DVP_INTSTAT,
FRAME_END_CLR);
cif_dev->irq_stats.all_frm_end_cnt++;
if (stream->stopping) {
rkcif_stream_stop(stream);
stream->stopping = false;
@@ -3855,7 +3936,15 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
stream->frame_idx++;
if (vb_done) {
vb_done->sequence = stream->frame_idx;
rkcif_vb_done_oneframe(stream, vb_done);
spin_lock(&stream->fps_lock);
if (stream->frame_phase & CIF_CSI_FRAME0_READY)
stream->fps_stats.frm0_timestamp = vb_done->vb2_buf.timestamp;
else if (stream->frame_phase & CIF_CSI_FRAME1_READY)
stream->fps_stats.frm1_timestamp = vb_done->vb2_buf.timestamp;
spin_unlock(&stream->fps_lock);
}
}
}

View File

@@ -25,6 +25,7 @@
#include <linux/io.h>
#include <linux/mfd/syscon.h>
#include "dev.h"
#include "procfs.h"
#define RKCIF_VERNO_LEN 10
@@ -292,8 +293,17 @@ static int rkcif_pipeline_set_stream(struct rkcif_pipeline *p, bool on)
(!on && atomic_dec_return(&p->stream_cnt) > 0))
return 0;
if (on)
if (on) {
rockchip_set_system_status(SYS_STATUS_CIF0);
cif_dev->irq_stats.csi_overflow_cnt = 0;
cif_dev->irq_stats.csi_bwidth_lack_cnt = 0;
cif_dev->irq_stats.dvp_bus_err_cnt = 0;
cif_dev->irq_stats.dvp_line_err_cnt = 0;
cif_dev->irq_stats.dvp_overflow_cnt = 0;
cif_dev->irq_stats.dvp_pix_err_cnt = 0;
cif_dev->irq_stats.all_err_cnt = 0;
cif_dev->irq_stats.all_frm_end_cnt = 0;
}
/* phy -> sensor */
for (i = 0; i < p->num_subdevs; i++) {
@@ -325,6 +335,17 @@ static int rkcif_pipeline_set_stream(struct rkcif_pipeline *p, bool on)
}
if ((on && can_be_set) || !on) {
if (on) {
cif_dev->irq_stats.csi_overflow_cnt = 0;
cif_dev->irq_stats.csi_bwidth_lack_cnt = 0;
cif_dev->irq_stats.dvp_bus_err_cnt = 0;
cif_dev->irq_stats.dvp_line_err_cnt = 0;
cif_dev->irq_stats.dvp_overflow_cnt = 0;
cif_dev->irq_stats.dvp_pix_err_cnt = 0;
cif_dev->irq_stats.all_err_cnt = 0;
cif_dev->irq_stats.all_frm_end_cnt = 0;
}
/* phy -> sensor */
for (i = 0; i < p->num_subdevs; i++) {
ret = v4l2_subdev_call(p->subdevs[i], video, s_stream, on);
@@ -881,6 +902,9 @@ static int rkcif_plat_probe(struct platform_device *pdev)
return ret;
}
if (rkcif_proc_init(cif_dev))
dev_warn(dev, "dev:%s create proc failed\n", dev_name(dev));
rkcif_soft_reset(cif_dev, true);
pm_runtime_enable(&pdev->dev);
@@ -893,6 +917,8 @@ static int rkcif_plat_remove(struct platform_device *pdev)
rkcif_plat_uninit(cif_dev);
rkcif_detach_hw(cif_dev);
rkcif_proc_cleanup(cif_dev);
return 0;
}

View File

@@ -163,12 +163,16 @@ extern int rkcif_debug;
* @mbus: media bus configuration
* @fi: v4l2 subdev frame interval
* @lanes: lane num of sensor
* @raw_rect: raw output rectangle of sensor, not crop or selection
* @selection: selection info of sensor
*/
struct rkcif_sensor_info {
struct v4l2_subdev *sd;
struct v4l2_mbus_config mbus;
struct v4l2_subdev_frame_interval fi;
int lanes;
struct v4l2_rect raw_rect;
struct v4l2_subdev_selection selection;
};
enum cif_fmt_type {
@@ -256,6 +260,37 @@ struct rkcif_hdr {
u8 mode;
};
/* struct rkcif_fps_stats - take notes on timestamp of buf
* @frm0_timestamp: timesstamp of buf in frm0
* @frm1_timestamp: timesstamp of buf in frm1
*/
struct rkcif_fps_stats {
u64 frm0_timestamp;
u64 frm1_timestamp;
};
/* struct rkcif_irq_stats - take notes on irq number
* @csi_overflow_cnt: count of csi overflow irq
* @csi_bwidth_lack_cnt: count of csi bandwidth lack irq
* @dvp_bus_err_cnt: count of dvp bus err irq
* @dvp_overflow_cnt: count dvp overflow irq
* @dvp_line_err_cnt: count dvp line err irq
* @dvp_pix_err_cnt: count dvp pix err irq
* @all_frm_end_cnt: raw frame end count
* @all_err_cnt: all err count
* @
*/
struct rkcif_irq_stats {
u64 csi_overflow_cnt;
u64 csi_bwidth_lack_cnt;
u64 dvp_bus_err_cnt;
u64 dvp_overflow_cnt;
u64 dvp_line_err_cnt;
u64 dvp_pix_err_cnt;
u64 all_frm_end_cnt;
u64 all_err_cnt;
};
/*
* struct rkcif_stream - Stream states TODO
*
@@ -266,6 +301,7 @@ struct rkcif_hdr {
* rkcif use shadowsock registers, so it need two buffer at a time
* @curr_buf: the buffer used for current frame
* @next_buf: the buffer used for next frame
* @fps_lock: to protect parameters about calculating fps
*/
struct rkcif_stream {
unsigned id:3;
@@ -286,6 +322,7 @@ struct rkcif_stream {
struct rkcif_buffer *next_buf;
spinlock_t vbq_lock; /* vfd lock */
spinlock_t fps_lock;
/* TODO: pad for dvp and mipi separately? */
struct media_pad pad;
@@ -293,6 +330,7 @@ struct rkcif_stream {
const struct cif_input_fmt *cif_fmt_in;
struct v4l2_pix_format_mplane pixm;
struct v4l2_rect crop[CROP_SRC_MAX];
struct rkcif_fps_stats fps_stats;
};
struct rkcif_lvds_subdev {
@@ -376,7 +414,9 @@ struct rkcif_device {
irqreturn_t (*isr_hdl)(int irq, struct rkcif_device *cif_dev);
int inf_id;
struct sditf_priv *sditf;
struct sditf_priv *sditf;
struct proc_dir_entry *proc_dir;
struct rkcif_irq_stats irq_stats;
};
extern struct platform_driver rkcif_plat_drv;

View File

@@ -26,15 +26,6 @@
#include <linux/mfd/syscon.h>
#include "dev.h"
struct rkcif_hw_match_data {
int chip_id;
const char * const *clks;
const char * const *rsts;
int clks_num;
int rsts_num;
const struct cif_reg *cif_regs;
};
static const struct cif_reg px30_cif_regs[] = {
[CIF_REG_DVP_CTRL] = CIF_REG(CIF_CTRL),
[CIF_REG_DVP_INTEN] = CIF_REG(CIF_INTEN),
@@ -711,6 +702,7 @@ static int rkcif_plat_probe(struct platform_device *pdev)
}
cif_hw->irq = irq;
cif_hw->match_data = data;
cif_hw->chip_id = data->chip_id;
if (data->chip_id == CHIP_RK1808_CIF ||
data->chip_id == CHIP_RV1126_CIF ||

View File

@@ -44,6 +44,15 @@ enum rkcif_chip_id {
CHIP_RV1126_CIF_LITE,
};
struct rkcif_hw_match_data {
int chip_id;
const char * const *clks;
const char * const *rsts;
int clks_num;
int rsts_num;
const struct cif_reg *cif_regs;
};
/*
* struct rkcif_device - ISP platform device
* @base_addr: base register address
@@ -68,6 +77,7 @@ struct rkcif_hw {
int dev_num;
atomic_t power_cnt;
const struct rkcif_hw_match_data *match_data;
};
void rkcif_hw_soft_reset(struct rkcif_hw *cif_hw, bool is_rst_iommu);

View File

@@ -0,0 +1,366 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) Rockchip Electronics Co., Ltd. */
#include <linux/clk.h>
#include <linux/math64.h>
#include <linux/proc_fs.h>
#include <linux/sem.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/v4l2-mediabus.h>
#include "hw.h"
#include "dev.h"
#include "procfs.h"
#ifdef CONFIG_PROC_FS
static const struct {
const char *name;
u32 mbus_code;
} mbus_formats[] = {
/* media bus code */
{ "RGB444_1X12", MEDIA_BUS_FMT_RGB444_1X12 },
{ "RGB444_2X8_PADHI_BE", MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE },
{ "RGB444_2X8_PADHI_LE", MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE },
{ "RGB555_2X8_PADHI_BE", MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE },
{ "RGB555_2X8_PADHI_LE", MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE },
{ "RGB565_1X16", MEDIA_BUS_FMT_RGB565_1X16 },
{ "BGR565_2X8_BE", MEDIA_BUS_FMT_BGR565_2X8_BE },
{ "BGR565_2X8_LE", MEDIA_BUS_FMT_BGR565_2X8_LE },
{ "RGB565_2X8_BE", MEDIA_BUS_FMT_RGB565_2X8_BE },
{ "RGB565_2X8_LE", MEDIA_BUS_FMT_RGB565_2X8_LE },
{ "RGB666_1X18", MEDIA_BUS_FMT_RGB666_1X18 },
{ "RBG888_1X24", MEDIA_BUS_FMT_RBG888_1X24 },
{ "RGB666_1X24_CPADHI", MEDIA_BUS_FMT_RGB666_1X24_CPADHI },
{ "RGB666_1X7X3_SPWG", MEDIA_BUS_FMT_RGB666_1X7X3_SPWG },
{ "BGR888_1X24", MEDIA_BUS_FMT_BGR888_1X24 },
{ "GBR888_1X24", MEDIA_BUS_FMT_GBR888_1X24 },
{ "RGB888_1X24", MEDIA_BUS_FMT_RGB888_1X24 },
{ "RGB888_2X12_BE", MEDIA_BUS_FMT_RGB888_2X12_BE },
{ "RGB888_2X12_LE", MEDIA_BUS_FMT_RGB888_2X12_LE },
{ "RGB888_1X7X4_SPWG", MEDIA_BUS_FMT_RGB888_1X7X4_SPWG },
{ "RGB888_1X7X4_JEIDA", MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA },
{ "ARGB8888_1X32", MEDIA_BUS_FMT_ARGB8888_1X32 },
{ "RGB888_1X32_PADHI", MEDIA_BUS_FMT_RGB888_1X32_PADHI },
{ "RGB101010_1X30", MEDIA_BUS_FMT_RGB101010_1X30 },
{ "RGB121212_1X36", MEDIA_BUS_FMT_RGB121212_1X36 },
{ "RGB161616_1X48", MEDIA_BUS_FMT_RGB161616_1X48 },
{ "Y8_1X8", MEDIA_BUS_FMT_Y8_1X8 },
{ "UV8_1X8", MEDIA_BUS_FMT_UV8_1X8 },
{ "UYVY8_1_5X8", MEDIA_BUS_FMT_UYVY8_1_5X8 },
{ "VYUY8_1_5X8", MEDIA_BUS_FMT_VYUY8_1_5X8 },
{ "YUYV8_1_5X8", MEDIA_BUS_FMT_YUYV8_1_5X8 },
{ "YVYU8_1_5X8", MEDIA_BUS_FMT_YVYU8_1_5X8 },
{ "UYVY8_2X8", MEDIA_BUS_FMT_UYVY8_2X8 },
{ "VYUY8_2X8", MEDIA_BUS_FMT_VYUY8_2X8 },
{ "YUYV8_2X8", MEDIA_BUS_FMT_YUYV8_2X8 },
{ "YVYU8_2X8", MEDIA_BUS_FMT_YVYU8_2X8 },
{ "Y10_1X10", MEDIA_BUS_FMT_Y10_1X10 },
{ "Y10_2X8_PADHI_LE", MEDIA_BUS_FMT_Y10_2X8_PADHI_LE },
{ "UYVY10_2X10", MEDIA_BUS_FMT_UYVY10_2X10 },
{ "VYUY10_2X10", MEDIA_BUS_FMT_VYUY10_2X10 },
{ "YUYV10_2X10", MEDIA_BUS_FMT_YUYV10_2X10 },
{ "YVYU10_2X10", MEDIA_BUS_FMT_YVYU10_2X10 },
{ "Y12_1X12", MEDIA_BUS_FMT_Y12_1X12 },
{ "UYVY12_2X12", MEDIA_BUS_FMT_UYVY12_2X12 },
{ "VYUY12_2X12", MEDIA_BUS_FMT_VYUY12_2X12 },
{ "YUYV12_2X12", MEDIA_BUS_FMT_YUYV12_2X12 },
{ "YVYU12_2X12", MEDIA_BUS_FMT_YVYU12_2X12 },
{ "UYVY8_1X16", MEDIA_BUS_FMT_UYVY8_1X16 },
{ "VYUY8_1X16", MEDIA_BUS_FMT_VYUY8_1X16 },
{ "YUYV8_1X16", MEDIA_BUS_FMT_YUYV8_1X16 },
{ "YVYU8_1X16", MEDIA_BUS_FMT_YVYU8_1X16 },
{ "YDYUYDYV8_1X16", MEDIA_BUS_FMT_YDYUYDYV8_1X16 },
{ "UYVY10_1X20", MEDIA_BUS_FMT_UYVY10_1X20 },
{ "VYUY10_1X20", MEDIA_BUS_FMT_VYUY10_1X20 },
{ "YUYV10_1X20", MEDIA_BUS_FMT_YUYV10_1X20 },
{ "YVYU10_1X20", MEDIA_BUS_FMT_YVYU10_1X20 },
{ "VUY8_1X24", MEDIA_BUS_FMT_VUY8_1X24 },
{ "YUV8_1X24", MEDIA_BUS_FMT_YUV8_1X24 },
{ "UYYVYY8_0_5X24", MEDIA_BUS_FMT_UYYVYY8_0_5X24 },
{ "UYVY12_1X24", MEDIA_BUS_FMT_UYVY12_1X24 },
{ "VYUY12_1X24", MEDIA_BUS_FMT_VYUY12_1X24 },
{ "YUYV12_1X24", MEDIA_BUS_FMT_YUYV12_1X24 },
{ "YVYU12_1X24", MEDIA_BUS_FMT_YVYU12_1X24 },
{ "YUV10_1X30", MEDIA_BUS_FMT_YUV10_1X30 },
{ "UYYVYY10_0_5X30", MEDIA_BUS_FMT_UYYVYY10_0_5X30 },
{ "AYUV8_1X32", MEDIA_BUS_FMT_AYUV8_1X32 },
{ "UYYVYY12_0_5X36", MEDIA_BUS_FMT_UYYVYY12_0_5X36 },
{ "YUV12_1X36", MEDIA_BUS_FMT_YUV12_1X36 },
{ "YUV16_1X48", MEDIA_BUS_FMT_YUV16_1X48 },
{ "UYYVYY16_0_5X48", MEDIA_BUS_FMT_UYYVYY16_0_5X48 },
{ "SBGGR8_1X8", MEDIA_BUS_FMT_SBGGR8_1X8 },
{ "SGBRG8_1X8", MEDIA_BUS_FMT_SGBRG8_1X8 },
{ "SGRBG8_1X8", MEDIA_BUS_FMT_SGRBG8_1X8 },
{ "SRGGB8_1X8", MEDIA_BUS_FMT_SRGGB8_1X8 },
{ "SBGGR10_ALAW8_1X8", MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8 },
{ "SGBRG10_ALAW8_1X8", MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8 },
{ "SGRBG10_ALAW8_1X8", MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8 },
{ "SRGGB10_ALAW8_1X8", MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8 },
{ "SBGGR10_DPCM8_1X8", MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8 },
{ "SGBRG10_DPCM8_1X8", MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8 },
{ "SGRBG10_DPCM8_1X8", MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8 },
{ "SRGGB10_DPCM8_1X8", MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8 },
{ "SBGGR10_2X8_PADHI_BE", MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE },
{ "SBGGR10_2X8_PADHI_LE", MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE },
{ "SBGGR10_2X8_PADLO_BE", MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE },
{ "SBGGR10_2X8_PADLO_LE", MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE },
{ "SBGGR10_1X10", MEDIA_BUS_FMT_SBGGR10_1X10 },
{ "SGBRG10_1X10", MEDIA_BUS_FMT_SGBRG10_1X10 },
{ "SGRBG10_1X10", MEDIA_BUS_FMT_SGRBG10_1X10 },
{ "SRGGB10_1X10", MEDIA_BUS_FMT_SRGGB10_1X10 },
{ "SBGGR12_1X12", MEDIA_BUS_FMT_SBGGR12_1X12 },
{ "SGBRG12_1X12", MEDIA_BUS_FMT_SGBRG12_1X12 },
{ "SGRBG12_1X12", MEDIA_BUS_FMT_SGRBG12_1X12 },
{ "SRGGB12_1X12", MEDIA_BUS_FMT_SRGGB12_1X12 },
{ "SBGGR14_1X14", MEDIA_BUS_FMT_SBGGR14_1X14 },
{ "SGBRG14_1X14", MEDIA_BUS_FMT_SGBRG14_1X14 },
{ "SGRBG14_1X14", MEDIA_BUS_FMT_SGRBG14_1X14 },
{ "SRGGB14_1X14", MEDIA_BUS_FMT_SRGGB14_1X14 },
{ "SBGGR16_1X16", MEDIA_BUS_FMT_SBGGR16_1X16 },
{ "SGBRG16_1X16", MEDIA_BUS_FMT_SGBRG16_1X16 },
{ "SGRBG16_1X16", MEDIA_BUS_FMT_SGRBG16_1X16 },
{ "SRGGB16_1X16", MEDIA_BUS_FMT_SRGGB16_1X16 },
{ "JPEG_1X8", MEDIA_BUS_FMT_JPEG_1X8 },
{ "S5C_UYVY_JPEG_1X8", MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8 },
{ "AHSV8888_1X32", MEDIA_BUS_FMT_AHSV8888_1X32 },
{ "FIXED", MEDIA_BUS_FMT_FIXED },
{ "Y8", MEDIA_BUS_FMT_Y8_1X8 },
{ "Y10", MEDIA_BUS_FMT_Y10_1X10 },
{ "Y12", MEDIA_BUS_FMT_Y12_1X12 },
{ "YUYV", MEDIA_BUS_FMT_YUYV8_1X16 },
{ "YUYV1_5X8", MEDIA_BUS_FMT_YUYV8_1_5X8 },
{ "YUYV2X8", MEDIA_BUS_FMT_YUYV8_2X8 },
{ "UYVY", MEDIA_BUS_FMT_UYVY8_1X16 },
{ "UYVY1_5X8", MEDIA_BUS_FMT_UYVY8_1_5X8 },
{ "UYVY2X8", MEDIA_BUS_FMT_UYVY8_2X8 },
{ "VUY24", MEDIA_BUS_FMT_VUY8_1X24 },
{ "SBGGR8", MEDIA_BUS_FMT_SBGGR8_1X8 },
{ "SGBRG8", MEDIA_BUS_FMT_SGBRG8_1X8 },
{ "SGRBG8", MEDIA_BUS_FMT_SGRBG8_1X8 },
{ "SRGGB8", MEDIA_BUS_FMT_SRGGB8_1X8 },
{ "SBGGR10", MEDIA_BUS_FMT_SBGGR10_1X10 },
{ "SGBRG10", MEDIA_BUS_FMT_SGBRG10_1X10 },
{ "SGRBG10", MEDIA_BUS_FMT_SGRBG10_1X10 },
{ "SRGGB10", MEDIA_BUS_FMT_SRGGB10_1X10 },
{ "SBGGR10_DPCM8", MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8 },
{ "SGBRG10_DPCM8", MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8 },
{ "SGRBG10_DPCM8", MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8 },
{ "SRGGB10_DPCM8", MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8 },
{ "SBGGR12", MEDIA_BUS_FMT_SBGGR12_1X12 },
{ "SGBRG12", MEDIA_BUS_FMT_SGBRG12_1X12 },
{ "SGRBG12", MEDIA_BUS_FMT_SGRBG12_1X12 },
{ "SRGGB12", MEDIA_BUS_FMT_SRGGB12_1X12 },
{ "AYUV32", MEDIA_BUS_FMT_AYUV8_1X32 },
{ "RBG24", MEDIA_BUS_FMT_RBG888_1X24 },
{ "RGB32", MEDIA_BUS_FMT_RGB888_1X32_PADHI },
{ "ARGB32", MEDIA_BUS_FMT_ARGB8888_1X32 },
/* v4l2 fourcc code */
{ "NV16", V4L2_PIX_FMT_NV16},
{ "NV61", V4L2_PIX_FMT_NV61},
{ "NV12", V4L2_PIX_FMT_NV12},
{ "NV21", V4L2_PIX_FMT_NV21},
{ "YUYV", V4L2_PIX_FMT_YUYV},
{ "YVYU", V4L2_PIX_FMT_YVYU},
{ "UYVY", V4L2_PIX_FMT_UYVY},
{ "VYUY", V4L2_PIX_FMT_VYUY},
{ "RGB3", V4L2_PIX_FMT_RGB24},
{ "RGBP", V4L2_PIX_FMT_RGB565},
{ "BGRH", V4L2_PIX_FMT_BGR666},
{ "RGGB", V4L2_PIX_FMT_SRGGB8},
{ "GRBG", V4L2_PIX_FMT_SGRBG8},
{ "GBRG", V4L2_PIX_FMT_SGBRG8},
{ "BA81", V4L2_PIX_FMT_SBGGR8},
{ "RG10", V4L2_PIX_FMT_SRGGB10},
{ "BA10", V4L2_PIX_FMT_SGRBG10},
{ "GB10", V4L2_PIX_FMT_SGBRG10},
{ "BG10", V4L2_PIX_FMT_SBGGR10},
{ "RG12", V4L2_PIX_FMT_SRGGB12},
{ "BA12", V4L2_PIX_FMT_SGRBG12},
{ "GB12", V4L2_PIX_FMT_SGBRG12},
{ "BG12", V4L2_PIX_FMT_SBGGR12},
{ "BYR2", V4L2_PIX_FMT_SBGGR16},
{ "Y16 ", V4L2_PIX_FMT_Y16},
};
static const char *rkcif_pixelcode_to_string(u32 mbus_code)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(mbus_formats); ++i) {
if (mbus_formats[i].mbus_code == mbus_code)
return mbus_formats[i].name;
}
return "unknown";
}
static void rkcif_show_mixed_info(struct rkcif_device *dev, struct seq_file *f)
{
seq_printf(f, "Driver Version:v%02x.%02x.%02x\n",
RKCIF_DRIVER_VERSION >> 16,
(RKCIF_DRIVER_VERSION & 0xff00) >> 8,
RKCIF_DRIVER_VERSION & 0x00ff);
seq_printf(f, "Work Mode:%s\n",
dev->workmode == RKCIF_WORKMODE_ONEFRAME ? "one frame" :
dev->workmode == RKCIF_WORKMODE_PINGPONG ? "ping pong" : "line loop");
}
static void rkcif_show_clks(struct rkcif_device *dev, struct seq_file *f)
{
int i;
struct rkcif_hw *hw = dev->hw_dev;
for (i = 0; i < hw->clk_size; i++) {
seq_printf(f, "%s:%ld\n",
hw->match_data->clks[i],
clk_get_rate(hw->clks[i]));
}
}
static void rkcif_show_format(struct rkcif_device *dev, struct seq_file *f)
{
struct rkcif_stream *stream = &dev->stream[0];
struct rkcif_pipeline *pipe = &dev->pipe;
struct rkcif_sensor_info *sensor = &dev->terminal_sensor;
struct v4l2_rect *rect = &sensor->raw_rect;
struct v4l2_subdev_frame_interval *interval = &sensor->fi;
struct v4l2_subdev_selection *sel = &sensor->selection;
u32 i, flags;
u64 fps, timestamp0, timestamp1;
unsigned long lock_flags = 0;
if (atomic_read(&pipe->stream_cnt) < 1)
return;
if (sensor) {
seq_puts(f, "Input Info:\n");
seq_printf(f, "\tsrc subdev:%s\n", sensor->sd->name);
flags = sensor->mbus.flags;
if (sensor->mbus.type == V4L2_MBUS_PARALLEL ||
sensor->mbus.type == V4L2_MBUS_BT656) {
seq_printf(f, "\tinterface:%s\n",
sensor->mbus.type == V4L2_MBUS_PARALLEL ? "BT601" : "BT656/BT1120");
seq_printf(f, "\thref_pol:%s\n",
flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH ? "high active" : "low active");
seq_printf(f, "\tvsync_pol:%s\n",
flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH ? "high active" : "low active");
} else {
seq_printf(f, "\tinterface:%s\n",
sensor->mbus.type == V4L2_MBUS_CSI2 ? "mipi csi2" :
sensor->mbus.type == V4L2_MBUS_CCP2 ? "lvds" : "unknown");
seq_printf(f, "\tlanes:%d\n", sensor->lanes);
seq_puts(f, "\tvc channel:");
if (flags & V4L2_MBUS_CSI2_CHANNELS) {
for (i = 0; i < 4; i++) {
if ((flags >> (4 + i)) & 0x1)
seq_printf(f, " %d", i);
}
seq_puts(f, "\n");
} else {
seq_puts(f, "unknown\n");
}
}
seq_printf(f, "\thdr mode: %s\n",
dev->hdr.mode == NO_HDR ? "normal" :
dev->hdr.mode == HDR_X2 ? "hdr_x2" : "hdr_x3");
seq_printf(f, "\tformat:%s/%ux%u@%d\n",
rkcif_pixelcode_to_string(stream->cif_fmt_in->mbus_code),
rect->width, rect->height,
interval->interval.denominator / interval->interval.numerator);
seq_printf(f, "\tcrop.bounds:(%u, %u)/%ux%u\n",
sel->r.left, sel->r.top,
sel->r.width, sel->r.height);
spin_lock_irqsave(&stream->fps_lock, lock_flags);
timestamp0 = stream->fps_stats.frm0_timestamp;
timestamp1 = stream->fps_stats.frm1_timestamp;
spin_unlock_irqrestore(&stream->fps_lock, lock_flags);
fps = timestamp0 > timestamp1 ?
timestamp0 - timestamp1 : timestamp1 - timestamp0;
fps = div_u64(fps, 1000000);
fps = div_u64(1000, fps);
seq_puts(f, "Output Info:\n");
seq_printf(f, "\tformat:%s/%ux%u(%u,%u)\n",
rkcif_pixelcode_to_string(stream->cif_fmt_out->fourcc),
dev->channels[0].width, dev->channels[0].height,
dev->channels[0].crop_st_x, dev->channels[0].crop_st_y);
seq_printf(f, "\tcompact:%s\n", stream->is_compact ? "enable" : "disabled");
seq_printf(f, "\tframe amount:%d\n", stream->frame_idx);
seq_printf(f, "\tfps:%llu\n", fps);
seq_puts(f, "\tirq statistics:\n");
seq_printf(f, "\t\t\ttotal:%llu\n",
dev->irq_stats.all_frm_end_cnt + dev->irq_stats.all_err_cnt);
if (sensor->mbus.type == V4L2_MBUS_PARALLEL ||
sensor->mbus.type == V4L2_MBUS_BT656) {
seq_printf(f, "\t\t\tdvp bus err:%llu\n", dev->irq_stats.dvp_bus_err_cnt);
seq_printf(f, "\t\t\tdvp pix err:%llu\n", dev->irq_stats.dvp_pix_err_cnt);
seq_printf(f, "\t\t\tdvp line err:%llu\n", dev->irq_stats.dvp_line_err_cnt);
seq_printf(f, "\t\t\tdvp over flow:%llu\n", dev->irq_stats.dvp_overflow_cnt);
} else {
seq_printf(f, "\t\t\tcsi over flow:%llu\n", dev->irq_stats.csi_overflow_cnt);
seq_printf(f, "\t\t\tcsi bandwidth lack:%llu\n", dev->irq_stats.csi_bwidth_lack_cnt);
}
seq_printf(f, "\t\t\tall err count:%llu\n", dev->irq_stats.all_err_cnt);
seq_printf(f, "\t\t\tframe dma end:%llu\n", dev->irq_stats.all_frm_end_cnt);
}
}
static int rkcif_proc_show(struct seq_file *f, void *v)
{
struct rkcif_device *dev = f->private;
if (dev) {
rkcif_show_mixed_info(dev, f);
rkcif_show_clks(dev, f);
rkcif_show_format(dev, f);
} else {
seq_puts(f, "dev null\n");
}
return 0;
}
static int rkcif_proc_open(struct inode *inode, struct file *file)
{
struct rkcif_device *data = PDE_DATA(inode);
return single_open(file, rkcif_proc_show, data);
}
static const struct file_operations rkcif_proc_fops = {
.owner = THIS_MODULE,
.open = rkcif_proc_open,
.release = single_release,
.read = seq_read,
.llseek = seq_lseek,
};
int rkcif_proc_init(struct rkcif_device *dev)
{
dev->proc_dir = proc_create_data(dev_name(dev->dev), 0444,
NULL, &rkcif_proc_fops,
dev);
if (!dev->proc_dir) {
dev_err(dev->dev, "create proc/%s failed!\n",
dev_name(dev->dev));
return -ENODEV;
}
return 0;
}
void rkcif_proc_cleanup(struct rkcif_device *dev)
{
remove_proc_entry(dev_name(dev->dev), NULL);
}
#endif

View File

@@ -0,0 +1,25 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2020 Rockchip Electronics Co., Ltd. */
#ifndef _RKCIF_PROCFS_H
#define _RKCIF_PROCFS_H
#ifdef CONFIG_PROC_FS
int rkcif_proc_init(struct rkcif_device *dev);
void rkcif_proc_cleanup(struct rkcif_device *dev);
#else
static inline int rkcif_proc_init(struct rkisp_device *dev)
{
return 0;
}
static inline void rkcif_proc_cleanup(struct rkisp_device *dev)
{
}
#endif
#endif

View File

@@ -281,10 +281,16 @@ enum cif_reg_index {
/* CIF INTSTAT */
#define INTSTAT_CLS (0x3FF)
#define FRAME_END (0x01 << 0)
#define LINE_ERR (0x1 << 2)
#define PIX_ERR (0x1 << 3)
#define IFIFO_OVERFLOW (0x1 << 4)
#define DFIFO_OVERFLOW (0x1 << 5)
#define BUS_ERR (0x1 << 6)
#define PST_INF_FRAME_END (0x01 << 9)
#define FRAME_END_CLR (0x01 << 0)
#define PST_INF_FRAME_END_CLR (0x01 << 9)
#define INTSTAT_ERR (0xFC)
#define DVP_ALL_OVERFLOW (IFIFO_OVERFLOW | DFIFO_OVERFLOW)
/* FRAME STATUS */
#define FRAME_STAT_CLS 0x00

View File

@@ -45,6 +45,8 @@
*2. add subdev as interface for isp
*3. support hdr_x3 mode
*4. support rk1808 mipi interface in kernel-4.19
*v0.1.8
*1. add proc interface
*/
#define RKCIF_DRIVER_VERSION RKCIF_API_VERSION

View File

@@ -9,7 +9,7 @@
#include <linux/types.h>
#include <linux/v4l2-controls.h>
#define RKCIF_API_VERSION KERNEL_VERSION(0, 1, 0x7)
#define RKCIF_API_VERSION KERNEL_VERSION(0, 1, 0x8)
#define V4L2_CID_CIF_DATA_COMPACT (V4L2_CID_PRIVATE_BASE + 0)