From 8e99dadcf8fd1919e42c656216e54da752268bcb Mon Sep 17 00:00:00 2001 From: Allon Huang Date: Thu, 10 Sep 2020 21:50:58 +0800 Subject: [PATCH] media: rockchip: cif: add proc interface Signed-off-by: Allon Huang Change-Id: Ifd8a5195ba7e5446a71c1d3f03e0ba2961ba49d5 --- drivers/media/platform/rockchip/cif/Makefile | 3 +- drivers/media/platform/rockchip/cif/capture.c | 99 ++++- drivers/media/platform/rockchip/cif/dev.c | 28 +- drivers/media/platform/rockchip/cif/dev.h | 42 +- drivers/media/platform/rockchip/cif/hw.c | 10 +- drivers/media/platform/rockchip/cif/hw.h | 10 + drivers/media/platform/rockchip/cif/procfs.c | 366 ++++++++++++++++++ drivers/media/platform/rockchip/cif/procfs.h | 25 ++ drivers/media/platform/rockchip/cif/regs.h | 6 + drivers/media/platform/rockchip/cif/version.h | 2 + include/uapi/linux/rkcif-config.h | 2 +- 11 files changed, 575 insertions(+), 18 deletions(-) create mode 100644 drivers/media/platform/rockchip/cif/procfs.c create mode 100644 drivers/media/platform/rockchip/cif/procfs.h diff --git a/drivers/media/platform/rockchip/cif/Makefile b/drivers/media/platform/rockchip/cif/Makefile index c6e1687939bd..fff927e78d24 100644 --- a/drivers/media/platform/rockchip/cif/Makefile +++ b/drivers/media/platform/rockchip/cif/Makefile @@ -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 diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index f117ae6a80a4..f2b758699e5d 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -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); } } } diff --git a/drivers/media/platform/rockchip/cif/dev.c b/drivers/media/platform/rockchip/cif/dev.c index 303b9699e621..80fef7aa6aa4 100644 --- a/drivers/media/platform/rockchip/cif/dev.c +++ b/drivers/media/platform/rockchip/cif/dev.c @@ -25,6 +25,7 @@ #include #include #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; } diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index e9594f344cb4..ea511de07885 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -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; diff --git a/drivers/media/platform/rockchip/cif/hw.c b/drivers/media/platform/rockchip/cif/hw.c index c66d5368a54e..078cd2caccdb 100644 --- a/drivers/media/platform/rockchip/cif/hw.c +++ b/drivers/media/platform/rockchip/cif/hw.c @@ -26,15 +26,6 @@ #include #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 || diff --git a/drivers/media/platform/rockchip/cif/hw.h b/drivers/media/platform/rockchip/cif/hw.h index 8e713069f311..b5144163d36e 100644 --- a/drivers/media/platform/rockchip/cif/hw.h +++ b/drivers/media/platform/rockchip/cif/hw.h @@ -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); diff --git a/drivers/media/platform/rockchip/cif/procfs.c b/drivers/media/platform/rockchip/cif/procfs.c new file mode 100644 index 000000000000..495d9efcd36f --- /dev/null +++ b/drivers/media/platform/rockchip/cif/procfs.c @@ -0,0 +1,366 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) Rockchip Electronics Co., Ltd. */ +#include +#include +#include +#include +#include +#include +#include + +#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 diff --git a/drivers/media/platform/rockchip/cif/procfs.h b/drivers/media/platform/rockchip/cif/procfs.h new file mode 100644 index 000000000000..798533849cd9 --- /dev/null +++ b/drivers/media/platform/rockchip/cif/procfs.h @@ -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 diff --git a/drivers/media/platform/rockchip/cif/regs.h b/drivers/media/platform/rockchip/cif/regs.h index 5dc1fe8f38f8..fba627f6ef12 100644 --- a/drivers/media/platform/rockchip/cif/regs.h +++ b/drivers/media/platform/rockchip/cif/regs.h @@ -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 diff --git a/drivers/media/platform/rockchip/cif/version.h b/drivers/media/platform/rockchip/cif/version.h index 9ae3585cd8cb..733733b7310f 100644 --- a/drivers/media/platform/rockchip/cif/version.h +++ b/drivers/media/platform/rockchip/cif/version.h @@ -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 diff --git a/include/uapi/linux/rkcif-config.h b/include/uapi/linux/rkcif-config.h index 7207bbc47e7a..4e75d9f41e54 100644 --- a/include/uapi/linux/rkcif-config.h +++ b/include/uapi/linux/rkcif-config.h @@ -9,7 +9,7 @@ #include #include -#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)