mirror of
https://github.com/torvalds/linux.git
synced 2026-06-08 06:25:52 +02:00
media: rockchip: isp: support lvds interface
Change-Id: I36e8c8eecd590e1862d0d6fa7dbd5f1091567020 Signed-off-by: Cai YiWei <cyw@rock-chips.com>
This commit is contained in:
parent
c01c6215ad
commit
51f1725a15
|
|
@ -93,7 +93,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_CSI | INP_DVP)))
|
||||
if (!(dev->isp_inp & (INP_CSI | INP_DVP | INP_LVDS)))
|
||||
return 0;
|
||||
|
||||
while (1) {
|
||||
|
|
@ -121,7 +121,6 @@ static int __isp_pipeline_prepare(struct rkisp_pipeline *p,
|
|||
if (me->num_pads == 1)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!p->num_subdevs)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -136,7 +135,7 @@ static int __isp_pipeline_s_isp_clk(struct rkisp_pipeline *p)
|
|||
u64 data_rate;
|
||||
int i;
|
||||
|
||||
if (!(dev->isp_inp & (INP_CSI | INP_DVP))) {
|
||||
if (!(dev->isp_inp & (INP_CSI | INP_DVP | INP_LVDS))) {
|
||||
if (dev->clks[0])
|
||||
clk_set_rate(dev->clks[0], 400 * 1000000UL);
|
||||
return 0;
|
||||
|
|
@ -270,55 +269,52 @@ static int rkisp_pipeline_set_stream(struct rkisp_pipeline *p, bool on)
|
|||
static int rkisp_create_links(struct rkisp_device *dev)
|
||||
{
|
||||
unsigned int s, pad;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
/* 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;
|
||||
bool en = s ? 0 : MEDIA_LNK_FL_ENABLED;
|
||||
|
||||
for (pad = 0; pad < sensor->sd->entity.num_pads; pad++)
|
||||
if (sensor->sd->entity.pads[pad].flags &
|
||||
MEDIA_PAD_FL_SOURCE)
|
||||
if (sensor->sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE)
|
||||
break;
|
||||
|
||||
if (pad == sensor->sd->entity.num_pads) {
|
||||
dev_err(dev->dev,
|
||||
"failed to find src pad for %s\n",
|
||||
dev_err(dev->dev, "failed to find src pad for %s\n",
|
||||
sensor->sd->name);
|
||||
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
ret = media_create_pad_link(&sensor->sd->entity, pad,
|
||||
&dev->isp_sdev.sd.entity, RKISP_ISP_PAD_SINK, en);
|
||||
} 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",
|
||||
sensor->sd->name);
|
||||
return ret;
|
||||
v4l2_subdev_call(sensor->sd, video,
|
||||
g_mbus_config, &sensor->mbus);
|
||||
if (sensor->mbus.type == V4L2_MBUS_CCP2) {
|
||||
/* mipi-phy lvds link -> isp */
|
||||
dev->isp_inp = INP_LVDS;
|
||||
ret = media_create_pad_link(&sensor->sd->entity, pad,
|
||||
&dev->isp_sdev.sd.entity, RKISP_ISP_PAD_SINK, en);
|
||||
} 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, en);
|
||||
ret |= media_create_pad_link(&dev->csi_dev.sd.entity, CSI_SRC_CH0,
|
||||
&dev->isp_sdev.sd.entity, RKISP_ISP_PAD_SINK, en);
|
||||
dev->csi_dev.sink[0].linked = en;
|
||||
dev->csi_dev.sink[0].index = BIT(0);
|
||||
}
|
||||
}
|
||||
if (ret)
|
||||
dev_err(dev->dev, "failed to create link for %s\n", sensor->sd->name);
|
||||
}
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _set_pipeline_default_fmt(struct rkisp_device *dev)
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ enum rkisp_isp_inp {
|
|||
INP_CSI = BIT(4),
|
||||
INP_DVP = BIT(5),
|
||||
INP_DMARX_ISP = BIT(6),
|
||||
INP_LVDS = BIT(7),
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
#define CTRL_VI_IRCL (CTRL_BASE + 0x00014)
|
||||
#define CTRL_VI_DPCL (CTRL_BASE + 0x00018)
|
||||
#define CTRL_SWS_CFG (CTRL_BASE + 0x0001c)
|
||||
#define LVDS_CTRL (CTRL_BASE + 0x00020)
|
||||
#define LVDS_SAV_EAV_ACT (CTRL_BASE + 0x00024)
|
||||
#define LVDS_SAV_EAV_BLK (CTRL_BASE + 0x00028)
|
||||
|
||||
#define IMG_EFF_BASE 0x00000200
|
||||
#define IMG_EFF_CTRL (IMG_EFF_BASE + 0x00000)
|
||||
|
|
@ -1736,6 +1739,9 @@
|
|||
#define IRCL_MIPI_SW_RST BIT(11)
|
||||
#define IRCL_3A_SW_RST BIT(13)
|
||||
|
||||
/* VI_DPCL */
|
||||
#define VI_DPCL_IF_SEL_LVDS BIT(8)
|
||||
|
||||
/* SWS_CFG */
|
||||
#define SW_SWS_EN BIT(0)
|
||||
#define SW_ISP2PP_PIPE_EN BIT(1)
|
||||
|
|
@ -1750,6 +1756,18 @@
|
|||
#define SW_3A_DDR_WRITE_EN BIT(24)
|
||||
#define SW_ISP2PP_HOLD BIT(31)
|
||||
|
||||
/* LVDS_CTRL */
|
||||
#define SW_LVDS_EN BIT(0)
|
||||
#define SW_LVDS_MODE BIT(1)
|
||||
#define SW_LVDS_WIDTH(a) (((a) & 0x3) << 2)
|
||||
#define SW_LVDS_LANE_EN(a) (((a) & 0xf) << 4)
|
||||
#define SW_LVDS_MAIN_LANE(a) (((a) & 0x3) << 8)
|
||||
#define SW_LVDS_START_X(a) (((a) & 0x7ff) << 10)
|
||||
#define SW_LVDS_START_Y(a) (((a) & 0x7ff) << 21)
|
||||
|
||||
#define SW_LVDS_SAV(a) ((a) & 0xfff)
|
||||
#define SW_LVDS_EAV(a) (((a) & 0xfff) << 16)
|
||||
|
||||
/* isp interrupt */
|
||||
#define ISP2X_OFF BIT(0)
|
||||
#define ISP2X_FRAME BIT(1)
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include <linux/iopoll.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/rk-camera-module.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/kfifo.h>
|
||||
|
|
@ -129,7 +130,7 @@ static struct v4l2_subdev *get_remote_sensor(struct v4l2_subdev *sd)
|
|||
struct media_entity *sensor_me;
|
||||
struct v4l2_subdev *remote_sd = NULL;
|
||||
|
||||
local = &sd->entity.pads[RKISP_ISP_PAD_SINK];
|
||||
local = &sd->entity.pads[0];
|
||||
if (!local)
|
||||
goto end;
|
||||
remote = rkisp_media_entity_remote_pad(local);
|
||||
|
|
@ -562,7 +563,9 @@ static int rkisp_config_isp(struct rkisp_device *dev)
|
|||
acq_prop = CIF_ISP_ACQ_PROP_DMA_RGB;
|
||||
} else if (in_fmt->fmt_type == FMT_YUV) {
|
||||
acq_mult = 2;
|
||||
if (sensor && sensor->mbus.type == V4L2_MBUS_CSI2) {
|
||||
if (sensor &&
|
||||
(sensor->mbus.type == V4L2_MBUS_CSI2 ||
|
||||
sensor->mbus.type == V4L2_MBUS_CCP2)) {
|
||||
isp_ctrl = CIF_ISP_CTRL_ISP_MODE_ITU601;
|
||||
} else {
|
||||
if (sensor && sensor->mbus.type == V4L2_MBUS_BT656)
|
||||
|
|
@ -677,6 +680,66 @@ static int rkisp_config_dvp(struct rkisp_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int rkisp_config_lvds(struct rkisp_device *dev)
|
||||
{
|
||||
struct rkisp_sensor_info *sensor = dev->active_sensor;
|
||||
struct ispsd_in_fmt *in_fmt = &dev->isp_sdev.in_fmt;
|
||||
struct rkmodule_lvds_cfg cfg;
|
||||
struct v4l2_subdev *sd = NULL;
|
||||
u32 ret = 0, val, lane, data;
|
||||
|
||||
sd = get_remote_sensor(sensor->sd);
|
||||
ret = v4l2_subdev_call(sd, core, ioctl, RKMODULE_GET_LVDS_CFG, &cfg);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
switch (sensor->mbus.flags & V4L2_MBUS_CSI2_LANES) {
|
||||
case V4L2_MBUS_CSI2_1_LANE:
|
||||
lane = 1;
|
||||
break;
|
||||
case V4L2_MBUS_CSI2_2_LANE:
|
||||
lane = 2;
|
||||
break;
|
||||
case V4L2_MBUS_CSI2_3_LANE:
|
||||
lane = 3;
|
||||
break;
|
||||
case V4L2_MBUS_CSI2_4_LANE:
|
||||
default:
|
||||
lane = 4;
|
||||
}
|
||||
lane = BIT(lane) - 1;
|
||||
|
||||
switch (in_fmt->bus_width) {
|
||||
case 8:
|
||||
data = 0;
|
||||
break;
|
||||
case 10:
|
||||
data = 1;
|
||||
break;
|
||||
case 12:
|
||||
data = 2;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
val = SW_LVDS_SAV(cfg.act.sav) | SW_LVDS_EAV(cfg.act.eav);
|
||||
writel(val, dev->base_addr + LVDS_SAV_EAV_ACT);
|
||||
val = SW_LVDS_SAV(cfg.blk.sav) | SW_LVDS_EAV(cfg.blk.eav);
|
||||
writel(val, dev->base_addr + LVDS_SAV_EAV_BLK);
|
||||
val = SW_LVDS_EN | SW_LVDS_WIDTH(data) | SW_LVDS_LANE_EN(lane) | cfg.mode;
|
||||
writel(val, dev->base_addr + LVDS_CTRL);
|
||||
v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
|
||||
"lvds CTRL:0x%x ACT:0x%x BLK:0x%x\n",
|
||||
readl(dev->base_addr + LVDS_CTRL),
|
||||
readl(dev->base_addr + LVDS_SAV_EAV_ACT),
|
||||
readl(dev->base_addr + LVDS_SAV_EAV_BLK));
|
||||
return ret;
|
||||
err:
|
||||
v4l2_err(&dev->v4l2_dev, "%s error ret:%d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Configure MUX */
|
||||
static int rkisp_config_path(struct rkisp_device *dev)
|
||||
{
|
||||
|
|
@ -684,16 +747,19 @@ static int rkisp_config_path(struct rkisp_device *dev)
|
|||
struct rkisp_sensor_info *sensor = dev->active_sensor;
|
||||
u32 dpcl = readl(dev->base_addr + CIF_VI_DPCL);
|
||||
|
||||
if (sensor && (sensor->mbus.type == V4L2_MBUS_BT656 ||
|
||||
sensor->mbus.type == V4L2_MBUS_PARALLEL)) {
|
||||
if (sensor &&
|
||||
(sensor->mbus.type == V4L2_MBUS_BT656 ||
|
||||
sensor->mbus.type == V4L2_MBUS_PARALLEL)) {
|
||||
ret = rkisp_config_dvp(dev);
|
||||
dpcl |= CIF_VI_DPCL_IF_SEL_PARALLEL;
|
||||
} else if ((sensor && sensor->mbus.type == V4L2_MBUS_CSI2) ||
|
||||
dev->isp_inp & (INP_RAWRD0 |
|
||||
INP_RAWRD1 | INP_RAWRD2)) {
|
||||
dev->isp_inp & (INP_RAWRD0 | INP_RAWRD1 | INP_RAWRD2)) {
|
||||
dpcl |= CIF_VI_DPCL_IF_SEL_MIPI;
|
||||
} else if (dev->isp_inp == INP_DMARX_ISP) {
|
||||
dpcl |= CIF_VI_DPCL_DMA_SW_ISP;
|
||||
} else if (sensor && sensor->mbus.type == V4L2_MBUS_CCP2) {
|
||||
ret = rkisp_config_lvds(dev);
|
||||
dpcl |= VI_DPCL_IF_SEL_LVDS;
|
||||
}
|
||||
|
||||
writel(dpcl, dev->base_addr + CIF_VI_DPCL);
|
||||
|
|
@ -1588,10 +1654,12 @@ static int rkisp_subdev_link_setup(struct media_entity *entity,
|
|||
if (!sd)
|
||||
return -ENODEV;
|
||||
dev = sd_to_isp_dev(sd);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
if (!strcmp(remote->entity->name, DMA_VDEV_NAME)) {
|
||||
stream = &dev->dmarx_dev.stream[RKISP_STREAM_DMARX];
|
||||
if (flags & MEDIA_LNK_FL_ENABLED) {
|
||||
if (dev->isp_inp)
|
||||
if (dev->isp_inp & ~INP_DMARX_ISP)
|
||||
goto err;
|
||||
if (dev->active_sensor)
|
||||
dev->active_sensor = NULL;
|
||||
|
|
@ -1610,7 +1678,7 @@ static int rkisp_subdev_link_setup(struct media_entity *entity,
|
|||
} else if (!strcmp(remote->entity->name, DMARX0_VDEV_NAME)) {
|
||||
stream = &dev->dmarx_dev.stream[RKISP_STREAM_RAWRD0];
|
||||
if (flags & MEDIA_LNK_FL_ENABLED) {
|
||||
if (dev->isp_inp == INP_DMARX_ISP)
|
||||
if (dev->isp_inp & ~(INP_CSI | rawrd))
|
||||
goto err;
|
||||
dev->isp_inp |= INP_RAWRD0;
|
||||
} else {
|
||||
|
|
@ -1619,7 +1687,7 @@ static int rkisp_subdev_link_setup(struct media_entity *entity,
|
|||
} else if (!strcmp(remote->entity->name, DMARX1_VDEV_NAME)) {
|
||||
stream = &dev->dmarx_dev.stream[RKISP_STREAM_RAWRD1];
|
||||
if (flags & MEDIA_LNK_FL_ENABLED) {
|
||||
if (dev->isp_inp == INP_DMARX_ISP)
|
||||
if (dev->isp_inp & ~(INP_CSI | rawrd))
|
||||
goto err;
|
||||
dev->isp_inp |= INP_RAWRD1;
|
||||
} else {
|
||||
|
|
@ -1628,7 +1696,7 @@ static int rkisp_subdev_link_setup(struct media_entity *entity,
|
|||
} else if (!strcmp(remote->entity->name, DMARX2_VDEV_NAME)) {
|
||||
stream = &dev->dmarx_dev.stream[RKISP_STREAM_RAWRD2];
|
||||
if (flags & MEDIA_LNK_FL_ENABLED) {
|
||||
if (dev->isp_inp == INP_DMARX_ISP)
|
||||
if (dev->isp_inp & ~(INP_CSI | rawrd))
|
||||
goto err;
|
||||
dev->isp_inp |= INP_RAWRD2;
|
||||
} else {
|
||||
|
|
@ -1650,9 +1718,17 @@ static int rkisp_subdev_link_setup(struct media_entity *entity,
|
|||
dev->cap_dev.stream[RKISP_STREAM_MP].linked))
|
||||
goto err;
|
||||
dev->br_dev.linked = flags & MEDIA_LNK_FL_ENABLED;
|
||||
} else if (!strcmp(remote->entity->name, "rockchip-mipi-dphy-rx")) {
|
||||
if (flags & MEDIA_LNK_FL_ENABLED) {
|
||||
if (dev->isp_inp & ~INP_LVDS)
|
||||
goto err;
|
||||
dev->isp_inp |= INP_LVDS;
|
||||
} else {
|
||||
dev->isp_inp &= ~INP_LVDS;
|
||||
}
|
||||
} else {
|
||||
if (flags & MEDIA_LNK_FL_ENABLED) {
|
||||
if (dev->isp_inp & ~(INP_DVP | rawrd))
|
||||
if (dev->isp_inp & ~INP_DVP)
|
||||
goto err;
|
||||
dev->isp_inp |= INP_DVP;
|
||||
} else {
|
||||
|
|
@ -1672,8 +1748,8 @@ static int rkisp_subdev_link_setup(struct media_entity *entity,
|
|||
return 0;
|
||||
err:
|
||||
v4l2_err(sd, "link error %s -> %s\n"
|
||||
"\tdmaread can't work with other input\n"
|
||||
"\tcsi dvp can't work together\n"
|
||||
"\tcsi dvp lvds dmaread can't work together\n"
|
||||
"\trawrd can't work with dvp lvds dmaread\n"
|
||||
"\tbridge can't work with mainpath/selfpath\n",
|
||||
local->entity->name, remote->entity->name);
|
||||
return -EINVAL;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user