mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 12:17:12 +09:00
media: rockchip: isp: init isp2.0
Change-Id: Ia22c5eefc931280dca77201dea420aff622f1e82 Signed-off-by: Cai YiWei <cyw@rock-chips.com>
This commit is contained in:
@@ -7,4 +7,6 @@ video_rkisp-objs += rkisp.o \
|
||||
isp_stats.o \
|
||||
isp_params.o \
|
||||
capture.o \
|
||||
dmarx.o
|
||||
dmarx.o \
|
||||
csi.o \
|
||||
mpfbc.o
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -88,8 +88,9 @@ struct rkisp_stream_mp {
|
||||
bool raw_enable;
|
||||
};
|
||||
|
||||
struct rkisp_stream_raw {
|
||||
struct rkisp_stream_dmatx {
|
||||
u8 pre_stop;
|
||||
u8 is_config;
|
||||
};
|
||||
|
||||
struct rkisp_stream_dmarx {
|
||||
@@ -105,6 +106,7 @@ struct stream_config {
|
||||
const int max_rsz_height;
|
||||
const int min_rsz_width;
|
||||
const int min_rsz_height;
|
||||
const int frame_end_id;
|
||||
/* registers */
|
||||
struct {
|
||||
u32 ctrl;
|
||||
@@ -149,7 +151,13 @@ struct stream_config {
|
||||
u32 y_offs_cnt_init;
|
||||
u32 cb_offs_cnt_init;
|
||||
u32 cr_offs_cnt_init;
|
||||
u32 y_base_ad_shd;
|
||||
} mi;
|
||||
struct {
|
||||
u32 ctrl;
|
||||
u32 pic_size;
|
||||
u32 pic_offs;
|
||||
} dma;
|
||||
};
|
||||
|
||||
/* Different reg ops between selfpath and mainpath */
|
||||
@@ -166,6 +174,8 @@ struct streams_ops {
|
||||
/*
|
||||
* struct rkisp_stream - ISP capture video device
|
||||
*
|
||||
* @id: stream video identify
|
||||
* @interlaced: selfpath interlaced flag
|
||||
* @out_isp_fmt: output isp format
|
||||
* @out_fmt: output buffer size
|
||||
* @dcrop: coordinates of dual-crop
|
||||
@@ -177,9 +187,12 @@ struct streams_ops {
|
||||
* rkisp 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
|
||||
* @done: wait frame end event queue
|
||||
* @burst: burst length for Y and CB/CR
|
||||
* @sequence: damtx video frame sequence
|
||||
*/
|
||||
struct rkisp_stream {
|
||||
unsigned id:2;
|
||||
unsigned int id;
|
||||
unsigned interlaced:1;
|
||||
struct rkisp_device *ispdev;
|
||||
struct rkisp_vdev_node vnode;
|
||||
@@ -198,22 +211,34 @@ struct rkisp_stream {
|
||||
bool frame_end;
|
||||
wait_queue_head_t done;
|
||||
unsigned int burst;
|
||||
atomic_t sequence;
|
||||
union {
|
||||
struct rkisp_stream_sp sp;
|
||||
struct rkisp_stream_mp mp;
|
||||
struct rkisp_stream_raw raw;
|
||||
struct rkisp_stream_dmarx dmarx;
|
||||
struct rkisp_stream_dmatx dmatx;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct rkisp_capture_device {
|
||||
struct rkisp_device *ispdev;
|
||||
struct rkisp_stream stream[RKISP_MAX_STREAM];
|
||||
};
|
||||
|
||||
void rkisp_unregister_stream_vdevs(struct rkisp_device *dev);
|
||||
int rkisp_register_stream_vdevs(struct rkisp_device *dev);
|
||||
void rkisp_mi_isr(u32 mis_val, struct rkisp_device *dev);
|
||||
void rkisp_stream_init(struct rkisp_device *dev, u32 id);
|
||||
void rkisp_set_stream_def_fmt(struct rkisp_device *dev, u32 id,
|
||||
u32 width, u32 height, u32 pixelformat);
|
||||
void rkisp_mipi_dmatx0_end(u32 status, struct rkisp_device *dev);
|
||||
int fcc_xysubs(u32 fcc, u32 *xsubs, u32 *ysubs);
|
||||
int rkisp_fh_open(struct file *filp);
|
||||
int rkisp_fop_release(struct file *file);
|
||||
|
||||
struct rkisp_dummy_buffer *hdr_dqbuf(struct list_head *q);
|
||||
void hdr_qbuf(struct list_head *q, struct rkisp_dummy_buffer *buf);
|
||||
int hdr_config_dmatx(struct rkisp_device *dev);
|
||||
int hdr_update_dmatx_buf(struct rkisp_device *dev);
|
||||
void hdr_stop_dmatx(struct rkisp_device *dev);
|
||||
void hdr_destroy_buf(struct rkisp_device *dev);
|
||||
#endif /* _RKISP_PATH_VIDEO_H */
|
||||
|
||||
@@ -47,10 +47,13 @@
|
||||
#define RKISP_DEFAULT_WIDTH 800
|
||||
#define RKISP_DEFAULT_HEIGHT 600
|
||||
|
||||
#define RKISP_MAX_STREAM 3
|
||||
#define RKISP_STREAM_MP 0
|
||||
#define RKISP_STREAM_SP 1
|
||||
#define RKISP_STREAM_RAW 2
|
||||
#define RKISP_MAX_STREAM 6
|
||||
#define RKISP_STREAM_MP 0
|
||||
#define RKISP_STREAM_SP 1
|
||||
#define RKISP_STREAM_DMATX0 2
|
||||
#define RKISP_STREAM_DMATX1 3
|
||||
#define RKISP_STREAM_DMATX2 4
|
||||
#define RKISP_STREAM_DMATX3 5
|
||||
|
||||
#define RKISP_PLANE_Y 0
|
||||
#define RKISP_PLANE_CB 1
|
||||
@@ -99,6 +102,7 @@ struct rkisp_buffer {
|
||||
};
|
||||
|
||||
struct rkisp_dummy_buffer {
|
||||
struct list_head queue;
|
||||
void *vaddr;
|
||||
dma_addr_t dma_addr;
|
||||
u32 size;
|
||||
|
||||
489
drivers/media/platform/rockchip/isp/csi.c
Normal file
489
drivers/media/platform/rockchip/isp/csi.c
Normal file
@@ -0,0 +1,489 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-event.h>
|
||||
#include <media/v4l2-fh.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
#include <media/videobuf2-dma-contig.h>
|
||||
#include <linux/dma-iommu.h>
|
||||
#include <linux/rk-camera-module.h>
|
||||
#include "dev.h"
|
||||
#include "regs.h"
|
||||
|
||||
static void get_remote_mipi_sensor(struct rkisp_device *dev,
|
||||
struct v4l2_subdev **sensor_sd)
|
||||
{
|
||||
struct media_graph graph;
|
||||
struct media_entity *entity = &dev->isp_sdev.sd.entity;
|
||||
struct media_device *mdev = entity->graph_obj.mdev;
|
||||
int ret;
|
||||
|
||||
/* Walk the graph to locate sensor nodes. */
|
||||
mutex_lock(&mdev->graph_mutex);
|
||||
ret = media_graph_walk_init(&graph, mdev);
|
||||
if (ret) {
|
||||
mutex_unlock(&mdev->graph_mutex);
|
||||
*sensor_sd = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
media_graph_walk_start(&graph, entity);
|
||||
while ((entity = media_graph_walk_next(&graph))) {
|
||||
if (entity->function == MEDIA_ENT_F_CAM_SENSOR)
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&mdev->graph_mutex);
|
||||
media_graph_walk_cleanup(&graph);
|
||||
|
||||
if (entity)
|
||||
*sensor_sd = media_entity_to_v4l2_subdev(entity);
|
||||
else
|
||||
*sensor_sd = NULL;
|
||||
}
|
||||
|
||||
static struct v4l2_subdev *get_remote_subdev(struct v4l2_subdev *sd)
|
||||
{
|
||||
struct media_pad *local, *remote;
|
||||
struct v4l2_subdev *remote_sd = NULL;
|
||||
|
||||
local = &sd->entity.pads[CSI_SINK];
|
||||
if (!local)
|
||||
goto end;
|
||||
remote = media_entity_remote_pad(local);
|
||||
if (!remote)
|
||||
goto end;
|
||||
|
||||
remote_sd = media_entity_to_v4l2_subdev(remote->entity);
|
||||
end:
|
||||
return remote_sd;
|
||||
}
|
||||
|
||||
static int rkisp_csi_link_setup(struct media_entity *entity,
|
||||
const struct media_pad *local,
|
||||
const struct media_pad *remote,
|
||||
u32 flags)
|
||||
{
|
||||
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
|
||||
struct rkisp_csi_device *csi;
|
||||
int ret = 0;
|
||||
u8 id;
|
||||
|
||||
if (!sd)
|
||||
return -ENODEV;
|
||||
|
||||
csi = v4l2_get_subdevdata(sd);
|
||||
if (local->flags & MEDIA_PAD_FL_SOURCE) {
|
||||
id = local->index - 1;
|
||||
if (flags & MEDIA_LNK_FL_ENABLED) {
|
||||
if (csi->sink[id].linked) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
csi->sink[id].linked = true;
|
||||
csi->sink[id].index = 1 << id;
|
||||
} else {
|
||||
csi->sink[id].linked = false;
|
||||
csi->sink[id].index = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
out:
|
||||
v4l2_err(sd, "pad%d is already linked\n", local->index);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rkisp_csi_g_mbus_config(struct v4l2_subdev *sd,
|
||||
struct v4l2_mbus_config *config)
|
||||
{
|
||||
struct v4l2_subdev *remote_sd;
|
||||
|
||||
if (!sd)
|
||||
return -ENODEV;
|
||||
remote_sd = get_remote_subdev(sd);
|
||||
return v4l2_subdev_call(remote_sd, video, g_mbus_config, config);
|
||||
}
|
||||
|
||||
static int rkisp_csi_get_set_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
struct v4l2_subdev *remote_sd;
|
||||
|
||||
if (fmt->pad != CSI_SINK)
|
||||
fmt->pad -= 1;
|
||||
|
||||
if (!sd)
|
||||
return -ENODEV;
|
||||
remote_sd = get_remote_subdev(sd);
|
||||
return v4l2_subdev_call(remote_sd, pad, get_fmt, NULL, fmt);
|
||||
}
|
||||
|
||||
static int rkisp_csi_s_stream(struct v4l2_subdev *sd, int on)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rkisp_csi_s_power(struct v4l2_subdev *sd, int on)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct media_entity_operations rkisp_csi_media_ops = {
|
||||
.link_setup = rkisp_csi_link_setup,
|
||||
.link_validate = v4l2_subdev_link_validate,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_pad_ops rkisp_csi_pad_ops = {
|
||||
.set_fmt = rkisp_csi_get_set_fmt,
|
||||
.get_fmt = rkisp_csi_get_set_fmt,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_video_ops rkisp_csi_video_ops = {
|
||||
.g_mbus_config = rkisp_csi_g_mbus_config,
|
||||
.s_stream = rkisp_csi_s_stream,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_core_ops rkisp_csi_core_ops = {
|
||||
.s_power = rkisp_csi_s_power,
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_ops rkisp_csi_ops = {
|
||||
.core = &rkisp_csi_core_ops,
|
||||
.video = &rkisp_csi_video_ops,
|
||||
.pad = &rkisp_csi_pad_ops,
|
||||
};
|
||||
|
||||
static int csi_config(struct rkisp_csi_device *csi)
|
||||
{
|
||||
struct rkisp_device *dev = csi->ispdev;
|
||||
void __iomem *base = dev->base_addr;
|
||||
struct rkisp_sensor_info *sensor = dev->active_sensor;
|
||||
struct v4l2_subdev *mipi_sensor;
|
||||
struct v4l2_ctrl *ctrl;
|
||||
u32 emd_vc, emd_dt, mipi_ctrl;
|
||||
int lanes, ret, i;
|
||||
|
||||
/*
|
||||
* sensor->mbus is set in isp or d-phy notifier_bound function
|
||||
*/
|
||||
switch (sensor->mbus.flags & V4L2_MBUS_CSI2_LANES) {
|
||||
case V4L2_MBUS_CSI2_4_LANE:
|
||||
lanes = 4;
|
||||
break;
|
||||
case V4L2_MBUS_CSI2_3_LANE:
|
||||
lanes = 3;
|
||||
break;
|
||||
case V4L2_MBUS_CSI2_2_LANE:
|
||||
lanes = 2;
|
||||
break;
|
||||
case V4L2_MBUS_CSI2_1_LANE:
|
||||
lanes = 1;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
emd_vc = 0xFF;
|
||||
emd_dt = 0;
|
||||
dev->hdr.sensor = NULL;
|
||||
get_remote_mipi_sensor(dev, &mipi_sensor);
|
||||
if (mipi_sensor) {
|
||||
ctrl = v4l2_ctrl_find(mipi_sensor->ctrl_handler,
|
||||
CIFISP_CID_EMB_VC);
|
||||
if (ctrl)
|
||||
emd_vc = v4l2_ctrl_g_ctrl(ctrl);
|
||||
|
||||
ctrl = v4l2_ctrl_find(mipi_sensor->ctrl_handler,
|
||||
CIFISP_CID_EMB_DT);
|
||||
if (ctrl)
|
||||
emd_dt = v4l2_ctrl_g_ctrl(ctrl);
|
||||
dev->hdr.sensor = mipi_sensor;
|
||||
}
|
||||
|
||||
dev->emd_dt = emd_dt;
|
||||
dev->emd_vc = emd_vc;
|
||||
dev->emd_data_idx = 0;
|
||||
if (emd_vc <= CIF_ISP_ADD_DATA_VC_MAX) {
|
||||
for (i = 0; i < RKISP_EMDDATA_FIFO_MAX; i++) {
|
||||
ret = kfifo_alloc(&dev->emd_data_fifo[i].mipi_kfifo,
|
||||
CIFISP_ADD_DATA_FIFO_SIZE,
|
||||
GFP_ATOMIC);
|
||||
if (ret) {
|
||||
v4l2_err(&dev->v4l2_dev,
|
||||
"kfifo_alloc failed with error %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->isp_ver == ISP_V13 ||
|
||||
dev->isp_ver == ISP_V12) {
|
||||
/* lanes */
|
||||
writel(lanes - 1, base + CIF_ISP_CSI0_CTRL1);
|
||||
|
||||
/* linecnt */
|
||||
writel(0x3FFF, base + CIF_ISP_CSI0_CTRL2);
|
||||
|
||||
/* Configure Data Type and Virtual Channel */
|
||||
writel(csi->mipi_di[0] | csi->mipi_di[1] << 8,
|
||||
base + CIF_ISP_CSI0_DATA_IDS_1);
|
||||
|
||||
/* clear interrupts state */
|
||||
readl(base + CIF_ISP_CSI0_ERR1);
|
||||
readl(base + CIF_ISP_CSI0_ERR2);
|
||||
readl(base + CIF_ISP_CSI0_ERR3);
|
||||
/* set interrupts mask */
|
||||
writel(0x1FFFFFF0, base + CIF_ISP_CSI0_MASK1);
|
||||
writel(0x03FFFFFF, base + CIF_ISP_CSI0_MASK2);
|
||||
writel(CIF_ISP_CSI0_IMASK_FRAME_END(0x3F) |
|
||||
CIF_ISP_CSI0_IMASK_RAW0_OUT_V_END |
|
||||
CIF_ISP_CSI0_IMASK_RAW1_OUT_V_END |
|
||||
CIF_ISP_CSI0_IMASK_LINECNT,
|
||||
base + CIF_ISP_CSI0_MASK3);
|
||||
|
||||
v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
|
||||
"CSI0_CTRL1 0x%08x\n"
|
||||
"CSI0_IDS 0x%08x\n"
|
||||
"CSI0_MASK3 0x%08x\n",
|
||||
readl(base + CIF_ISP_CSI0_CTRL1),
|
||||
readl(base + CIF_ISP_CSI0_DATA_IDS_1),
|
||||
readl(base + CIF_ISP_CSI0_MASK3));
|
||||
} else if (dev->isp_ver == ISP_V20) {
|
||||
struct rkmodule_hdr_cfg hdr_cfg;
|
||||
u32 val;
|
||||
|
||||
dev->hdr.op_mode = HDR_NORMAL;
|
||||
dev->hdr.esp_mode = HDR_NORMAL_VC;
|
||||
if (mipi_sensor) {
|
||||
ret = v4l2_subdev_call(mipi_sensor,
|
||||
core, ioctl,
|
||||
RKMODULE_HDR_CFG,
|
||||
&hdr_cfg);
|
||||
if (!ret) {
|
||||
dev->hdr.op_mode = hdr_cfg.hdr_mode;
|
||||
dev->hdr.esp_mode = hdr_cfg.esp.mode;
|
||||
}
|
||||
}
|
||||
#if RKISP_HDR_DBG_MODE
|
||||
switch (dev->hdr.op_mode) {
|
||||
case HDR_FRAMEX2_DDR:
|
||||
case HDR_LINEX2_DDR:
|
||||
case HDR_LINEX2_NO_DDR:
|
||||
dev->hdr.op_mode = HDR_DBG_FRAME2;
|
||||
break;
|
||||
case HDR_FRAMEX3_DDR:
|
||||
case HDR_LINEX3_DDR:
|
||||
case HDR_LINEX3_NO_DDR:
|
||||
dev->hdr.op_mode = HDR_DBG_FRAME3;
|
||||
break;
|
||||
case HDR_NORMAL:
|
||||
dev->hdr.op_mode = HDR_DBG_FRAME1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
writel(SW_IBUF_OP_MODE(dev->hdr.op_mode) |
|
||||
SW_HDR_ESP_MODE(dev->hdr.esp_mode),
|
||||
base + CSI2RX_CTRL0);
|
||||
writel(lanes - 1, base + CSI2RX_CTRL1);
|
||||
writel(0x3FFF, base + CSI2RX_CTRL2);
|
||||
val = SW_CSI_ID0(csi->mipi_di[0]) |
|
||||
SW_CSI_ID1(csi->mipi_di[1]) |
|
||||
SW_CSI_ID2(csi->mipi_di[2]) |
|
||||
SW_CSI_ID3(csi->mipi_di[3]);
|
||||
writel(val, base + CSI2RX_DATA_IDS_1);
|
||||
val = SW_CSI_ID4(csi->mipi_di[4]);
|
||||
writel(val, base + CSI2RX_DATA_IDS_2);
|
||||
/* clear interrupts state */
|
||||
readl(base + CSI2RX_ERR_PHY);
|
||||
/* set interrupts mask */
|
||||
writel(0xF0FFFF, base + CSI2RX_MASK_PHY);
|
||||
writel(0xF1FFFFF, base + CSI2RX_MASK_PACKET);
|
||||
writel(0x7F7FF1, base + CSI2RX_MASK_OVERFLOW);
|
||||
writel(0x7FFFFF7F, base + CSI2RX_MASK_STAT);
|
||||
|
||||
/* hdr merge */
|
||||
switch (dev->hdr.op_mode) {
|
||||
case HDR_DBG_FRAME2:
|
||||
case HDR_FRAMEX2_DDR:
|
||||
case HDR_LINEX2_DDR:
|
||||
case HDR_LINEX2_NO_DDR:
|
||||
val = SW_HDRMGE_EN |
|
||||
SW_HDRMGE_MODE_FRAMEX2;
|
||||
break;
|
||||
case HDR_DBG_FRAME3:
|
||||
case HDR_FRAMEX3_DDR:
|
||||
case HDR_LINEX3_DDR:
|
||||
case HDR_LINEX3_NO_DDR:
|
||||
val = SW_HDRMGE_EN |
|
||||
SW_HDRMGE_MODE_FRAMEX3;
|
||||
break;
|
||||
default:
|
||||
val = 0;
|
||||
}
|
||||
writel(val, base + ISP_HDRMGE_BASE);
|
||||
writel(val & SW_HDRMGE_EN, base + ISP_HDRTMO_BASE);
|
||||
|
||||
v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
|
||||
"CSI2RX_IDS 0x%08x 0x%08x\n",
|
||||
readl(base + CSI2RX_DATA_IDS_1),
|
||||
readl(base + CSI2RX_DATA_IDS_2));
|
||||
} else {
|
||||
mipi_ctrl = CIF_MIPI_CTRL_NUM_LANES(lanes - 1) |
|
||||
CIF_MIPI_CTRL_SHUTDOWNLANES(0xf) |
|
||||
CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_SKIP |
|
||||
CIF_MIPI_CTRL_CLOCKLANE_ENA;
|
||||
|
||||
writel(mipi_ctrl, base + CIF_MIPI_CTRL);
|
||||
|
||||
/* Configure Data Type and Virtual Channel */
|
||||
writel(csi->mipi_di[0],
|
||||
base + CIF_MIPI_IMG_DATA_SEL);
|
||||
|
||||
writel(CIF_MIPI_DATA_SEL_DT(emd_dt) |
|
||||
CIF_MIPI_DATA_SEL_VC(emd_vc),
|
||||
base + CIF_MIPI_ADD_DATA_SEL_1);
|
||||
writel(CIF_MIPI_DATA_SEL_DT(emd_dt) |
|
||||
CIF_MIPI_DATA_SEL_VC(emd_vc),
|
||||
base + CIF_MIPI_ADD_DATA_SEL_2);
|
||||
writel(CIF_MIPI_DATA_SEL_DT(emd_dt) |
|
||||
CIF_MIPI_DATA_SEL_VC(emd_vc),
|
||||
base + CIF_MIPI_ADD_DATA_SEL_3);
|
||||
writel(CIF_MIPI_DATA_SEL_DT(emd_dt) |
|
||||
CIF_MIPI_DATA_SEL_VC(emd_vc),
|
||||
base + CIF_MIPI_ADD_DATA_SEL_4);
|
||||
|
||||
/* Clear MIPI interrupts */
|
||||
writel(~0, base + CIF_MIPI_ICR);
|
||||
/*
|
||||
* Disable CIF_MIPI_ERR_DPHY interrupt here temporary for
|
||||
* isp bus may be dead when switch isp.
|
||||
*/
|
||||
writel(CIF_MIPI_FRAME_END | CIF_MIPI_ERR_CSI |
|
||||
CIF_MIPI_ERR_DPHY | CIF_MIPI_SYNC_FIFO_OVFLW(0x0F) |
|
||||
CIF_MIPI_ADD_DATA_OVFLW, base + CIF_MIPI_IMSC);
|
||||
|
||||
v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
|
||||
"\n MIPI_CTRL 0x%08x\n"
|
||||
" MIPI_IMG_DATA_SEL 0x%08x\n"
|
||||
" MIPI_STATUS 0x%08x\n"
|
||||
" MIPI_IMSC 0x%08x\n",
|
||||
readl(base + CIF_MIPI_CTRL),
|
||||
readl(base + CIF_MIPI_IMG_DATA_SEL),
|
||||
readl(base + CIF_MIPI_STATUS),
|
||||
readl(base + CIF_MIPI_IMSC));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rkisp_csi_config_patch(struct rkisp_device *dev)
|
||||
{
|
||||
int val = 0, ret = 0;
|
||||
|
||||
if (dev->isp_inp & INP_CSI) {
|
||||
ret = csi_config(&dev->csi_dev);
|
||||
} else {
|
||||
switch (dev->isp_inp & 0x7) {
|
||||
case INP_RAWRD2 | INP_RAWRD0:
|
||||
dev->hdr.op_mode = HDR_DBG_FRAME2;
|
||||
val = SW_HDRMGE_EN |
|
||||
SW_HDRMGE_MODE_FRAMEX2;
|
||||
break;
|
||||
case INP_RAWRD2 | INP_RAWRD1 | INP_RAWRD0:
|
||||
dev->hdr.op_mode = HDR_DBG_FRAME3;
|
||||
val = SW_HDRMGE_EN |
|
||||
SW_HDRMGE_MODE_FRAMEX3;
|
||||
break;
|
||||
default: //INP_RAWRD2
|
||||
dev->hdr.op_mode = HDR_DBG_FRAME1;
|
||||
}
|
||||
writel(SW_IBUF_OP_MODE(dev->hdr.op_mode),
|
||||
dev->base_addr + CSI2RX_CTRL0);
|
||||
writel(val, dev->base_addr + ISP_HDRMGE_BASE);
|
||||
writel(val & SW_HDRMGE_EN, dev->base_addr + ISP_HDRTMO_BASE);
|
||||
writel(0x7FFFFF7F, dev->base_addr + CSI2RX_MASK_STAT);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* for hdr debug mode, rawrd read back data
|
||||
* this will update rawrd base addr to shadow.
|
||||
*/
|
||||
void rkisp_trigger_read_back(struct rkisp_csi_device *csi, u8 dma2frm)
|
||||
{
|
||||
struct rkisp_device *dev = csi->ispdev;
|
||||
void __iomem *addr = dev->base_addr + CSI2RX_CTRL0;
|
||||
|
||||
writel(SW_CSI2RX_EN | SW_DMA_2FRM_MODE(dma2frm) | readl(addr), addr);
|
||||
}
|
||||
|
||||
int rkisp_register_csi_subdev(struct rkisp_device *dev,
|
||||
struct v4l2_device *v4l2_dev)
|
||||
{
|
||||
struct rkisp_csi_device *csi_dev = &dev->csi_dev;
|
||||
struct v4l2_subdev *sd;
|
||||
int ret;
|
||||
|
||||
memset(csi_dev, 0, sizeof(*csi_dev));
|
||||
csi_dev->ispdev = dev;
|
||||
sd = &csi_dev->sd;
|
||||
|
||||
v4l2_subdev_init(sd, &rkisp_csi_ops);
|
||||
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
sd->entity.ops = &rkisp_csi_media_ops;
|
||||
sd->entity.function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
|
||||
snprintf(sd->name, sizeof(sd->name), CSI_DEV_NAME);
|
||||
|
||||
csi_dev->pads[CSI_SINK].flags =
|
||||
MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
|
||||
csi_dev->pads[CSI_SRC_CH0].flags =
|
||||
MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT;
|
||||
|
||||
csi_dev->max_pad = CSI_SRC_CH0 + 1;
|
||||
if (dev->isp_ver == ISP_V12 ||
|
||||
dev->isp_ver == ISP_V13) {
|
||||
csi_dev->max_pad = CSI_SRC_CH1 + 1;
|
||||
csi_dev->pads[CSI_SRC_CH1].flags = MEDIA_PAD_FL_SOURCE;
|
||||
} else if (dev->isp_ver == ISP_V20) {
|
||||
csi_dev->max_pad = CSI_PAD_MAX;
|
||||
csi_dev->pads[CSI_SRC_CH1].flags = MEDIA_PAD_FL_SOURCE;
|
||||
csi_dev->pads[CSI_SRC_CH2].flags = MEDIA_PAD_FL_SOURCE;
|
||||
csi_dev->pads[CSI_SRC_CH3].flags = MEDIA_PAD_FL_SOURCE;
|
||||
csi_dev->pads[CSI_SRC_CH4].flags = MEDIA_PAD_FL_SOURCE;
|
||||
}
|
||||
|
||||
ret = media_entity_pads_init(&sd->entity, csi_dev->max_pad,
|
||||
csi_dev->pads);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
sd->owner = THIS_MODULE;
|
||||
v4l2_set_subdevdata(sd, csi_dev);
|
||||
sd->grp_id = GRP_ID_CSI;
|
||||
ret = v4l2_device_register_subdev(v4l2_dev, sd);
|
||||
if (ret < 0) {
|
||||
v4l2_err(v4l2_dev, "Failed to register csi subdev\n");
|
||||
goto free_media;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
free_media:
|
||||
media_entity_cleanup(&sd->entity);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rkisp_unregister_csi_subdev(struct rkisp_device *dev)
|
||||
{
|
||||
struct v4l2_subdev *sd = &dev->csi_dev.sd;
|
||||
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
media_entity_cleanup(&sd->entity);
|
||||
}
|
||||
69
drivers/media/platform/rockchip/isp/csi.h
Normal file
69
drivers/media/platform/rockchip/isp/csi.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */
|
||||
|
||||
#ifndef _RKISP_CSI_H
|
||||
#define _RKISP_CSI_H
|
||||
|
||||
#define CSI_DEV_NAME DRIVER_NAME "-csi-subdev"
|
||||
|
||||
#define RKISP_HDR_DBG_MODE 0
|
||||
|
||||
#define HDR_MAX_DUMMY_BUF 3
|
||||
/* define max dmatx to use for hdr */
|
||||
#define HDR_DMA_MAX 3
|
||||
#define HDR_DMA0 0
|
||||
#define HDR_DMA1 1
|
||||
#define HDR_DMA2 2
|
||||
|
||||
#define IS_HDR_DBG(x) ({ \
|
||||
typeof(x) __x = (x); \
|
||||
(__x == HDR_DBG_FRAME1 || \
|
||||
__x == HDR_DBG_FRAME2 || \
|
||||
__x == HDR_DBG_FRAME3); \
|
||||
})
|
||||
|
||||
enum hdr_op_mode {
|
||||
HDR_NORMAL = 0,
|
||||
HDR_DBG_FRAME1 = 4,
|
||||
HDR_DBG_FRAME2 = 5,
|
||||
HDR_DBG_FRAME3 = 6,
|
||||
HDR_FRAMEX2_DDR = 8,
|
||||
HDR_LINEX2_DDR = 9,
|
||||
HDR_LINEX2_NO_DDR = 10,
|
||||
HDR_FRAMEX3_DDR = 12,
|
||||
HDR_LINEX3_DDR = 13,
|
||||
HDR_LINEX3_NO_DDR = 14,
|
||||
};
|
||||
|
||||
enum rkisp_csi_pad {
|
||||
CSI_SINK,
|
||||
CSI_SRC_CH0,
|
||||
CSI_SRC_CH1,
|
||||
CSI_SRC_CH2,
|
||||
CSI_SRC_CH3,
|
||||
CSI_SRC_CH4,
|
||||
CSI_PAD_MAX
|
||||
};
|
||||
|
||||
struct sink_info {
|
||||
u8 index;
|
||||
u8 linked;
|
||||
};
|
||||
|
||||
struct rkisp_csi_device {
|
||||
struct rkisp_device *ispdev;
|
||||
struct v4l2_subdev sd;
|
||||
struct media_pad pads[CSI_PAD_MAX];
|
||||
int max_pad;
|
||||
struct sink_info sink[CSI_PAD_MAX - 1];
|
||||
/* Data Identifier */
|
||||
u8 mipi_di[CSI_PAD_MAX - 1];
|
||||
};
|
||||
|
||||
int rkisp_register_csi_subdev(struct rkisp_device *dev,
|
||||
struct v4l2_device *v4l2_dev);
|
||||
void rkisp_unregister_csi_subdev(struct rkisp_device *dev);
|
||||
|
||||
int rkisp_csi_config_patch(struct rkisp_device *dev);
|
||||
void rkisp_trigger_read_back(struct rkisp_csi_device *csi, u8 dma2frm);
|
||||
#endif
|
||||
@@ -92,7 +92,7 @@ static int __isp_pipeline_prepare(struct rkisp_pipeline *p,
|
||||
p->num_subdevs = 0;
|
||||
memset(p->subdevs, 0, sizeof(p->subdevs));
|
||||
|
||||
if (dev->isp_inp == INP_DMARX_ISP)
|
||||
if (!(dev->isp_inp & (INP_CSI | INP_DVP)))
|
||||
return 0;
|
||||
|
||||
while (1) {
|
||||
@@ -104,7 +104,7 @@ static int __isp_pipeline_prepare(struct rkisp_pipeline *p,
|
||||
|
||||
if (!(spad->flags & MEDIA_PAD_FL_SINK))
|
||||
continue;
|
||||
pad = media_entity_remote_pad(spad);
|
||||
pad = rkisp_media_entity_remote_pad(spad);
|
||||
if (pad)
|
||||
break;
|
||||
}
|
||||
@@ -135,8 +135,9 @@ static int __isp_pipeline_s_isp_clk(struct rkisp_pipeline *p)
|
||||
u64 data_rate;
|
||||
int i;
|
||||
|
||||
if (dev->isp_inp == INP_DMARX_ISP) {
|
||||
clk_set_rate(dev->clks[0], 400 * 1000000UL);
|
||||
if (!(dev->isp_inp & (INP_CSI | INP_DVP))) {
|
||||
if (dev->clks[0])
|
||||
clk_set_rate(dev->clks[0], 400 * 1000000UL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -188,6 +189,7 @@ static int rkisp_pipeline_open(struct rkisp_pipeline *p,
|
||||
bool prepare)
|
||||
{
|
||||
int ret;
|
||||
struct rkisp_device *dev = container_of(p, struct rkisp_device, pipe);
|
||||
|
||||
if (WARN_ON(!p || !me))
|
||||
return -EINVAL;
|
||||
@@ -205,6 +207,8 @@ static int rkisp_pipeline_open(struct rkisp_pipeline *p,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (dev->isp_inp & (INP_CSI | INP_RAWRD0 | INP_RAWRD1 | INP_RAWRD2))
|
||||
rkisp_csi_config_patch(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -264,13 +268,13 @@ err_stream_off:
|
||||
|
||||
static int rkisp_create_links(struct rkisp_device *dev)
|
||||
{
|
||||
struct media_entity *source, *sink;
|
||||
unsigned int flags, s, pad;
|
||||
unsigned int s, pad;
|
||||
int ret;
|
||||
|
||||
/* sensor links(or mipi-phy) */
|
||||
for (s = 0; s < dev->num_sensors; ++s) {
|
||||
struct rkisp_sensor_info *sensor = &dev->sensors[s];
|
||||
u32 type = sensor->sd->entity.function;
|
||||
|
||||
for (pad = 0; pad < sensor->sd->entity.num_pads; pad++)
|
||||
if (sensor->sd->entity.pads[pad].flags &
|
||||
@@ -285,11 +289,27 @@ static int rkisp_create_links(struct rkisp_device *dev)
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
ret = media_create_pad_link(
|
||||
&sensor->sd->entity, pad,
|
||||
&dev->isp_sdev.sd.entity,
|
||||
/* sensor link -> isp */
|
||||
if (type == MEDIA_ENT_F_CAM_SENSOR) {
|
||||
dev->isp_inp = INP_DVP;
|
||||
ret = media_create_pad_link(&sensor->sd->entity,
|
||||
pad, &dev->isp_sdev.sd.entity,
|
||||
RKISP_ISP_PAD_SINK,
|
||||
s ? 0 : MEDIA_LNK_FL_ENABLED);
|
||||
} else {
|
||||
/* mipi-phy link -> csi -> isp */
|
||||
dev->isp_inp = INP_CSI;
|
||||
ret = media_create_pad_link(&sensor->sd->entity,
|
||||
pad, &dev->csi_dev.sd.entity, CSI_SINK,
|
||||
s ? 0 : MEDIA_LNK_FL_ENABLED);
|
||||
ret |= media_create_pad_link(&dev->csi_dev.sd.entity,
|
||||
CSI_SRC_CH0, &dev->isp_sdev.sd.entity,
|
||||
RKISP_ISP_PAD_SINK,
|
||||
s ? 0 : MEDIA_LNK_FL_ENABLED);
|
||||
dev->csi_dev.sink[0].linked = true;
|
||||
dev->csi_dev.sink[0].index = BIT(0);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
dev_err(dev->dev,
|
||||
"failed to create link for %s\n",
|
||||
@@ -297,52 +317,7 @@ static int rkisp_create_links(struct rkisp_device *dev)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* params links */
|
||||
source = &dev->params_vdev.vnode.vdev.entity;
|
||||
sink = &dev->isp_sdev.sd.entity;
|
||||
flags = MEDIA_LNK_FL_ENABLED;
|
||||
ret = media_create_pad_link(source, 0, sink,
|
||||
RKISP_ISP_PAD_SINK_PARAMS, flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* create isp internal links */
|
||||
if (dev->isp_ver != ISP_V10_1) {
|
||||
/* SP links */
|
||||
source = &dev->isp_sdev.sd.entity;
|
||||
sink = &dev->stream[RKISP_STREAM_SP].vnode.vdev.entity;
|
||||
ret = media_create_pad_link(source,
|
||||
RKISP_ISP_PAD_SOURCE_PATH,
|
||||
sink, 0, flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* MP links */
|
||||
source = &dev->isp_sdev.sd.entity;
|
||||
sink = &dev->stream[RKISP_STREAM_MP].vnode.vdev.entity;
|
||||
ret = media_create_pad_link(source, RKISP_ISP_PAD_SOURCE_PATH,
|
||||
sink, 0, flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (dev->isp_ver == ISP_V12 ||
|
||||
dev->isp_ver == ISP_V13) {
|
||||
/* MIPI RAW links */
|
||||
source = &dev->isp_sdev.sd.entity;
|
||||
sink = &dev->stream[RKISP_STREAM_RAW].vnode.vdev.entity;
|
||||
ret = media_create_pad_link(source,
|
||||
RKISP_ISP_PAD_SOURCE_PATH, sink, 0, flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 3A stats links */
|
||||
source = &dev->isp_sdev.sd.entity;
|
||||
sink = &dev->stats_vdev.vnode.vdev.entity;
|
||||
return media_create_pad_link(source, RKISP_ISP_PAD_SOURCE_STATS,
|
||||
sink, 0, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _set_pipeline_default_fmt(struct rkisp_device *dev)
|
||||
@@ -356,10 +331,7 @@ static int _set_pipeline_default_fmt(struct rkisp_device *dev)
|
||||
|
||||
isp = &dev->isp_sdev.sd;
|
||||
|
||||
fmt = dev->active_sensor->fmt;
|
||||
ori_width = fmt.format.width;
|
||||
ori_height = fmt.format.height;
|
||||
ori_code = fmt.format.code;
|
||||
fmt = dev->active_sensor->fmt[0];
|
||||
|
||||
if (dev->isp_ver == ISP_V12) {
|
||||
fmt.format.width = clamp_t(u32, fmt.format.width,
|
||||
@@ -417,10 +389,32 @@ static int _set_pipeline_default_fmt(struct rkisp_device *dev)
|
||||
if (dev->isp_ver != ISP_V10_1)
|
||||
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_SP,
|
||||
width, height, V4L2_PIX_FMT_YUYV);
|
||||
if (dev->isp_ver == ISP_V12 || dev->isp_ver == ISP_V13)
|
||||
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_RAW, ori_width,
|
||||
ori_height, rkisp_mbus_pixelcode_to_v4l2(ori_code));
|
||||
|
||||
if ((dev->isp_ver == ISP_V12 ||
|
||||
dev->isp_ver == ISP_V13 ||
|
||||
dev->isp_ver == ISP_V20) &&
|
||||
dev->active_sensor->mbus.type == V4L2_MBUS_CSI2) {
|
||||
ori_width = dev->active_sensor->fmt[1].format.width;
|
||||
ori_height = dev->active_sensor->fmt[1].format.height;
|
||||
ori_code = dev->active_sensor->fmt[1].format.code;
|
||||
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_DMATX0,
|
||||
ori_width, ori_height,
|
||||
rkisp_mbus_pixelcode_to_v4l2(ori_code));
|
||||
}
|
||||
if (dev->isp_ver == ISP_V20 &&
|
||||
dev->active_sensor->mbus.type == V4L2_MBUS_CSI2) {
|
||||
ori_width = dev->active_sensor->fmt[2].format.width;
|
||||
ori_height = dev->active_sensor->fmt[2].format.height;
|
||||
ori_code = dev->active_sensor->fmt[2].format.code;
|
||||
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_DMATX1,
|
||||
ori_width, ori_height,
|
||||
rkisp_mbus_pixelcode_to_v4l2(ori_code));
|
||||
ori_width = dev->active_sensor->fmt[3].format.width;
|
||||
ori_height = dev->active_sensor->fmt[3].format.height;
|
||||
ori_code = dev->active_sensor->fmt[3].format.code;
|
||||
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_DMATX2,
|
||||
ori_width, ori_height,
|
||||
rkisp_mbus_pixelcode_to_v4l2(ori_code));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -539,10 +533,18 @@ static int rkisp_register_platform_subdevs(struct rkisp_device *dev)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = rkisp_register_stream_vdevs(dev);
|
||||
ret = rkisp_register_csi_subdev(dev, &dev->v4l2_dev);
|
||||
if (ret < 0)
|
||||
goto err_unreg_isp_subdev;
|
||||
|
||||
ret = rkisp_register_mpfbc_subdev(dev, &dev->v4l2_dev);
|
||||
if (ret < 0)
|
||||
goto err_unreg_csi_subdev;
|
||||
|
||||
ret = rkisp_register_stream_vdevs(dev);
|
||||
if (ret < 0)
|
||||
goto err_unreg_mpfbc_subdev;
|
||||
|
||||
ret = rkisp_register_dmarx_vdev(dev);
|
||||
if (ret < 0)
|
||||
goto err_unreg_stream_vdev;
|
||||
@@ -559,6 +561,10 @@ static int rkisp_register_platform_subdevs(struct rkisp_device *dev)
|
||||
if (ret < 0) {
|
||||
v4l2_err(&dev->v4l2_dev,
|
||||
"Failed to register subdev notifier(%d)\n", ret);
|
||||
/* maybe use dmarx to input image */
|
||||
ret = v4l2_device_register_subdev_nodes(&dev->v4l2_dev);
|
||||
if (ret == 0)
|
||||
return 0;
|
||||
goto err_unreg_params_vdev;
|
||||
}
|
||||
|
||||
@@ -571,6 +577,10 @@ err_unreg_dmarx_vdev:
|
||||
rkisp_unregister_dmarx_vdev(dev);
|
||||
err_unreg_stream_vdev:
|
||||
rkisp_unregister_stream_vdevs(dev);
|
||||
err_unreg_mpfbc_subdev:
|
||||
rkisp_unregister_mpfbc_subdev(dev);
|
||||
err_unreg_csi_subdev:
|
||||
rkisp_unregister_csi_subdev(dev);
|
||||
err_unreg_isp_subdev:
|
||||
rkisp_unregister_isp_subdev(dev);
|
||||
|
||||
@@ -628,21 +638,32 @@ static irqreturn_t rkisp_mipi_irq_hdl(int irq, void *ctx)
|
||||
{
|
||||
struct device *dev = ctx;
|
||||
struct rkisp_device *rkisp_dev = dev_get_drvdata(dev);
|
||||
unsigned int mis_val;
|
||||
unsigned int err1, err2, err3;
|
||||
|
||||
if (rkisp_dev->isp_ver == ISP_V13 ||
|
||||
rkisp_dev->isp_ver == ISP_V12) {
|
||||
u32 err1, err2, err3;
|
||||
|
||||
err1 = readl(rkisp_dev->base_addr + CIF_ISP_CSI0_ERR1);
|
||||
err2 = readl(rkisp_dev->base_addr + CIF_ISP_CSI0_ERR2);
|
||||
err3 = readl(rkisp_dev->base_addr + CIF_ISP_CSI0_ERR3);
|
||||
|
||||
if (err3 & 0x1)
|
||||
if (err3 & 0xf)
|
||||
rkisp_mipi_dmatx0_end(err3, rkisp_dev);
|
||||
if (err1 || err2 || err3)
|
||||
rkisp_mipi_v13_isr(err1, err2, err3, rkisp_dev);
|
||||
} else if (rkisp_dev->isp_ver == ISP_V20) {
|
||||
u32 phy, packet, overflow, state;
|
||||
|
||||
state = readl(rkisp_dev->base_addr + CSI2RX_ERR_STAT);
|
||||
phy = readl(rkisp_dev->base_addr + CSI2RX_ERR_PHY);
|
||||
packet = readl(rkisp_dev->base_addr + CSI2RX_ERR_PACKET);
|
||||
overflow = readl(rkisp_dev->base_addr + CSI2RX_ERR_OVERFLOW);
|
||||
if (phy | packet | overflow | state)
|
||||
rkisp_mipi_v20_isr(phy, packet, overflow,
|
||||
state, rkisp_dev);
|
||||
} else {
|
||||
mis_val = readl(rkisp_dev->base_addr + CIF_MIPI_MIS);
|
||||
u32 mis_val = readl(rkisp_dev->base_addr + CIF_MIPI_MIS);
|
||||
|
||||
if (mis_val)
|
||||
rkisp_mipi_isr(mis_val, rkisp_dev);
|
||||
}
|
||||
@@ -966,7 +987,9 @@ static int rkisp_plat_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (isp_dev->mipi_irq == irq)
|
||||
if (isp_dev->mipi_irq == irq &&
|
||||
(isp_dev->isp_ver == ISP_V12 ||
|
||||
isp_dev->isp_ver == ISP_V13))
|
||||
disable_irq(isp_dev->mipi_irq);
|
||||
}
|
||||
} else {
|
||||
@@ -1010,9 +1033,12 @@ static int rkisp_plat_probe(struct platform_device *pdev)
|
||||
isp_dev->pipe.close = rkisp_pipeline_close;
|
||||
isp_dev->pipe.set_stream = rkisp_pipeline_set_stream;
|
||||
|
||||
rkisp_stream_init(isp_dev, RKISP_STREAM_SP);
|
||||
rkisp_stream_init(isp_dev, RKISP_STREAM_MP);
|
||||
rkisp_stream_init(isp_dev, RKISP_STREAM_RAW);
|
||||
if (isp_dev->isp_ver == ISP_V20) {
|
||||
for (i = 0; i < HDR_DMA_MAX; i++) {
|
||||
INIT_LIST_HEAD(&isp_dev->hdr.q_tx[i]);
|
||||
INIT_LIST_HEAD(&isp_dev->hdr.q_rx[i]);
|
||||
}
|
||||
}
|
||||
|
||||
strlcpy(isp_dev->media_dev.model, DRIVER_NAME,
|
||||
sizeof(isp_dev->media_dev.model));
|
||||
@@ -1083,6 +1109,8 @@ static int rkisp_plat_remove(struct platform_device *pdev)
|
||||
rkisp_unregister_params_vdev(&isp_dev->params_vdev);
|
||||
rkisp_unregister_stats_vdev(&isp_dev->stats_vdev);
|
||||
rkisp_unregister_stream_vdevs(isp_dev);
|
||||
rkisp_unregister_mpfbc_subdev(isp_dev);
|
||||
rkisp_unregister_csi_subdev(isp_dev);
|
||||
rkisp_unregister_isp_subdev(isp_dev);
|
||||
media_device_cleanup(&isp_dev->media_dev);
|
||||
|
||||
|
||||
@@ -36,17 +36,31 @@
|
||||
#define _RKISP_DEV_H
|
||||
|
||||
#include "capture.h"
|
||||
#include "csi.h"
|
||||
#include "dmarx.h"
|
||||
#include "mpfbc.h"
|
||||
#include "rkisp.h"
|
||||
#include "isp_params.h"
|
||||
#include "isp_stats.h"
|
||||
|
||||
#ifdef VIDEO_ROCKCHIP_ISP1
|
||||
#define DRIVER_NAME "rkisp1"
|
||||
#else
|
||||
#define DRIVER_NAME "rkisp"
|
||||
#endif
|
||||
|
||||
#define ISP_VDEV_NAME DRIVER_NAME "_ispdev"
|
||||
#define SP_VDEV_NAME DRIVER_NAME "_selfpath"
|
||||
#define MP_VDEV_NAME DRIVER_NAME "_mainpath"
|
||||
#define DMA_VDEV_NAME DRIVER_NAME "_dmapath"
|
||||
#define RAW_VDEV_NAME DRIVER_NAME "_rawpath"
|
||||
#define DMATX0_VDEV_NAME DRIVER_NAME "_rawwr0"
|
||||
#define DMATX1_VDEV_NAME DRIVER_NAME "_rawwr1"
|
||||
#define DMATX2_VDEV_NAME DRIVER_NAME "_rawwr2"
|
||||
#define DMATX3_VDEV_NAME DRIVER_NAME "_rawwr3"
|
||||
#define DMARX0_VDEV_NAME DRIVER_NAME "_rawrd0_m"
|
||||
#define DMARX1_VDEV_NAME DRIVER_NAME "_rawrd1_l"
|
||||
#define DMARX2_VDEV_NAME DRIVER_NAME "_rawrd2_s"
|
||||
|
||||
#define GRP_ID_SENSOR BIT(0)
|
||||
#define GRP_ID_MIPIPHY BIT(1)
|
||||
@@ -54,10 +68,12 @@
|
||||
#define GRP_ID_ISP_MP BIT(3)
|
||||
#define GRP_ID_ISP_SP BIT(4)
|
||||
#define GRP_ID_ISP_DMARX BIT(5)
|
||||
#define GRP_ID_ISP_MPFBC BIT(6)
|
||||
#define GRP_ID_CSI BIT(7)
|
||||
|
||||
#define RKISP_MAX_BUS_CLK 8
|
||||
#define RKISP_MAX_SENSOR 2
|
||||
#define RKISP_MAX_PIPELINE 4
|
||||
#define RKISP_MAX_BUS_CLK 8
|
||||
#define RKISP_MAX_SENSOR 2
|
||||
#define RKISP_MAX_PIPELINE 4
|
||||
|
||||
#define RKISP_MEDIA_BUS_FMT_MASK 0xF000
|
||||
#define RKISP_MEDIA_BUS_FMT_BAYER 0x3000
|
||||
@@ -71,6 +87,7 @@ enum rkisp_isp_ver {
|
||||
ISP_V11 = 0x10,
|
||||
ISP_V12 = 0x20,
|
||||
ISP_V13 = 0x30,
|
||||
ISP_V20 = 0x40,
|
||||
};
|
||||
|
||||
enum rkisp_isp_state {
|
||||
@@ -81,9 +98,12 @@ enum rkisp_isp_state {
|
||||
|
||||
enum rkisp_isp_inp {
|
||||
INP_INVAL = 0,
|
||||
INP_CSI,
|
||||
INP_DVP,
|
||||
INP_DMARX_ISP,
|
||||
INP_RAWRD0 = BIT(0),
|
||||
INP_RAWRD1 = BIT(1),
|
||||
INP_RAWRD2 = BIT(2),
|
||||
INP_CSI = BIT(4),
|
||||
INP_DVP = BIT(5),
|
||||
INP_DMARX_ISP = BIT(6),
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -114,18 +134,43 @@ struct rkisp_pipeline {
|
||||
struct rkisp_sensor_info {
|
||||
struct v4l2_subdev *sd;
|
||||
struct v4l2_mbus_config mbus;
|
||||
struct v4l2_subdev_format fmt;
|
||||
struct v4l2_subdev_format fmt[CSI_PAD_MAX - 1];
|
||||
struct v4l2_subdev_pad_config cfg;
|
||||
};
|
||||
|
||||
/* struct rkisp_hdr - hdr configured
|
||||
* @cnt: open counter
|
||||
* @op_mode: hdr optional mode
|
||||
* @esp_mode: hdr especial mode
|
||||
* @index: hdr dma index
|
||||
* @q_tx: dmatx buf list
|
||||
* @q_rx: dmarx buf list
|
||||
* @rx_cur_buf: rawrd current buf
|
||||
* @dummy_buf: hdr dma internal buf
|
||||
*/
|
||||
struct rkisp_hdr {
|
||||
u8 cnt;
|
||||
u8 op_mode;
|
||||
u8 esp_mode;
|
||||
u8 index[HDR_DMA_MAX];
|
||||
struct v4l2_subdev *sensor;
|
||||
struct list_head q_tx[HDR_DMA_MAX];
|
||||
struct list_head q_rx[HDR_DMA_MAX];
|
||||
struct rkisp_dummy_buffer *rx_cur_buf[HDR_DMA_MAX];
|
||||
struct rkisp_dummy_buffer dummy_buf[HDR_DMA_MAX][HDR_MAX_DUMMY_BUF];
|
||||
};
|
||||
|
||||
/*
|
||||
* struct rkisp_device - ISP platform device
|
||||
* @base_addr: base register address
|
||||
* @active_sensor: sensor in-use, set when streaming on
|
||||
* @isp_sdev: ISP sub-device
|
||||
* @rkisp_stream: capture video device
|
||||
* @cap_dev: image capture device
|
||||
* @stats_vdev: ISP statistics output device
|
||||
* @params_vdev: ISP input parameters device
|
||||
* @dmarx_dev: image input device
|
||||
* @csi_dev: mipi csi device
|
||||
* @mpfbc_dev: mpfbc output device
|
||||
*/
|
||||
struct rkisp_device {
|
||||
struct list_head list;
|
||||
@@ -144,10 +189,12 @@ struct rkisp_device {
|
||||
struct rkisp_sensor_info sensors[RKISP_MAX_SENSOR];
|
||||
int num_sensors;
|
||||
struct rkisp_isp_subdev isp_sdev;
|
||||
struct rkisp_stream stream[RKISP_MAX_STREAM];
|
||||
struct rkisp_capture_device cap_dev;
|
||||
struct rkisp_isp_stats_vdev stats_vdev;
|
||||
struct rkisp_isp_params_vdev params_vdev;
|
||||
struct rkisp_dmarx_device dmarx_dev;
|
||||
struct rkisp_csi_device csi_dev;
|
||||
struct rkisp_mpfbc_device mpfbc_dev;
|
||||
struct rkisp_pipeline pipe;
|
||||
struct iommu_domain *domain;
|
||||
enum rkisp_isp_ver isp_ver;
|
||||
@@ -161,10 +208,10 @@ struct rkisp_device {
|
||||
int vs_irq;
|
||||
int mipi_irq;
|
||||
struct gpio_desc *vs_irq_gpio;
|
||||
struct v4l2_subdev *hdr_sensor;
|
||||
struct rkisp_hdr hdr;
|
||||
enum rkisp_isp_state isp_state;
|
||||
unsigned int isp_err_cnt;
|
||||
enum rkisp_isp_inp isp_inp;
|
||||
unsigned int isp_inp;
|
||||
struct mutex apilock; /* mutex to serialize the calls of stream */
|
||||
struct mutex iqlock; /* mutex to serialize the calls of iq */
|
||||
wait_queue_head_t sync_onoff;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "dev.h"
|
||||
#include "regs.h"
|
||||
|
||||
#define CIF_ISP_REQ_BUFS_MIN 1
|
||||
#define CIF_ISP_REQ_BUFS_MIN 0
|
||||
|
||||
static const struct capture_fmt dmarx_fmts[] = {
|
||||
/* bayer raw */
|
||||
@@ -111,6 +111,36 @@ static struct stream_config rkisp_dmarx_stream_config = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct stream_config rkisp2_dmarx0_stream_config = {
|
||||
.fmts = dmarx_fmts,
|
||||
.fmt_size = ARRAY_SIZE(dmarx_fmts),
|
||||
.frame_end_id = RAW0_RD_FRAME,
|
||||
.mi = {
|
||||
.y_base_ad_init = MI_RAW0_RD_BASE,
|
||||
.y_base_ad_shd = MI_RAW0_RD_BASE_SHD,
|
||||
},
|
||||
};
|
||||
|
||||
static struct stream_config rkisp2_dmarx1_stream_config = {
|
||||
.fmts = dmarx_fmts,
|
||||
.fmt_size = ARRAY_SIZE(dmarx_fmts),
|
||||
.frame_end_id = RAW1_RD_FRAME,
|
||||
.mi = {
|
||||
.y_base_ad_init = MI_RAW1_RD_BASE,
|
||||
.y_base_ad_shd = MI_RAW1_RD_BASE_SHD,
|
||||
},
|
||||
};
|
||||
|
||||
static struct stream_config rkisp2_dmarx2_stream_config = {
|
||||
.fmts = dmarx_fmts,
|
||||
.fmt_size = ARRAY_SIZE(dmarx_fmts),
|
||||
.frame_end_id = RAW2_RD_FRAME,
|
||||
.mi = {
|
||||
.y_base_ad_init = MI_RAW2_RD_BASE,
|
||||
.y_base_ad_shd = MI_RAW2_RD_BASE_SHD,
|
||||
},
|
||||
};
|
||||
|
||||
static const
|
||||
struct capture_fmt *find_fmt(struct rkisp_stream *stream,
|
||||
const u32 pixelfmt)
|
||||
@@ -133,7 +163,7 @@ static int dmarx_config_mi(struct rkisp_stream *stream)
|
||||
struct capture_fmt *dmarx_in_fmt = &stream->out_isp_fmt;
|
||||
|
||||
v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
|
||||
"%s %dx%x y_stride:%d\n", __func__,
|
||||
"%s %dx%d y_stride:%d\n", __func__,
|
||||
stream->out_fmt.width,
|
||||
stream->out_fmt.height,
|
||||
stream->u.dmarx.y_stride);
|
||||
@@ -182,6 +212,90 @@ static struct streams_ops rkisp_dmarx_streams_ops = {
|
||||
.update_mi = update_dmarx,
|
||||
};
|
||||
|
||||
static int rawrd_config_mi(struct rkisp_stream *stream)
|
||||
{
|
||||
struct rkisp_device *dev = stream->ispdev;
|
||||
void __iomem *base = dev->base_addr;
|
||||
|
||||
v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
|
||||
"%s id:%d %dx%d\n", __func__,
|
||||
stream->id,
|
||||
stream->out_fmt.width,
|
||||
stream->out_fmt.height);
|
||||
|
||||
raw_rd_set_pic_size(base,
|
||||
stream->out_fmt.width,
|
||||
stream->out_fmt.height);
|
||||
isp_set_bits(base + CSI2RX_RAW_RD_CTRL, 0,
|
||||
SW_CSI_RAW_RD_SIMG_SWP |
|
||||
SW_CSI_RAW_RD_SIMG_MOD |
|
||||
1 << (stream->id - 1));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void update_rawrd(struct rkisp_stream *stream)
|
||||
{
|
||||
struct rkisp_device *dev = stream->ispdev;
|
||||
void __iomem *base = dev->base_addr;
|
||||
|
||||
if (stream->curr_buf) {
|
||||
mi_set_y_addr(stream,
|
||||
stream->curr_buf->buff_addr[RKISP_PLANE_Y]);
|
||||
stream->frame_end = false;
|
||||
} else if (dev->dmarx_dev.trigger == T_AUTO) {
|
||||
/* internal raw wr/rd buf rotate */
|
||||
struct rkisp_dummy_buffer *buf;
|
||||
u32 id, rawwr_addr;
|
||||
|
||||
switch (stream->id) {
|
||||
case RKISP_STREAM_RAWRD2:
|
||||
id = dev->hdr.index[HDR_DMA2];
|
||||
rawwr_addr = MI_RAW2_WR_BASE_SHD;
|
||||
break;
|
||||
case RKISP_STREAM_RAWRD1:
|
||||
id = dev->hdr.index[HDR_DMA1];
|
||||
rawwr_addr = MI_RAW1_WR_BASE_SHD;
|
||||
break;
|
||||
case RKISP_STREAM_RAWRD0:
|
||||
default:
|
||||
id = dev->hdr.index[HDR_DMA0];
|
||||
rawwr_addr = MI_RAW0_WR_BASE_SHD;
|
||||
}
|
||||
if (dev->hdr.rx_cur_buf[id]) {
|
||||
hdr_qbuf(&dev->hdr.q_tx[id], dev->hdr.rx_cur_buf[id]);
|
||||
dev->hdr.rx_cur_buf[id] = NULL;
|
||||
}
|
||||
buf = hdr_dqbuf(&dev->hdr.q_rx[id]);
|
||||
if (buf) {
|
||||
mi_set_y_addr(stream, buf->dma_addr);
|
||||
dev->hdr.rx_cur_buf[id] = buf;
|
||||
} else {
|
||||
mi_set_y_addr(stream,
|
||||
readl(base + rawwr_addr));
|
||||
}
|
||||
}
|
||||
v4l2_dbg(2, rkisp_debug, &dev->v4l2_dev,
|
||||
"%s stream:%d Y:0x%x SHD:0x%x\n",
|
||||
__func__, stream->id,
|
||||
readl(base + stream->config->mi.y_base_ad_init),
|
||||
readl(base + stream->config->mi.y_base_ad_shd));
|
||||
}
|
||||
|
||||
static void rawrd_stop_mi(struct rkisp_stream *stream)
|
||||
{
|
||||
void __iomem *base = &stream->ispdev->base_addr;
|
||||
|
||||
isp_clear_bits(base + CSI2RX_RAW_RD_CTRL,
|
||||
1 << (stream->id - 1));
|
||||
}
|
||||
|
||||
static struct streams_ops rkisp2_dmarx_streams_ops = {
|
||||
.config_mi = rawrd_config_mi,
|
||||
.stop_mi = rawrd_stop_mi,
|
||||
.update_mi = update_rawrd,
|
||||
};
|
||||
|
||||
static int dmarx_frame_end(struct rkisp_stream *stream)
|
||||
{
|
||||
unsigned long lock_flags = 0;
|
||||
@@ -219,7 +333,7 @@ static void dmarx_stop(struct rkisp_stream *stream)
|
||||
!stream->frame_end) {
|
||||
ret = wait_event_timeout(stream->done,
|
||||
!stream->streaming,
|
||||
msecs_to_jiffies(500));
|
||||
msecs_to_jiffies(100));
|
||||
if (!ret)
|
||||
v4l2_warn(v4l2_dev,
|
||||
"dmarx:%d waiting on event return error %d\n",
|
||||
@@ -383,10 +497,6 @@ static int rkisp_init_vb2_queue(struct vb2_queue *q,
|
||||
struct rkisp_stream *stream,
|
||||
enum v4l2_buf_type buf_type)
|
||||
{
|
||||
struct rkisp_vdev_node *node;
|
||||
|
||||
node = queue_to_node(q);
|
||||
|
||||
q->type = buf_type;
|
||||
q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_USERPTR;
|
||||
q->drv_priv = stream;
|
||||
@@ -396,6 +506,7 @@ static int rkisp_init_vb2_queue(struct vb2_queue *q,
|
||||
q->min_buffers_needed = CIF_ISP_REQ_BUFS_MIN;
|
||||
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
|
||||
q->lock = &stream->ispdev->apilock;
|
||||
q->dev = stream->ispdev->dev;
|
||||
|
||||
return vb2_queue_init(q);
|
||||
}
|
||||
@@ -607,7 +718,7 @@ static int rkisp_register_dmarx_video(struct rkisp_stream *stream)
|
||||
ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
|
||||
if (ret < 0) {
|
||||
v4l2_err(v4l2_dev,
|
||||
"video register failed with error %d\n", ret);
|
||||
"%s failed with error %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -643,7 +754,27 @@ void rkisp_dmarx_isr(u32 mis_val, struct rkisp_device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
int rkisp_register_dmarx_vdev(struct rkisp_device *dev)
|
||||
void rkisp2_rawrd_isr(u32 mis_val, struct rkisp_device *dev)
|
||||
{
|
||||
struct rkisp_stream *stream;
|
||||
int i;
|
||||
|
||||
for (i = RKISP_STREAM_RAWRD0; i < RKISP_MAX_DMARX_STREAM; i++) {
|
||||
stream = &dev->dmarx_dev.stream[i];
|
||||
if (!(mis_val & CIF_MI_FRAME(stream)))
|
||||
continue;
|
||||
stream->frame_end = true;
|
||||
if (stream->stopping) {
|
||||
stream->stopping = false;
|
||||
stream->streaming = false;
|
||||
wake_up(&stream->done);
|
||||
} else {
|
||||
dmarx_frame_end(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int dmarx_init(struct rkisp_device *dev, u32 id)
|
||||
{
|
||||
struct rkisp_dmarx_device *dmarx_dev = &dev->dmarx_dev;
|
||||
struct rkisp_stream *stream;
|
||||
@@ -651,31 +782,86 @@ int rkisp_register_dmarx_vdev(struct rkisp_device *dev)
|
||||
struct media_entity *source, *sink;
|
||||
int ret = 0;
|
||||
|
||||
stream = &dmarx_dev->stream[id];
|
||||
INIT_LIST_HEAD(&stream->buf_queue);
|
||||
init_waitqueue_head(&stream->done);
|
||||
spin_lock_init(&stream->vbq_lock);
|
||||
stream->id = id;
|
||||
stream->ispdev = dev;
|
||||
vdev = &stream->vnode.vdev;
|
||||
|
||||
switch (id) {
|
||||
case RKISP_STREAM_DMARX:
|
||||
strlcpy(vdev->name, DMA_VDEV_NAME,
|
||||
sizeof(vdev->name));
|
||||
stream->ops = &rkisp_dmarx_streams_ops;
|
||||
stream->config = &rkisp_dmarx_stream_config;
|
||||
break;
|
||||
case RKISP_STREAM_RAWRD0:
|
||||
strlcpy(vdev->name, DMARX0_VDEV_NAME,
|
||||
sizeof(vdev->name));
|
||||
stream->ops = &rkisp2_dmarx_streams_ops;
|
||||
stream->config = &rkisp2_dmarx0_stream_config;
|
||||
break;
|
||||
case RKISP_STREAM_RAWRD1:
|
||||
strlcpy(vdev->name, DMARX1_VDEV_NAME,
|
||||
sizeof(vdev->name));
|
||||
stream->ops = &rkisp2_dmarx_streams_ops;
|
||||
stream->config = &rkisp2_dmarx1_stream_config;
|
||||
break;
|
||||
case RKISP_STREAM_RAWRD2:
|
||||
strlcpy(vdev->name, DMARX2_VDEV_NAME,
|
||||
sizeof(vdev->name));
|
||||
stream->ops = &rkisp2_dmarx_streams_ops;
|
||||
stream->config = &rkisp2_dmarx2_stream_config;
|
||||
break;
|
||||
default:
|
||||
v4l2_err(&dev->v4l2_dev, "Invalid dmarx\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = rkisp_register_dmarx_video(stream);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* dmarx link -> isp subdev */
|
||||
source = &vdev->entity;
|
||||
sink = &dev->isp_sdev.sd.entity;
|
||||
return media_create_pad_link(source, 0, sink,
|
||||
RKISP_ISP_PAD_SINK, 0);
|
||||
}
|
||||
|
||||
int rkisp_register_dmarx_vdev(struct rkisp_device *dev)
|
||||
{
|
||||
struct rkisp_dmarx_device *dmarx_dev = &dev->dmarx_dev;
|
||||
int ret = 0;
|
||||
|
||||
memset(dmarx_dev, 0, sizeof(*dmarx_dev));
|
||||
dmarx_dev->ispdev = dev;
|
||||
|
||||
if (dev->isp_ver <= ISP_V13) {
|
||||
stream = &dmarx_dev->stream[RKISP_STREAM_DMARX];
|
||||
INIT_LIST_HEAD(&stream->buf_queue);
|
||||
init_waitqueue_head(&stream->done);
|
||||
spin_lock_init(&stream->vbq_lock);
|
||||
stream->id = RKISP_STREAM_DMARX;
|
||||
stream->ispdev = dev;
|
||||
stream->ops = &rkisp_dmarx_streams_ops;
|
||||
stream->config = &rkisp_dmarx_stream_config;
|
||||
vdev = &stream->vnode.vdev;
|
||||
strlcpy(vdev->name, DMA_VDEV_NAME, sizeof(vdev->name));
|
||||
ret = rkisp_register_dmarx_video(stream);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = dmarx_init(dev, RKISP_STREAM_DMARX);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
/* dmarx links -> isp subdev */
|
||||
source = &vdev->entity;
|
||||
sink = &dev->isp_sdev.sd.entity;
|
||||
ret = media_create_pad_link(source, 0,
|
||||
sink, RKISP_ISP_PAD_SINK, 0);
|
||||
if (dev->isp_ver == ISP_V20) {
|
||||
ret = dmarx_init(dev, RKISP_STREAM_RAWRD0);
|
||||
if (ret < 0)
|
||||
goto err_free_dmarx;
|
||||
ret = dmarx_init(dev, RKISP_STREAM_RAWRD1);
|
||||
if (ret < 0)
|
||||
goto err_free_dmarx0;
|
||||
ret = dmarx_init(dev, RKISP_STREAM_RAWRD2);
|
||||
if (ret < 0)
|
||||
goto err_free_dmarx1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_free_dmarx1:
|
||||
rkisp_unregister_dmarx_video(&dmarx_dev->stream[RKISP_STREAM_RAWRD1]);
|
||||
err_free_dmarx0:
|
||||
rkisp_unregister_dmarx_video(&dmarx_dev->stream[RKISP_STREAM_RAWRD0]);
|
||||
err_free_dmarx:
|
||||
rkisp_unregister_dmarx_video(&dmarx_dev->stream[RKISP_STREAM_DMARX]);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -684,8 +870,17 @@ void rkisp_unregister_dmarx_vdev(struct rkisp_device *dev)
|
||||
struct rkisp_dmarx_device *dmarx_dev = &dev->dmarx_dev;
|
||||
struct rkisp_stream *stream;
|
||||
|
||||
if (dev->isp_ver <= ISP_V13) {
|
||||
stream = &dmarx_dev->stream[RKISP_STREAM_DMARX];
|
||||
stream = &dmarx_dev->stream[RKISP_STREAM_DMARX];
|
||||
rkisp_unregister_dmarx_video(stream);
|
||||
|
||||
if (dev->isp_ver == ISP_V20) {
|
||||
stream = &dmarx_dev->stream[RKISP_STREAM_RAWRD0];
|
||||
rkisp_unregister_dmarx_video(stream);
|
||||
|
||||
stream = &dmarx_dev->stream[RKISP_STREAM_RAWRD1];
|
||||
rkisp_unregister_dmarx_video(stream);
|
||||
|
||||
stream = &dmarx_dev->stream[RKISP_STREAM_RAWRD2];
|
||||
rkisp_unregister_dmarx_video(stream);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,10 @@
|
||||
#include "common.h"
|
||||
|
||||
#define RKISP_STREAM_DMARX 0
|
||||
#define RKISP_MAX_DMARX_STREAM 1
|
||||
#define RKISP_STREAM_RAWRD0 1
|
||||
#define RKISP_STREAM_RAWRD1 2
|
||||
#define RKISP_STREAM_RAWRD2 3
|
||||
#define RKISP_MAX_DMARX_STREAM 4
|
||||
|
||||
struct rkisp_dmarx_device;
|
||||
|
||||
@@ -18,12 +21,19 @@ enum rkisp_dmarx_pad {
|
||||
RKISP_DMARX_PAD_MAX
|
||||
};
|
||||
|
||||
enum rkisp_dmarx_trigger {
|
||||
T_AUTO = 0,
|
||||
T_MANUAL,
|
||||
};
|
||||
|
||||
struct rkisp_dmarx_device {
|
||||
struct rkisp_device *ispdev;
|
||||
struct rkisp_stream stream[RKISP_MAX_DMARX_STREAM];
|
||||
enum rkisp_dmarx_trigger trigger;
|
||||
};
|
||||
|
||||
void rkisp_dmarx_isr(u32 mis_val, struct rkisp_device *dev);
|
||||
void rkisp2_rawrd_isr(u32 mis_val, struct rkisp_device *dev);
|
||||
void rkisp_unregister_dmarx_vdev(struct rkisp_device *dev);
|
||||
int rkisp_register_dmarx_vdev(struct rkisp_device *dev);
|
||||
#endif /* _RKISP_DMARX_H */
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "dev.h"
|
||||
#include "regs.h"
|
||||
|
||||
#define PARAMS_NAME DRIVER_NAME "-input-params"
|
||||
#define RKISP_ISP_PARAMS_REQ_BUFS_MIN 2
|
||||
#define RKISP_ISP_PARAMS_REQ_BUFS_MAX 8
|
||||
|
||||
@@ -2123,7 +2124,7 @@ void __preisp_isr_update_hdrae_para(struct rkisp_isp_params_vdev *params_vdev,
|
||||
lsc = &new_params->others.lsc_config;
|
||||
awb_gain = &new_params->others.awb_gain_config;
|
||||
|
||||
if (!params_vdev->dev->hdr_sensor)
|
||||
if (!params_vdev->dev->hdr.sensor)
|
||||
return;
|
||||
|
||||
if ((module_en_update & CIFISP_MODULE_AWB_GAIN) ||
|
||||
@@ -2160,10 +2161,10 @@ void __preisp_isr_update_hdrae_para(struct rkisp_isp_params_vdev *params_vdev,
|
||||
}
|
||||
}
|
||||
|
||||
ret = v4l2_subdev_call(params_vdev->dev->hdr_sensor, core, ioctl,
|
||||
ret = v4l2_subdev_call(params_vdev->dev->hdr.sensor, core, ioctl,
|
||||
PREISP_CMD_SAVE_HDRAE_PARAM, hdrae);
|
||||
if (ret)
|
||||
params_vdev->dev->hdr_sensor = NULL;
|
||||
params_vdev->dev->hdr.sensor = NULL;
|
||||
}
|
||||
|
||||
void rkisp_params_isr(struct rkisp_isp_params_vdev *params_vdev, u32 isp_mis)
|
||||
@@ -2566,10 +2567,6 @@ static int
|
||||
rkisp_params_init_vb2_queue(struct vb2_queue *q,
|
||||
struct rkisp_isp_params_vdev *params_vdev)
|
||||
{
|
||||
struct rkisp_vdev_node *node;
|
||||
|
||||
node = queue_to_node(q);
|
||||
|
||||
q->type = V4L2_BUF_TYPE_META_OUTPUT;
|
||||
q->io_modes = VB2_MMAP | VB2_USERPTR;
|
||||
q->drv_priv = params_vdev;
|
||||
@@ -2607,11 +2604,12 @@ int rkisp_register_params_vdev(struct rkisp_isp_params_vdev *params_vdev,
|
||||
int ret;
|
||||
struct rkisp_vdev_node *node = ¶ms_vdev->vnode;
|
||||
struct video_device *vdev = &node->vdev;
|
||||
struct media_entity *source, *sink;
|
||||
|
||||
params_vdev->dev = dev;
|
||||
spin_lock_init(¶ms_vdev->config_lock);
|
||||
|
||||
strlcpy(vdev->name, "rkisp1-input-params", sizeof(vdev->name));
|
||||
strlcpy(vdev->name, PARAMS_NAME, sizeof(vdev->name));
|
||||
|
||||
video_set_drvdata(vdev, params_vdev);
|
||||
vdev->ioctl_ops = &rkisp_params_ioctl;
|
||||
@@ -2640,6 +2638,14 @@ int rkisp_register_params_vdev(struct rkisp_isp_params_vdev *params_vdev,
|
||||
"could not register Video for Linux device\n");
|
||||
goto err_cleanup_media_entity;
|
||||
}
|
||||
|
||||
source = ¶ms_vdev->vnode.vdev.entity;
|
||||
sink = ¶ms_vdev->dev->isp_sdev.sd.entity;
|
||||
ret = media_create_pad_link(source, 0, sink,
|
||||
RKISP_ISP_PAD_SINK_PARAMS, MEDIA_LNK_FL_ENABLED);
|
||||
if (ret < 0)
|
||||
goto err_cleanup_media_entity;
|
||||
|
||||
return 0;
|
||||
err_cleanup_media_entity:
|
||||
media_entity_cleanup(&vdev->entity);
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "dev.h"
|
||||
#include "regs.h"
|
||||
|
||||
#define STATS_NAME DRIVER_NAME "-statistics"
|
||||
#define RKISP_ISP_STATS_REQ_BUFS_MIN 2
|
||||
#define RKISP_ISP_STATS_REQ_BUFS_MAX 8
|
||||
|
||||
@@ -200,10 +201,6 @@ static struct vb2_ops rkisp_stats_vb2_ops = {
|
||||
static int rkisp_stats_init_vb2_queue(struct vb2_queue *q,
|
||||
struct rkisp_isp_stats_vdev *stats_vdev)
|
||||
{
|
||||
struct rkisp_vdev_node *node;
|
||||
|
||||
node = queue_to_node(q);
|
||||
|
||||
q->type = V4L2_BUF_TYPE_META_CAPTURE;
|
||||
q->io_modes = VB2_MMAP | VB2_USERPTR;
|
||||
q->drv_priv = stats_vdev;
|
||||
@@ -618,13 +615,14 @@ int rkisp_register_stats_vdev(struct rkisp_isp_stats_vdev *stats_vdev,
|
||||
int ret;
|
||||
struct rkisp_vdev_node *node = &stats_vdev->vnode;
|
||||
struct video_device *vdev = &node->vdev;
|
||||
struct media_entity *source, *sink;
|
||||
|
||||
stats_vdev->dev = dev;
|
||||
INIT_LIST_HEAD(&stats_vdev->stat);
|
||||
spin_lock_init(&stats_vdev->irq_lock);
|
||||
spin_lock_init(&stats_vdev->rd_lock);
|
||||
|
||||
strlcpy(vdev->name, "rkisp1-statistics", sizeof(vdev->name));
|
||||
strlcpy(vdev->name, STATS_NAME, sizeof(vdev->name));
|
||||
|
||||
video_set_drvdata(vdev, stats_vdev);
|
||||
vdev->ioctl_ops = &rkisp_stats_ioctl;
|
||||
@@ -651,6 +649,13 @@ int rkisp_register_stats_vdev(struct rkisp_isp_stats_vdev *stats_vdev,
|
||||
goto err_cleanup_media_entity;
|
||||
}
|
||||
|
||||
source = &dev->isp_sdev.sd.entity;
|
||||
sink = &stats_vdev->vnode.vdev.entity;
|
||||
ret = media_create_pad_link(source, RKISP_ISP_PAD_SOURCE_STATS,
|
||||
sink, 0, MEDIA_LNK_FL_ENABLED);
|
||||
if (ret < 0)
|
||||
goto err_cleanup_media_entity;
|
||||
|
||||
ret = kfifo_alloc(&stats_vdev->rd_kfifo,
|
||||
RKISP_READOUT_WORK_SIZE,
|
||||
GFP_KERNEL);
|
||||
|
||||
322
drivers/media/platform/rockchip/isp/mpfbc.c
Normal file
322
drivers/media/platform/rockchip/isp/mpfbc.c
Normal file
@@ -0,0 +1,322 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-event.h>
|
||||
#include <media/v4l2-fh.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
#include <media/videobuf2-dma-contig.h>
|
||||
#include <linux/dma-iommu.h>
|
||||
#include <linux/rk-camera-module.h>
|
||||
#include "dev.h"
|
||||
#include "regs.h"
|
||||
|
||||
static int mpfbc_get_set_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
struct rkisp_mpfbc_device *mpfbc_dev = v4l2_get_subdevdata(sd);
|
||||
struct rkisp_device *dev = mpfbc_dev->ispdev;
|
||||
int ret;
|
||||
|
||||
/* get isp out format */
|
||||
fmt->pad = RKISP_ISP_PAD_SOURCE_PATH;
|
||||
ret = v4l2_subdev_call(&dev->isp_sdev.sd, pad, get_fmt, NULL, fmt);
|
||||
mpfbc_dev->fmt = *fmt;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mpfbc_s_rx_buffer(struct v4l2_subdev *sd,
|
||||
void *buf, unsigned int *size)
|
||||
{
|
||||
struct rkisp_mpfbc_device *mpfbc_dev = v4l2_get_subdevdata(sd);
|
||||
struct rkisp_device *dev = mpfbc_dev->ispdev;
|
||||
void __iomem *base = dev->base_addr;
|
||||
u32 w = ALIGN(mpfbc_dev->fmt.format.width, 16);
|
||||
u32 h = ALIGN(mpfbc_dev->fmt.format.height, 16);
|
||||
u32 sizes = (w * h >> 4) + w * h * 2;
|
||||
|
||||
/* picture or gain buffer */
|
||||
if (*size == sizes) {
|
||||
if (mpfbc_dev->pic_cur) {
|
||||
mpfbc_dev->pic_nxt = (u32 *)buf;
|
||||
writel(*mpfbc_dev->pic_nxt,
|
||||
base + ISP_MPFBC_HEAD_PTR2);
|
||||
writel(*mpfbc_dev->pic_nxt + (w * h >> 4),
|
||||
base + ISP_MPFBC_PAYL_PTR2);
|
||||
mpfbc_dev->pingpong = true;
|
||||
} else {
|
||||
mpfbc_dev->pic_cur = (u32 *)buf;
|
||||
writel(*mpfbc_dev->pic_cur,
|
||||
base + ISP_MPFBC_HEAD_PTR);
|
||||
writel(*mpfbc_dev->pic_cur + (w * h >> 4),
|
||||
base + ISP_MPFBC_PAYL_PTR);
|
||||
mpfbc_dev->pingpong = false;
|
||||
}
|
||||
} else {
|
||||
if (mpfbc_dev->gain_cur) {
|
||||
mpfbc_dev->gain_nxt = (u32 *)buf;
|
||||
writel(*mpfbc_dev->gain_nxt,
|
||||
base + MI_GAIN_WR_BASE2);
|
||||
mi_wr_ctrl2(base, SW_GAIN_WR_PINGPONG);
|
||||
} else {
|
||||
mpfbc_dev->gain_cur = (u32 *)buf;
|
||||
writel(*mpfbc_dev->gain_cur,
|
||||
base + MI_GAIN_WR_BASE);
|
||||
isp_clear_bits(base + MI_WR_CTRL2,
|
||||
SW_GAIN_WR_PINGPONG);
|
||||
}
|
||||
writel(*size, base + MI_GAIN_WR_SIZE);
|
||||
writel(w >> 4, base + MI_GAIN_WR_LENGTH);
|
||||
mi_wr_ctrl2(base, SW_GAIN_WR_AUTOUPD);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpfbc_start(struct rkisp_mpfbc_device *mpfbc_dev)
|
||||
{
|
||||
struct rkisp_device *dev = mpfbc_dev->ispdev;
|
||||
void __iomem *base = dev->base_addr;
|
||||
u32 h = ALIGN(mpfbc_dev->fmt.format.height, 16);
|
||||
|
||||
writel(mpfbc_dev->pingpong << 4 | SW_MPFBC_YUV_MODE(1) |
|
||||
SW_MPFBC_MAINISP_MODE | SW_MPFBC_EN,
|
||||
base + ISP_MPFBC_BASE);
|
||||
writel(0, base + ISP_MPFBC_VIR_WIDTH);
|
||||
writel(h, base + ISP_MPFBC_VIR_HEIGHT);
|
||||
isp_set_bits(base + CTRL_SWS_CFG, 0, SW_ISP2PP_PIPE_EN);
|
||||
isp_set_bits(base + MI_IMSC, 0, MI_MPFBC_FRAME);
|
||||
isp_set_bits(base + MI_WR_CTRL, 0, CIF_MI_CTRL_INIT_BASE_EN);
|
||||
mp_set_data_path(base);
|
||||
force_cfg_update(base);
|
||||
mpfbc_dev->en = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpfbc_stop(struct rkisp_mpfbc_device *mpfbc_dev)
|
||||
{
|
||||
struct rkisp_device *dev = mpfbc_dev->ispdev;
|
||||
void __iomem *base = dev->base_addr;
|
||||
int ret;
|
||||
|
||||
mpfbc_dev->stopping = true;
|
||||
writel(SW_MPFBC_YUV_MODE(1),
|
||||
base + ISP_MPFBC_BASE);
|
||||
hdr_stop_dmatx(dev);
|
||||
ret = wait_event_timeout(mpfbc_dev->done,
|
||||
!mpfbc_dev->en,
|
||||
msecs_to_jiffies(1000));
|
||||
if (!ret)
|
||||
v4l2_warn(&mpfbc_dev->sd,
|
||||
"waiting on event return error %d\n", ret);
|
||||
isp_clear_bits(base + MI_IMSC, MI_MPFBC_FRAME);
|
||||
hdr_destroy_buf(dev);
|
||||
mpfbc_dev->en = false;
|
||||
mpfbc_dev->pic_cur = NULL;
|
||||
mpfbc_dev->pic_nxt = NULL;
|
||||
mpfbc_dev->gain_cur = NULL;
|
||||
mpfbc_dev->gain_nxt = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpfbc_start_stream(struct v4l2_subdev *sd)
|
||||
{
|
||||
struct rkisp_mpfbc_device *mpfbc_dev = v4l2_get_subdevdata(sd);
|
||||
struct rkisp_device *dev = mpfbc_dev->ispdev;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(mpfbc_dev->en) ||
|
||||
!dev->isp_inp)
|
||||
return -EBUSY;
|
||||
|
||||
if (dev->isp_inp & INP_CSI ||
|
||||
dev->isp_inp & INP_DVP) {
|
||||
/* Always update sensor info in case media topology changed */
|
||||
ret = rkisp_update_sensor_info(dev);
|
||||
if (ret < 0) {
|
||||
v4l2_err(&dev->v4l2_dev,
|
||||
"update sensor info failed %d\n",
|
||||
ret);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
/* enable clocks/power-domains */
|
||||
ret = dev->pipe.open(&dev->pipe, &sd->entity, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
hdr_config_dmatx(dev);
|
||||
ret = mpfbc_start(mpfbc_dev);
|
||||
if (ret < 0)
|
||||
goto close_pipe;
|
||||
hdr_update_dmatx_buf(dev);
|
||||
|
||||
/* start sub-devices */
|
||||
ret = dev->pipe.set_stream(&dev->pipe, true);
|
||||
if (ret < 0)
|
||||
goto stop_mpfbc;
|
||||
|
||||
ret = media_pipeline_start(&sd->entity, &dev->pipe.pipe);
|
||||
if (ret < 0)
|
||||
goto pipe_stream_off;
|
||||
|
||||
return 0;
|
||||
pipe_stream_off:
|
||||
dev->pipe.set_stream(&dev->pipe, false);
|
||||
stop_mpfbc:
|
||||
mpfbc_stop(mpfbc_dev);
|
||||
close_pipe:
|
||||
dev->pipe.close(&dev->pipe);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mpfbc_stop_stream(struct v4l2_subdev *sd)
|
||||
{
|
||||
struct rkisp_mpfbc_device *mpfbc_dev = v4l2_get_subdevdata(sd);
|
||||
struct rkisp_device *dev = mpfbc_dev->ispdev;
|
||||
|
||||
mpfbc_stop(mpfbc_dev);
|
||||
media_pipeline_stop(&sd->entity);
|
||||
dev->pipe.set_stream(&dev->pipe, false);
|
||||
dev->pipe.close(&dev->pipe);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpfbc_s_stream(struct v4l2_subdev *sd, int on)
|
||||
{
|
||||
struct rkisp_mpfbc_device *mpfbc_dev = v4l2_get_subdevdata(sd);
|
||||
int ret = 0;
|
||||
|
||||
if (on)
|
||||
ret = mpfbc_start_stream(sd);
|
||||
else if (mpfbc_dev->en)
|
||||
ret = mpfbc_stop_stream(sd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mpfbc_s_power(struct v4l2_subdev *sd, int on)
|
||||
{
|
||||
struct rkisp_mpfbc_device *mpfbc_dev = v4l2_get_subdevdata(sd);
|
||||
struct rkisp_device *dev = mpfbc_dev->ispdev;
|
||||
int ret;
|
||||
|
||||
if (on) {
|
||||
atomic_inc(&dev->open_cnt);
|
||||
ret = v4l2_pipeline_pm_use(&sd->entity, 1);
|
||||
} else {
|
||||
ret = v4l2_pipeline_pm_use(&sd->entity, 0);
|
||||
atomic_dec(&dev->open_cnt);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rkisp_mpfbc_isr(u32 mis_val, struct rkisp_device *dev)
|
||||
{
|
||||
struct rkisp_mpfbc_device *mpfbc_dev = &dev->mpfbc_dev;
|
||||
void __iomem *base = dev->base_addr;
|
||||
|
||||
writel(MI_MPFBC_FRAME, base + CIF_MI_ICR);
|
||||
|
||||
if (mpfbc_dev->stopping) {
|
||||
if (is_mpfbc_stopped(base)) {
|
||||
mpfbc_dev->en = false;
|
||||
mpfbc_dev->stopping = false;
|
||||
wake_up(&mpfbc_dev->done);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_pad_ops mpfbc_pad_ops = {
|
||||
.set_fmt = mpfbc_get_set_fmt,
|
||||
.get_fmt = mpfbc_get_set_fmt,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_video_ops mpfbc_video_ops = {
|
||||
.s_rx_buffer = mpfbc_s_rx_buffer,
|
||||
.s_stream = mpfbc_s_stream,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_core_ops mpfbc_core_ops = {
|
||||
.s_power = mpfbc_s_power,
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_ops mpfbc_v4l2_ops = {
|
||||
.core = &mpfbc_core_ops,
|
||||
.video = &mpfbc_video_ops,
|
||||
.pad = &mpfbc_pad_ops,
|
||||
};
|
||||
|
||||
int rkisp_register_mpfbc_subdev(struct rkisp_device *dev,
|
||||
struct v4l2_device *v4l2_dev)
|
||||
{
|
||||
struct rkisp_mpfbc_device *mpfbc_dev = &dev->mpfbc_dev;
|
||||
struct v4l2_subdev *sd;
|
||||
struct media_entity *source, *sink;
|
||||
int ret;
|
||||
|
||||
memset(mpfbc_dev, 0, sizeof(*mpfbc_dev));
|
||||
if (dev->isp_ver != ISP_V20)
|
||||
return 0;
|
||||
|
||||
mpfbc_dev->ispdev = dev;
|
||||
sd = &mpfbc_dev->sd;
|
||||
|
||||
v4l2_subdev_init(sd, &mpfbc_v4l2_ops);
|
||||
//sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
sd->entity.obj_type = 0;
|
||||
snprintf(sd->name, sizeof(sd->name), MPFBC_DEV_NAME);
|
||||
|
||||
mpfbc_dev->pad.flags = MEDIA_PAD_FL_SINK;
|
||||
|
||||
ret = media_entity_pads_init(&sd->entity, 1, &mpfbc_dev->pad);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
sd->owner = THIS_MODULE;
|
||||
v4l2_set_subdevdata(sd, mpfbc_dev);
|
||||
sd->grp_id = GRP_ID_ISP_MPFBC;
|
||||
ret = v4l2_device_register_subdev(v4l2_dev, sd);
|
||||
if (ret < 0) {
|
||||
v4l2_err(v4l2_dev, "Failed to register mpfbc subdev\n");
|
||||
goto free_media;
|
||||
}
|
||||
|
||||
/* mpfbc links */
|
||||
source = &dev->isp_sdev.sd.entity;
|
||||
sink = &sd->entity;
|
||||
ret = media_create_pad_link(source, RKISP_ISP_PAD_SOURCE_PATH,
|
||||
sink, 0, MEDIA_LNK_FL_ENABLED);
|
||||
|
||||
init_waitqueue_head(&mpfbc_dev->done);
|
||||
return ret;
|
||||
|
||||
free_media:
|
||||
media_entity_cleanup(&sd->entity);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rkisp_unregister_mpfbc_subdev(struct rkisp_device *dev)
|
||||
{
|
||||
struct v4l2_subdev *sd = &dev->mpfbc_dev.sd;
|
||||
|
||||
if (dev->isp_ver != ISP_V20)
|
||||
return;
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
media_entity_cleanup(&sd->entity);
|
||||
}
|
||||
|
||||
void rkisp_get_mpfbc_sd(struct platform_device *dev,
|
||||
struct v4l2_subdev **sd)
|
||||
{
|
||||
struct rkisp_device *isp_dev = platform_get_drvdata(dev);
|
||||
|
||||
if (isp_dev)
|
||||
*sd = &isp_dev->mpfbc_dev.sd;
|
||||
else
|
||||
*sd = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(rkisp_get_mpfbc_sd);
|
||||
34
drivers/media/platform/rockchip/isp/mpfbc.h
Normal file
34
drivers/media/platform/rockchip/isp/mpfbc.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */
|
||||
|
||||
#ifndef _RKISP_mpfbc_H
|
||||
#define _RKISP_mpfbc_H
|
||||
|
||||
#include "linux/platform_device.h"
|
||||
|
||||
#define MPFBC_DEV_NAME DRIVER_NAME "-mpfbc-subdev"
|
||||
|
||||
struct rkisp_mpfbc_device;
|
||||
|
||||
struct rkisp_mpfbc_device {
|
||||
struct rkisp_device *ispdev;
|
||||
struct v4l2_subdev sd;
|
||||
struct v4l2_subdev_format fmt;
|
||||
struct media_pad pad;
|
||||
wait_queue_head_t done;
|
||||
u32 *pic_cur;
|
||||
u32 *pic_nxt;
|
||||
u32 *gain_cur;
|
||||
u32 *gain_nxt;
|
||||
u8 pingpong;
|
||||
u8 stopping;
|
||||
u8 en;
|
||||
};
|
||||
|
||||
int rkisp_register_mpfbc_subdev(struct rkisp_device *dev,
|
||||
struct v4l2_device *v4l2_dev);
|
||||
void rkisp_unregister_mpfbc_subdev(struct rkisp_device *dev);
|
||||
void rkisp_mpfbc_isr(u32 mis_val, struct rkisp_device *dev);
|
||||
void rkisp_get_mpfbc_sd(struct platform_device *dev,
|
||||
struct v4l2_subdev **sd);
|
||||
#endif
|
||||
@@ -51,7 +51,8 @@ void disable_dcrop(struct rkisp_stream *stream, bool async)
|
||||
writel(val, dc_ctrl_addr);
|
||||
}
|
||||
|
||||
void config_dcrop(struct rkisp_stream *stream, struct v4l2_rect *rect, bool async)
|
||||
void config_dcrop(struct rkisp_stream *stream,
|
||||
struct v4l2_rect *rect, bool async)
|
||||
{
|
||||
void __iomem *base = stream->ispdev->base_addr;
|
||||
void __iomem *dc_ctrl_addr = base + stream->config->dual_crop.ctrl;
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#ifndef _RKISP_REGS_H
|
||||
#define _RKISP_REGS_H
|
||||
#include "dev.h"
|
||||
#include "regs_v2x.h"
|
||||
|
||||
#define CIF_ISP_PACK_4BYTE(a, b, c, d) \
|
||||
(((a) & 0xFF) << 0 | ((b) & 0xFF) << 8 | \
|
||||
@@ -218,7 +219,13 @@
|
||||
#define CIF_RSZ_SCALER_FACTOR BIT(16)
|
||||
|
||||
/* MI_IMSC - MI_MIS - MI_RIS - MI_ICR - MI_ISR */
|
||||
#define CIF_MI_FRAME(stream) BIT((stream)->id)
|
||||
#define CIF_MI_FRAME(stream) ({ \
|
||||
typeof(stream) __stream = (stream); \
|
||||
!__stream->config ? 0 : \
|
||||
__stream->config->frame_end_id; \
|
||||
})
|
||||
#define CIF_MI_MP_FRAME BIT(0)
|
||||
#define CIF_MI_SP_FRAME BIT(1)
|
||||
#define CIF_MI_MBLK_LINE BIT(2)
|
||||
#define CIF_MI_FILL_MP_Y BIT(3)
|
||||
#define CIF_MI_WRAP_MP_Y BIT(4)
|
||||
@@ -1628,6 +1635,20 @@ bool sp_is_frame_end_int_masked(void __iomem *base);
|
||||
bool mp_is_stream_stopped(void __iomem *base);
|
||||
bool sp_is_stream_stopped(void __iomem *base);
|
||||
|
||||
static inline void isp_set_bits(void __iomem *addr, u32 bit_mask, u32 val)
|
||||
{
|
||||
u32 tmp = readl(addr) & ~bit_mask;
|
||||
|
||||
writel(tmp | val, addr);
|
||||
}
|
||||
|
||||
static inline void isp_clear_bits(void __iomem *addr, u32 bit_mask)
|
||||
{
|
||||
u32 val = readl(addr);
|
||||
|
||||
writel(val & ~bit_mask, addr);
|
||||
}
|
||||
|
||||
static inline void mi_set_y_size(struct rkisp_stream *stream, int val)
|
||||
{
|
||||
void __iomem *base = stream->ispdev->base_addr;
|
||||
|
||||
1922
drivers/media/platform/rockchip/isp/regs_v2x.h
Normal file
1922
drivers/media/platform/rockchip/isp/regs_v2x.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -48,6 +48,7 @@
|
||||
#include "common.h"
|
||||
#include "regs.h"
|
||||
|
||||
#define ISP_SUBDEV_NAME DRIVER_NAME "-isp-subdev"
|
||||
/*
|
||||
* NOTE: MIPI controller and input MUX are also configured in this file,
|
||||
* because ISP Subdev is not only describe ISP submodule(input size,format, output size, format),
|
||||
@@ -82,53 +83,72 @@ static inline struct rkisp_device *sd_to_isp_dev(struct v4l2_subdev *sd)
|
||||
return container_of(sd->v4l2_dev, struct rkisp_device, v4l2_dev);
|
||||
}
|
||||
|
||||
static int mbus_pixelcode_to_mipi_dt(u32 pixelcode)
|
||||
{
|
||||
int mipi_dt;
|
||||
|
||||
switch (pixelcode) {
|
||||
case MEDIA_BUS_FMT_Y8_1X8:
|
||||
case MEDIA_BUS_FMT_SRGGB8_1X8:
|
||||
case MEDIA_BUS_FMT_SBGGR8_1X8:
|
||||
case MEDIA_BUS_FMT_SGBRG8_1X8:
|
||||
case MEDIA_BUS_FMT_SGRBG8_1X8:
|
||||
mipi_dt = CIF_CSI2_DT_RAW8;
|
||||
break;
|
||||
case MEDIA_BUS_FMT_Y10_1X10:
|
||||
case MEDIA_BUS_FMT_SBGGR10_1X10:
|
||||
case MEDIA_BUS_FMT_SRGGB10_1X10:
|
||||
case MEDIA_BUS_FMT_SGBRG10_1X10:
|
||||
case MEDIA_BUS_FMT_SGRBG10_1X10:
|
||||
mipi_dt = CIF_CSI2_DT_RAW10;
|
||||
break;
|
||||
case MEDIA_BUS_FMT_Y12_1X12:
|
||||
case MEDIA_BUS_FMT_SRGGB12_1X12:
|
||||
case MEDIA_BUS_FMT_SBGGR12_1X12:
|
||||
case MEDIA_BUS_FMT_SGBRG12_1X12:
|
||||
case MEDIA_BUS_FMT_SGRBG12_1X12:
|
||||
mipi_dt = CIF_CSI2_DT_RAW12;
|
||||
break;
|
||||
case MEDIA_BUS_FMT_YUYV8_2X8:
|
||||
case MEDIA_BUS_FMT_YVYU8_2X8:
|
||||
case MEDIA_BUS_FMT_UYVY8_2X8:
|
||||
case MEDIA_BUS_FMT_VYUY8_2X8:
|
||||
mipi_dt = CIF_CSI2_DT_YUV422_8b;
|
||||
break;
|
||||
default:
|
||||
mipi_dt = -EINVAL;
|
||||
}
|
||||
return mipi_dt;
|
||||
}
|
||||
|
||||
/* Get sensor by enabled media link */
|
||||
static struct v4l2_subdev *get_remote_sensor(struct v4l2_subdev *sd)
|
||||
{
|
||||
struct media_pad *local, *remote;
|
||||
struct media_entity *sensor_me;
|
||||
struct v4l2_subdev *remote_sd = NULL;
|
||||
|
||||
local = &sd->entity.pads[RKISP_ISP_PAD_SINK];
|
||||
if (!local)
|
||||
return NULL;
|
||||
remote = media_entity_remote_pad(local);
|
||||
goto end;
|
||||
remote = rkisp_media_entity_remote_pad(local);
|
||||
if (!remote)
|
||||
return NULL;
|
||||
goto end;
|
||||
|
||||
//skip csi subdev
|
||||
if (!strcmp(remote->entity->name, CSI_DEV_NAME)) {
|
||||
local = &remote->entity->pads[CSI_SINK];
|
||||
if (!local)
|
||||
goto end;
|
||||
remote = media_entity_remote_pad(local);
|
||||
if (!remote)
|
||||
goto end;
|
||||
}
|
||||
|
||||
sensor_me = remote->entity;
|
||||
|
||||
return media_entity_to_v4l2_subdev(sensor_me);
|
||||
}
|
||||
|
||||
static void get_remote_mipi_sensor(struct rkisp_device *dev,
|
||||
struct v4l2_subdev **sensor_sd)
|
||||
{
|
||||
struct media_graph graph;
|
||||
struct media_entity *entity = &dev->isp_sdev.sd.entity;
|
||||
struct media_device *mdev = entity->graph_obj.mdev;
|
||||
int ret;
|
||||
|
||||
/* Walk the graph to locate sensor nodes. */
|
||||
mutex_lock(&mdev->graph_mutex);
|
||||
ret = media_graph_walk_init(&graph, mdev);
|
||||
if (ret) {
|
||||
mutex_unlock(&mdev->graph_mutex);
|
||||
*sensor_sd = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
media_graph_walk_start(&graph, entity);
|
||||
while ((entity = media_graph_walk_next(&graph))) {
|
||||
if (entity->function == MEDIA_ENT_F_CAM_SENSOR)
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&mdev->graph_mutex);
|
||||
media_graph_walk_cleanup(&graph);
|
||||
|
||||
if (entity)
|
||||
*sensor_sd = media_entity_to_v4l2_subdev(entity);
|
||||
else
|
||||
*sensor_sd = NULL;
|
||||
remote_sd = media_entity_to_v4l2_subdev(sensor_me);
|
||||
end:
|
||||
return remote_sd;
|
||||
}
|
||||
|
||||
static struct rkisp_sensor_info *sd_to_sensor(struct rkisp_device *dev,
|
||||
@@ -143,12 +163,35 @@ static struct rkisp_sensor_info *sd_to_sensor(struct rkisp_device *dev,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct media_pad *rkisp_media_entity_remote_pad(struct media_pad *pad)
|
||||
{
|
||||
struct media_link *link;
|
||||
|
||||
list_for_each_entry(link, &pad->entity->links, list) {
|
||||
if (!(link->flags & MEDIA_LNK_FL_ENABLED) ||
|
||||
!strcmp(link->source->entity->name,
|
||||
DMARX0_VDEV_NAME) ||
|
||||
!strcmp(link->source->entity->name,
|
||||
DMARX1_VDEV_NAME) ||
|
||||
!strcmp(link->source->entity->name,
|
||||
DMARX2_VDEV_NAME))
|
||||
continue;
|
||||
if (link->source == pad)
|
||||
return link->sink;
|
||||
if (link->sink == pad)
|
||||
return link->source;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int rkisp_update_sensor_info(struct rkisp_device *dev)
|
||||
{
|
||||
struct v4l2_subdev *sd = &dev->isp_sdev.sd;
|
||||
struct rkisp_sensor_info *sensor;
|
||||
struct v4l2_subdev *sensor_sd;
|
||||
int ret = 0;
|
||||
struct v4l2_subdev_format *fmt;
|
||||
int i, ret = 0;
|
||||
|
||||
sensor_sd = get_remote_sensor(sd);
|
||||
if (!sensor_sd)
|
||||
@@ -159,11 +202,61 @@ int rkisp_update_sensor_info(struct rkisp_device *dev)
|
||||
&sensor->mbus);
|
||||
if (ret && ret != -ENOIOCTLCMD)
|
||||
return ret;
|
||||
sensor->fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
|
||||
ret = v4l2_subdev_call(sensor->sd, pad, get_fmt,
|
||||
&sensor->cfg, &sensor->fmt);
|
||||
if (ret && ret != -ENOIOCTLCMD)
|
||||
return ret;
|
||||
|
||||
if (sensor->mbus.type == V4L2_MBUS_CSI2) {
|
||||
u8 vc = 0;
|
||||
|
||||
memset(dev->csi_dev.mipi_di, 0,
|
||||
sizeof(dev->csi_dev.mipi_di));
|
||||
memset(sensor->fmt, 0, sizeof(sensor->fmt));
|
||||
for (i = 0; i < dev->csi_dev.max_pad - 1; i++) {
|
||||
fmt = &sensor->fmt[i];
|
||||
fmt->pad = i;
|
||||
fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
|
||||
ret = v4l2_subdev_call(sensor->sd, pad, get_fmt,
|
||||
&sensor->cfg, fmt);
|
||||
if (ret && ret != -ENOIOCTLCMD)
|
||||
return ret;
|
||||
ret = mbus_pixelcode_to_mipi_dt(fmt->format.code);
|
||||
if (ret < 0) {
|
||||
v4l2_err(&dev->v4l2_dev,
|
||||
"Invalid mipi data type\n");
|
||||
return ret;
|
||||
}
|
||||
/* v4l2_subdev_format reserved[0]
|
||||
* using as mipi virtual channel
|
||||
*/
|
||||
switch (fmt->reserved[0]) {
|
||||
case V4L2_MBUS_CSI2_CHANNEL_3:
|
||||
vc = 3;
|
||||
break;
|
||||
case V4L2_MBUS_CSI2_CHANNEL_2:
|
||||
vc = 2;
|
||||
break;
|
||||
case V4L2_MBUS_CSI2_CHANNEL_1:
|
||||
vc = 1;
|
||||
break;
|
||||
case V4L2_MBUS_CSI2_CHANNEL_0:
|
||||
default:
|
||||
vc = 0;
|
||||
}
|
||||
dev->csi_dev.mipi_di[i] = CIF_MIPI_DATA_SEL_DT(ret) |
|
||||
CIF_MIPI_DATA_SEL_VC(vc);
|
||||
v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
|
||||
"CSI ch%d vc:%d dt:0x%x %dx%d\n",
|
||||
i, vc, ret,
|
||||
fmt->format.width,
|
||||
fmt->format.height);
|
||||
}
|
||||
} else {
|
||||
sensor->fmt[0].pad = 0;
|
||||
sensor->fmt[0].which = V4L2_SUBDEV_FORMAT_ACTIVE;
|
||||
ret = v4l2_subdev_call(sensor->sd, pad, get_fmt,
|
||||
&sensor->cfg, &sensor->fmt[0]);
|
||||
if (ret && ret != -ENOIOCTLCMD)
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev->active_sensor = sensor;
|
||||
|
||||
return ret;
|
||||
@@ -226,6 +319,9 @@ static void rkisp_config_clk(struct rkisp_device *dev, int on)
|
||||
CIF_ICCL_SRSZ_CLK | CIF_ICCL_JPEG_CLK | CIF_ICCL_MI_CLK |
|
||||
CIF_ICCL_IE_CLK | CIF_ICCL_MIPI_CLK | CIF_ICCL_DCROP_CLK;
|
||||
|
||||
if (dev->isp_ver == ISP_V20 && on)
|
||||
val |= ICCL_MPFBC_CLK;
|
||||
|
||||
writel(val, dev->base_addr + CIF_ICCL);
|
||||
|
||||
if (dev->isp_ver == ISP_V12 || dev->isp_ver == ISP_V13) {
|
||||
@@ -236,6 +332,14 @@ static void rkisp_config_clk(struct rkisp_device *dev, int on)
|
||||
CIF_CLK_CTRL_CP | CIF_CLK_CTRL_IE;
|
||||
|
||||
writel(val, dev->base_addr + CIF_VI_ISP_CLK_CTRL_V12);
|
||||
} else if (dev->isp_ver == ISP_V20) {
|
||||
val = !on ? 0 :
|
||||
CLK_CTRL_MI_LDC | CLK_CTRL_MI_MP |
|
||||
CLK_CTRL_MI_JPEG | CLK_CTRL_MI_DP |
|
||||
CLK_CTRL_MI_Y12 | CLK_CTRL_MI_SP |
|
||||
CLK_CTRL_MI_RAW0 | CLK_CTRL_MI_RAW1 |
|
||||
CLK_CTRL_MI_READ | CLK_CTRL_MI_RAWRD;
|
||||
writel(val, dev->base_addr + CTRL_VI_ISP_CLK_CTRL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,6 +354,10 @@ static void rkisp_config_ism(struct rkisp_device *dev)
|
||||
struct v4l2_rect *out_crop = &dev->isp_sdev.out_crop;
|
||||
u32 val;
|
||||
|
||||
/* isp2.0 no ism */
|
||||
if (dev->isp_ver == ISP_V20)
|
||||
return;
|
||||
|
||||
writel(0, base + CIF_ISP_IS_RECENTER);
|
||||
writel(0, base + CIF_ISP_IS_MAX_DX);
|
||||
writel(0, base + CIF_ISP_IS_MAX_DY);
|
||||
@@ -257,7 +365,7 @@ static void rkisp_config_ism(struct rkisp_device *dev)
|
||||
writel(out_crop->left, base + CIF_ISP_IS_H_OFFS);
|
||||
writel(out_crop->top, base + CIF_ISP_IS_V_OFFS);
|
||||
writel(out_crop->width, base + CIF_ISP_IS_H_SIZE);
|
||||
if (dev->stream[RKISP_STREAM_SP].interlaced)
|
||||
if (dev->cap_dev.stream[RKISP_STREAM_SP].interlaced)
|
||||
writel(out_crop->height / 2, base + CIF_ISP_IS_V_SIZE);
|
||||
else
|
||||
writel(out_crop->height, base + CIF_ISP_IS_V_SIZE);
|
||||
@@ -277,7 +385,7 @@ static int rkisp_config_isp(struct rkisp_device *dev)
|
||||
struct ispsd_in_fmt *in_fmt;
|
||||
struct ispsd_out_fmt *out_fmt;
|
||||
struct v4l2_mbus_framefmt *in_frm;
|
||||
struct v4l2_rect *out_crop, *in_crop;
|
||||
struct v4l2_rect *in_crop;
|
||||
struct rkisp_sensor_info *sensor;
|
||||
void __iomem *base = dev->base_addr;
|
||||
u32 isp_ctrl = 0;
|
||||
@@ -290,7 +398,6 @@ static int rkisp_config_isp(struct rkisp_device *dev)
|
||||
in_frm = &dev->isp_sdev.in_frm;
|
||||
in_fmt = &dev->isp_sdev.in_fmt;
|
||||
out_fmt = &dev->isp_sdev.out_fmt;
|
||||
out_crop = &dev->isp_sdev.out_crop;
|
||||
in_crop = &dev->isp_sdev.in_crop;
|
||||
|
||||
if (in_fmt->fmt_type == FMT_BAYER) {
|
||||
@@ -306,13 +413,23 @@ static int rkisp_config_isp(struct rkisp_device *dev)
|
||||
/* demosaicing bypass for grey sensor */
|
||||
if (in_fmt->mbus_code == MEDIA_BUS_FMT_Y8_1X8 ||
|
||||
in_fmt->mbus_code == MEDIA_BUS_FMT_Y10_1X10 ||
|
||||
in_fmt->mbus_code == MEDIA_BUS_FMT_Y12_1X12)
|
||||
writel(CIF_ISP_DEMOSAIC_BYPASS |
|
||||
CIF_ISP_DEMOSAIC_TH(0xc),
|
||||
base + CIF_ISP_DEMOSAIC);
|
||||
else
|
||||
writel(CIF_ISP_DEMOSAIC_TH(0xc),
|
||||
base + CIF_ISP_DEMOSAIC);
|
||||
in_fmt->mbus_code == MEDIA_BUS_FMT_Y12_1X12) {
|
||||
if (dev->isp_ver == ISP_V20)
|
||||
writel(0, base + ISP_DEBAYER_CONTROL);
|
||||
else
|
||||
writel(CIF_ISP_DEMOSAIC_BYPASS |
|
||||
CIF_ISP_DEMOSAIC_TH(0xc),
|
||||
base + CIF_ISP_DEMOSAIC);
|
||||
} else {
|
||||
if (dev->isp_ver == ISP_V20)
|
||||
writel(SW_DEBAYER_EN |
|
||||
SW_DEBAYER_FILTER_G_EN |
|
||||
SW_DEBAYER_FILTER_C_EN,
|
||||
base + ISP_DEBAYER_CONTROL);
|
||||
else
|
||||
writel(CIF_ISP_DEMOSAIC_TH(0xc),
|
||||
base + CIF_ISP_DEMOSAIC);
|
||||
}
|
||||
|
||||
if (sensor && sensor->mbus.type == V4L2_MBUS_BT656)
|
||||
isp_ctrl = CIF_ISP_CTRL_ISP_MODE_BAYER_ITU656;
|
||||
@@ -372,7 +489,7 @@ static int rkisp_config_isp(struct rkisp_device *dev)
|
||||
writel(in_crop->top, base + CIF_ISP_OUT_V_OFFS);
|
||||
writel(in_crop->width, base + CIF_ISP_OUT_H_SIZE);
|
||||
|
||||
if (dev->stream[RKISP_STREAM_SP].interlaced) {
|
||||
if (dev->cap_dev.stream[RKISP_STREAM_SP].interlaced) {
|
||||
writel(in_frm->height / 2, base + CIF_ISP_ACQ_V_SIZE);
|
||||
writel(in_crop->height / 2, base + CIF_ISP_OUT_V_SIZE);
|
||||
} else {
|
||||
@@ -432,138 +549,6 @@ static int rkisp_config_dvp(struct rkisp_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rkisp_config_mipi(struct rkisp_device *dev)
|
||||
{
|
||||
u32 mipi_ctrl;
|
||||
void __iomem *base = dev->base_addr;
|
||||
struct ispsd_in_fmt *in_fmt = &dev->isp_sdev.in_fmt;
|
||||
struct rkisp_sensor_info *sensor = dev->active_sensor;
|
||||
struct v4l2_subdev *mipi_sensor;
|
||||
struct v4l2_ctrl *ctrl;
|
||||
u32 emd_vc, emd_dt;
|
||||
int lanes, ret, i;
|
||||
|
||||
/*
|
||||
* sensor->mbus is set in isp or d-phy notifier_bound function
|
||||
*/
|
||||
switch (sensor->mbus.flags & V4L2_MBUS_CSI2_LANES) {
|
||||
case V4L2_MBUS_CSI2_4_LANE:
|
||||
lanes = 4;
|
||||
break;
|
||||
case V4L2_MBUS_CSI2_3_LANE:
|
||||
lanes = 3;
|
||||
break;
|
||||
case V4L2_MBUS_CSI2_2_LANE:
|
||||
lanes = 2;
|
||||
break;
|
||||
case V4L2_MBUS_CSI2_1_LANE:
|
||||
lanes = 1;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
emd_vc = 0xFF;
|
||||
emd_dt = 0;
|
||||
dev->hdr_sensor = NULL;
|
||||
get_remote_mipi_sensor(dev, &mipi_sensor);
|
||||
if (mipi_sensor) {
|
||||
ctrl = v4l2_ctrl_find(mipi_sensor->ctrl_handler,
|
||||
CIFISP_CID_EMB_VC);
|
||||
if (ctrl)
|
||||
emd_vc = v4l2_ctrl_g_ctrl(ctrl);
|
||||
|
||||
ctrl = v4l2_ctrl_find(mipi_sensor->ctrl_handler,
|
||||
CIFISP_CID_EMB_DT);
|
||||
if (ctrl)
|
||||
emd_dt = v4l2_ctrl_g_ctrl(ctrl);
|
||||
dev->hdr_sensor = mipi_sensor;
|
||||
}
|
||||
|
||||
dev->emd_dt = emd_dt;
|
||||
dev->emd_vc = emd_vc;
|
||||
dev->emd_data_idx = 0;
|
||||
if (emd_vc <= CIF_ISP_ADD_DATA_VC_MAX) {
|
||||
for (i = 0; i < RKISP_EMDDATA_FIFO_MAX; i++) {
|
||||
ret = kfifo_alloc(&dev->emd_data_fifo[i].mipi_kfifo,
|
||||
CIFISP_ADD_DATA_FIFO_SIZE,
|
||||
GFP_ATOMIC);
|
||||
if (ret) {
|
||||
v4l2_err(&dev->v4l2_dev,
|
||||
"kfifo_alloc failed with error %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->isp_ver == ISP_V13 ||
|
||||
dev->isp_ver == ISP_V12) {
|
||||
/* lanes */
|
||||
writel(lanes - 1, base + CIF_ISP_CSI0_CTRL1);
|
||||
|
||||
/* linecnt */
|
||||
writel(0x3FFF, base + CIF_ISP_CSI0_CTRL2);
|
||||
|
||||
/* Configure Data Type and Virtual Channel */
|
||||
writel(CIF_MIPI_DATA_SEL_DT(in_fmt->mipi_dt) | CIF_MIPI_DATA_SEL_VC(0),
|
||||
base + CIF_ISP_CSI0_DATA_IDS_1);
|
||||
|
||||
/* clear interrupts state */
|
||||
readl(base + CIF_ISP_CSI0_ERR1);
|
||||
readl(base + CIF_ISP_CSI0_ERR2);
|
||||
readl(base + CIF_ISP_CSI0_ERR3);
|
||||
/* set interrupts mask */
|
||||
writel(0x1FFFFFF0, base + CIF_ISP_CSI0_MASK1);
|
||||
writel(0x03FFFFFF, base + CIF_ISP_CSI0_MASK2);
|
||||
writel(CIF_ISP_CSI0_IMASK_FRAME_END(0x3F) |
|
||||
CIF_ISP_CSI0_IMASK_RAW0_OUT_V_END |
|
||||
CIF_ISP_CSI0_IMASK_RAW1_OUT_V_END |
|
||||
CIF_ISP_CSI0_IMASK_LINECNT,
|
||||
base + CIF_ISP_CSI0_MASK3);
|
||||
} else {
|
||||
mipi_ctrl = CIF_MIPI_CTRL_NUM_LANES(lanes - 1) |
|
||||
CIF_MIPI_CTRL_SHUTDOWNLANES(0xf) |
|
||||
CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_SKIP |
|
||||
CIF_MIPI_CTRL_CLOCKLANE_ENA;
|
||||
writel(mipi_ctrl, base + CIF_MIPI_CTRL);
|
||||
|
||||
/* Configure Data Type and Virtual Channel */
|
||||
writel(CIF_MIPI_DATA_SEL_DT(in_fmt->mipi_dt) | CIF_MIPI_DATA_SEL_VC(0),
|
||||
base + CIF_MIPI_IMG_DATA_SEL);
|
||||
|
||||
writel(CIF_MIPI_DATA_SEL_DT(emd_dt) | CIF_MIPI_DATA_SEL_VC(emd_vc),
|
||||
base + CIF_MIPI_ADD_DATA_SEL_1);
|
||||
writel(CIF_MIPI_DATA_SEL_DT(emd_dt) | CIF_MIPI_DATA_SEL_VC(emd_vc),
|
||||
base + CIF_MIPI_ADD_DATA_SEL_2);
|
||||
writel(CIF_MIPI_DATA_SEL_DT(emd_dt) | CIF_MIPI_DATA_SEL_VC(emd_vc),
|
||||
base + CIF_MIPI_ADD_DATA_SEL_3);
|
||||
writel(CIF_MIPI_DATA_SEL_DT(emd_dt) | CIF_MIPI_DATA_SEL_VC(emd_vc),
|
||||
base + CIF_MIPI_ADD_DATA_SEL_4);
|
||||
|
||||
/* Clear MIPI interrupts */
|
||||
writel(~0, base + CIF_MIPI_ICR);
|
||||
/*
|
||||
* Disable CIF_MIPI_ERR_DPHY interrupt here temporary for
|
||||
* isp bus may be dead when switch isp.
|
||||
*/
|
||||
writel(CIF_MIPI_FRAME_END | CIF_MIPI_ERR_CSI | CIF_MIPI_ERR_DPHY |
|
||||
CIF_MIPI_SYNC_FIFO_OVFLW(0x0F) | CIF_MIPI_ADD_DATA_OVFLW,
|
||||
base + CIF_MIPI_IMSC);
|
||||
}
|
||||
|
||||
v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev, "\n MIPI_CTRL 0x%08x\n"
|
||||
" MIPI_IMG_DATA_SEL 0x%08x\n"
|
||||
" MIPI_STATUS 0x%08x\n"
|
||||
" MIPI_IMSC 0x%08x\n",
|
||||
readl(base + CIF_MIPI_CTRL),
|
||||
readl(base + CIF_MIPI_IMG_DATA_SEL),
|
||||
readl(base + CIF_MIPI_STATUS),
|
||||
readl(base + CIF_MIPI_IMSC));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Configure MUX */
|
||||
static int rkisp_config_path(struct rkisp_device *dev)
|
||||
{
|
||||
@@ -575,11 +560,10 @@ static int rkisp_config_path(struct rkisp_device *dev)
|
||||
sensor->mbus.type == V4L2_MBUS_PARALLEL)) {
|
||||
ret = rkisp_config_dvp(dev);
|
||||
dpcl |= CIF_VI_DPCL_IF_SEL_PARALLEL;
|
||||
dev->isp_inp = INP_DVP;
|
||||
} else if (sensor && sensor->mbus.type == V4L2_MBUS_CSI2) {
|
||||
ret = rkisp_config_mipi(dev);
|
||||
} else if ((sensor && sensor->mbus.type == V4L2_MBUS_CSI2) ||
|
||||
dev->isp_inp & (INP_RAWRD0 |
|
||||
INP_RAWRD1 | INP_RAWRD2)) {
|
||||
dpcl |= CIF_VI_DPCL_IF_SEL_MIPI;
|
||||
dev->isp_inp = INP_CSI;
|
||||
} else if (dev->isp_inp == INP_DMARX_ISP) {
|
||||
dpcl |= CIF_VI_DPCL_DMA_SW_ISP;
|
||||
}
|
||||
@@ -597,8 +581,8 @@ static int rkisp_config_cif(struct rkisp_device *dev)
|
||||
|
||||
v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
|
||||
"SP streaming = %d, MP streaming = %d\n",
|
||||
dev->stream[RKISP_STREAM_SP].streaming,
|
||||
dev->stream[RKISP_STREAM_MP].streaming);
|
||||
dev->cap_dev.stream[RKISP_STREAM_SP].streaming,
|
||||
dev->cap_dev.stream[RKISP_STREAM_MP].streaming);
|
||||
|
||||
cif_id = readl(dev->base_addr + CIF_VI_ID);
|
||||
v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev, "CIF_ID 0x%08x\n", cif_id);
|
||||
@@ -682,8 +666,8 @@ static int rkisp_isp_stop(struct rkisp_device *dev)
|
||||
|
||||
v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
|
||||
"SP streaming = %d, MP streaming = %d\n",
|
||||
dev->stream[RKISP_STREAM_SP].streaming,
|
||||
dev->stream[RKISP_STREAM_MP].streaming);
|
||||
dev->cap_dev.stream[RKISP_STREAM_SP].streaming,
|
||||
dev->cap_dev.stream[RKISP_STREAM_MP].streaming);
|
||||
|
||||
/*
|
||||
* ISP(mi) stop in mi frame end -> Stop ISP(mipi) ->
|
||||
@@ -697,6 +681,15 @@ static int rkisp_isp_stop(struct rkisp_device *dev)
|
||||
readl(base + CIF_ISP_CSI0_ERR1);
|
||||
readl(base + CIF_ISP_CSI0_ERR2);
|
||||
readl(base + CIF_ISP_CSI0_ERR3);
|
||||
} else if (dev->isp_ver == ISP_V20) {
|
||||
writel(0, base + CSI2RX_MASK_PHY);
|
||||
writel(0, base + CSI2RX_MASK_PACKET);
|
||||
writel(0, base + CSI2RX_MASK_OVERFLOW);
|
||||
writel(0, base + CSI2RX_MASK_STAT);
|
||||
readl(base + CSI2RX_ERR_PHY);
|
||||
readl(base + CSI2RX_ERR_PACKET);
|
||||
readl(base + CSI2RX_ERR_OVERFLOW);
|
||||
readl(base + CSI2RX_ERR_STAT);
|
||||
} else {
|
||||
writel(0, base + CIF_MIPI_IMSC);
|
||||
writel(~0, base + CIF_MIPI_ICR);
|
||||
@@ -709,7 +702,7 @@ static int rkisp_isp_stop(struct rkisp_device *dev)
|
||||
writel(~0, base + CIF_MI_ICR);
|
||||
if (dev->isp_ver == ISP_V12 || dev->isp_ver == ISP_V13) {
|
||||
writel(0, base + CIF_ISP_CSI0_CTRL0);
|
||||
} else {
|
||||
} else if (dev->isp_ver < ISP_V12) {
|
||||
val = readl(base + CIF_MIPI_CTRL);
|
||||
val = val & (~CIF_MIPI_CTRL_SHUTDOWNLANES(0xf));
|
||||
writel(val & (~CIF_MIPI_CTRL_OUTPUT_ENA), base + CIF_MIPI_CTRL);
|
||||
@@ -727,8 +720,8 @@ static int rkisp_isp_stop(struct rkisp_device *dev)
|
||||
val, val & CIF_ISP_OFF, 20, 100);
|
||||
v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
|
||||
"streaming(MP:%d, SP:%d), MI_CTRL:%x, ISP_CTRL:%x, MIPI_CTRL:%x\n",
|
||||
dev->stream[RKISP_STREAM_SP].streaming,
|
||||
dev->stream[RKISP_STREAM_MP].streaming,
|
||||
dev->cap_dev.stream[RKISP_STREAM_SP].streaming,
|
||||
dev->cap_dev.stream[RKISP_STREAM_MP].streaming,
|
||||
readl(base + CIF_MI_CTRL),
|
||||
readl(base + CIF_ISP_CTRL),
|
||||
readl(base + CIF_MIPI_CTRL));
|
||||
@@ -756,6 +749,8 @@ static int rkisp_isp_stop(struct rkisp_device *dev)
|
||||
writel(0, base + CIF_ISP_CSI0_MASK1);
|
||||
writel(0, base + CIF_ISP_CSI0_MASK2);
|
||||
writel(0, base + CIF_ISP_CSI0_MASK3);
|
||||
} else if (dev->isp_ver == ISP_V20) {
|
||||
writel(0, base + CSI2RX_CSI2_RESETN);
|
||||
}
|
||||
|
||||
rkisp_config_clk(dev, true);
|
||||
@@ -764,8 +759,10 @@ static int rkisp_isp_stop(struct rkisp_device *dev)
|
||||
|
||||
domain = iommu_get_domain_for_dev(dev->dev);
|
||||
if (domain) {
|
||||
#ifdef CONFIG_IOMMU_API
|
||||
domain->ops->detach_dev(domain, dev->dev);
|
||||
domain->ops->attach_dev(domain, dev->dev);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
dev->isp_state = ISP_STOP;
|
||||
@@ -776,8 +773,8 @@ static int rkisp_isp_stop(struct rkisp_device *dev)
|
||||
dev->emd_vc = 0xFF;
|
||||
}
|
||||
|
||||
if (dev->hdr_sensor)
|
||||
dev->hdr_sensor = NULL;
|
||||
if (dev->hdr.sensor)
|
||||
dev->hdr.sensor = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -791,8 +788,8 @@ static int rkisp_isp_start(struct rkisp_device *dev)
|
||||
|
||||
v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
|
||||
"SP streaming = %d, MP streaming = %d\n",
|
||||
dev->stream[RKISP_STREAM_SP].streaming,
|
||||
dev->stream[RKISP_STREAM_MP].streaming);
|
||||
dev->cap_dev.stream[RKISP_STREAM_SP].streaming,
|
||||
dev->cap_dev.stream[RKISP_STREAM_MP].streaming);
|
||||
|
||||
/* Activate MIPI */
|
||||
if (sensor && sensor->mbus.type == V4L2_MBUS_CSI2) {
|
||||
@@ -803,7 +800,7 @@ static int rkisp_isp_start(struct rkisp_device *dev)
|
||||
readl(base + CIF_ISP_CSI0_ERR3);
|
||||
/* csi2host enable */
|
||||
writel(1, base + CIF_ISP_CSI0_CTRL0);
|
||||
} else {
|
||||
} else if (dev->isp_ver < ISP_V12) {
|
||||
val = readl(base + CIF_MIPI_CTRL);
|
||||
writel(val | CIF_MIPI_CTRL_OUTPUT_ENA,
|
||||
base + CIF_MIPI_CTRL);
|
||||
@@ -827,8 +824,8 @@ static int rkisp_isp_start(struct rkisp_device *dev)
|
||||
v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
|
||||
"SP streaming = %d, MP streaming = %d MI_CTRL 0x%08x\n"
|
||||
" ISP_CTRL 0x%08x MIPI_CTRL 0x%08x\n",
|
||||
dev->stream[RKISP_STREAM_SP].streaming,
|
||||
dev->stream[RKISP_STREAM_MP].streaming,
|
||||
dev->cap_dev.stream[RKISP_STREAM_SP].streaming,
|
||||
dev->cap_dev.stream[RKISP_STREAM_MP].streaming,
|
||||
readl(base + CIF_MI_CTRL),
|
||||
readl(base + CIF_ISP_CTRL),
|
||||
readl(base + CIF_MIPI_CTRL));
|
||||
@@ -1079,7 +1076,7 @@ static int rkisp_isp_sd_enum_mbus_code(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
struct v4l2_subdev_mbus_code_enum *code)
|
||||
{
|
||||
int i = code->index;
|
||||
unsigned int i = code->index;
|
||||
|
||||
if (code->pad == RKISP_ISP_PAD_SINK) {
|
||||
if (i >= ARRAY_SIZE(rkisp_isp_input_formats))
|
||||
@@ -1200,10 +1197,8 @@ static int rkisp_isp_sd_set_fmt(struct v4l2_subdev *sd,
|
||||
rkisp_isp_sd_try_fmt(sd, fmt->pad, mf);
|
||||
|
||||
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
|
||||
struct v4l2_mbus_framefmt *try_mf;
|
||||
|
||||
mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
|
||||
*try_mf = *mf;
|
||||
fmt->format = *mf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1328,7 +1323,7 @@ static int rkisp_isp_sd_set_selection(struct v4l2_subdev *sd,
|
||||
struct v4l2_rect *try_sel;
|
||||
|
||||
try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
|
||||
*try_sel = sel->r;
|
||||
sel->r = *try_sel;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1349,6 +1344,10 @@ static void rkisp_isp_read_add_fifo_data(struct rkisp_device *dev)
|
||||
u32 fifo_data = 0;
|
||||
u32 i, idx, cur_frame_id;
|
||||
|
||||
if (dev->isp_ver != ISP_V10 &&
|
||||
dev->isp_ver != ISP_V10_1)
|
||||
return;
|
||||
|
||||
cur_frame_id = atomic_read(&dev->isp_sdev.frm_sync_seq) - 1;
|
||||
idx = dev->emd_data_idx;
|
||||
dev->emd_data_fifo[idx].frame_id = 0;
|
||||
@@ -1439,16 +1438,76 @@ static int rkisp_subdev_link_setup(struct media_entity *entity,
|
||||
u32 flags)
|
||||
{
|
||||
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
|
||||
struct rkisp_device *dev = sd_to_isp_dev(sd);
|
||||
struct rkisp_device *dev;
|
||||
u8 rawrd = INP_RAWRD0 | INP_RAWRD1 | INP_RAWRD2;
|
||||
|
||||
if (!sd)
|
||||
return -ENODEV;
|
||||
dev = sd_to_isp_dev(sd);
|
||||
if (!strcmp(remote->entity->name, DMA_VDEV_NAME)) {
|
||||
if (flags & MEDIA_LNK_FL_ENABLED)
|
||||
if (flags & MEDIA_LNK_FL_ENABLED) {
|
||||
if (dev->isp_inp)
|
||||
goto err;
|
||||
if (dev->active_sensor)
|
||||
dev->active_sensor = NULL;
|
||||
dev->isp_inp = INP_DMARX_ISP;
|
||||
else
|
||||
} else {
|
||||
dev->isp_inp = INP_INVAL;
|
||||
}
|
||||
} else if (!strcmp(remote->entity->name, CSI_DEV_NAME)) {
|
||||
if (flags & MEDIA_LNK_FL_ENABLED) {
|
||||
if (dev->isp_inp & ~(INP_CSI | rawrd))
|
||||
goto err;
|
||||
dev->isp_inp |= INP_CSI;
|
||||
} else {
|
||||
dev->isp_inp &= ~INP_CSI;
|
||||
}
|
||||
} else if (!strcmp(remote->entity->name, DMARX0_VDEV_NAME)) {
|
||||
if (flags & MEDIA_LNK_FL_ENABLED) {
|
||||
if (dev->isp_inp == INP_DMARX_ISP)
|
||||
goto err;
|
||||
dev->isp_inp |= INP_RAWRD0;
|
||||
} else {
|
||||
dev->isp_inp &= ~INP_RAWRD0;
|
||||
}
|
||||
} else if (!strcmp(remote->entity->name, DMARX1_VDEV_NAME)) {
|
||||
if (flags & MEDIA_LNK_FL_ENABLED) {
|
||||
if (dev->isp_inp == INP_DMARX_ISP)
|
||||
goto err;
|
||||
dev->isp_inp |= INP_RAWRD1;
|
||||
} else {
|
||||
dev->isp_inp &= ~INP_RAWRD1;
|
||||
}
|
||||
} else if (!strcmp(remote->entity->name, DMARX2_VDEV_NAME)) {
|
||||
if (flags & MEDIA_LNK_FL_ENABLED) {
|
||||
if (dev->isp_inp == INP_DMARX_ISP)
|
||||
goto err;
|
||||
dev->isp_inp |= INP_RAWRD2;
|
||||
} else {
|
||||
dev->isp_inp &= ~INP_RAWRD2;
|
||||
}
|
||||
} else {
|
||||
if (flags & MEDIA_LNK_FL_ENABLED) {
|
||||
if (dev->isp_inp & ~(INP_DVP | rawrd))
|
||||
goto err;
|
||||
dev->isp_inp |= INP_DVP;
|
||||
} else {
|
||||
dev->isp_inp &= ~INP_INVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->isp_inp & rawrd)
|
||||
dev->dmarx_dev.trigger = T_MANUAL;
|
||||
else
|
||||
dev->dmarx_dev.trigger = T_AUTO;
|
||||
|
||||
v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
|
||||
"isp input:0x%x\n", dev->isp_inp);
|
||||
return 0;
|
||||
err:
|
||||
v4l2_err(sd, "dmaread can't work with other input\n"
|
||||
"csi dvp can't work together\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int rkisp_subdev_link_validate(struct media_link *link)
|
||||
@@ -1459,6 +1518,7 @@ static int rkisp_subdev_link_validate(struct media_link *link)
|
||||
return v4l2_subdev_link_validate(link);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MEDIA_CONTROLLER
|
||||
static int rkisp_subdev_fmt_link_validate(struct v4l2_subdev *sd,
|
||||
struct media_link *link,
|
||||
struct v4l2_subdev_format *source_fmt,
|
||||
@@ -1474,9 +1534,10 @@ static int rkisp_subdev_fmt_link_validate(struct v4l2_subdev *sd,
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
riksp1_isp_queue_event_sof(struct rkisp_isp_subdev *isp)
|
||||
rkisp_isp_queue_event_sof(struct rkisp_isp_subdev *isp)
|
||||
{
|
||||
struct v4l2_event event = {
|
||||
.type = V4L2_EVENT_FRAME_SYNC,
|
||||
@@ -1505,7 +1566,9 @@ static const struct v4l2_subdev_pad_ops rkisp_isp_sd_pad_ops = {
|
||||
.set_selection = rkisp_isp_sd_set_selection,
|
||||
.get_fmt = rkisp_isp_sd_get_fmt,
|
||||
.set_fmt = rkisp_isp_sd_set_fmt,
|
||||
#ifdef CONFIG_MEDIA_CONTROLLER
|
||||
.link_validate = rkisp_subdev_fmt_link_validate,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct media_entity_operations rkisp_isp_sd_media_ops = {
|
||||
@@ -1563,7 +1626,7 @@ int rkisp_register_isp_subdev(struct rkisp_device *isp_dev,
|
||||
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
|
||||
sd->entity.ops = &rkisp_isp_sd_media_ops;
|
||||
sd->entity.function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
|
||||
snprintf(sd->name, sizeof(sd->name), "rkisp1-isp-subdev");
|
||||
snprintf(sd->name, sizeof(sd->name), ISP_SUBDEV_NAME);
|
||||
|
||||
isp_sdev->pads[RKISP_ISP_PAD_SINK].flags =
|
||||
MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
|
||||
@@ -1586,7 +1649,7 @@ int rkisp_register_isp_subdev(struct rkisp_device *isp_dev,
|
||||
}
|
||||
|
||||
rkisp_isp_sd_init_default_fmt(isp_sdev);
|
||||
isp_dev->hdr_sensor = NULL;
|
||||
isp_dev->hdr.sensor = NULL;
|
||||
isp_dev->isp_state = ISP_STOP;
|
||||
|
||||
return 0;
|
||||
@@ -1611,6 +1674,9 @@ void rkisp_mipi_isr(unsigned int mis, struct rkisp_device *dev)
|
||||
void __iomem *base = dev->base_addr;
|
||||
u32 val;
|
||||
|
||||
v4l2_dbg(3, rkisp_debug, &dev->v4l2_dev,
|
||||
"mipi isr:0x%x\n", mis);
|
||||
|
||||
writel(~0, base + CIF_MIPI_ICR);
|
||||
|
||||
/*
|
||||
@@ -1654,6 +1720,10 @@ void rkisp_mipi_v13_isr(unsigned int err1, unsigned int err2,
|
||||
void __iomem *base = dev->base_addr;
|
||||
u32 val, mask;
|
||||
|
||||
v4l2_dbg(3, rkisp_debug, &dev->v4l2_dev,
|
||||
"mipi isr err1:0x%x err2:0x%x err3:0x%x\n",
|
||||
err1, err2, err3);
|
||||
|
||||
/*
|
||||
* Disable DPHY errctrl interrupt, because this dphy
|
||||
* erctrl signal is asserted until the next changes
|
||||
@@ -1702,9 +1772,12 @@ void rkisp_isp_isr(unsigned int isp_mis, struct rkisp_device *dev)
|
||||
unsigned int isp_mis_tmp = 0;
|
||||
unsigned int isp_err = 0;
|
||||
|
||||
v4l2_dbg(3, rkisp_debug, &dev->v4l2_dev,
|
||||
"isp isr:0x%x\n", isp_mis);
|
||||
|
||||
/* start edge of v_sync */
|
||||
if (isp_mis & CIF_ISP_V_START) {
|
||||
if (dev->stream[RKISP_STREAM_SP].interlaced) {
|
||||
if (dev->cap_dev.stream[RKISP_STREAM_SP].interlaced) {
|
||||
/* 0 = ODD 1 = EVEN */
|
||||
if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2) {
|
||||
void __iomem *addr = NULL;
|
||||
@@ -1717,16 +1790,16 @@ void rkisp_isp_isr(unsigned int isp_mis, struct rkisp_device *dev)
|
||||
addr = base + CIF_ISP_CSI0_FRAME_NUM_RO;
|
||||
|
||||
if (addr)
|
||||
dev->stream[RKISP_STREAM_SP].u.sp.field =
|
||||
dev->cap_dev.stream[RKISP_STREAM_SP].u.sp.field =
|
||||
(readl(addr) >> 16) % 2;
|
||||
} else {
|
||||
dev->stream[RKISP_STREAM_SP].u.sp.field =
|
||||
dev->cap_dev.stream[RKISP_STREAM_SP].u.sp.field =
|
||||
(readl(base + CIF_ISP_FLAGS_SHD) >> 2) & BIT(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->vs_irq < 0)
|
||||
riksp1_isp_queue_event_sof(&dev->isp_sdev);
|
||||
rkisp_isp_queue_event_sof(&dev->isp_sdev);
|
||||
|
||||
writel(CIF_ISP_V_START, base + CIF_ISP_ICR);
|
||||
isp_mis_tmp = readl(base + CIF_ISP_MIS);
|
||||
@@ -1809,7 +1882,7 @@ irqreturn_t rkisp_vs_isr_handler(int irq, void *ctx)
|
||||
struct rkisp_device *rkisp_dev = dev_get_drvdata(dev);
|
||||
|
||||
if (rkisp_dev->vs_irq >= 0)
|
||||
riksp1_isp_queue_event_sof(&rkisp_dev->isp_sdev);
|
||||
rkisp_isp_queue_event_sof(&rkisp_dev->isp_sdev);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -134,10 +134,16 @@ void rkisp_mipi_isr(unsigned int mipi_mis, struct rkisp_device *dev);
|
||||
void rkisp_mipi_v13_isr(unsigned int err1, unsigned int err2,
|
||||
unsigned int err3, struct rkisp_device *dev);
|
||||
|
||||
void rkisp_mipi_v20_isr(unsigned int phy, unsigned int packet,
|
||||
unsigned int overflow, unsigned int state,
|
||||
struct rkisp_device *dev);
|
||||
|
||||
void rkisp_isp_isr(unsigned int isp_mis, struct rkisp_device *dev);
|
||||
|
||||
irqreturn_t rkisp_vs_isr_handler(int irq, void *ctx);
|
||||
|
||||
struct media_pad *rkisp_media_entity_remote_pad(struct media_pad *pad);
|
||||
|
||||
int rkisp_update_sensor_info(struct rkisp_device *dev);
|
||||
|
||||
u32 rkisp_mbus_pixelcode_to_v4l2(u32 pixelcode);
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
#define RKMODULE_LSC_CFG \
|
||||
_IOW('V', BASE_VIDIOC_PRIVATE + 3, struct rkmodule_lsc_cfg)
|
||||
|
||||
#define RKMODULE_HDR_CFG \
|
||||
_IOW('V', BASE_VIDIOC_PRIVATE + 4, struct rkmodule_hdr_cfg)
|
||||
|
||||
/**
|
||||
* struct rkmodule_base_inf - module base information
|
||||
*
|
||||
@@ -143,4 +146,53 @@ struct rkmodule_lsc_cfg {
|
||||
__u32 enable;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/**
|
||||
* NO_HDR: linear mode
|
||||
* HDR_X2: hdr two frame or line mode
|
||||
* HDR_X3: hdr three or line mode
|
||||
*/
|
||||
enum rkmodule_hdr_mode {
|
||||
NO_HDR = 0,
|
||||
HDR_X2 = 5,
|
||||
HDR_X3 = 6,
|
||||
};
|
||||
|
||||
/**
|
||||
* HDR_NORMAL_VC: hdr frame with diff virtual channels
|
||||
* HDR_LINE_CNT: hdr frame with line counter
|
||||
* HDR_ID_CODE: hdr frame with identification code
|
||||
*/
|
||||
enum hdr_esp_mode {
|
||||
HDR_NORMAL_VC = 0,
|
||||
HDR_LINE_CNT,
|
||||
HDR_ID_CODE,
|
||||
};
|
||||
|
||||
/**
|
||||
* lcnt: line counter
|
||||
* padnum: the pixels of padding row
|
||||
* padpix: the payload of padding
|
||||
* idcd: identification code
|
||||
* efpix: identification code of Effective line
|
||||
* obpix: identification code of OB line
|
||||
*/
|
||||
struct rkmodule_hdr_esp {
|
||||
enum hdr_esp_mode mode;
|
||||
union {
|
||||
struct {
|
||||
__u32 padnum;
|
||||
__u32 padpix;
|
||||
} lcnt;
|
||||
struct {
|
||||
__u32 efpix;
|
||||
__u32 obpix;
|
||||
} idcd;
|
||||
} val;
|
||||
};
|
||||
|
||||
struct rkmodule_hdr_cfg {
|
||||
__u32 hdr_mode;
|
||||
struct rkmodule_hdr_esp esp;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#endif /* _UAPI_RKMODULE_CAMERA_H */
|
||||
|
||||
Reference in New Issue
Block a user