camera: sync V5.7 code and verify single_online_test

Change-Id: I0f894b8b50bcb2cf4ea10d749d9de1b0e11265e2
This commit is contained in:
lizhirong
2024-11-04 21:15:20 +08:00
committed by zhangmeng
parent f5dd9fa83b
commit e314924ff0
10 changed files with 2185 additions and 87 deletions

View File

@@ -69,12 +69,14 @@
interrupt-names = "ipe-irq";
clocks = <&ccu CLK_CSI>,
<&ccu CLK_CCIC_4X>,
<&ccu CLK_ISP_BUS>;
clock-names = "csi_func", "ccic_func", "isp_axi";
<&ccu CLK_ISP_BUS>,
<&ccu CLK_DPU_MCLK>;
clock-names = "csi_func", "ccic_func", "isp_axi", "dpu_mclk";
resets = <&reset RESET_ISP_AHB>, <&reset RESET_CSI>,
<&reset RESET_CCIC_4X>, <&reset RESET_ISP_CI>;
<&reset RESET_CCIC_4X>, <&reset RESET_ISP_CI>,
<&reset RESET_LCD_MCLK>;
reset-names = "isp_ahb_reset", "csi_reset",
"ccic_4x_reset", "isp_ci_reset";
"ccic_4x_reset", "isp_ci_reset", "mclk_reset";
interconnects = <&dram_range3>;
interconnect-names = "dma-mem";
status = "okay";
@@ -89,14 +91,16 @@
interrupt-parent = <&intc>;
interrupts = <82>;
interrupt-names = "ipe-irq";
clocks = <&ccu CLK_CSI>, <&ccu CLK_CCIC_4X>,
<&ccu CLK_ISP_BUS>;
clock-names = "csi_func", "ccic_func",
"isp_axi";
clocks = <&ccu CLK_CSI>,
<&ccu CLK_CCIC_4X>,
<&ccu CLK_ISP_BUS>,
<&ccu CLK_DPU_MCLK>;
clock-names = "csi_func", "ccic_func", "isp_axi", "dpu_mclk";
resets = <&reset RESET_ISP_AHB>, <&reset RESET_CSI>,
<&reset RESET_CCIC_4X>, <&reset RESET_ISP_CI>;
<&reset RESET_CCIC_4X>, <&reset RESET_ISP_CI>,
<&reset RESET_LCD_MCLK>;
reset-names = "isp_ahb_reset", "csi_reset",
"ccic_4x_reset", "isp_ci_reset";
"ccic_4x_reset", "isp_ci_reset", "mclk_reset";
interconnects = <&dram_range3>;
interconnect-names = "dma-mem";
status = "okay";
@@ -111,14 +115,16 @@
interrupt-parent = <&intc>;
interrupts = <83>;
interrupt-names = "ipe-irq";
clocks = <&ccu CLK_CSI>, <&ccu CLK_CCIC_4X>,
<&ccu CLK_ISP_BUS>;
clock-names = "csi_func", "ccic_func",
"isp_axi";
clocks = <&ccu CLK_CSI>,
<&ccu CLK_CCIC_4X>,
<&ccu CLK_ISP_BUS>,
<&ccu CLK_DPU_MCLK>;
clock-names = "csi_func", "ccic_func", "isp_axi", "dpu_mclk";
resets = <&reset RESET_ISP_AHB>, <&reset RESET_CSI>,
<&reset RESET_CCIC_4X>, <&reset RESET_ISP_CI>;
<&reset RESET_CCIC_4X>, <&reset RESET_ISP_CI>,
<&reset RESET_LCD_MCLK>;
reset-names = "isp_ahb_reset", "csi_reset",
"ccic_4x_reset", "isp_ci_reset";
"ccic_4x_reset", "isp_ci_reset", "mclk_reset";
interconnects = <&dram_range3>;
interconnect-names = "dma-mem";
status = "okay";

View File

@@ -12,6 +12,7 @@ cam_ccic_v2-objs += cam_ccic/ccic_hwreg.o
cam_ccic_v2-objs += cam_ccic/csiphy.o
cam_ccic_v2-objs += cam_ccic/ccic_drv.o
cam_ccic_v2-objs += cam_ccic/dptc_drv.o
cam_ccic_v2-objs += cam_ccic/ccic_vdev.o
obj-$(CONFIG_SPACEMIT_K1X_CPP_V2) += cam_cpp_v2.o
cam_cpp_v2-objs += cam_cpp/k1x_cpp.o

View File

