Merge commit 'a9ed7b93e657b49420dc7c02c3ce9ce810e9b7d3'

* commit 'a9ed7b93e657b49420dc7c02c3ce9ce810e9b7d3':
  media: rockchip: vicap compatible with rk3588s2
  media: rockchip: vicap support combine two mipi to one dev
  phy: rockchip: csi2-dphy: logic node of mipi phy can control all hw of mipi phy

Conflicts:
	drivers/phy/rockchip/phy-rockchip-csi2-dphy.c

Ignore:
commit 08330d500d ("phy: rockchip: csi2-dphy: logic node of mipi phy can control all hw of mipi phy")

Change-Id: Ief48fe16863dc477a183289f9a4c49881d2d2942
This commit is contained in:
Tao Huang
2023-08-21 19:31:15 +08:00
11 changed files with 989 additions and 297 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -364,8 +364,8 @@ static int rkcif_scale_enum_framesizes(struct file *file, void *prov,
input_rect.height = RKCIF_DEFAULT_HEIGHT;
if (terminal_sensor && terminal_sensor->sd)
get_input_fmt(terminal_sensor->sd,
&input_rect, 0, &csi_info);
rkcif_get_input_fmt(dev,
&input_rect, 0, &csi_info);
switch (fsize->index) {
case SCALE_8TIMES:

View File

@@ -300,8 +300,8 @@ static int rkcif_tools_enum_framesizes(struct file *file, void *prov,
input_rect.height = RKCIF_DEFAULT_HEIGHT;
if (terminal_sensor && terminal_sensor->sd)
get_input_fmt(terminal_sensor->sd,
&input_rect, 0, &csi_info);
rkcif_get_input_fmt(dev,
&input_rect, 0, &csi_info);
fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
s->width = input_rect.width;

View File

@@ -1556,16 +1556,6 @@ static int subdev_notifier_complete(struct v4l2_async_notifier *notifier)
if (!completion_done(&dev->cmpl_ntf))
complete(&dev->cmpl_ntf);
if (dev->active_sensor &&
(dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY ||
dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY)) {
ret = v4l2_subdev_call(dev->active_sensor->sd,
core, ioctl,
RKCIF_CMD_SET_CSI_IDX,
&dev->csi_host_idx);
if (ret)
v4l2_err(&dev->v4l2_dev, "set csi idx %d fail\n", dev->csi_host_idx);
}
v4l2_info(&dev->v4l2_dev, "Async subdev notifier completed\n");
return ret;
@@ -1924,6 +1914,7 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int
cif_dev->early_line = 0;
cif_dev->is_thunderboot = false;
cif_dev->rdbk_debug = 0;
memset(&cif_dev->channels[0].capture_info, 0, sizeof(cif_dev->channels[0].capture_info));
if (cif_dev->chip_id == CHIP_RV1126_CIF_LITE)
cif_dev->isr_hdl = rkcif_irq_lite_handler;
@@ -1981,6 +1972,17 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int
cif_dev->csi_host_idx = of_alias_get_id(node, "rkcif_mipi_lvds");
if (cif_dev->csi_host_idx < 0 || cif_dev->csi_host_idx > 5)
cif_dev->csi_host_idx = 0;
if (cif_dev->hw_dev->is_rk3588s2) {
if (cif_dev->csi_host_idx == 0)
cif_dev->csi_host_idx = 2;
else if (cif_dev->csi_host_idx == 2)
cif_dev->csi_host_idx = 4;
else if (cif_dev->csi_host_idx == 3)
cif_dev->csi_host_idx = 5;
v4l2_info(&cif_dev->v4l2_dev, "rk3588s2 attach to mipi%d\n",
cif_dev->csi_host_idx);
}
cif_dev->csi_host_idx_def = cif_dev->csi_host_idx;
cif_dev->media_dev.dev = dev;
v4l2_dev = &cif_dev->v4l2_dev;
v4l2_dev->mdev = &cif_dev->media_dev;
@@ -2143,7 +2145,9 @@ static int rkcif_plat_probe(struct platform_device *pdev)
if (sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp))
return -ENODEV;
rkcif_attach_hw(cif_dev);
ret = rkcif_attach_hw(cif_dev);
if (ret)
return ret;
rkcif_parse_dts(cif_dev);

View File

@@ -280,10 +280,12 @@ struct csi_channel_info {
unsigned int width;
unsigned int height;
unsigned int virtual_width;
unsigned int left_virtual_width;
unsigned int crop_st_x;
unsigned int crop_st_y;
unsigned int dsi_input;
struct rkmodule_lvds_cfg lvds_cfg;
struct rkmodule_capture_info capture_info;
};
struct rkcif_vdev_node {
@@ -843,6 +845,7 @@ struct rkcif_device {
struct rkcif_work_struct reset_work;
int id_use_cnt;
unsigned int csi_host_idx;
unsigned int csi_host_idx_def;
unsigned int dvp_sof_in_oneframe;
unsigned int wait_line;
unsigned int wait_line_bak;
@@ -885,7 +888,7 @@ void rkcif_vb_done_tasklet(struct rkcif_stream *stream, struct rkcif_buffer *buf
int rkcif_scale_start(struct rkcif_scale_vdev *scale_vdev);
const struct
cif_input_fmt *get_input_fmt(struct v4l2_subdev *sd,
cif_input_fmt *rkcif_get_input_fmt(struct rkcif_device *dev,
struct v4l2_rect *rect,
u32 pad_id, struct csi_channel_info *csi_info);

View File

@@ -8,6 +8,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_graph.h>
@@ -1252,6 +1253,51 @@ void rkcif_hw_soft_reset(struct rkcif_hw *cif_hw, bool is_rst_iommu)
rkcif_iommu_enable(cif_hw);
}
static int rkcif_get_efuse_value(struct device_node *np, char *porp_name,
u8 *value)
{
struct nvmem_cell *cell;
unsigned char *buf;
size_t len;
cell = of_nvmem_cell_get(np, porp_name);
if (IS_ERR(cell))
return PTR_ERR(cell);
buf = (unsigned char *)nvmem_cell_read(cell, &len);
nvmem_cell_put(cell);
if (IS_ERR(buf))
return PTR_ERR(buf);
*value = buf[0];
kfree(buf);
return 0;
}
static int rkcif_get_speciand_package_number(struct device_node *np)
{
u8 spec = 0, package = 0, low = 0, high = 0;
if (rkcif_get_efuse_value(np, "specification", &spec))
return -EINVAL;
if (rkcif_get_efuse_value(np, "package_low", &low))
return -EINVAL;
if (rkcif_get_efuse_value(np, "package_high", &high))
return -EINVAL;
package = ((high & 0x1) << 3) | low;
/* RK3588S */
if (spec == 0x13)
return package;
return -EINVAL;
}
static int rkcif_plat_hw_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
@@ -1265,6 +1311,7 @@ static int rkcif_plat_hw_probe(struct platform_device *pdev)
int i, ret, irq;
bool is_mem_reserved = false;
struct notifier_block *notifier;
int package = 0;
match = of_match_node(rkcif_plat_of_match, node);
if (IS_ERR(match))
@@ -1278,6 +1325,13 @@ static int rkcif_plat_hw_probe(struct platform_device *pdev)
dev_set_drvdata(dev, cif_hw);
cif_hw->dev = dev;
package = rkcif_get_speciand_package_number(node);
if (package == 0x2) {
cif_hw->is_rk3588s2 = true;
dev_info(dev, "attach rk3588s2\n");
} else {
cif_hw->is_rk3588s2 = false;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
@@ -1506,6 +1560,7 @@ int rk_cif_plat_drv_init(void)
ret = platform_driver_register(&rkcif_hw_plat_drv);
if (ret)
return ret;
rkcif_csi2_hw_plat_drv_init();
return rkcif_csi2_plat_drv_init();
}
@@ -1513,6 +1568,7 @@ static void __exit rk_cif_plat_drv_exit(void)
{
platform_driver_unregister(&rkcif_hw_plat_drv);
rkcif_csi2_plat_drv_exit();
rkcif_csi2_hw_plat_drv_exit();
}
#if defined(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP) && !defined(CONFIG_INITCALL_ASYNC)

View File

@@ -152,6 +152,7 @@ struct rkcif_hw {
bool is_dma_contig;
bool adapt_to_usbcamerahal;
u64 irq_time;
bool is_rk3588s2;
};
void rkcif_hw_soft_reset(struct rkcif_hw *cif_hw, bool is_rst_iommu);

View File

@@ -13,12 +13,12 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/rk-camera-module.h>
#include <media/v4l2-ioctl.h>
#include "mipi-csi2.h"
#include <linux/rkcif-config.h>
#include <linux/regulator/consumer.h>
static int csi2_debug;
@@ -129,47 +129,55 @@ static void csi2_update_sensor_info(struct csi2_dev *csi2)
}
static void csi2_hw_do_reset(struct csi2_dev *csi2)
static void csi2_hw_do_reset(struct csi2_hw *csi2_hw)
{
reset_control_assert(csi2->rsts_bulk);
if (!csi2_hw->rsts_bulk)
return;
reset_control_assert(csi2_hw->rsts_bulk);
udelay(5);
reset_control_deassert(csi2->rsts_bulk);
reset_control_deassert(csi2_hw->rsts_bulk);
}
static int csi2_enable_clks(struct csi2_dev *csi2)
static int csi2_enable_clks(struct csi2_hw *csi2_hw)
{
int ret = 0;
ret = clk_bulk_prepare_enable(csi2->clks_num, csi2->clks_bulk);
if (!csi2_hw->clks_bulk)
return -EINVAL;
ret = clk_bulk_prepare_enable(csi2_hw->clks_num, csi2_hw->clks_bulk);
if (ret)
dev_err(csi2->dev, "failed to enable clks\n");
dev_err(csi2_hw->dev, "failed to enable clks\n");
return ret;
}
static void csi2_disable_clks(struct csi2_dev *csi2)
static void csi2_disable_clks(struct csi2_hw *csi2_hw)
{
clk_bulk_disable_unprepare(csi2->clks_num, csi2->clks_bulk);
if (!csi2_hw->clks_bulk)
return;
clk_bulk_disable_unprepare(csi2_hw->clks_num, csi2_hw->clks_bulk);
}
static void csi2_disable(struct csi2_dev *csi2)
static void csi2_disable(struct csi2_hw *csi2_hw)
{
void __iomem *base = csi2->base;
write_csihost_reg(base, CSIHOST_RESETN, 0);
write_csihost_reg(base, CSIHOST_MSK1, 0xffffffff);
write_csihost_reg(base, CSIHOST_MSK2, 0xffffffff);
write_csihost_reg(csi2_hw->base, CSIHOST_RESETN, 0);
write_csihost_reg(csi2_hw->base, CSIHOST_MSK1, 0xffffffff);
write_csihost_reg(csi2_hw->base, CSIHOST_MSK2, 0xffffffff);
}
static int csi2_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id,
struct v4l2_mbus_config *mbus);
static void csi2_enable(struct csi2_dev *csi2,
static void csi2_enable(struct csi2_hw *csi2_hw,
enum host_type_t host_type)
{
void __iomem *base = csi2->base;
void __iomem *base = csi2_hw->base;
struct csi2_dev *csi2 = csi2_hw->csi2;
int lanes = csi2->bus.num_data_lanes;
struct v4l2_mbus_config mbus;
u32 val = 0;
@@ -207,16 +215,10 @@ static int csi2_start(struct csi2_dev *csi2)
{
enum host_type_t host_type;
int ret, i;
int csi_idx = 0;
atomic_set(&csi2->frm_sync_seq, 0);
csi2_hw_do_reset(csi2);
ret = csi2_enable_clks(csi2);
if (ret) {
v4l2_err(&csi2->sd, "%s: enable clks failed\n", __func__);
return ret;
}
csi2_update_sensor_info(csi2);
if (csi2->dsi_input_en == RKMODULE_DSI_INPUT)
@@ -224,7 +226,16 @@ static int csi2_start(struct csi2_dev *csi2)
else
host_type = RK_CSI_RXHOST;
csi2_enable(csi2, host_type);
for (i = 0; i < csi2->csi_info.csi_num; i++) {
csi_idx = csi2->csi_info.csi_idx[i];
csi2_hw_do_reset(csi2->csi2_hw[csi_idx]);
ret = csi2_enable_clks(csi2->csi2_hw[csi_idx]);
if (ret) {
v4l2_err(&csi2->sd, "%s: enable clks failed\n", __func__);
return ret;
}
csi2_enable(csi2->csi2_hw[csi_idx], host_type);
}
pr_debug("stream sd: %s\n", csi2->src_sd->name);
ret = v4l2_subdev_call(csi2->src_sd, video, s_stream, 1);
@@ -238,20 +249,29 @@ static int csi2_start(struct csi2_dev *csi2)
return 0;
err_assert_reset:
csi2_disable(csi2);
csi2_disable_clks(csi2);
for (i = 0; i < csi2->csi_info.csi_num; i++) {
csi_idx = csi2->csi_info.csi_idx[i];
csi2_disable(csi2->csi2_hw[csi_idx]);
csi2_disable_clks(csi2->csi2_hw[csi_idx]);
}
return ret;
}
static void csi2_stop(struct csi2_dev *csi2)
{
int i = 0;
int csi_idx = 0;
/* stop upstream */
v4l2_subdev_call(csi2->src_sd, video, s_stream, 0);
csi2_disable(csi2);
csi2_hw_do_reset(csi2);
csi2_disable_clks(csi2);
for (i = 0; i < csi2->csi_info.csi_num; i++) {
csi_idx = csi2->csi_info.csi_idx[i];
csi2_disable(csi2->csi2_hw[csi_idx]);
csi2_hw_do_reset(csi2->csi2_hw[csi_idx]);
csi2_disable_clks(csi2->csi2_hw[csi_idx]);
}
}
/*
@@ -361,7 +381,6 @@ static int csi2_media_init(struct v4l2_subdev *sd)
csi2->crop.left = 0;
csi2->crop.width = RKCIF_DEFAULT_WIDTH;
csi2->crop.height = RKCIF_DEFAULT_HEIGHT;
csi2->csi_idx = 0;
return media_entity_pads_init(&sd->entity, num_pads, csi2->pad);
}
@@ -549,11 +568,19 @@ static int rkcif_csi2_s_power(struct v4l2_subdev *sd, int on)
static long rkcif_csi2_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct csi2_dev *csi2 = sd_to_dev(sd);
struct v4l2_subdev *sensor = get_remote_sensor(sd);
long ret = 0;
int i = 0;
switch (cmd) {
case RKCIF_CMD_SET_CSI_IDX:
csi2->csi_idx = *((u32 *)arg);
csi2->csi_info = *((struct rkcif_csi_info *)arg);
for (i = 0; i < csi2->csi_info.csi_num; i++)
csi2->csi2_hw[csi2->csi_info.csi_idx[i]]->csi2 = csi2;
if (csi2->match_data->chip_id > CHIP_RV1126_CSI2)
ret = v4l2_subdev_call(sensor, core, ioctl,
RKCIF_CMD_SET_CSI_IDX,
arg);
break;
default:
ret = -ENOIOCTLCMD;
@@ -568,15 +595,15 @@ static long rkcif_csi2_compat_ioctl32(struct v4l2_subdev *sd,
unsigned int cmd, unsigned long arg)
{
void __user *up = compat_ptr(arg);
u32 csi_idx = 0;
struct rkcif_csi_info csi_info;
long ret;
switch (cmd) {
case RKCIF_CMD_SET_CSI_IDX:
if (copy_from_user(&csi_idx, up, sizeof(u32)))
if (copy_from_user(&csi_info, up, sizeof(struct rkcif_csi_info)))
return -EFAULT;
ret = rkcif_csi2_ioctl(sd, cmd, &csi_idx);
ret = rkcif_csi2_ioctl(sd, cmd, &csi_info);
break;
default:
ret = -ENOIOCTLCMD;
@@ -721,7 +748,8 @@ static void csi2_find_err_vc(int val, char *vc_info)
static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx)
{
struct device *dev = ctx;
struct csi2_dev *csi2 = sd_to_dev(dev_get_drvdata(dev));
struct csi2_hw *csi2_hw = dev_get_drvdata(dev);
struct csi2_dev *csi2 = csi2_hw->csi2;
struct csi2_err_stats *err_list = NULL;
unsigned long err_stat = 0;
u32 val;
@@ -730,7 +758,7 @@ static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx)
char vc_info[CSI_VCINFO_LEN] = {0};
bool is_add_cnt = false;
val = read_csihost_reg(csi2->base, CSIHOST_ERR1);
val = read_csihost_reg(csi2_hw->base, CSIHOST_ERR1);
if (val) {
if (val & CSIHOST_ERR1_PHYERR_SPTSYNCHS) {
err_list = &csi2->err_list[RK_CSI2_ERR_SOTSYN];
@@ -739,7 +767,7 @@ static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx)
if (err_list->cnt > 3 &&
csi2->err_list[RK_CSI2_ERR_ALL].cnt <= err_list->cnt) {
csi2->is_check_sot_sync = false;
write_csihost_reg(csi2->base, CSIHOST_MSK1, 0xf);
write_csihost_reg(csi2_hw->base, CSIHOST_MSK1, 0xf);
}
if (csi2->is_check_sot_sync) {
csi2_find_err_vc(val & 0xf, vc_info);
@@ -804,7 +832,7 @@ static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx)
csi2_err_strncat(err_str, cur_str);
}
pr_err("%s ERR1:0x%x %s\n", csi2->dev_name, val, err_str);
pr_err("%s ERR1:0x%x %s\n", csi2_hw->dev_name, val, err_str);
if (is_add_cnt) {
csi2->err_list[RK_CSI2_ERR_ALL].cnt++;
@@ -813,7 +841,7 @@ static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx)
atomic_notifier_call_chain(&g_csi_host_chain,
err_stat,
&csi2->csi_idx);
&csi2->csi_info.csi_idx[csi2->csi_info.csi_num - 1]);
}
}
@@ -824,13 +852,13 @@ static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx)
static irqreturn_t rk_csirx_irq2_handler(int irq, void *ctx)
{
struct device *dev = ctx;
struct csi2_dev *csi2 = sd_to_dev(dev_get_drvdata(dev));
struct csi2_hw *csi2_hw = dev_get_drvdata(dev);
u32 val;
char cur_str[CSI_ERRSTR_LEN] = {0};
char err_str[CSI_ERRSTR_LEN] = {0};
char vc_info[CSI_VCINFO_LEN] = {0};
val = read_csihost_reg(csi2->base, CSIHOST_ERR2);
val = read_csihost_reg(csi2_hw->base, CSIHOST_ERR2);
if (val) {
if (val & CSIHOST_ERR2_PHYERR_ESC) {
csi2_find_err_vc(val & 0xf, vc_info);
@@ -857,7 +885,7 @@ static irqreturn_t rk_csirx_irq2_handler(int irq, void *ctx)
csi2_err_strncat(err_str, cur_str);
}
pr_err("%s ERR2:0x%x %s\n", csi2->dev_name, val, err_str);
pr_err("%s ERR2:0x%x %s\n", csi2_hw->dev_name, val, err_str);
}
return IRQ_HANDLED;
@@ -896,31 +924,43 @@ static int csi2_notifier(struct csi2_dev *csi2)
static const struct csi2_match_data rk1808_csi2_match_data = {
.chip_id = CHIP_RK1808_CSI2,
.num_pads = CSI2_NUM_PADS,
.num_hw = 1,
};
static const struct csi2_match_data rk3288_csi2_match_data = {
.chip_id = CHIP_RK3288_CSI2,
.num_pads = CSI2_NUM_PADS_SINGLE_LINK,
.num_hw = 1,
};
static const struct csi2_match_data rv1126_csi2_match_data = {
.chip_id = CHIP_RV1126_CSI2,
.num_pads = CSI2_NUM_PADS,
.num_hw = 1,
};
static const struct csi2_match_data rk3568_csi2_match_data = {
.chip_id = CHIP_RK3568_CSI2,
.num_pads = CSI2_NUM_PADS,
.num_hw = 1,
};
static const struct csi2_match_data rk3588_csi2_match_data = {
.chip_id = CHIP_RK3588_CSI2,
.num_pads = CSI2_NUM_PADS_MAX,
.num_hw = 6,
};
static const struct csi2_match_data rv1106_csi2_match_data = {
.chip_id = CHIP_RV1106_CSI2,
.num_pads = CSI2_NUM_PADS_MAX,
.num_hw = 2,
};
static const struct csi2_match_data rk3562_csi2_match_data = {
.chip_id = CHIP_RK3562_CSI2,
.num_pads = CSI2_NUM_PADS_MAX,
.num_hw = 4,
};
static const struct of_device_id csi2_dt_ids[] = {
@@ -944,6 +984,10 @@ static const struct of_device_id csi2_dt_ids[] = {
.compatible = "rockchip,rk3588-mipi-csi2",
.data = &rk3588_csi2_match_data,
},
{
.compatible = "rockchip,rv1106-mipi-csi2",
.data = &rv1106_csi2_match_data,
},
{
.compatible = "rockchip,rk3562-mipi-csi2",
.data = &rk3562_csi2_match_data,
@@ -952,15 +996,48 @@ static const struct of_device_id csi2_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, csi2_dt_ids);
static int csi2_attach_hw(struct csi2_dev *csi2)
{
struct device_node *np;
struct platform_device *pdev;
struct csi2_hw *hw;
int i = 0;
for (i = 0; i < csi2->match_data->num_hw; i++) {
np = of_parse_phandle(csi2->dev->of_node, "rockchip,hw", i);
if (!np || !of_device_is_available(np)) {
dev_err(csi2->dev, "failed to get csi2 hw node\n");
return -ENODEV;
}
pdev = of_find_device_by_node(np);
of_node_put(np);
if (!pdev) {
dev_err(csi2->dev, "failed to get csi2 hw from node\n");
return -ENODEV;
}
hw = platform_get_drvdata(pdev);
if (!hw) {
dev_err(csi2->dev, "failed attach csi2 hw\n");
return -EINVAL;
}
hw->csi2 = csi2;
csi2->csi2_hw[i] = hw;
}
dev_info(csi2->dev, "attach to csi2 hw node\n");
return 0;
}
static int csi2_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
struct device *dev = &pdev->dev;
struct device_node *node = pdev->dev.of_node;
struct csi2_dev *csi2 = NULL;
struct resource *res;
const struct csi2_match_data *data;
int ret, irq;
int ret;
match = of_match_node(csi2_dt_ids, node);
if (IS_ERR(match))
@@ -986,63 +1063,11 @@ static int csi2_probe(struct platform_device *pdev)
v4l2_err(&csi2->sd, "failed to copy name\n");
platform_set_drvdata(pdev, &csi2->sd);
csi2->clks_num = devm_clk_bulk_get_all(dev, &csi2->clks_bulk);
if (csi2->clks_num < 0) {
csi2->clks_num = 0;
dev_err(dev, "failed to get csi2 clks\n");
ret = csi2_attach_hw(csi2);
if (ret) {
v4l2_err(&csi2->sd, "must enable all mipi csi2 hw node\n");
return -EINVAL;
}
csi2->rsts_bulk = devm_reset_control_array_get_optional_exclusive(dev);
if (IS_ERR(csi2->rsts_bulk)) {
if (PTR_ERR(csi2->rsts_bulk) != -EPROBE_DEFER)
dev_err(dev, "failed to get csi2 reset\n");
csi2->rsts_bulk = NULL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
csi2->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(csi2->base)) {
resource_size_t offset = res->start;
resource_size_t size = resource_size(res);
dev_warn(&pdev->dev, "avoid secondary mipi resource check!\n");
csi2->base = devm_ioremap(&pdev->dev, offset, size);
if (IS_ERR(csi2->base)) {
dev_err(&pdev->dev, "Failed to ioremap resource\n");
return PTR_ERR(csi2->base);
}
}
irq = platform_get_irq_byname(pdev, "csi-intr1");
if (irq > 0) {
ret = devm_request_irq(&pdev->dev, irq,
rk_csirx_irq1_handler, 0,
dev_driver_string(&pdev->dev),
&pdev->dev);
if (ret < 0)
v4l2_err(&csi2->sd, "request csi-intr1 irq failed: %d\n",
ret);
csi2->irq1 = irq;
} else {
v4l2_err(&csi2->sd, "No found irq csi-intr1\n");
}
irq = platform_get_irq_byname(pdev, "csi-intr2");
if (irq > 0) {
ret = devm_request_irq(&pdev->dev, irq,
rk_csirx_irq2_handler, 0,
dev_driver_string(&pdev->dev),
&pdev->dev);
if (ret < 0)
v4l2_err(&csi2->sd, "request csi-intr2 failed: %d\n",
ret);
csi2->irq2 = irq;
} else {
v4l2_err(&csi2->sd, "No found irq csi-intr2\n");
}
mutex_init(&csi2->lock);
ret = csi2_media_init(&csi2->sd);
@@ -1087,11 +1112,183 @@ int rkcif_csi2_plat_drv_init(void)
return platform_driver_register(&csi2_driver);
}
void __exit rkcif_csi2_plat_drv_exit(void)
void rkcif_csi2_plat_drv_exit(void)
{
platform_driver_unregister(&csi2_driver);
}
static const struct csi2_hw_match_data rk1808_csi2_hw_match_data = {
.chip_id = CHIP_RK1808_CSI2,
};
static const struct csi2_hw_match_data rk3288_csi2_hw_match_data = {
.chip_id = CHIP_RK3288_CSI2,
};
static const struct csi2_hw_match_data rv1126_csi2_hw_match_data = {
.chip_id = CHIP_RV1126_CSI2,
};
static const struct csi2_hw_match_data rk3568_csi2_hw_match_data = {
.chip_id = CHIP_RK3568_CSI2,
};
static const struct csi2_hw_match_data rk3588_csi2_hw_match_data = {
.chip_id = CHIP_RK3588_CSI2,
};
static const struct csi2_hw_match_data rv1106_csi2_hw_match_data = {
.chip_id = CHIP_RV1106_CSI2,
};
static const struct csi2_hw_match_data rk3562_csi2_hw_match_data = {
.chip_id = CHIP_RK3562_CSI2,
};
static const struct of_device_id csi2_hw_ids[] = {
{
.compatible = "rockchip,rk1808-mipi-csi2-hw",
.data = &rk1808_csi2_hw_match_data,
},
{
.compatible = "rockchip,rk3288-mipi-csi2-hw",
.data = &rk3288_csi2_hw_match_data,
},
{
.compatible = "rockchip,rk3568-mipi-csi2-hw",
.data = &rk3568_csi2_hw_match_data,
},
{
.compatible = "rockchip,rv1126-mipi-csi2-hw",
.data = &rv1126_csi2_hw_match_data,
},
{
.compatible = "rockchip,rk3588-mipi-csi2-hw",
.data = &rk3588_csi2_hw_match_data,
},
{
.compatible = "rockchip,rv1106-mipi-csi2-hw",
.data = &rv1106_csi2_hw_match_data,
},
{
.compatible = "rockchip,rk3562-mipi-csi2-hw",
.data = &rk3588_csi2_hw_match_data,
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, csi2_hw_ids);
static int csi2_hw_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
struct device *dev = &pdev->dev;
struct device_node *node = pdev->dev.of_node;
struct csi2_hw *csi2_hw = NULL;
struct resource *res;
const struct csi2_hw_match_data *data;
int ret, irq;
dev_info(&pdev->dev, "enter mipi csi2 hw probe!\n");
match = of_match_node(csi2_hw_ids, node);
if (IS_ERR(match))
return PTR_ERR(match);
data = match->data;
csi2_hw = devm_kzalloc(&pdev->dev, sizeof(*csi2_hw), GFP_KERNEL);
if (!csi2_hw)
return -ENOMEM;
csi2_hw->dev = &pdev->dev;
csi2_hw->match_data = data;
csi2_hw->dev_name = node->name;
csi2_hw->clks_num = devm_clk_bulk_get_all(dev, &csi2_hw->clks_bulk);
if (csi2_hw->clks_num < 0) {
csi2_hw->clks_num = 0;
dev_err(dev, "failed to get csi2 clks\n");
}
csi2_hw->rsts_bulk = devm_reset_control_array_get_optional_exclusive(dev);
if (IS_ERR(csi2_hw->rsts_bulk)) {
if (PTR_ERR(csi2_hw->rsts_bulk) != -EPROBE_DEFER)
dev_err(dev, "failed to get csi2 reset\n");
csi2_hw->rsts_bulk = NULL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
csi2_hw->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(csi2_hw->base)) {
resource_size_t offset = res->start;
resource_size_t size = resource_size(res);
dev_warn(&pdev->dev, "avoid secondary mipi resource check!\n");
csi2_hw->base = devm_ioremap(&pdev->dev, offset, size);
if (IS_ERR(csi2_hw->base)) {
dev_err(&pdev->dev, "Failed to ioremap resource\n");
return PTR_ERR(csi2_hw->base);
}
}
irq = platform_get_irq_byname(pdev, "csi-intr1");
if (irq > 0) {
ret = devm_request_irq(&pdev->dev, irq,
rk_csirx_irq1_handler, 0,
dev_driver_string(&pdev->dev),
&pdev->dev);
if (ret < 0)
dev_err(&pdev->dev, "request csi-intr1 irq failed: %d\n",
ret);
csi2_hw->irq1 = irq;
} else {
dev_err(&pdev->dev, "No found irq csi-intr1\n");
}
irq = platform_get_irq_byname(pdev, "csi-intr2");
if (irq > 0) {
ret = devm_request_irq(&pdev->dev, irq,
rk_csirx_irq2_handler, 0,
dev_driver_string(&pdev->dev),
&pdev->dev);
if (ret < 0)
dev_err(&pdev->dev, "request csi-intr2 failed: %d\n",
ret);
csi2_hw->irq2 = irq;
} else {
dev_err(&pdev->dev, "No found irq csi-intr2\n");
}
platform_set_drvdata(pdev, csi2_hw);
dev_info(&pdev->dev, "probe success, v4l2_dev:%s!\n", csi2_hw->dev_name);
return 0;
}
static int csi2_hw_remove(struct platform_device *pdev)
{
return 0;
}
static struct platform_driver csi2_hw_driver = {
.driver = {
.name = DEVICE_NAME_HW,
.of_match_table = csi2_hw_ids,
},
.probe = csi2_hw_probe,
.remove = csi2_hw_remove,
};
int rkcif_csi2_hw_plat_drv_init(void)
{
return platform_driver_register(&csi2_hw_driver);
}
void rkcif_csi2_hw_plat_drv_exit(void)
{
platform_driver_unregister(&csi2_hw_driver);
}
MODULE_DESCRIPTION("Rockchip MIPI CSI2 driver");
MODULE_AUTHOR("Macrofly.xu <xuhf@rock-chips.com>");
MODULE_LICENSE("GPL");

View File

@@ -8,6 +8,7 @@
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-event.h>
#include <linux/rkcif-config.h>
#define CSI2_ERR_FSFE_MASK (0xff << 8)
#define CSI2_ERR_COUNT_ALL_MASK (0xff)
@@ -42,6 +43,7 @@
#define CSIHOST_MAX_ERRINT_COUNT 10
#define DEVICE_NAME "rockchip-mipi-csi2"
#define DEVICE_NAME_HW "rockchip-mipi-csi2-hw"
/* CSI Host Registers Define */
#define CSIHOST_N_LANES 0x04
@@ -76,6 +78,8 @@
#define SW_DATATYPE_LS(x) ((x) << 20)
#define SW_DATATYPE_LE(x) ((x) << 26)
#define RK_MAX_CSI_HW (6)
/*
* add new chip id in tail in time order
* by increasing to distinguish csi2 host version
@@ -88,6 +92,7 @@ enum rkcsi2_chip_id {
CHIP_RV1126_CSI2,
CHIP_RK3568_CSI2,
CHIP_RK3588_CSI2,
CHIP_RV1106_CSI2,
CHIP_RK3562_CSI2,
};
@@ -117,6 +122,11 @@ enum host_type_t {
struct csi2_match_data {
int chip_id;
int num_pads;
int num_hw;
};
struct csi2_hw_match_data {
int chip_id;
};
struct csi2_sensor_info {
@@ -155,10 +165,29 @@ struct csi2_dev {
int num_sensors;
atomic_t frm_sync_seq;
struct csi2_err_stats err_list[RK_CSI2_ERR_MAX];
struct csi2_hw *csi2_hw[RK_MAX_CSI_HW];
int irq1;
int irq2;
int dsi_input_en;
u32 csi_idx;
struct rkcif_csi_info csi_info;
const char *dev_name;
};
struct csi2_hw {
struct device *dev;
struct clk_bulk_data *clks_bulk;
int clks_num;
struct reset_control *rsts_bulk;
struct csi2_dev *csi2;
const struct csi2_hw_match_data *match_data;
void __iomem *base;
/* lock to protect all members below */
struct mutex lock;
int irq1;
int irq2;
const char *dev_name;
};
@@ -166,7 +195,9 @@ u32 rkcif_csi2_get_sof(struct csi2_dev *csi2_dev);
void rkcif_csi2_set_sof(struct csi2_dev *csi2_dev, u32 seq);
void rkcif_csi2_event_inc_sof(struct csi2_dev *csi2_dev);
int rkcif_csi2_plat_drv_init(void);
void __exit rkcif_csi2_plat_drv_exit(void);
void rkcif_csi2_plat_drv_exit(void);
int rkcif_csi2_hw_plat_drv_init(void);
void rkcif_csi2_hw_plat_drv_exit(void);
int rkcif_csi2_register_notifier(struct notifier_block *nb);
int rkcif_csi2_unregister_notifier(struct notifier_block *nb);
void rkcif_csi2_event_reset_pipe(struct csi2_dev *csi2_dev, int reset_src);

View File

@@ -337,7 +337,10 @@ static long sditf_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
mode = (struct rkisp_vicap_mode *)arg;
memcpy(&priv->mode, mode, sizeof(*mode));
sditf_reinit_mode(priv, &priv->mode);
mode->input.merge_num = cif_dev->sditf_cnt;
if (priv->is_combine_mode)
mode->input.merge_num = cif_dev->sditf_cnt;
else
mode->input.merge_num = 1;
mode->input.index = priv->combine_index;
return 0;
case RKISP_VICAP_CMD_INIT_BUF:
@@ -425,6 +428,7 @@ static long sditf_compat_ioctl32(struct v4l2_subdev *sd,
static int sditf_channel_enable(struct sditf_priv *priv, int user)
{
struct rkcif_device *cif_dev = priv->cif_dev;
struct rkmodule_capture_info *capture_info = &cif_dev->channels[0].capture_info;
unsigned int ch0 = 0, ch1 = 0, ch2 = 0;
unsigned int ctrl_val = 0;
unsigned int int_en = 0;
@@ -432,11 +436,25 @@ static int sditf_channel_enable(struct sditf_priv *priv, int user)
unsigned int offset_y = 0;
unsigned int width = priv->cap_info.width;
unsigned int height = priv->cap_info.height;
int csi_idx = cif_dev->csi_host_idx;
if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE &&
priv->toisp_inf.link_mode == TOISP_UNITE) {
if (capture_info->multi_dev.dev_num != 2 ||
capture_info->multi_dev.pixel_offset != RKMOUDLE_UNITE_EXTEND_PIXEL) {
v4l2_err(&cif_dev->v4l2_dev,
"param error of online mode, combine dev num %d, offset %d\n",
capture_info->multi_dev.dev_num,
capture_info->multi_dev.pixel_offset);
return -EINVAL;
}
csi_idx = capture_info->multi_dev.dev_idx[user];
}
if (priv->hdr_cfg.hdr_mode == NO_HDR ||
priv->hdr_cfg.hdr_mode == HDR_COMPR) {
if (cif_dev->inf_id == RKCIF_MIPI_LVDS)
ch0 = cif_dev->csi_host_idx * 4;
ch0 = csi_idx * 4;
else
ch0 = 24;//dvp
ctrl_val = (ch0 << 3) | 0x1;
@@ -491,7 +509,10 @@ static int sditf_channel_enable(struct sditf_priv *priv, int user)
}
} else {
if (priv->toisp_inf.link_mode == TOISP_UNITE) {
offset_x = priv->cap_info.width / 2 - RKMOUDLE_UNITE_EXTEND_PIXEL;
if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE)
offset_x = 0;
else
offset_x = priv->cap_info.width / 2 - RKMOUDLE_UNITE_EXTEND_PIXEL;
width = priv->cap_info.width / 2 + RKMOUDLE_UNITE_EXTEND_PIXEL;
}
rkcif_write_register(cif_dev, CIF_REG_TOISP1_CTRL, ctrl_val);

View File

@@ -67,6 +67,8 @@
*7. add keepint time to csi2 err for resetting
*8. mipi supports pdaf/embedded data
*9. mipi supports interlaced capture
*v0.2.0
*1. vicap support combine multi mipi dev to one dev, this function is mainly used for rk3588
*/
#define RKCIF_DRIVER_VERSION RKCIF_API_VERSION