mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
media: rockchip: rk-cif: v0.1.1
support the mipi vc multi-channel input in cif driver for rk1808 Change-Id: I432c628b30e6f6f23e8515158dcf516e499bf79a Signed-off-by: Xu Hongfei <xuhf@rock-chips.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,12 @@
|
||||
#include <linux/reset.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <media/videobuf2-dma-contig.h>
|
||||
#include <media/v4l2-fwnode.h>
|
||||
#include <linux/dma-iommu.h>
|
||||
#include <dt-bindings/soc/rockchip-system-status.h>
|
||||
#include <soc/rockchip/rockchip-system-status.h>
|
||||
|
||||
#include "dev.h"
|
||||
#include "regs.h"
|
||||
@@ -32,7 +37,7 @@ struct cif_match_data {
|
||||
int rsts_num;
|
||||
};
|
||||
|
||||
int rkcif_debug;
|
||||
int rkcif_debug = 3;
|
||||
module_param_named(debug, rkcif_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Debug level (0-1)");
|
||||
|
||||
@@ -45,40 +50,205 @@ int using_pingpong;
|
||||
static DEFINE_MUTEX(rkcif_dev_mutex);
|
||||
static LIST_HEAD(rkcif_device_list);
|
||||
|
||||
/**************************** pipeline operations *****************************/
|
||||
|
||||
static int __cif_pipeline_prepare(struct rkcif_pipeline *p,
|
||||
struct media_entity *me)
|
||||
{
|
||||
struct v4l2_subdev *sd;
|
||||
int i;
|
||||
|
||||
p->num_subdevs = 0;
|
||||
memset(p->subdevs, 0, sizeof(p->subdevs));
|
||||
|
||||
while (1) {
|
||||
struct media_pad *pad = NULL;
|
||||
|
||||
/* Find remote source pad */
|
||||
for (i = 0; i < me->num_pads; i++) {
|
||||
struct media_pad *spad = &me->pads[i];
|
||||
|
||||
if (!(spad->flags & MEDIA_PAD_FL_SINK))
|
||||
continue;
|
||||
pad = media_entity_remote_pad(spad);
|
||||
if (pad)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!pad)
|
||||
break;
|
||||
|
||||
sd = media_entity_to_v4l2_subdev(pad->entity);
|
||||
p->subdevs[p->num_subdevs++] = sd;
|
||||
me = &sd->entity;
|
||||
if (me->num_pads == 1)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __subdev_set_power(struct v4l2_subdev *sd, int on)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!sd)
|
||||
return -ENXIO;
|
||||
|
||||
ret = v4l2_subdev_call(sd, core, s_power, on);
|
||||
|
||||
return ret != -ENOIOCTLCMD ? ret : 0;
|
||||
}
|
||||
|
||||
static int __cif_pipeline_s_power(struct rkcif_pipeline *p, bool on)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
if (on) {
|
||||
for (i = p->num_subdevs - 1; i >= 0; --i) {
|
||||
ret = __subdev_set_power(p->subdevs[i], true);
|
||||
if (ret < 0 && ret != -ENXIO)
|
||||
goto err_power_off;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < p->num_subdevs; ++i)
|
||||
__subdev_set_power(p->subdevs[i], false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_power_off:
|
||||
for (++i; i < p->num_subdevs; ++i)
|
||||
__subdev_set_power(p->subdevs[i], false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __cif_pipeline_s_cif_clk(struct rkcif_pipeline *p)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rkcif_pipeline_open(struct rkcif_pipeline *p,
|
||||
struct media_entity *me,
|
||||
bool prepare)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(!p || !me))
|
||||
return -EINVAL;
|
||||
if (atomic_inc_return(&p->power_cnt) > 1)
|
||||
return 0;
|
||||
|
||||
/* go through media graphic and get subdevs */
|
||||
if (prepare)
|
||||
__cif_pipeline_prepare(p, me);
|
||||
|
||||
if (!p->num_subdevs)
|
||||
return -EINVAL;
|
||||
|
||||
ret = __cif_pipeline_s_cif_clk(p);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = __cif_pipeline_s_power(p, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rkcif_pipeline_close(struct rkcif_pipeline *p)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (atomic_dec_return(&p->power_cnt) > 0)
|
||||
return 0;
|
||||
ret = __cif_pipeline_s_power(p, 0);
|
||||
|
||||
return ret == -ENXIO ? 0 : ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* stream-on order: isp_subdev, mipi dphy, sensor
|
||||
* stream-off order: mipi dphy, sensor, isp_subdev
|
||||
*/
|
||||
static int rkcif_pipeline_set_stream(struct rkcif_pipeline *p, bool on)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
if ((on && atomic_inc_return(&p->stream_cnt) > 1) ||
|
||||
(!on && atomic_dec_return(&p->stream_cnt) > 0))
|
||||
return 0;
|
||||
|
||||
if (on)
|
||||
rockchip_set_system_status(SYS_STATUS_CIF0);
|
||||
|
||||
/* phy -> sensor */
|
||||
for (i = p->num_subdevs; i > -1; --i) {
|
||||
ret = v4l2_subdev_call(p->subdevs[i], video, s_stream, on);
|
||||
if (on && ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
|
||||
goto err_stream_off;
|
||||
}
|
||||
|
||||
if (!on)
|
||||
rockchip_clear_system_status(SYS_STATUS_CIF0);
|
||||
|
||||
return 0;
|
||||
|
||||
err_stream_off:
|
||||
for (--i; i >= 0; --i)
|
||||
v4l2_subdev_call(p->subdevs[i], video, s_stream, false);
|
||||
rockchip_clear_system_status(SYS_STATUS_CIF0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***************************** media controller *******************************/
|
||||
static int rkcif_create_links(struct rkcif_device *dev)
|
||||
{
|
||||
unsigned int s, pad;
|
||||
unsigned int s, pad, id;
|
||||
int ret;
|
||||
|
||||
/* sensor links(or mipi-phy) */
|
||||
for (s = 0; s < dev->num_sensors; ++s) {
|
||||
struct rkcif_sensor_info *sensor = &dev->sensors[s];
|
||||
|
||||
for (pad = 0; pad < sensor->sd->entity.num_pads; pad++)
|
||||
for (pad = 0; pad < sensor->sd->entity.num_pads; pad++) {
|
||||
if (sensor->sd->entity.pads[pad].flags &
|
||||
MEDIA_PAD_FL_SOURCE)
|
||||
break;
|
||||
MEDIA_PAD_FL_SOURCE) {
|
||||
if (pad == sensor->sd->entity.num_pads) {
|
||||
dev_err(dev->dev,
|
||||
"failed to find src pad for %s\n",
|
||||
sensor->sd->name);
|
||||
|
||||
if (pad == sensor->sd->entity.num_pads) {
|
||||
dev_err(dev->dev, "failed to find src pad for %s\n",
|
||||
sensor->sd->name);
|
||||
return -ENXIO;
|
||||
}
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
ret = media_create_pad_link(&sensor->sd->entity,
|
||||
pad, &dev->stream.vdev.entity, 0,
|
||||
s ? 0 : MEDIA_LNK_FL_ENABLED);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "failed to create link for %s\n",
|
||||
sensor->sd->name);
|
||||
return ret;
|
||||
for (id = 0; id < RKCIF_MAX_STREAM_MIPI; id++) {
|
||||
ret = media_entity_create_link(
|
||||
&sensor->sd->entity,
|
||||
pad,
|
||||
&dev->stream[id].vnode.vdev.entity,
|
||||
0,
|
||||
id == pad - 1 ? MEDIA_LNK_FL_ENABLED : 0);
|
||||
if (ret) {
|
||||
dev_err(dev->dev,
|
||||
"failed to create link for %s\n",
|
||||
sensor->sd->name);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _set_pipeline_default_fmt(struct rkcif_device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int subdev_notifier_complete(struct v4l2_async_notifier *notifier)
|
||||
{
|
||||
struct rkcif_device *dev;
|
||||
@@ -86,7 +256,7 @@ static int subdev_notifier_complete(struct v4l2_async_notifier *notifier)
|
||||
|
||||
dev = container_of(notifier, struct rkcif_device, notifier);
|
||||
|
||||
mutex_lock(&dev->media_dev.graph_mutex);
|
||||
/* mutex_lock(&dev->media_dev.graph_mutex); */
|
||||
|
||||
ret = rkcif_create_links(dev);
|
||||
if (ret < 0)
|
||||
@@ -96,10 +266,13 @@ static int subdev_notifier_complete(struct v4l2_async_notifier *notifier)
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
|
||||
ret = _set_pipeline_default_fmt(dev);
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
v4l2_info(&dev->v4l2_dev, "Async subdev notifier completed\n");
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&dev->media_dev.graph_mutex);
|
||||
/* mutex_unlock(&dev->media_dev.graph_mutex); */
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -187,18 +360,26 @@ static int rkcif_register_platform_subdevs(struct rkcif_device *cif_dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = rkcif_register_stream_vdev(cif_dev);
|
||||
cif_dev->alloc_ctx = vb2_dma_contig_init_ctx(cif_dev->v4l2_dev.dev);
|
||||
|
||||
ret = rkcif_register_stream_vdevs(cif_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto err_cleanup_ctx;
|
||||
|
||||
ret = cif_subdev_notifier(cif_dev);
|
||||
if (ret < 0) {
|
||||
v4l2_err(&cif_dev->v4l2_dev,
|
||||
"Failed to register subdev notifier(%d)\n", ret);
|
||||
rkcif_unregister_stream_vdev(cif_dev);
|
||||
goto err_unreg_stream_vdev;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_unreg_stream_vdev:
|
||||
rkcif_unregister_stream_vdevs(cif_dev);
|
||||
err_cleanup_ctx:
|
||||
vb2_dma_contig_cleanup_ctx(cif_dev->alloc_ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char * const px30_cif_clks[] = {
|
||||
@@ -219,7 +400,7 @@ static const char * const rk1808_cif_clks[] = {
|
||||
"dclk_cif",
|
||||
"hclk_cif",
|
||||
"sclk_cif_out",
|
||||
"pclk_csi2host"
|
||||
/* "pclk_csi2host" */
|
||||
};
|
||||
|
||||
static const char * const rk1808_cif_rsts[] = {
|
||||
@@ -316,50 +497,6 @@ static irqreturn_t rkcif_irq_handler(int irq, void *ctx)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
#define CSIHOST_MAX_ERRINT_COUNT 10
|
||||
|
||||
static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx)
|
||||
{
|
||||
struct device *dev = ctx;
|
||||
struct rkcif_device *cif_dev = dev_get_drvdata(dev);
|
||||
static int csi_err1_cnt;
|
||||
u32 val;
|
||||
|
||||
val = read_csihost_reg(cif_dev->csi_base, CSIHOST_ERR1);
|
||||
if (val) {
|
||||
pr_err("ERROR: csi err1 intr: 0x%x\n", val);
|
||||
|
||||
if (++csi_err1_cnt > CSIHOST_MAX_ERRINT_COUNT) {
|
||||
write_csihost_reg(cif_dev->csi_base,
|
||||
CSIHOST_MSK1, 0xffffffff);
|
||||
csi_err1_cnt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t rk_csirx_irq2_handler(int irq, void *ctx)
|
||||
{
|
||||
struct device *dev = ctx;
|
||||
struct rkcif_device *cif_dev = dev_get_drvdata(dev);
|
||||
static int csi_err2_cnt;
|
||||
u32 val;
|
||||
|
||||
val = read_csihost_reg(cif_dev->csi_base, CSIHOST_ERR2);
|
||||
if (val) {
|
||||
pr_err("ERROR: csi err2 intr: 0x%x\n", val);
|
||||
|
||||
if (++csi_err2_cnt > CSIHOST_MAX_ERRINT_COUNT) {
|
||||
write_csihost_reg(cif_dev->csi_base,
|
||||
CSIHOST_MSK2, 0xffffffff);
|
||||
csi_err2_cnt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void rkcif_disable_sys_clk(struct rkcif_device *cif_dev)
|
||||
{
|
||||
int i;
|
||||
@@ -379,6 +516,7 @@ static int rkcif_enable_sys_clk(struct rkcif_device *cif_dev)
|
||||
goto err;
|
||||
}
|
||||
|
||||
write_cif_reg_and(cif_dev->base_addr, CIF_CSI_INTEN, 0x0);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
@@ -470,33 +608,6 @@ static int rkcif_plat_probe(struct platform_device *pdev)
|
||||
cif_dev->base_addr = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(cif_dev->base_addr))
|
||||
return PTR_ERR(cif_dev->base_addr);
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csihost_regs");
|
||||
cif_dev->csi_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(cif_dev->csi_base))
|
||||
return PTR_ERR(cif_dev->csi_base);
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "csi-intr1");
|
||||
if (irq > 0) {
|
||||
ret = devm_request_irq(dev, irq, rk_csirx_irq1_handler,
|
||||
0, dev_driver_string(dev), dev);
|
||||
if (ret < 0)
|
||||
dev_err(dev, "request csi-intr1 irq failed: %d\n",
|
||||
ret);
|
||||
} else {
|
||||
dev_err(dev, "No found irq csi-intr1\n");
|
||||
}
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "csi-intr2");
|
||||
if (irq > 0) {
|
||||
ret = devm_request_irq(dev, irq, rk_csirx_irq2_handler,
|
||||
0, dev_driver_string(dev), dev);
|
||||
if (ret < 0)
|
||||
dev_err(dev, "request csi-intr2 failed: %d\n",
|
||||
ret);
|
||||
} else {
|
||||
dev_err(dev, "No found irq csi-intr2\n");
|
||||
}
|
||||
} else {
|
||||
using_pingpong = 0;
|
||||
|
||||
@@ -533,7 +644,18 @@ static int rkcif_plat_probe(struct platform_device *pdev)
|
||||
cif_dev->cif_rst[i] = rst;
|
||||
}
|
||||
|
||||
rkcif_stream_init(cif_dev);
|
||||
atomic_set(&cif_dev->pipe.power_cnt, 0);
|
||||
atomic_set(&cif_dev->pipe.stream_cnt, 0);
|
||||
mutex_init(&cif_dev->dev_lock);
|
||||
cif_dev->pipe.open = rkcif_pipeline_open;
|
||||
cif_dev->pipe.close = rkcif_pipeline_close;
|
||||
cif_dev->pipe.set_stream = rkcif_pipeline_set_stream;
|
||||
|
||||
rkcif_stream_init(cif_dev, RKCIF_STREAM_MIPI_ID0);
|
||||
rkcif_stream_init(cif_dev, RKCIF_STREAM_MIPI_ID1);
|
||||
rkcif_stream_init(cif_dev, RKCIF_STREAM_MIPI_ID2);
|
||||
rkcif_stream_init(cif_dev, RKCIF_STREAM_MIPI_ID3);
|
||||
rkcif_stream_init(cif_dev, RKCIF_STREAM_DVP);
|
||||
|
||||
strlcpy(cif_dev->media_dev.model, "rkcif",
|
||||
sizeof(cif_dev->media_dev.model));
|
||||
@@ -569,6 +691,7 @@ static int rkcif_plat_probe(struct platform_device *pdev)
|
||||
"No reserved memory region assign to CIF\n");
|
||||
}
|
||||
|
||||
rkcif_soft_reset(cif_dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
mutex_lock(&rkcif_dev_mutex);
|
||||
@@ -592,7 +715,8 @@ static int rkcif_plat_remove(struct platform_device *pdev)
|
||||
|
||||
media_device_unregister(&cif_dev->media_dev);
|
||||
v4l2_device_unregister(&cif_dev->v4l2_dev);
|
||||
rkcif_unregister_stream_vdev(cif_dev);
|
||||
rkcif_unregister_stream_vdevs(cif_dev);
|
||||
vb2_dma_contig_cleanup_ctx(cif_dev->alloc_ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -19,19 +19,46 @@
|
||||
#define CIF_DRIVER_NAME "rkcif"
|
||||
#define CIF_VIDEODEVICE_NAME "stream_cif"
|
||||
|
||||
#define CIF_DVP_VDEV_NAME CIF_VIDEODEVICE_NAME "_dvp"
|
||||
#define CIF_MIPI_ID0_VDEV_NAME CIF_VIDEODEVICE_NAME "_mipi_id0"
|
||||
#define CIF_MIPI_ID1_VDEV_NAME CIF_VIDEODEVICE_NAME "_mipi_id1"
|
||||
#define CIF_MIPI_ID2_VDEV_NAME CIF_VIDEODEVICE_NAME "_mipi_id2"
|
||||
#define CIF_MIPI_ID3_VDEV_NAME CIF_VIDEODEVICE_NAME "_mipi_id3"
|
||||
|
||||
/*
|
||||
* Rk1808 support 5 channel inputs simultaneously:
|
||||
* dvp + 4 mipi virtual channels
|
||||
*/
|
||||
#define RKCIF_MAX_STREAM 5
|
||||
#define RKCIF_STREAM_MIPI_ID0 0
|
||||
#define RKCIF_STREAM_MIPI_ID1 1
|
||||
#define RKCIF_STREAM_MIPI_ID2 2
|
||||
#define RKCIF_STREAM_MIPI_ID3 3
|
||||
#define RKCIF_MAX_STREAM_MIPI 4
|
||||
#define RKCIF_STREAM_DVP 4
|
||||
|
||||
#define RKCIF_MAX_BUS_CLK 8
|
||||
#define RKCIF_MAX_SENSOR 2
|
||||
#define RKCIF_MAX_RESET 5
|
||||
#define RKCIF_MAX_CSI_CHANNEL 4
|
||||
#define RKCIF_MAX_PIPELINE 4
|
||||
|
||||
#define RKCIF_DEFAULT_WIDTH 640
|
||||
#define RKCIF_DEFAULT_HEIGHT 480
|
||||
|
||||
#define write_cif_reg(base, addr, val) writel(val, (addr) + (base))
|
||||
#define write_cif_reg(base, addr, val) \
|
||||
do { \
|
||||
writel(val, (addr) + (base)); \
|
||||
} while (0)
|
||||
#define read_cif_reg(base, addr) readl((addr) + (base))
|
||||
|
||||
#define write_csihost_reg(base, addr, val) writel(val, (addr) + (base))
|
||||
#define read_csihost_reg(base, addr) readl((addr) + (base))
|
||||
#define write_cif_reg_or(base, addr, val) \
|
||||
do { \
|
||||
writel(readl((addr) + (base)) | (val), (addr) + (base)); \
|
||||
} while (0)
|
||||
#define write_cif_reg_and(base, addr, val) \
|
||||
do { \
|
||||
writel(readl((addr) + (base)) & (val), (addr) + (base)); \
|
||||
} while (0)
|
||||
|
||||
enum rkcif_state {
|
||||
RKCIF_STATE_DISABLED,
|
||||
@@ -51,6 +78,27 @@ enum host_type_t {
|
||||
RK_DSI_RXHOST
|
||||
};
|
||||
|
||||
/*
|
||||
* struct rkcif_pipeline - An CIF hardware pipeline
|
||||
*
|
||||
* Capture device call other devices via pipeline
|
||||
*
|
||||
* @num_subdevs: number of linked subdevs
|
||||
* @power_cnt: pipeline power count
|
||||
* @stream_cnt: stream power count
|
||||
*/
|
||||
struct rkcif_pipeline {
|
||||
struct media_pipeline pipe;
|
||||
int num_subdevs;
|
||||
atomic_t power_cnt;
|
||||
atomic_t stream_cnt;
|
||||
struct v4l2_subdev *subdevs[RKCIF_MAX_PIPELINE];
|
||||
int (*open)(struct rkcif_pipeline *p,
|
||||
struct media_entity *me, bool prepare);
|
||||
int (*close)(struct rkcif_pipeline *p);
|
||||
int (*set_stream)(struct rkcif_pipeline *p, bool on);
|
||||
};
|
||||
|
||||
struct rkcif_buffer {
|
||||
struct vb2_v4l2_buffer vb;
|
||||
struct list_head queue;
|
||||
@@ -68,11 +116,6 @@ struct rkcif_dummy_buffer {
|
||||
|
||||
extern int rkcif_debug;
|
||||
|
||||
static inline struct rkcif_buffer *to_rkcif_buffer(struct vb2_v4l2_buffer *vb)
|
||||
{
|
||||
return container_of(vb, struct rkcif_buffer, vb);
|
||||
}
|
||||
|
||||
/*
|
||||
* struct rkcif_sensor_info - Sensor infomations
|
||||
* @mbus: media bus configuration
|
||||
@@ -135,6 +178,14 @@ struct csi_channel_info {
|
||||
unsigned int crop_st_y;
|
||||
};
|
||||
|
||||
struct rkcif_vdev_node {
|
||||
struct vb2_queue buf_queue;
|
||||
/* vfd lock */
|
||||
struct mutex vlock;
|
||||
struct video_device vdev;
|
||||
struct media_pad pad;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct rkcif_stream - Stream states TODO
|
||||
*
|
||||
@@ -147,7 +198,9 @@ struct csi_channel_info {
|
||||
* @next_buf: the buffer used for next frame
|
||||
*/
|
||||
struct rkcif_stream {
|
||||
unsigned id:3;
|
||||
struct rkcif_device *cifdev;
|
||||
struct rkcif_vdev_node vnode;
|
||||
enum rkcif_state state;
|
||||
bool stopping;
|
||||
wait_queue_head_t wq_stopped;
|
||||
@@ -155,16 +208,12 @@ struct rkcif_stream {
|
||||
int frame_phase;
|
||||
|
||||
/* lock between irq and buf_queue */
|
||||
spinlock_t vbq_lock;
|
||||
struct vb2_queue buf_queue;
|
||||
struct list_head buf_head;
|
||||
struct rkcif_dummy_buffer dummy_buf;
|
||||
struct rkcif_buffer *curr_buf;
|
||||
struct rkcif_buffer *next_buf;
|
||||
|
||||
/* vfd lock */
|
||||
struct mutex vlock;
|
||||
struct video_device vdev;
|
||||
spinlock_t vbq_lock; /* vfd lock */
|
||||
/* TODO: pad for dvp and mipi separately? */
|
||||
struct media_pad pad;
|
||||
|
||||
@@ -175,9 +224,33 @@ struct rkcif_stream {
|
||||
int crop_enable;
|
||||
};
|
||||
|
||||
static inline struct rkcif_stream *to_rkcif_stream(struct video_device *vdev)
|
||||
static inline struct rkcif_buffer *to_rkcif_buffer(struct vb2_v4l2_buffer *vb)
|
||||
{
|
||||
return container_of(vdev, struct rkcif_stream, vdev);
|
||||
return container_of(vb, struct rkcif_buffer, vb);
|
||||
}
|
||||
|
||||
static inline
|
||||
struct rkcif_vdev_node *vdev_to_node(struct video_device *vdev)
|
||||
{
|
||||
return container_of(vdev, struct rkcif_vdev_node, vdev);
|
||||
}
|
||||
|
||||
static inline
|
||||
struct rkcif_stream *to_rkcif_stream(struct rkcif_vdev_node *vnode)
|
||||
{
|
||||
return container_of(vnode, struct rkcif_stream, vnode);
|
||||
}
|
||||
|
||||
static inline struct rkcif_vdev_node *queue_to_node(struct vb2_queue *q)
|
||||
{
|
||||
return container_of(q, struct rkcif_vdev_node, buf_queue);
|
||||
}
|
||||
|
||||
static inline struct vb2_queue *to_vb2_queue(struct file *file)
|
||||
{
|
||||
struct rkcif_vdev_node *vnode = video_drvdata(file);
|
||||
|
||||
return &vnode->buf_queue;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -207,16 +280,21 @@ struct rkcif_device {
|
||||
u32 num_sensors;
|
||||
struct rkcif_sensor_info *active_sensor;
|
||||
|
||||
struct rkcif_stream stream;
|
||||
struct rkcif_stream stream[RKCIF_MAX_STREAM];
|
||||
struct rkcif_pipeline pipe;
|
||||
|
||||
struct csi_channel_info channels[RKCIF_MAX_CSI_CHANNEL];
|
||||
int num_channels;
|
||||
int chip_id;
|
||||
bool working;
|
||||
bool is_cif_rst;
|
||||
/* dev operate mutex */
|
||||
struct mutex dev_lock;
|
||||
};
|
||||
|
||||
void rkcif_unregister_stream_vdev(struct rkcif_device *dev);
|
||||
int rkcif_register_stream_vdev(struct rkcif_device *dev);
|
||||
void rkcif_stream_init(struct rkcif_device *dev);
|
||||
void rkcif_unregister_stream_vdevs(struct rkcif_device *dev);
|
||||
int rkcif_register_stream_vdevs(struct rkcif_device *dev);
|
||||
void rkcif_stream_init(struct rkcif_device *dev, u32 id);
|
||||
|
||||
void rkcif_irq_oneframe(struct rkcif_device *cif_dev);
|
||||
void rkcif_irq_pingpong(struct rkcif_device *cif_dev);
|
||||
|
||||
@@ -192,7 +192,6 @@
|
||||
#define CSI_ENABLE_CROP (0x1 << 5)
|
||||
|
||||
/* CIF_CSI_INTEN */
|
||||
#define CSI_FRAME0_START_INTEN(id) (0x1 << ((id) * 2))
|
||||
#define CSI_FRAME1_START_INTEN(id) (0x1 << ((id) * 2 + 1))
|
||||
#define CSI_FRAME0_END_INTEN(id) (0x1 << ((id) * 2 + 8))
|
||||
#define CSI_FRAME1_END_INTEN(id) (0x1 << ((id) * 2 + 9))
|
||||
@@ -205,6 +204,14 @@
|
||||
#define CSI_ALL_FRAME_END_INTEN (0xff << 8)
|
||||
#define CSI_ALL_ERROR_INTEN (0x1f << 16)
|
||||
|
||||
#define CSI_START_INTEN(id) (0x3 << ((id) * 2))
|
||||
#define CSI_DMA_END_INTEN(id) (0x3 << ((id) * 2 + 8))
|
||||
#define CSI_LINE_INTEN(id) (0x1 << ((id) + 21))
|
||||
|
||||
#define CSI_START_INTSTAT(id) (0x3 << ((id) * 2))
|
||||
#define CSI_DMA_END_INTSTAT(id) (0x3 << ((id) * 2 + 8))
|
||||
#define CSI_LINE_INTSTAT(id) (0x1 << ((id) + 21))
|
||||
|
||||
/* CIF_CSI_INTSTAT */
|
||||
#define CSI_FRAME0_START_ID0 (0x1 << 0)
|
||||
#define CSI_FRAME1_START_ID0 (0x1 << 1)
|
||||
@@ -228,6 +235,14 @@
|
||||
#define CSI_BANDWIDTH_LACK (0x1 << 19)
|
||||
#define CSI_RX_FIFO_OVERFLOW (0x1 << 20)
|
||||
|
||||
#define CSI_FRAME_END_ID0 (CSI_FRAME0_END_ID0 |\
|
||||
CSI_FRAME1_END_ID0)
|
||||
#define CSI_FRAME_END_ID1 (CSI_FRAME0_END_ID1 |\
|
||||
CSI_FRAME1_END_ID1)
|
||||
#define CSI_FRAME_END_ID2 (CSI_FRAME0_END_ID2 |\
|
||||
CSI_FRAME1_END_ID2)
|
||||
#define CSI_FRAME_END_ID3 (CSI_FRAME0_END_ID3 |\
|
||||
CSI_FRAME1_END_ID3)
|
||||
#define CSI_FIFO_OVERFLOW (CSI_DMA_Y_FIFO_OVERFLOW | \
|
||||
CSI_DMA_UV_FIFO_OVERFLOW | \
|
||||
CSI_CONFIG_FIFO_OVERFLOW | \
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
*
|
||||
*v0.1.0:
|
||||
*1. First version;
|
||||
*v0.1.1
|
||||
*support the mipi vc multi-channel input in cif driver for rk1808
|
||||
*
|
||||
*/
|
||||
|
||||
#define RKCIF_DRIVER_VERSION KERNEL_VERSION(0, 1, 0x0)
|
||||
#define RKCIF_DRIVER_VERSION KERNEL_VERSION(0, 1, 0x1)
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user