@@ -18,11 +18,13 @@
#include <media/v4l2-dev.h>
#include <media/videobuf2-dma-contig.h>
#include <media/videobuf2-dma-sg.h>
#include <linux/media-bus-format.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include "ccic_drv.h"
#include "ccic_hwreg.h"
#include "csiphy.h"
#include "ccic_vdev.h"
#ifdef CONFIG_ARCH_ZYNQMP
#include "dptc_drv.h"
@@ -31,8 +33,19 @@
#define K1X_CCIC_DRV_NAME "k1xccic"
#define CAM_ALIGN(a, b) ({ \
unsigned int ___tmp1 = (a); \
unsigned int ___tmp2 = (b); \
unsigned int ___tmp3 = ___tmp1 % ___tmp2; \
___tmp1 /= ___tmp2; \
if (___tmp3) \
___tmp1++; \
___tmp1 *= ___tmp2; \
___tmp1; \
})
static LIST_HEAD(ccic_devices);
static DEFINE_MUTEX(list_lock);
static void ccic_dma_bh_handler(struct ccic_dma_work_struct *ccic_dma_work);
static void ccic_irqmask(struct ccic_ctrl *ctrl, int on)
{
@@ -131,17 +144,23 @@ static int ccic_config_csi2_dphy(struct ccic_ctrl *ctrl,
return ret;
}
static int ccic_config_csi2_vc(struct ccic_ctrl *ctrl, int md, u8 vc0, u8 vc1)
static int ccic_config_csi2_vc_dt(struct ccic_ctrl *ctrl, int md, u8 vc0, u8 vc1, u8 dt0, u8 dt1)
{
int ret = 0;
struct ccic_dev *ccic_dev = ctrl->ccic_dev;
switch (md) {
case CCIC_CSI2VC_NM: /* Normal mode */
ccic_reg_clear_bit(ccic_dev, REG_CSI2_VCCTRL, CSI2_VCCTRL_DT_ENABLE);
ccic_reg_clear_bit(ccic_dev, REG_CSI2_DT_FLT, CSI2_DT_FLT0_EN);
ccic_reg_clear_bit(ccic_dev, REG_CSI2_DT_FLT, CSI2_DT_FLT1_EN);
ccic_reg_write_mask(ccic_dev, REG_CSI2_VCCTRL,
CSI2_VCCTRL_MD_NORMAL, CSI2_VCCTRL_MD_MASK);
break;
case CCIC_CSI2VC_VC: /* Virtual Channel mode */
ccic_reg_clear_bit(ccic_dev, REG_CSI2_VCCTRL, CSI2_VCCTRL_DT_ENABLE);
ccic_reg_clear_bit(ccic_dev, REG_CSI2_DT_FLT, CSI2_DT_FLT0_EN);
ccic_reg_clear_bit(ccic_dev, REG_CSI2_DT_FLT, CSI2_DT_FLT1_EN);
ccic_reg_write_mask(ccic_dev, REG_CSI2_VCCTRL,
CSI2_VCCTRL_MD_VC, CSI2_VCCTRL_MD_MASK);
ccic_reg_write_mask(ccic_dev, REG_CSI2_VCCTRL, vc0 << 14,
@@ -150,9 +169,23 @@ static int ccic_config_csi2_vc(struct ccic_ctrl *ctrl, int md, u8 vc0, u8 vc1)
CSI2_VCCTRL_VC1_MASK);
break;
case CCIC_CSI2VC_DT: /* TODO: Data-Type Interleaving */
ccic_reg_write_mask(ccic_dev, REG_CSI2_VCCTRL,
CSI2_VCCTRL_MD_DT, CSI2_VCCTRL_MD_MASK);
//ccic_reg_write_mask(ccic_dev, REG_CSI2_VCCTRL,
// CSI2_VCCTRL_MD_DT, CSI2_VCCTRL_MD_MASK);
pr_err("csi2 vc mode %d todo\n", md);
ret = -EINVAL;
break;
case CCIC_CSI2VC_VCDT:
ccic_reg_set_bit(ccic_dev, REG_CSI2_VCCTRL, CSI2_VCCTRL_DT_ENABLE);
ccic_reg_set_bit(ccic_dev, REG_CSI2_DT_FLT, CSI2_DT_FLT0_EN);
ccic_reg_set_bit(ccic_dev, REG_CSI2_DT_FLT, CSI2_DT_FLT2_EN);
ccic_reg_write_mask(ccic_dev, REG_CSI2_VCCTRL, vc0 << 14,
CSI2_VCCTRL_VC0_MASK);
ccic_reg_write_mask(ccic_dev, REG_CSI2_VCCTRL, vc1 << 22,
CSI2_VCCTRL_VC1_MASK);
ccic_reg_write_mask(ccic_dev, REG_CSI2_DT_FLT, dt0 << CSI2_DT_FLT0_SHIFT,
CSI2_DT_FLT0_MASK);
ccic_reg_write_mask(ccic_dev, REG_CSI2_DT_FLT, dt1 << CSI2_DT_FLT2_SHIFT,
CSI2_DT_FLT2_MASK);
break;
default:
dev_err(ccic_dev->dev, "invalid csi2 vc mode %d\n", md);
@@ -292,10 +325,10 @@ static int axi_set_clock_rates(struct clk *clock)
return 0;
}
int ccic_dma_clk_enable(struct ccic_dma *dma, int on)
static int ccic_dma_clk_enable(struct ccic_dma *dma, int on)
{
struct ccic_dev *ccic = dma->ccic_dev;
struct device *dev = &ccic->pdev->dev;
struct ccic_dev *ccic_dev = dma->ccic_dev;
struct device *dev = &ccic_dev->pdev->dev;
int ret;
if (on) {
@@ -303,30 +336,198 @@ int ccic_dma_clk_enable(struct ccic_dma *dma, int on)
if (ret < 0)
return ret;
ret = clk_prepare_enable(ccic->axi_clk);
ret = clk_prepare_enable(ccic_dev->axi_clk);
if (ret < 0) {
pm_runtime_put_sync(dev);
return ret;
}
reset_control_deassert(ccic->isp_ci_reset);
reset_control_deassert(ccic_dev->isp_ci_reset);
ret = axi_set_clock_rates(ccic->axi_clk);
ret = axi_set_clock_rates(ccic_dev->axi_clk);
if (ret < 0) {
pm_runtime_put_sync(dev);
return ret;
}
reset_control_deassert(ccic->isp_ci_reset);
reset_control_deassert(ccic_dev->isp_ci_reset);
} else {
clk_disable_unprepare(ccic->axi_clk);
reset_control_assert(ccic->isp_ci_reset);
clk_disable_unprepare(ccic_dev->axi_clk);
reset_control_assert(ccic_dev->isp_ci_reset);
pm_runtime_put_sync(dev);
}
return 0;
}
static int ccic_dma_enable(struct ccic_dma *dma_dev, int enable)
{
struct ccic_dev *ccic_dev = dma_dev->ccic_dev;
if (enable) {
//ccic_reg_set_bit(ccic_dev, REG_IRQMASK, FRAMEIRQS);
ccic_dma_set_burst(ccic_dev);
/* 0x3c: enable ccic dma */
ccic_reg_set_bit(ccic_dev, REG_CTRL0, BIT(0));
ccic_reg_set_bit(ccic_dev, 0x40, BIT(31) | BIT(26));
ccic_reg_clear_bit(ccic_dev, 0x40, BIT(25));
} else {
//ccic_reg_clear_bit(ccic_dev, REG_IRQMASK, FRAMEIRQS);
/* 0x3c: disable ccic dma */
ccic_reg_clear_bit(ccic_dev, REG_CTRL0, BIT(0));
}
return 0;
}
static int ccic_dma_set_fmt(struct ccic_dma *dma_dev,
unsigned int width,
unsigned int height,
unsigned int pix_fmt)
{
struct ccic_dev *ccic_dev = dma_dev->ccic_dev;
struct device *dev = ccic_dev->dev;
unsigned int data_fmt = C0_DF_BAYER, imgsz_w = 0, imgsz_h = 0;
unsigned int stride_y = 0, stride_uv = 0;
switch (pix_fmt) {
case MEDIA_BUS_FMT_UYVY8_2X8:
data_fmt = C0_DF_BAYER;
imgsz_w = width;
stride_y = 0;
imgsz_h = height;
stride_uv = 0;
break;
case MEDIA_BUS_FMT_SBGGR8_1X8:
case MEDIA_BUS_FMT_SGBRG8_1X8:
case MEDIA_BUS_FMT_SGRBG8_1X8:
case MEDIA_BUS_FMT_SRGGB8_1X8:
data_fmt = C0_DF_BAYER;
imgsz_w = width;
stride_y = 0;//CAM_ALIGN(imgsz_w, 8);
imgsz_h = height;
stride_uv = 0;
break;
case MEDIA_BUS_FMT_SBGGR10_1X10:
case MEDIA_BUS_FMT_SGBRG10_1X10:
case MEDIA_BUS_FMT_SGRBG10_1X10:
case MEDIA_BUS_FMT_SRGGB10_1X10:
data_fmt = C0_DF_BAYER;
imgsz_w = width * 5 / 4;
stride_y = 0;//CAM_ALIGN(imgsz_w, 8);
imgsz_h = height;
stride_uv = 0;
break;
case MEDIA_BUS_FMT_SBGGR12_1X12:
case MEDIA_BUS_FMT_SGBRG12_1X12:
case MEDIA_BUS_FMT_SGRBG12_1X12:
case MEDIA_BUS_FMT_SRGGB12_1X12:
data_fmt = C0_DF_BAYER;
imgsz_w = width * 3 / 2;
stride_y = 0;//CAM_ALIGN(imgsz_w, 8);
imgsz_h = height;
stride_uv = 0;
break;
default:
pr_err("%s failed: invalid pixfmt %d\n", __func__, pix_fmt);
return -1;
}
dev_info(dev, "stride_y=0x%x, width=%u\n", stride_y, width);
ccic_reg_write(ccic_dev, REG_IMGPITCH, stride_uv << 16 | stride_y);
ccic_reg_write(ccic_dev, REG_IMGSIZE, imgsz_h << 16 | imgsz_w);
ccic_reg_write(ccic_dev, REG_IMGOFFSET, 0x0);
ccic_reg_write_mask(ccic_dev, REG_CTRL0, data_fmt, C0_DF_MASK);
/* Make sure it knows we want to use hsync/vsync. */
ccic_reg_write_mask(ccic_dev, REG_CTRL0, C0_SIF_HVSYNC, C0_SIFM_MASK);
/* Need set following bit for auto-recovery */
ccic_reg_set_bit(ccic_dev, REG_CTRL0, C0_EOFFLUSH);
return 0;
}
static int ccic_dma_set_addr(struct ccic_dma *dma_dev,
unsigned long addr_y,
unsigned long addr_u,
unsigned long addr_v)
{
struct ccic_dev *ccic_dev = dma_dev->ccic_dev;
ccic_reg_write(ccic_dev, 0x00, (u32)(addr_y & 0xffffffff));
ccic_reg_write(ccic_dev, 0x0c, (u32)(addr_u & 0xffffffff));
ccic_reg_write(ccic_dev, 0x18, (u32)(addr_v & 0xffffffff));
return 0;
}
static int ccic_dma_shadow_ready(struct ccic_dma *dma_dev)
{
struct ccic_dev *ccic_dev = dma_dev->ccic_dev;
ccic_reg_set_bit(ccic_dev, REG_CTRL1, C1_SHADOW_RDY);
return 0;
}
static int ccic_dma_src_select(struct ccic_dma *dma_dev, int src, unsigned int main_ccic_id)
{
struct ccic_dev *ccic_dev = dma_dev->ccic_dev;
return ccic_dma_src_sel(ccic_dev, src, main_ccic_id);
}
static void ccic_dma_dump_regs(struct ccic_dma *dma_dev)
{
unsigned int reg_val = 0;
struct ccic_dev *ccic_dev = dma_dev->ccic_dev;
reg_val = ccic_reg_read(ccic_dev, 0x30);
printk(KERN_INFO "ccic%d [0x30]=0x%08x\n", ccic_dev->index, reg_val);
reg_val = ccic_reg_read(ccic_dev, 0x28);
printk(KERN_INFO "ccic%d [0x28]=0x%08x\n", ccic_dev->index, reg_val);
reg_val = ccic_reg_read(ccic_dev, 0x2c);
printk(KERN_INFO "ccic%d [0x2c]=0x%08x\n", ccic_dev->index, reg_val);
reg_val = ccic_reg_read(ccic_dev, 0x24);
printk(KERN_INFO "ccic%d [0x24]=0x%08x\n", ccic_dev->index, reg_val);
reg_val = ccic_reg_read(ccic_dev, 0x34);
printk(KERN_INFO "ccic%d [0x34]=0x%08x\n", ccic_dev->index, reg_val);
reg_val = ccic_reg_read(ccic_dev, 0x38);
printk(KERN_INFO "ccic%d [0x38]=0x%08x\n", ccic_dev->index, reg_val);
reg_val = ccic_reg_read(ccic_dev, 0x3c);
printk(KERN_INFO "ccic%d [0x3c]=0x%08x\n", ccic_dev->index, reg_val);
reg_val = ccic_reg_read(ccic_dev, 0x40);
printk(KERN_INFO "ccic%d [0x40]=0x%08x\n", ccic_dev->index, reg_val);
reg_val = ccic_reg_read(ccic_dev, 0x44);
printk(KERN_INFO "ccic%d [0x44]=0x%08x\n", ccic_dev->index, reg_val);
reg_val = ccic_reg_read(ccic_dev, 0x48);
printk(KERN_INFO "ccic%d [0x48]=0x%08x\n", ccic_dev->index, reg_val);
reg_val = ccic_reg_read(ccic_dev, 0x310);
printk(KERN_INFO "ccic%d [0x310]=0x%08x\n", ccic_dev->index, reg_val);
reg_val = ccic_reg_read(ccic_dev, 0x60);
printk(KERN_INFO "ccic%d [0x60]=0x%08x\n", ccic_dev->index, reg_val);
reg_val = ccic_reg_read(ccic_dev, 0x23c);
printk(KERN_INFO "ccic%d [0x23c]=0x%08x\n", ccic_dev->index, reg_val);
reg_val = ccic_reg_read(ccic_dev, 0x128);
printk(KERN_INFO "ccic%d [0x128]=0x%08x\n", ccic_dev->index, reg_val);
reg_val = ccic_reg_read(ccic_dev, 0x12c);
printk(KERN_INFO "ccic%d [0x12c]=0x%08x\n", ccic_dev->index, reg_val);
reg_val = ccic_reg_read(ccic_dev, 0x134);
printk(KERN_INFO "ccic%d [0x134]=0x%08x\n", ccic_dev->index, reg_val);
reg_val = ccic_reg_read(ccic_dev, 0x138);
printk(KERN_INFO "ccic%d [0x138]=0x%08x\n", ccic_dev->index, reg_val);
reg_val = ccic_reg_read(ccic_dev, 0x100);
printk(KERN_INFO "ccic%d [0x100]=0x%08x\n", ccic_dev->index, reg_val);
reg_val = ccic_reg_read(ccic_dev, 0x140);
printk(KERN_INFO "ccic%d [0x140]=0x%08x\n", ccic_dev->index, reg_val);
reg_val = ccic_reg_read(ccic_dev, 0x144);
printk(KERN_INFO "ccic%d [0x144]=0x%08x\n", ccic_dev->index, reg_val);
reg_val = ccic_reg_read(ccic_dev, 0x124);
printk(KERN_INFO "ccic%d [0x124]=0x%08x\n", ccic_dev->index, reg_val);
}
static struct ccic_dma_ops ccic_dma_ops = {
.set_fmt = ccic_dma_set_fmt,
.shadow_ready = ccic_dma_shadow_ready,
.set_addr = ccic_dma_set_addr,
.ccic_enable = ccic_dma_enable,
.clk_enable = ccic_dma_clk_enable,
.src_sel = ccic_dma_src_select,
.dump_regs = ccic_dma_dump_regs,
};
/*
@@ -372,10 +573,13 @@ int ccic_clk_enable(struct ccic_ctrl *ctrl, int en)
pr_err("rpm get failed\n");
return ret;
}
pm_stay_awake(&ccic_dev->pdev->dev);
clk_prepare_enable(ccic_dev->dpu_clk);
reset_control_deassert(ccic_dev->mclk_reset);
//clk_prepare_enable(ccic_dev->ahb_clk);
reset_control_deassert(ccic_dev->ahb_reset);
clk_prepare_enable(ccic_dev->clk4x);
reset_control_deassert(ccic_dev->ccic_4x_reset);
clk_prepare_enable(ccic_dev->csi_clk);
@@ -394,9 +598,12 @@ int ccic_clk_enable(struct ccic_ctrl *ctrl, int en)
clk_disable_unprepare(ccic_dev->clk4x);
reset_control_assert(ccic_dev->ccic_4x_reset);
clk_disable_unprepare(ccic_dev->dpu_clk);
reset_control_assert(ccic_dev->mclk_reset);
//clk_disable_unprepare(ccic_dev->ahb_clk);
reset_control_assert(ccic_dev->ahb_reset);
pm_relax(&ccic_dev->pdev->dev);
pm_runtime_put_sync(&ccic_dev->pdev->dev);
}
@@ -405,13 +612,14 @@ int ccic_clk_enable(struct ccic_ctrl *ctrl, int en)
return ret;
}
int ccic_config_csi2_mbus(struct ccic_ctrl *ctrl, int md, u8 vc0, u8 vc1, int lanes)
int ccic_config_csi2_mbus(struct ccic_ctrl *ctrl, int md, u8 vc0, u8 vc1, u8 dt0, u8 dt1,
int lanes)
{
int ret;
struct ccic_dev *ccic_dev = ctrl->ccic_dev;
struct mipi_csi2 csi2para;
ret = ccic_config_csi2_vc(ctrl, md, vc0, vc1);
ret = ccic_config_csi2_vc_dt(ctrl, md, vc0, vc1, dt0, dt1);
if (ret)
return ret;
@@ -545,9 +753,16 @@ static int ccic_init_clk(struct ccic_dev *dev)
if (IS_ERR_OR_NULL(dev->isp_ci_reset))
return PTR_ERR(dev->isp_ci_reset);
dev->mclk_reset = devm_reset_control_get_optional_shared(&dev->pdev->dev, "mclk_reset");
if (IS_ERR_OR_NULL(dev->mclk_reset))
return PTR_ERR(dev->mclk_reset);
dev->csi_clk = devm_clk_get(&dev->pdev->dev, "csi_func");
if (IS_ERR(dev->csi_clk))
return PTR_ERR(dev->csi_clk);
dev->dpu_clk = devm_clk_get(&dev->pdev->dev, "dpu_mclk");
if (IS_ERR(dev->dpu_clk))
return PTR_ERR(dev->dpu_clk);
dev->clk4x = devm_clk_get(&dev->pdev->dev, "ccic_func");
return PTR_ERR_OR_ZERO(dev->clk4x);
@@ -650,6 +865,31 @@ void ccic_ctrl_put(struct ccic_ctrl *ctrl)
EXPORT_SYMBOL(ccic_ctrl_put);
int ccic_dma_get(struct ccic_dma **ccic_dma, int id)
{
struct ccic_dev *ccic_dev = NULL;
struct ccic_dev *tmp = NULL;
struct ccic_dma *dma = NULL;
list_for_each_entry(tmp, &ccic_devices, list) {
if (tmp->index == id) {
ccic_dev = tmp;
break;
}
}
if (!ccic_dev) {
pr_err("ccic%d not found", id);
return -ENODEV;
}
dma = ccic_dev->dma;
*ccic_dma = dma;
pr_debug("acquire ccic%d dma dev succeed\n", id);
return 0;
}
EXPORT_SYMBOL(ccic_dma_get);
static void ipe_error_irq_handler(struct ccic_dev *ccic, u32 ipestatus, u32 csi2status)
{
static DEFINE_RATELIMIT_STATE(rs, 5 * HZ, 20);
@@ -664,10 +904,110 @@ static void ipe_error_irq_handler(struct ccic_dev *ccic, u32 ipestatus, u32 csi2
}
}
static int ccic_put_dma_work(struct ccic_dma_context *dma_ctx,
struct ccic_dma_work_struct *ccic_dma_work)
{
unsigned long flags = 0;
spin_lock_irqsave(&dma_ctx->slock, flags);
list_del_init(&ccic_dma_work->busy_list_entry);
list_add(&ccic_dma_work->idle_list_entry, &dma_ctx->dma_work_idle_list);
spin_unlock_irqrestore(&dma_ctx->slock, flags);
return 0;
}
static int ccic_get_dma_work(struct ccic_dma_context *dma_ctx,
struct ccic_dma_work_struct **ccic_dma_work)
{
unsigned long flags = 0;
spin_lock_irqsave(&dma_ctx->slock, flags);
*ccic_dma_work = list_first_entry_or_null(&dma_ctx->dma_work_idle_list, struct ccic_dma_work_struct, idle_list_entry);
if (NULL == *ccic_dma_work) {
spin_unlock_irqrestore(&dma_ctx->slock, flags);
return -1;
}
list_del_init(&((*ccic_dma_work)->idle_list_entry));
list_add(&((*ccic_dma_work)->busy_list_entry), &dma_ctx->dma_work_busy_list);
spin_unlock_irqrestore(&dma_ctx->slock, flags);
return 0;
}
static void ccic_dma_bh_handler(struct ccic_dma_work_struct *ccic_dma_work)
{
struct spm_ccic_vnode *ac_vnode = ccic_dma_work->ac_vnode;
struct device *dev = ac_vnode->ccic_dev->dev;
struct ccic_dma_context *dma_ctx = &ac_vnode->dma_ctx;
struct spm_ccic_vbuffer *n = NULL, *pos = NULL;
//unsigned int irq_status = ccic_dma_work->irq_status;
LIST_HEAD(export_list);
unsigned long flags = 0;
spin_lock(&ac_vnode->waitq_head.lock);
ac_vnode->in_tasklet = 1;
if (ac_vnode->in_streamoff || !ac_vnode->is_streaming) {
wake_up_locked(&ac_vnode->waitq_head);
spin_unlock(&ac_vnode->waitq_head.lock);
goto dma_tasklet_finish;
}
wake_up_locked(&ac_vnode->waitq_head);
spin_unlock(&ac_vnode->waitq_head.lock);
spin_lock_irqsave(&ac_vnode->slock, flags);
list_for_each_entry_safe(pos, n, &ac_vnode->busy_list, list_entry) {
if (pos->flags & (AC_BUF_FLAG_HW_ERR | AC_BUF_FLAG_SW_ERR | AC_BUF_FLAG_DONE_TOUCH)) {
list_del_init(&(pos->list_entry));
atomic_dec(&ac_vnode->busy_buf_cnt);
list_add_tail(&(pos->list_entry), &export_list);
}
}
spin_unlock_irqrestore(&ac_vnode->slock, flags);
list_for_each_entry_safe(pos, n, &export_list, list_entry) {
if (!(pos->flags & AC_BUF_FLAG_SOF_TOUCH)) {
dev_warn(dev, "%s export buf index=%u frameid=%u without sof touch\n", ac_vnode->name, pos->vb2_v4l2_buf.vb2_buf.index, pos->vb2_v4l2_buf.sequence);
}
if (pos->flags & AC_BUF_FLAG_HW_ERR) {
//pos->vb2_v4l2_buf.flags |= V4L2_BUF_FLAG_ERROR_HW;
dev_warn(dev, "%s export buf index=%u frameid=%u with hw error\n", ac_vnode->name, pos->vb2_v4l2_buf.vb2_buf.index, pos->vb2_v4l2_buf.sequence);
spm_cvdev_export_ccic_vbuffer(pos, 1);
ac_vnode->hw_err_frm++;
} else if (pos->flags & AC_BUF_FLAG_SW_ERR) {
//pos->vb2_v4l2_buf.flags |= V4L2_BUF_FLAG_ERROR_SW;
dev_warn(dev, "%s export buf index=%u frameid=%u with sw error\n", ac_vnode->name, pos->vb2_v4l2_buf.vb2_buf.index, pos->vb2_v4l2_buf.sequence);
spm_cvdev_export_ccic_vbuffer(pos, 1);
ac_vnode->sw_err_frm++;
} else if (pos->flags & AC_BUF_FLAG_DONE_TOUCH) {
spm_cvdev_export_ccic_vbuffer(pos, 0);
ac_vnode->ok_frm++;
}
}
dma_tasklet_finish:
if (ac_vnode) {
spin_lock(&ac_vnode->waitq_head.lock);
ac_vnode->in_tasklet = 0;
wake_up_locked(&ac_vnode->waitq_head);
spin_unlock(&ac_vnode->waitq_head.lock);
}
ccic_put_dma_work(dma_ctx, ccic_dma_work);
}
static void ccic_dma_tasklet_handler(unsigned long param)
{
struct ccic_dma_work_struct *ccic_dma_work = (struct ccic_dma_work_struct*)param;
ccic_dma_bh_handler(ccic_dma_work);
}
static irqreturn_t k1x_ccic_isr(int irq, void *data)
{
struct ccic_dev *ccic_dev = data;
uint32_t irqs, csi2status;
struct spm_ccic_vnode *ac_vnode = (struct spm_ccic_vnode*)ccic_dev->vnode;
struct ccic_dma_context *dma_ctx = &ac_vnode->dma_ctx;
struct spm_ccic_vbuffer *pos = NULL, *ac_vb = NULL;
struct ccic_dma_work_struct *ccic_dma_work = NULL;
struct ccic_dma *ccic_dma = ac_vnode->ccic_dev->dma;
struct device *dev = ac_vnode->ccic_dev->dev;
uint32_t irqs = 0, csi2status = 0, tmp = 0;
int ret = 0;
irqs = ccic_reg_read(ccic_dev, REG_IRQSTAT);
if (!(irqs & ~IRQ_IDI_PRO_LINE))
@@ -682,8 +1022,8 @@ static irqreturn_t k1x_ccic_isr(int irq, void *data)
if (irqs & IRQ_DMA_PRO_LINE)
pr_debug("CCIC%d: IRQ_DMA_PRO_LINE\n", ccic_dev->index);
if (irqs & IRQ_IDI_PRO_LINE)
pr_debug("CCIC%d: IRQ_IDI_PRO_LINE\n", ccic_dev->index);
//if (irqs & IRQ_IDI_PRO_LINE)
// pr_debug("CCIC%d: IRQ_IDI_PRO_LINE\n", ccic_dev->index);
if (irqs & IRQ_CSI2IDI_FLUSH)
pr_debug("CCIC%d: IRQ_CSI2IDI_FLUSH\n", ccic_dev->index);
@@ -700,6 +1040,84 @@ static irqreturn_t k1x_ccic_isr(int irq, void *data)
if (irqs & IRQ_DPHY_LN_ULPS_ACTIVE)
pr_debug("CCIC%d: IRQ_DPHY_LN_ULPS_ACTIVE\n", ccic_dev->index);
//if (irqs & IRQ_DMA_SOF) {
// dev_dbg(dev, "CCIC%d: IRQ_DMA_SOF\n", ccic_dev->index);
//}
if (irqs & IRQ_DMA_SOF || irqs & IRQ_SHADOW_NOT_RDY) {
ac_vnode->frame_id++;
ac_vnode->total_frm++;
}
spin_lock(&ac_vnode->waitq_head.lock);
ac_vnode->in_irq = 1;
if (ac_vnode->in_streamoff) {
ac_vnode->in_irq = 0;
wake_up_locked(&ac_vnode->waitq_head);
spin_unlock(&ac_vnode->waitq_head.lock);
return IRQ_HANDLED;
}
spin_unlock(&ac_vnode->waitq_head.lock);
if (ac_vnode->is_streaming && (irqs & FRAMEIRQS)) {
//if (irqs & IRQ_CSI_SOF) {
if (irqs & IRQ_DMA_SOF || irqs & IRQ_SHADOW_NOT_RDY) {
spm_cvdev_dq_idle_vbuffer(ac_vnode, &ac_vb);
if (ac_vb) {
spm_cvdev_q_busy_vbuffer(ac_vnode, ac_vb);
ccic_update_dma_addr(ac_vnode, ac_vb, 0);
ccic_dma->ops->shadow_ready(ccic_dma);
}
}
tmp = irqs;
spin_lock(&(ac_vnode->slock));
list_for_each_entry(pos, &(ac_vnode->busy_list), list_entry) {
if (!tmp)
break;
if (tmp & (IRQ_DMA_OVERFLOW | IRQ_DMA_NOT_DONE)) {
if (!(pos->flags & AC_BUF_FLAG_SOF_TOUCH)) {
dev_info(dev, "CCIC%d: dma err(0x%08x) without sof, drop it\n", ccic_dev->index, tmp);
tmp &= ~(IRQ_DMA_OVERFLOW | IRQ_DMA_NOT_DONE);
} else if (!(pos->flags & AC_BUF_FLAG_HW_ERR)) {
pos->flags |= AC_BUF_FLAG_HW_ERR;
dev_info(dev, "CCIC%d: dma err(0x%08x)\n", ccic_dev->index, tmp);
tmp &= ~(IRQ_DMA_OVERFLOW | IRQ_DMA_NOT_DONE);
}
}
if (tmp & IRQ_DMA_EOF) {
if (!(pos->flags & AC_BUF_FLAG_SOF_TOUCH)) {
dev_info(dev, "CCIC%d: dma done without sof, drop it\n", ccic_dev->index);
tmp &= ~IRQ_DMA_EOF;
} else if (!(pos->flags & AC_BUF_FLAG_DONE_TOUCH)) {
pos->flags |= AC_BUF_FLAG_DONE_TOUCH;
pos->vb2_v4l2_buf.sequence = ac_vnode->frame_id - 1;
pos->vb2_v4l2_buf.vb2_buf.timestamp = ktime_get_ns();
tmp &= ~IRQ_DMA_EOF;
//dev_info(dev, "CCIC%d: dma done\n", ccic_dev->index);
}
}
if (tmp & IRQ_DMA_SOF) {
if (pos->flags & AC_BUF_FLAG_SOF_TOUCH) {
if (!(pos->flags & (AC_BUF_FLAG_DONE_TOUCH | AC_BUF_FLAG_HW_ERR | AC_BUF_FLAG_SW_ERR))) {
dev_warn(dev, "CCIC%d: next sof arrived without dma done or err\n", ccic_dev->index);
pos->flags |= AC_BUF_FLAG_SW_ERR;
}
} else {
pos->flags |= (AC_BUF_FLAG_SOF_TOUCH | AC_BUF_FLAG_TIMESTAMPED);
tmp &= ~IRQ_DMA_SOF;
}
}
}
spin_unlock(&(ac_vnode->slock));
ret = ccic_get_dma_work(dma_ctx, &ccic_dma_work);
if (ret) {
dev_warn(dev, "CCIC%d: dma work idle list was null\n", ccic_dev->index);
} else {
ccic_dma_work->irq_status = irqs;
tasklet_schedule(&(ccic_dma_work->dma_tasklet));
}
}
spin_lock(&ac_vnode->waitq_head.lock);
ac_vnode->in_irq = 0;
wake_up_locked(&ac_vnode->waitq_head);
spin_unlock(&ac_vnode->waitq_head.lock);
return IRQ_HANDLED;
}
@@ -710,10 +1128,8 @@ static int k1x_ccic_probe(struct platform_device *pdev)
struct ccic_ctrl *ccic_ctrl;
struct ccic_dma *ccic_dma;
struct device *dev = &pdev->dev;
char buf[32];
int ret;
int irq;
pr_debug("%s begin to probe\n", dev_name(&pdev->dev));
ret = of_property_read_u32(np, "cell-index", &pdev->id);
if (ret < 0) {
@@ -753,13 +1169,13 @@ static int k1x_ccic_probe(struct platform_device *pdev)
}
/* get irqs */
irq = platform_get_irq_byname(pdev, "ipe-irq");
if (irq < 0) {
ccic_dev->irq = platform_get_irq_byname(pdev, "ipe-irq");
if (ccic_dev->irq < 0) {
dev_err(&pdev->dev, "no irq resource");
return -ENODEV;
}
dev_dbg(&pdev->dev, "ipe irq: %d\n", irq);
ret = devm_request_irq(&pdev->dev, irq, k1x_ccic_isr,
ret = devm_request_irq(&pdev->dev, ccic_dev->irq, k1x_ccic_isr,
IRQF_SHARED, K1X_CCIC_DRV_NAME, ccic_dev);
if (ret) {
dev_err(&pdev->dev, "fail to request irq\n");
@@ -786,7 +1202,7 @@ static int k1x_ccic_probe(struct platform_device *pdev)
ccic_dev->dev = &pdev->dev;
ccic_dev->ctrl = ccic_ctrl;
ccic_dev->dma = ccic_dma;
ccic_dev->interrupt_mask_value = CSI2PHYERRS;
ccic_dev->interrupt_mask_value = CSI2PHYERRS | FRAMEIRQS;
dev_set_drvdata(dev, ccic_dev);
/* enable runtime pm */
@@ -796,7 +1212,24 @@ static int k1x_ccic_probe(struct platform_device *pdev)
ccic_device_register(ccic_dev);
pr_debug("%s probed", dev_name(&pdev->dev));
dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(33));
ret = v4l2_device_register(&pdev->dev, &ccic_dev->v4l2_dev);
if (ret) {
dev_err(&pdev->dev, "failed to register v4l2 dev\n");
return ret;
}
snprintf(buf, 32, "CCIC%d", ccic_ctrl->index);
ccic_dev->vnode = spm_cvdev_create_vnode(buf, ccic_dev->index,
&ccic_dev->v4l2_dev,
&pdev->dev,
ccic_dev,
ccic_dma_tasklet_handler,
0);
if (NULL == ccic_dev->vnode) {
dev_err(&pdev->dev, "failed to create ccic vnode\n");
return -EPROBE_DEFER;
}
pr_info("%s probed in %s", dev_name(&pdev->dev), __func__);
return ret;
}
@@ -809,6 +1242,8 @@ static int k1x_ccic_remove(struct platform_device *pdev)
ccic_dev = dev_get_drvdata(&pdev->dev);
dma = ccic_dev->dma;
spm_cvdev_destroy_vnode((struct spm_ccic_vnode*)ccic_dev->vnode);
v4l2_device_unregister(&ccic_dev->v4l2_dev);
ccic_device_unregister(ccic_dev);
/* disable runtime pm */

View File

@@ -48,8 +48,8 @@ struct mipi_csi2 {
int dphy_type; /* 0: DPHY on chip, 1: DPTC off chip */
u32 dphy[5]; /* DPHY: CSI2_DPHY1, CSI2_DPHY2, CSI2_DPHY3, CSI2_DPHY5, CSI2_DPHY6 */
int calc_dphy;
int enable_dpcm;
struct csi_dphy_desc dphy_desc;
int enable_dpcm;
};
#define HS_SETTLE_POS_MAX (100)
@@ -106,36 +106,27 @@ enum ccic_csi2vc_mode {
CCIC_CSI2VC_NM = 0,
CCIC_CSI2VC_VC,
CCIC_CSI2VC_DT,
CCIC_CSI2VC_VCDT,
};
enum ccic_csi2vc_chnl {
CCIC_CSI2VC_MAIN = 0,
CCIC_CSI2VC_VCDT,
CCIC_CSI2VC_SUB,
};
struct ccic_ctrl_ops {
void (*irq_mask)(struct ccic_ctrl *ctrl, int on);
int (*clk_enable)(struct ccic_ctrl *ctrl, int en);
int (*config_csi2_mbus)(struct ccic_ctrl *ctrl, int md, u8 vc0, u8 vc1,
int lanes);
int (*config_csi2_mbus)(struct ccic_ctrl *ctrl, int md, u8 vc0, u8 vc1, u8 dt0, u8 dt1, int lanes);
int (*config_csi2idi_mux)(struct ccic_ctrl *ctrl, int chnl, int idi, int en);
int (*reset_csi2idi)(struct ccic_ctrl *ctrl, int idi, int rst);
};
struct ccic_dma {
int index;
struct v4l2_device v4l2_dev;
struct video_device vdev;
struct ccic_dev *ccic_dev;
struct v4l2_pix_format pix_format;
struct mutex ops_mutex;
spinlock_t dev_lock;
struct list_head pending_bq;
struct list_head active_bq;
struct vb2_queue vb_queue;
u32 csi_sof_cnt;
u32 dma_sof_cnt;
u32 dma_eof_cnt;
struct ccic_dma_ops *ops;
};
@@ -148,11 +139,16 @@ enum ccic_dma_sel {
};
struct ccic_dma_ops {
int (*setup_image)(struct ccic_dma *dma_dev);
int (*shadow_ready)(struct ccic_dma *dma_dev, int enable);
int (*set_addr)(struct ccic_dma *dma_dev, u8 chnl, u32 addr);
int (*ccic_enable)(struct ccic_dma *dma_dev, int enable);
int (*clk_enable)(struct ccic_dma *dma_dev, int enable);
int (*set_fmt)(struct ccic_dma *dma_dev,
unsigned int width,
unsigned int height,
unsigned int pix_fmt);
int (*shadow_ready)(struct ccic_dma *dma_dev);
int (*set_addr)(struct ccic_dma *dma_dev, unsigned long addr_y, unsigned long addr_u, unsigned long addr_v);
int (*ccic_enable)(struct ccic_dma *dma_dev, int enable);
int (*clk_enable)(struct ccic_dma *dma_dev, int enable);
int (*src_sel)(struct ccic_dma *dma_dev, int src, unsigned int main_ccic_id);
void (*dump_regs)(struct ccic_dma *dma_dev);
};
struct ccic_dev {
@@ -160,17 +156,19 @@ struct ccic_dev {
struct device *dev;
struct platform_device *pdev;
struct list_head list;
struct resource *irq;
int irq;
struct resource *mem;
void __iomem *base;
struct clk *csi_clk;
struct clk *clk4x;
// struct clk *ahb_clk;
//struct clk *ahb_clk;
struct clk *axi_clk;
struct clk *dpu_clk;
struct reset_control *ahb_reset;
struct reset_control *csi_reset;
struct reset_control *ccic_4x_reset;
struct reset_control *isp_ci_reset;
struct reset_control *mclk_reset;
int dma_burst;
spinlock_t ccic_lock; /* protect the struct members and HW */
@@ -182,6 +180,8 @@ struct ccic_dev {
struct ccic_dma *dma;
/* object for csiphy part */
struct csiphy_device *csiphy;
struct v4l2_device v4l2_dev;
void *vnode;
};
/*
@@ -220,5 +220,6 @@ static inline void ccic_reg_clear_bit(struct ccic_dev *ccic_dev,
int ccic_ctrl_get(struct ccic_ctrl **ctrl_host, int id,
irqreturn_t(*handler) (struct ccic_ctrl *, u32));
int ccic_dma_get(struct ccic_dma **ccic_dma, int id);
int ccic_dphy_hssettle_set(unsigned int ccic_id, unsigned int dphy_freg);
#endif

View File

@@ -64,7 +64,7 @@ int ccic_csi2_lanes_enable(struct ccic_dev *ccic_dev, int lanes)
return 0;
}
#if 0
int ccic_csi2_vc_ctrl(struct ccic_dev *ccic_dev, int md, u8 vc0, u8 vc1)
{
int ret = 0;
@@ -94,27 +94,51 @@ int ccic_csi2_vc_ctrl(struct ccic_dev *ccic_dev, int md, u8 vc0, u8 vc1)
return ret;
}
int ccic_dma_src_sel(struct ccic_dev *ccic_dev, int sel)
#endif
int ccic_dma_src_sel(struct ccic_dev *ccic_dev, int sel, unsigned int main_ccic_id)
{
switch (sel) {
case CCIC_DMA_SEL_LOCAL_MAIN:
ccic_reg_clear_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_EXT_TIM_ENA);
ccic_reg_clear_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_VCDC_SEL);
/* FIXME: no need */
ccic_reg_set_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_ENABLE);
break;
case CCIC_DMA_SEL_LOCAL_VCDT:
ccic_reg_clear_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_EXT_TIM_ENA);
ccic_reg_set_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_VCDC_SEL);
ccic_reg_clear_bit(ccic_dev, REG_CSI2_CTRL0,
CSI2_C0_EXT_TIM_ENA);
ccic_reg_clear_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_VCDT_SEL);
/* FIXME: no need */
ccic_reg_set_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_ENABLE);
break;
case CCIC_DMA_SEL_REMOTE_VCDT:
ccic_reg_set_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_EXT_TIM_ENA);
ccic_reg_clear_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_VCDC_SEL);
/* When EXT_TIM_ENA is enabled, this field must be enabled too. */
ccic_reg_set_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_ENABLE);
if (ccic_dev->index == 0) {
if (main_ccic_id == 2) {
ccic_reg_set_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_EXT_TIM_ENA);
ccic_reg_clear_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_VCDT_SEL);
ccic_reg_set_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_ENABLE);
} else {
ccic_reg_set_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_EXT_TIM_ENA);
ccic_reg_set_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_VCDT_SEL);
ccic_reg_set_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_ENABLE);
}
} else if (ccic_dev->index == 1) {
if (main_ccic_id == 2) {
ccic_reg_set_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_EXT_TIM_ENA);
ccic_reg_clear_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_VCDT_SEL);
ccic_reg_set_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_ENABLE);
} else {
ccic_reg_set_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_EXT_TIM_ENA);
ccic_reg_set_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_VCDT_SEL);
ccic_reg_set_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_ENABLE);
}
} else {
if (main_ccic_id == 0) {
ccic_reg_set_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_EXT_TIM_ENA);
ccic_reg_clear_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_VCDT_SEL);
ccic_reg_set_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_ENABLE);
} else {
ccic_reg_set_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_EXT_TIM_ENA);
ccic_reg_set_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_VCDT_SEL);
/* When EXT_TIM_ENA is enabled, this field must be enabled too. */
ccic_reg_set_bit(ccic_dev, REG_CSI2_CTRL0, CSI2_C0_ENABLE);
}
}
break;
case CCIC_DMA_SEL_REMOTE_MAIN:
default:

View File

@@ -8,6 +8,9 @@
#ifndef __CCIC_HWREG_H__
#define __CCIC_HWREG_H__
#ifndef BIT
#define BIT(nr) (1 << (nr))
#endif
#define REG_Y0BAR 0x00
#define REG_U0BAR 0x0c
#define REG_V0BAR 0x18
@@ -51,7 +54,7 @@
#define IRQ_CSI2PARSE_ERR (BIT(29))
#define IRQ_CSI2GENSHORTPACKVALID (BIT(30))
#define IRQ_CSI2GENSHORTPACK_ERR (BIT(31))
// #define FRAMEIRQS (IRQ_CSI_SOF | IRQ_CSI_EOF | IRQ_DMA_SOF | IRQ_DMA_EOF)
// #define FRAMEIRQS (IRQ_CSI_SOF | IRQ_CSI_EOF | IRQ_DMA_SOF | IRQ_DMA_EOF | IRQ_DMA_OVERFLOW | IRQ_DMA_NOT_DONE | IRQ_SHADOW_NOT_RDY)
#define FRAMEIRQS (IRQ_DMA_SOF | IRQ_DMA_EOF | IRQ_DMA_OVERFLOW | IRQ_DMA_NOT_DONE | IRQ_SHADOW_NOT_RDY)
#define CSI2PHYERRS (0xFF0B0000)
#define ALLIRQS (FRAMEIRQS | CSI2PHYERRS | IRQ_CSI2IDI_HBLK2HSYNC)
@@ -151,7 +154,7 @@
#define CSI2_C0_EXT_TIM_ENA (0x1 << 3)
#define CSI2_C0_VLEN (0x4 << 4)
#define CSI2_C0_VLEN_MASK (0xf << 4)
#define CSI2_C0_VCDC_SEL (0x1 << 13)
#define CSI2_C0_VCDT_SEL (0x1 << 13)
#define REG_CSI2_VCCTRL 0x114
#define CSI2_VCCTRL_MD_MASK (0x3 << 0)
#define CSI2_VCCTRL_MD_NORMAL (0x0 << 0)
@@ -160,6 +163,17 @@
#define CSI2_VCCTRL_VC0_MASK (0x3 << 14)
#define CSI2_VCCTRL_DT1_MASK (0x3 << 16)
#define CSI2_VCCTRL_VC1_MASK (0x3 << 22)
#define CSI2_VCCTRL_DT_ENABLE (0x1 << 24)
#define REG_CSI2_DT_FLT 0x11c
#define CSI2_DT_FLT0_MASK (BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(4)|BIT(5))
#define CSI2_DT_FLT0_SHIFT (0)
#define CSI2_DT_FLT0_EN (BIT(6))
#define CSI2_DT_FLT1_MASK (BIT(8)|BIT(9)|BIT(10)|BIT(11)|BIT(12)|BIT(13))
#define CSI2_DT_FLT1_SHIFT (8)
#define CSI2_DT_FLT1_EN (BIT(14))
#define CSI2_DT_FLT2_MASK (BIT(16)|BIT(17)|BIT(18)|BIT(19)|BIT(20)|BIT(21))
#define CSI2_DT_FLT2_SHIFT (16)
#define CSI2_DT_FLT2_EN (BIT(22))
#define REG_CSI2_DPHY1 0x124
#define CSI2_DHPY1_ANA_PU (0x1 << 0)
#define CSI2_DHPY1_BIF_EN (0x1 << 1)
@@ -225,12 +239,11 @@
int ccic_csi2_config_dphy(struct ccic_dev *ccic_dev, int lanes, int enable);
int ccic_csi2_lanes_enable(struct ccic_dev *ccic_dev, int lanes);
int ccic_csi2_vc_ctrl(struct ccic_dev *ccic_dev, int md, u8 vc0, u8 vc1);
int ccic_dma_src_sel(struct ccic_dev *ccic_dev, int sel);
int ccic_dma_set_out_format(struct ccic_dev *ccic_dev, u32 pixfmt, u32 width,
u32 height);
//int ccic_csi2_vc_ctrl(struct ccic_dev *ccic_dev, int md, u8 vc0, u8 vc1);
int ccic_dma_src_sel(struct ccic_dev *ccic_dev, int sel, unsigned int main_ccic_id);
int ccic_dma_set_out_format(struct ccic_dev *ccic_dev, u32 pixfmt, u32 width, u32 height);
int ccic_dma_set_burst(struct ccic_dev *ccic_dev);
void ccic_dma_enable(struct ccic_dev *ccic_dev, int en);
//void ccic_dma_enable(struct ccic_dev *ccic_dev, int en);
int ccic_csi2idi_src_sel(struct ccic_dev *ccic_dev, int sel);
void ccic_csi2idi_reset(struct ccic_dev *ccic_dev, int reset);
void ccic_hw_dump_regs(struct ccic_dev *ccic_dev);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,174 @@
// SPDX-License-Identifier: GPL-2.0
/*
* vdev.h - video divece functions
*
* Copyright(C) 2019 SPM Micro Limited
*/
#ifndef _SPM_VDEV_H_
#define _SPM_VDEV_H_
#include <media/v4l2-dev.h>
#include <media/v4l2-device.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-v4l2.h>
#include <linux/notifier.h>
#include "ccic_drv.h"
#define CCIC_DMA_WORK_MAX_CNT (16)
struct spm_ccic_vbuffer;
struct spm_ccic_vnode;
struct ccic_dma_context
{
struct list_head dma_work_idle_list;
struct list_head dma_work_busy_list;
spinlock_t slock;
struct spm_ccic_vnode *ac_vnode;
};
struct spm_ccic_vnode {
struct video_device vnode;
char name[32];
struct vb2_queue buf_queue;
struct list_head queued_list;
struct list_head busy_list;
struct ccic_dma_context dma_ctx;
atomic_t queued_buf_cnt;
atomic_t busy_buf_cnt;
atomic_t ref_cnt;
spinlock_t slock;
struct mutex mlock;
struct v4l2_format cur_fmt;
struct wait_queue_head waitq_head;
int in_streamoff;
int in_tasklet;
int in_irq;
int is_streaming;
unsigned int idx;
unsigned int total_frm;
unsigned int sw_err_frm;
unsigned int hw_err_frm;
unsigned int ok_frm;
unsigned int planes_offset[VB2_MAX_FRAME][VB2_MAX_PLANES];
unsigned int v4l2_buf_flags[VB2_MAX_FRAME];
struct ccic_dev *ccic_dev;
int csi2vc;
int src_sel;
int lane_num;
int ccic_mode;
int ch_mode;
unsigned int main_ccic_id;
unsigned int main_vc;
unsigned int sub_vc;
unsigned int main_dt;
unsigned int sub_dt;
uint64_t frame_id;
void *usr_data;
};
struct ccic_dma_work_struct {
struct tasklet_struct dma_tasklet;
struct list_head idle_list_entry;
struct list_head busy_list_entry;
unsigned int irq_status;
struct spm_ccic_vnode *ac_vnode;
};
#define AC_BUF_FLAG_SOF_TOUCH (1 << 0)
#define AC_BUF_FLAG_DONE_TOUCH (1 << 1)
#define AC_BUF_FLAG_HW_ERR (1 << 2)
#define AC_BUF_FLAG_SW_ERR (1 << 3)
#define AC_BUF_FLAG_TIMESTAMPED (1 << 4)
#define AC_BUF_FLAG_CCIC_TOUCH (1 << 5)
#define AC_BUF_RESERVED_DATA_LEN (32)
struct spm_ccic_vbuffer {
struct vb2_v4l2_buffer vb2_v4l2_buf;
struct list_head list_entry;
unsigned int reset_flag;
unsigned int flags;
struct spm_ccic_vnode *ac_vnode;
unsigned char reserved[AC_BUF_RESERVED_DATA_LEN];
};
#define vb2_buffer_to_spm_ccic_vbuffer(vb) ((struct spm_ccic_vbuffer*)(vb))
#define CAM_ALIGN(a, b) ({ \
unsigned int ___tmp1 = (a); \
unsigned int ___tmp2 = (b); \
unsigned int ___tmp3 = ___tmp1 % ___tmp2; \
___tmp1 /= ___tmp2; \
if (___tmp3) \
___tmp1++; \
___tmp1 *= ___tmp2; \
___tmp1; \
})
#define is_vnode_streaming(vnode) ((vnode)->buf_queue.streaming)
static inline dma_addr_t spm_vb2_buf_paddr(struct vb2_buffer *vb, unsigned int plane_no)
{
unsigned int offset = 0;
dma_addr_t paddr = 0;
struct spm_ccic_vbuffer *ac_vb = vb2_buffer_to_spm_ccic_vbuffer(vb);
struct spm_ccic_vnode *ac_vnode = ac_vb->ac_vnode;
dma_addr_t *dma_addr = (dma_addr_t*)vb2_plane_cookie(vb, plane_no);
BUG_ON(!ac_vnode);
offset = ac_vnode->planes_offset[vb->index][plane_no];
paddr = *dma_addr + offset;
return paddr;
}
static inline void ccic_update_dma_addr(struct spm_ccic_vnode *ac_vnode,
struct spm_ccic_vbuffer *ac_vbuf, unsigned int offset)
{
dma_addr_t p0 = 0;
struct ccic_dma *ccic_dma = ac_vnode->ccic_dev->dma;
struct vb2_buffer *vb2_buf = &(ac_vbuf->vb2_v4l2_buf.vb2_buf);
p0 = spm_vb2_buf_paddr(vb2_buf, 0) + offset;
ccic_dma->ops->set_addr(ccic_dma, p0, 0, 0);
}
static inline void* ac_vnode_get_usrdata(struct spm_ccic_vnode *ac_vnode)
{
return ac_vnode->usr_data;
}
static inline struct spm_ccic_vbuffer* to_ccic_vbuffer(struct vb2_buffer *vb2)
{
struct vb2_v4l2_buffer *vb2_v4l2_buf = to_vb2_v4l2_buffer(vb2);
return container_of(vb2_v4l2_buf, struct spm_ccic_vbuffer, vb2_v4l2_buf);
}
struct spm_ccic_vnode* spm_cvdev_create_vnode(const char *name,
unsigned int idx,
struct v4l2_device *v4l2_dev,
struct device *alloc_dev,
struct ccic_dev *ccic_dev,
void (*dma_tasklet_handler)(unsigned long),
unsigned int min_buffers_needed);
void spm_cvdev_destroy_vnode(struct spm_ccic_vnode *ac_vnode);
int spm_cvdev_busy_list_empty(struct spm_ccic_vnode *ac_vnode);
int __spm_cvdev_busy_list_empty(struct spm_ccic_vnode *ac_vnode);
int spm_cvdev_idle_list_empty(struct spm_ccic_vnode *ac_vnode);
int __spm_cvdev_idle_list_empty(struct spm_ccic_vnode *ac_vnode);
int spm_cvdev_dq_idle_vbuffer(struct spm_ccic_vnode *ac_vnode, struct spm_ccic_vbuffer **ac_vb);
int spm_cvdev_pick_idle_vbuffer(struct spm_ccic_vnode *ac_vnode, struct spm_ccic_vbuffer **ac_vb);
int __spm_cvdev_pick_idle_vbuffer(struct spm_ccic_vnode *ac_vnode, struct spm_ccic_vbuffer **ac_vb);
int spm_cvdev_q_idle_vbuffer(struct spm_ccic_vnode *ac_vnode, struct spm_ccic_vbuffer *ac_vb);
int __spm_cvdev_dq_idle_vbuffer(struct spm_ccic_vnode *ac_vnode, struct spm_ccic_vbuffer **ac_vb);
int __spm_cvdev_q_idle_vbuffer(struct spm_ccic_vnode *ac_vnode, struct spm_ccic_vbuffer *ac_vb);
int spm_cvdev_dq_busy_vbuffer(struct spm_ccic_vnode *ac_vnode, struct spm_ccic_vbuffer **ac_vb);
int spm_cvdev_pick_busy_vbuffer(struct spm_ccic_vnode *ac_vnode, struct spm_ccic_vbuffer **ac_vb);
int __spm_cvdev_pick_busy_vbuffer(struct spm_ccic_vnode *ac_vnode, struct spm_ccic_vbuffer **ac_vb);
int spm_cvdev_q_busy_vbuffer(struct spm_ccic_vnode *ac_vnode, struct spm_ccic_vbuffer *ac_vb);
int __spm_cvdev_dq_busy_vbuffer(struct spm_ccic_vnode *ac_vnode, struct spm_ccic_vbuffer **ac_vb);
int __spm_cvdev_q_busy_vbuffer(struct spm_ccic_vnode *ac_vnode, struct spm_ccic_vbuffer *ac_vb);
int spm_cvdev_export_ccic_vbuffer(struct spm_ccic_vbuffer *ac_vb, int with_error);
void spm_cvdev_fill_v4l2_format(struct v4l2_format *f);
#endif

View File

@@ -1185,7 +1185,7 @@ static int csi_subdev_video_s_stream(struct v4l2_subdev *sd, int enable)
cam_err("%s(%s) config mux(enable) failed ret=%d", __func__, sc_subdev->name, ret);
return ret;
}
ret = csi_ctrl->ops->config_csi2_mbus(csi_ctrl, CCIC_CSI2VC_NM, 0, 0, mipi_lane_num);
ret = csi_ctrl->ops->config_csi2_mbus(csi_ctrl, CCIC_CSI2VC_NM, 0, 0, 0, 0, mipi_lane_num);
if (ret) {
cam_err("%s(%s) config mbus(enable) lane=%d failed ret=%d", __func__, sc_subdev->name, 4, ret);
return ret;
@@ -1193,7 +1193,7 @@ static int csi_subdev_video_s_stream(struct v4l2_subdev *sd, int enable)
csi_ctrl->ops->irq_mask(csi_ctrl, 1);
} else {
csi_ctrl->ops->irq_mask(csi_ctrl, 0);
csi_ctrl->ops->config_csi2_mbus(csi_ctrl, CCIC_CSI2VC_NM, 0, 0, 0);
csi_ctrl->ops->config_csi2_mbus(csi_ctrl, CCIC_CSI2VC_NM, 0, 0, 0, 0, 0);
csi_ctrl->ops->config_csi2idi_mux(csi_ctrl, csi2vc, csi2idi, 0);
csi_subdev_core_s_power(sd, 0);
}

View File

@@ -0,0 +1,37 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
* mars11_ccic_uapi.h - Driver uapi for SPACEMIT K1X CCIC
*
* Copyright (C) 2024 SPACEMIT Micro Limited
*/
#ifndef _UAPI_LINUX_K1X_CCIC_H_
#define _UAPI_LINUX_K1X_CCIC_H_
//#include <linux/videodev2.h>
enum {
CCIC_MODE_NM = 0,
CCIC_MODE_VC,
CCIC_MODE_VCDT,
};
enum {
CCIC_CH_MODE_MAIN = 0,
CCIC_CH_MODE_SUB,
};
struct v4l2_ccic_params {
unsigned int lane_num;
int ccic_mode;
int ch_mode;
unsigned int main_ccic_id;
unsigned int main_vc;
unsigned int sub_vc;
unsigned int main_dt;
unsigned int sub_dt;
};
#define BASE_VIDIOC_CCIC (BASE_VIDIOC_PRIVATE + 20)
#define VIDIOC_CCIC_S_PARAMS _IOWR('V', BASE_VIDIOC_CCIC + 1, struct v4l2_ccic_params)
#endif