media: rockchip: cif support rk3588

Signed-off-by: Zefa Chen <zefa.chen@rock-chips.com>
Change-Id: I4398f9163b858c8f7dd32c88f2f2d37a9f464bcc
This commit is contained in:
Zefa Chen
2021-10-14 17:54:36 +08:00
committed by Tao Huang
parent ac5a379e10
commit 2d1d48e930
16 changed files with 4551 additions and 478 deletions

View File

@@ -6,4 +6,6 @@ video_rkcif-objs += dev.o \
cif-luma.o \
hw.o \
subdev-itf.o \
procfs.o
procfs.o \
cif-scale.o \
common.o

File diff suppressed because it is too large Load Diff

View File

@@ -289,7 +289,7 @@ static void rkcif_luma_readout_task(unsigned long data)
void rkcif_luma_isr(struct rkcif_luma_vdev *luma_vdev, int mipi_id, u32 frame_id)
{
u8 hdr_mode = luma_vdev->cifdev->hdr.mode;
u8 hdr_mode = luma_vdev->cifdev->hdr.hdr_mode;
enum rkcif_luma_frm_mode frm_mode;
bool send_task;
u32 i, value;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,187 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2021 Rockchip Electronics Co., Ltd */
#include <media/videobuf2-dma-contig.h>
#include <media/videobuf2-dma-sg.h>
#include <linux/of_platform.h>
#include "dev.h"
#include "common.h"
static int rkcif_alloc_buffer(struct rkcif_device *dev,
struct rkcif_dummy_buffer *buf)
{
unsigned long attrs = buf->is_need_vaddr ? 0 : DMA_ATTR_NO_KERNEL_MAPPING;
const struct vb2_mem_ops *g_ops = dev->hw_dev->mem_ops;
struct sg_table *sg_tbl;
void *mem_priv;
int ret = 0;
if (!buf->size) {
ret = -EINVAL;
goto err;
}
if (dev->hw_dev->is_dma_contig)
attrs |= DMA_ATTR_FORCE_CONTIGUOUS;
buf->size = PAGE_ALIGN(buf->size);
mem_priv = g_ops->alloc(dev->hw_dev->dev, attrs, buf->size,
DMA_BIDIRECTIONAL, GFP_KERNEL | GFP_DMA32);
if (IS_ERR_OR_NULL(mem_priv)) {
ret = -ENOMEM;
goto err;
}
buf->mem_priv = mem_priv;
if (dev->hw_dev->is_dma_sg_ops) {
sg_tbl = (struct sg_table *)g_ops->cookie(mem_priv);
buf->dma_addr = sg_dma_address(sg_tbl->sgl);
g_ops->prepare(mem_priv);
} else {
buf->dma_addr = *((dma_addr_t *)g_ops->cookie(mem_priv));
}
if (buf->is_need_vaddr)
buf->vaddr = g_ops->vaddr(mem_priv);
if (buf->is_need_dbuf) {
buf->dbuf = g_ops->get_dmabuf(mem_priv, O_RDWR);
if (buf->is_need_dmafd) {
buf->dma_fd = dma_buf_fd(buf->dbuf, O_CLOEXEC);
if (buf->dma_fd < 0) {
dma_buf_put(buf->dbuf);
ret = buf->dma_fd;
goto err;
}
get_dma_buf(buf->dbuf);
}
}
v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev,
"%s buf:0x%x~0x%x size:%d\n", __func__,
(u32)buf->dma_addr, (u32)buf->dma_addr + buf->size, buf->size);
return ret;
err:
dev_err(dev->dev, "%s failed ret:%d\n", __func__, ret);
return ret;
}
static void rkcif_free_buffer(struct rkcif_device *dev,
struct rkcif_dummy_buffer *buf)
{
const struct vb2_mem_ops *g_ops = dev->hw_dev->mem_ops;
if (buf && buf->mem_priv) {
v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev,
"%s buf:0x%x~0x%x\n", __func__,
(u32)buf->dma_addr, (u32)buf->dma_addr + buf->size);
if (buf->dbuf)
dma_buf_put(buf->dbuf);
g_ops->put(buf->mem_priv);
buf->size = 0;
buf->dbuf = NULL;
buf->vaddr = NULL;
buf->mem_priv = NULL;
buf->is_need_dbuf = false;
buf->is_need_vaddr = false;
buf->is_need_dmafd = false;
}
}
static int rkcif_alloc_page_dummy_buf(struct rkcif_device *dev, struct rkcif_dummy_buffer *buf)
{
struct rkcif_hw *hw = dev->hw_dev;
u32 i, n_pages = PAGE_ALIGN(buf->size) >> PAGE_SHIFT;
struct page *page = NULL, **pages = NULL;
struct sg_table *sg = NULL;
int ret = -ENOMEM;
page = alloc_pages(GFP_KERNEL | GFP_DMA32, 0);
if (!page)
goto err;
pages = kvmalloc_array(n_pages, sizeof(struct page *), GFP_KERNEL);
if (!pages)
goto free_page;
for (i = 0; i < n_pages; i++)
pages[i] = page;
sg = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
if (!sg)
goto free_pages;
ret = sg_alloc_table_from_pages(sg, pages, n_pages, 0,
n_pages << PAGE_SHIFT, GFP_KERNEL);
if (ret)
goto free_sg;
ret = dma_map_sg(hw->dev, sg->sgl, sg->nents, DMA_BIDIRECTIONAL);
buf->dma_addr = sg_dma_address(sg->sgl);
buf->mem_priv = sg;
buf->pages = pages;
v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev,
"%s buf:0x%x map cnt:%d size:%d\n", __func__,
(u32)buf->dma_addr, ret, buf->size);
return 0;
free_sg:
kfree(sg);
free_pages:
kvfree(pages);
free_page:
__free_pages(page, 0);
err:
return ret;
}
static void rkcif_free_page_dummy_buf(struct rkcif_device *dev, struct rkcif_dummy_buffer *buf)
{
struct sg_table *sg = buf->mem_priv;
if (!sg)
return;
dma_unmap_sg(dev->hw_dev->dev, sg->sgl, sg->nents, DMA_BIDIRECTIONAL);
sg_free_table(sg);
kfree(sg);
__free_pages(buf->pages[0], 0);
kvfree(buf->pages);
buf->mem_priv = NULL;
buf->pages = NULL;
}
int rkcif_alloc_common_dummy_buf(struct rkcif_device *dev, struct rkcif_dummy_buffer *buf)
{
struct rkcif_hw *hw = dev->hw_dev;
int ret = 0;
mutex_lock(&hw->dev_lock);
if (buf->mem_priv)
goto end;
if (buf->size == 0)
goto end;
if (hw->iommu_en) {
ret = rkcif_alloc_page_dummy_buf(dev, buf);
goto end;
}
ret = rkcif_alloc_buffer(dev, buf);
if (!ret)
v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev,
"%s buf:0x%x size:%d\n", __func__,
(u32)buf->dma_addr, buf->size);
end:
if (ret < 0)
v4l2_err(&dev->v4l2_dev, "%s failed:%d\n", __func__, ret);
mutex_unlock(&hw->dev_lock);
return ret;
}
void rkcif_free_common_dummy_buf(struct rkcif_device *dev, struct rkcif_dummy_buffer *buf)
{
struct rkcif_hw *hw = dev->hw_dev;
mutex_lock(&hw->dev_lock);
if (hw->iommu_en)
rkcif_free_page_dummy_buf(dev, buf);
else
rkcif_free_buffer(dev, buf);
mutex_unlock(&hw->dev_lock);
}

View File

@@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2021 Rockchip Electronics Co., Ltd. */
#ifndef _RKCIF_COMMON_H
#define _RKCIF_COMMON_H
#include <linux/clk.h>
#include <linux/mutex.h>
#include <linux/media.h>
#include <media/media-device.h>
#include <media/media-entity.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/videobuf2-dma-contig.h>
#include <media/videobuf2-v4l2.h>
#include <media/v4l2-mc.h>
#include "dev.h"
int rkcif_alloc_common_dummy_buf(struct rkcif_device *dev, struct rkcif_dummy_buffer *buf);
void rkcif_free_common_dummy_buf(struct rkcif_device *dev, struct rkcif_dummy_buffer *buf);
#endif /* _RKCIF_COMMON_H */

View File

@@ -92,6 +92,9 @@ static ssize_t rkcif_store_compact_mode(struct device *dev,
return len;
}
static DEVICE_ATTR(compact_test, S_IWUSR | S_IRUSR,
rkcif_show_compact_mode, rkcif_store_compact_mode);
static ssize_t rkcif_show_line_int_num(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -109,9 +112,15 @@ static ssize_t rkcif_store_line_int_num(struct device *dev,
const char *buf, size_t len)
{
struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev);
struct sditf_priv *priv = cif_dev->sditf;
int val = 0;
int ret = 0;
if (priv->toisp_inf.link_mode != TOISP_NONE) {
dev_info(cif_dev->dev,
"current mode is on the fly, wake up mode wouldn't used\n");
return len;
}
ret = kstrtoint(buf, 0, &val);
if (!ret && val >= 0 && val <= 0x3fff)
cif_dev->wait_line_cache = val;
@@ -120,6 +129,9 @@ static ssize_t rkcif_store_line_int_num(struct device *dev,
return len;
}
static DEVICE_ATTR(wait_line, S_IWUSR | S_IRUSR,
rkcif_show_line_int_num, rkcif_store_line_int_num);
static ssize_t rkcif_show_dummybuf_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -152,8 +164,11 @@ static ssize_t rkcif_store_dummybuf_mode(struct device *dev,
return len;
}
/* show the compact mode of each stream in stream index order,
* 1 for compact, 0 for 16bit
static DEVICE_ATTR(is_use_dummybuf, S_IWUSR | S_IRUSR,
rkcif_show_dummybuf_mode, rkcif_store_dummybuf_mode);
/* show the memory mode of each stream in stream index order,
* 1 for high align, 0 for low align
*/
static ssize_t rkcif_show_memory_mode(struct device *dev,
struct device_attribute *attr,
@@ -210,24 +225,303 @@ static ssize_t rkcif_store_memory_mode(struct device *dev,
return len;
}
static DEVICE_ATTR(compact_test, S_IWUSR | S_IRUSR,
rkcif_show_compact_mode, rkcif_store_compact_mode);
static DEVICE_ATTR(wait_line, S_IWUSR | S_IRUSR,
rkcif_show_line_int_num, rkcif_store_line_int_num);
static DEVICE_ATTR(is_use_dummybuf, S_IWUSR | S_IRUSR,
rkcif_show_dummybuf_mode, rkcif_store_dummybuf_mode);
static DEVICE_ATTR(is_high_align, S_IWUSR | S_IRUSR,
rkcif_show_memory_mode, rkcif_store_memory_mode);
static ssize_t rkcif_show_scale_ch0_blc(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev);
int ret;
ret = snprintf(buf, PAGE_SIZE, "ch0 pattern00: %d, pattern01: %d, pattern02: %d, pattern03: %d\n",
cif_dev->scale_vdev[0].blc.pattern00,
cif_dev->scale_vdev[0].blc.pattern01,
cif_dev->scale_vdev[0].blc.pattern02,
cif_dev->scale_vdev[0].blc.pattern03);
return ret;
}
static ssize_t rkcif_store_scale_ch0_blc(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev);
int i = 0, index = 0;
unsigned int val[4] = {0};
unsigned int temp = 0;
int ret = 0;
int j = 0;
char cha[2] = {0};
if (buf) {
index = 0;
for (i = 0; i < len; i++) {
if (((buf[i] == ' ') || (buf[i] == '\n')) && j) {
index++;
j = 0;
if (index == 4)
break;
continue;
} else {
if (buf[i] < '0' || buf[i] > '9')
continue;
cha[0] = buf[i];
cha[1] = '\0';
ret = kstrtoint(cha, 0, &temp);
if (!ret) {
if (j)
val[index] *= 10;
val[index] += temp;
j++;
}
}
}
if (val[0] > 255 || val[1] > 255 || val[2] > 255 || val[3] > 255)
return -EINVAL;
cif_dev->scale_vdev[0].blc.pattern00 = val[0];
cif_dev->scale_vdev[0].blc.pattern01 = val[1];
cif_dev->scale_vdev[0].blc.pattern02 = val[2];
cif_dev->scale_vdev[0].blc.pattern03 = val[3];
dev_info(cif_dev->dev,
"set ch0 pattern00: %d, pattern01: %d, pattern02: %d, pattern03: %d\n",
cif_dev->scale_vdev[0].blc.pattern00,
cif_dev->scale_vdev[0].blc.pattern01,
cif_dev->scale_vdev[0].blc.pattern02,
cif_dev->scale_vdev[0].blc.pattern03);
}
return len;
}
static DEVICE_ATTR(scale_ch0_blc, S_IWUSR | S_IRUSR,
rkcif_show_scale_ch0_blc, rkcif_store_scale_ch0_blc);
static ssize_t rkcif_show_scale_ch1_blc(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev);
int ret;
ret = snprintf(buf, PAGE_SIZE, "ch1 pattern00: %d, pattern01: %d, pattern02: %d, pattern03: %d\n",
cif_dev->scale_vdev[1].blc.pattern00,
cif_dev->scale_vdev[1].blc.pattern01,
cif_dev->scale_vdev[1].blc.pattern02,
cif_dev->scale_vdev[1].blc.pattern03);
return ret;
}
static ssize_t rkcif_store_scale_ch1_blc(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev);
int i = 0, index = 0;
unsigned int val[4] = {0};
unsigned int temp = 0;
int ret = 0;
int j = 0;
char cha[2] = {0};
if (buf) {
index = 0;
for (i = 0; i < len; i++) {
if (((buf[i] == ' ') || (buf[i] == '\n')) && j) {
index++;
j = 0;
if (index == 4)
break;
continue;
} else {
if (buf[i] < '0' || buf[i] > '9')
continue;
cha[0] = buf[i];
cha[1] = '\0';
ret = kstrtoint(cha, 0, &temp);
if (!ret) {
if (j)
val[index] *= 10;
val[index] += temp;
j++;
}
}
}
if (val[0] > 255 || val[1] > 255 || val[2] > 255 || val[3] > 255)
return -EINVAL;
cif_dev->scale_vdev[1].blc.pattern00 = val[0];
cif_dev->scale_vdev[1].blc.pattern01 = val[1];
cif_dev->scale_vdev[1].blc.pattern02 = val[2];
cif_dev->scale_vdev[1].blc.pattern03 = val[3];
dev_info(cif_dev->dev,
"set ch1 pattern00: %d, pattern01: %d, pattern02: %d, pattern03: %d\n",
cif_dev->scale_vdev[1].blc.pattern00,
cif_dev->scale_vdev[1].blc.pattern01,
cif_dev->scale_vdev[1].blc.pattern02,
cif_dev->scale_vdev[1].blc.pattern03);
}
return len;
}
static DEVICE_ATTR(scale_ch1_blc, S_IWUSR | S_IRUSR,
rkcif_show_scale_ch1_blc, rkcif_store_scale_ch1_blc);
static ssize_t rkcif_show_scale_ch2_blc(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev);
int ret;
ret = snprintf(buf, PAGE_SIZE, "ch2 pattern00: %d, pattern01: %d, pattern02: %d, pattern03: %d\n",
cif_dev->scale_vdev[2].blc.pattern00,
cif_dev->scale_vdev[2].blc.pattern01,
cif_dev->scale_vdev[2].blc.pattern02,
cif_dev->scale_vdev[2].blc.pattern03);
return ret;
}
static ssize_t rkcif_store_scale_ch2_blc(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev);
int i = 0, index = 0;
unsigned int val[4] = {0};
unsigned int temp = 0;
int ret = 0;
int j = 0;
char cha[2] = {0};
if (buf) {
index = 0;
for (i = 0; i < len; i++) {
if (((buf[i] == ' ') || (buf[i] == '\n')) && j) {
index++;
j = 0;
if (index == 4)
break;
continue;
} else {
if (buf[i] < '0' || buf[i] > '9')
continue;
cha[0] = buf[i];
cha[1] = '\0';
ret = kstrtoint(cha, 0, &temp);
if (!ret) {
if (j)
val[index] *= 10;
val[index] += temp;
j++;
}
}
}
if (val[0] > 255 || val[1] > 255 || val[2] > 255 || val[3] > 255)
return -EINVAL;
cif_dev->scale_vdev[2].blc.pattern00 = val[0];
cif_dev->scale_vdev[2].blc.pattern01 = val[1];
cif_dev->scale_vdev[2].blc.pattern02 = val[2];
cif_dev->scale_vdev[2].blc.pattern03 = val[3];
dev_info(cif_dev->dev,
"set ch2 pattern00: %d, pattern01: %d, pattern02: %d, pattern03: %d\n",
cif_dev->scale_vdev[2].blc.pattern00,
cif_dev->scale_vdev[2].blc.pattern01,
cif_dev->scale_vdev[2].blc.pattern02,
cif_dev->scale_vdev[2].blc.pattern03);
}
return len;
}
static DEVICE_ATTR(scale_ch2_blc, S_IWUSR | S_IRUSR,
rkcif_show_scale_ch2_blc, rkcif_store_scale_ch2_blc);
static ssize_t rkcif_show_scale_ch3_blc(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev);
int ret;
ret = snprintf(buf, PAGE_SIZE, "ch3 pattern00: %d, pattern01: %d, pattern02: %d, pattern03: %d\n",
cif_dev->scale_vdev[3].blc.pattern00,
cif_dev->scale_vdev[3].blc.pattern01,
cif_dev->scale_vdev[3].blc.pattern02,
cif_dev->scale_vdev[3].blc.pattern03);
return ret;
}
static ssize_t rkcif_store_scale_ch3_blc(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct rkcif_device *cif_dev = (struct rkcif_device *)dev_get_drvdata(dev);
int i = 0, index = 0;
unsigned int val[4] = {0};
unsigned int temp = 0;
int ret = 0;
int j = 0;
char cha[2] = {0};
if (buf) {
index = 0;
for (i = 0; i < len; i++) {
if (((buf[i] == ' ') || (buf[i] == '\n')) && j) {
index++;
j = 0;
if (index == 4)
break;
continue;
} else {
if (buf[i] < '0' || buf[i] > '9')
continue;
cha[0] = buf[i];
cha[1] = '\0';
ret = kstrtoint(cha, 0, &temp);
if (!ret) {
if (j)
val[index] *= 10;
val[index] += temp;
j++;
}
}
}
if (val[0] > 255 || val[1] > 255 || val[2] > 255 || val[3] > 255)
return -EINVAL;
cif_dev->scale_vdev[3].blc.pattern00 = val[0];
cif_dev->scale_vdev[3].blc.pattern01 = val[1];
cif_dev->scale_vdev[3].blc.pattern02 = val[2];
cif_dev->scale_vdev[3].blc.pattern03 = val[3];
dev_info(cif_dev->dev,
"set ch3 pattern00: %d, pattern01: %d, pattern02: %d, pattern03: %d\n",
cif_dev->scale_vdev[3].blc.pattern00,
cif_dev->scale_vdev[3].blc.pattern01,
cif_dev->scale_vdev[3].blc.pattern02,
cif_dev->scale_vdev[3].blc.pattern03);
}
return len;
}
static DEVICE_ATTR(scale_ch3_blc, S_IWUSR | S_IRUSR,
rkcif_show_scale_ch3_blc, rkcif_store_scale_ch3_blc);
static struct attribute *dev_attrs[] = {
&dev_attr_compact_test.attr,
&dev_attr_wait_line.attr,
&dev_attr_is_use_dummybuf.attr,
&dev_attr_is_high_align.attr,
&dev_attr_scale_ch0_blc.attr,
&dev_attr_scale_ch1_blc.attr,
&dev_attr_scale_ch2_blc.attr,
&dev_attr_scale_ch3_blc.attr,
NULL,
};
@@ -244,11 +538,17 @@ void rkcif_write_register(struct rkcif_device *dev,
{
void __iomem *base = dev->hw_dev->base_addr;
const struct cif_reg *reg = &dev->hw_dev->cif_regs[index];
int csi_offset = 0;
if (dev->inf_id == RKCIF_MIPI_LVDS &&
dev->chip_id == CHIP_RK3588_CIF &&
index >= CIF_REG_MIPI_LVDS_ID0_CTRL0 &&
index <= CIF_REG_MIPI_ON_PAD)
csi_offset = dev->csi_host_idx * 0x100;
if (index < CIF_REG_INDEX_MAX) {
if (index == CIF_REG_DVP_CTRL ||
(index != CIF_REG_DVP_CTRL && reg->offset != 0x0))
write_cif_reg(base, reg->offset, val);
write_cif_reg(base, reg->offset + csi_offset, val);
else
v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev,
"write reg[%d]:0x%x failed, maybe useless!!!\n",
@@ -262,13 +562,20 @@ void rkcif_write_register_or(struct rkcif_device *dev,
unsigned int reg_val = 0x0;
void __iomem *base = dev->hw_dev->base_addr;
const struct cif_reg *reg = &dev->hw_dev->cif_regs[index];
int csi_offset = 0;
if (dev->inf_id == RKCIF_MIPI_LVDS &&
dev->chip_id == CHIP_RK3588_CIF &&
index >= CIF_REG_MIPI_LVDS_ID0_CTRL0 &&
index <= CIF_REG_MIPI_ON_PAD)
csi_offset = dev->csi_host_idx * 0x100;
if (index < CIF_REG_INDEX_MAX) {
if (index == CIF_REG_DVP_CTRL ||
(index != CIF_REG_DVP_CTRL && reg->offset != 0x0)) {
reg_val = read_cif_reg(base, reg->offset);
reg_val = read_cif_reg(base, reg->offset + csi_offset);
reg_val |= val;
write_cif_reg(base, reg->offset, reg_val);
write_cif_reg(base, reg->offset + csi_offset, reg_val);
} else {
v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev,
"write reg[%d]:0x%x with OR failed, maybe useless!!!\n",
@@ -283,13 +590,20 @@ void rkcif_write_register_and(struct rkcif_device *dev,
unsigned int reg_val = 0x0;
void __iomem *base = dev->hw_dev->base_addr;
const struct cif_reg *reg = &dev->hw_dev->cif_regs[index];
int csi_offset = 0;
if (dev->inf_id == RKCIF_MIPI_LVDS &&
dev->chip_id == CHIP_RK3588_CIF &&
index >= CIF_REG_MIPI_LVDS_ID0_CTRL0 &&
index <= CIF_REG_MIPI_ON_PAD)
csi_offset = dev->csi_host_idx * 0x100;
if (index < CIF_REG_INDEX_MAX) {
if (index == CIF_REG_DVP_CTRL ||
(index != CIF_REG_DVP_CTRL && reg->offset != 0x0)) {
reg_val = read_cif_reg(base, reg->offset);
reg_val = read_cif_reg(base, reg->offset + csi_offset);
reg_val &= val;
write_cif_reg(base, reg->offset, reg_val);
write_cif_reg(base, reg->offset + csi_offset, reg_val);
} else {
v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev,
"write reg[%d]:0x%x with OR failed, maybe useless!!!\n",
@@ -304,11 +618,18 @@ unsigned int rkcif_read_register(struct rkcif_device *dev,
unsigned int val = 0x0;
void __iomem *base = dev->hw_dev->base_addr;
const struct cif_reg *reg = &dev->hw_dev->cif_regs[index];
int csi_offset = 0;
if (dev->inf_id == RKCIF_MIPI_LVDS &&
dev->chip_id == CHIP_RK3588_CIF &&
index >= CIF_REG_MIPI_LVDS_ID0_CTRL0 &&
index <= CIF_REG_MIPI_ON_PAD)
csi_offset = dev->csi_host_idx * 0x100;
if (index < CIF_REG_INDEX_MAX) {
if (index == CIF_REG_DVP_CTRL ||
(index != CIF_REG_DVP_CTRL && reg->offset != 0x0))
val = read_cif_reg(base, reg->offset);
val = read_cif_reg(base, reg->offset + csi_offset);
else
v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev,
"read reg[%d] failed, maybe useless!!!\n",
@@ -375,6 +696,12 @@ void rkcif_enable_dvp_clk_dual_edge(struct rkcif_device *dev, bool on)
else
val = CIF_SAMPLING_EDGE_SINGLE;
rkcif_write_grf_reg(dev, CIF_REG_GRF_CIFIO_CON, val);
} else if (dev->chip_id == CHIP_RK3588_CIF) {
if (on)
val = RK3588_CIF_PCLK_DUAL_EDGE;
else
val = RK3588_CIF_PCLK_SINGLE_EDGE;
rkcif_write_grf_reg(dev, CIF_REG_GRF_CIFIO_CON, val);
}
}
@@ -402,6 +729,13 @@ void rkcif_config_dvp_clk_sampling_edge(struct rkcif_device *dev,
else
val = RK3568_CIF_PCLK_SAMPLING_EDGE_FALLING;
}
if (dev->chip_id == CHIP_RK3588_CIF) {
if (edge == RKCIF_CLK_RISING)
val = RK3588_CIF_PCLK_SAMPLING_EDGE_RISING;
else
val = RK3588_CIF_PCLK_SAMPLING_EDGE_FALLING;
}
rkcif_write_grf_reg(dev, CIF_REG_GRF_CIFIO_CON, val);
}
}
@@ -490,7 +824,7 @@ static int rkcif_pipeline_set_stream(struct rkcif_pipeline *p, bool on)
bool can_be_set = false;
int i, ret;
if (cif_dev->hdr.mode == NO_HDR) {
if (cif_dev->hdr.hdr_mode == NO_HDR) {
if ((on && atomic_inc_return(&p->stream_cnt) > 1) ||
(!on && atomic_dec_return(&p->stream_cnt) > 0))
return 0;
@@ -504,6 +838,9 @@ static int rkcif_pipeline_set_stream(struct rkcif_pipeline *p, bool on)
cif_dev->irq_stats.dvp_overflow_cnt = 0;
cif_dev->irq_stats.dvp_pix_err_cnt = 0;
cif_dev->irq_stats.all_err_cnt = 0;
cif_dev->irq_stats.csi_size_err_cnt = 0;
cif_dev->irq_stats.dvp_size_err_cnt = 0;
cif_dev->irq_stats.dvp_bwidth_lack_cnt = 0;
cif_dev->irq_stats.all_frm_end_cnt = 0;
cif_dev->reset_watchdog_timer.is_triggered = false;
cif_dev->reset_watchdog_timer.is_running = false;
@@ -524,14 +861,14 @@ static int rkcif_pipeline_set_stream(struct rkcif_pipeline *p, bool on)
if (on) {
atomic_inc(&p->stream_cnt);
if (cif_dev->hdr.mode == HDR_X2) {
if (cif_dev->hdr.hdr_mode == HDR_X2) {
if (atomic_read(&p->stream_cnt) == 1) {
rockchip_set_system_status(SYS_STATUS_CIF0);
can_be_set = false;
} else if (atomic_read(&p->stream_cnt) == 2) {
can_be_set = true;
}
} else if (cif_dev->hdr.mode == HDR_X3) {
} else if (cif_dev->hdr.hdr_mode == HDR_X3) {
if (atomic_read(&p->stream_cnt) == 1) {
rockchip_set_system_status(SYS_STATUS_CIF0);
can_be_set = false;
@@ -549,7 +886,10 @@ static int rkcif_pipeline_set_stream(struct rkcif_pipeline *p, bool on)
cif_dev->irq_stats.dvp_line_err_cnt = 0;
cif_dev->irq_stats.dvp_overflow_cnt = 0;
cif_dev->irq_stats.dvp_pix_err_cnt = 0;
cif_dev->irq_stats.dvp_bwidth_lack_cnt = 0;
cif_dev->irq_stats.all_err_cnt = 0;
cif_dev->irq_stats.csi_size_err_cnt = 0;
cif_dev->irq_stats.dvp_size_err_cnt = 0;
cif_dev->irq_stats.all_frm_end_cnt = 0;
cif_dev->is_start_hdr = true;
cif_dev->reset_watchdog_timer.is_triggered = false;
@@ -581,98 +921,104 @@ err_stream_off:
return ret;
}
/***************************** media controller *******************************/
static int rkcif_create_links(struct rkcif_device *dev)
static int rkcif_create_link(struct rkcif_device *dev,
struct rkcif_sensor_info *sensor,
u32 stream_num,
bool *mipi_lvds_linked)
{
int ret;
u32 flags;
unsigned int s, pad, id, stream_num = 0;
bool mipi_lvds_linked = false;
struct rkcif_sensor_info linked_sensor;
struct media_entity *source_entity, *sink_entity;
int ret = 0;
u32 flags, pad, id;
if (dev->chip_id < CHIP_RV1126_CIF) {
if (dev->inf_id == RKCIF_MIPI_LVDS)
stream_num = RKCIF_MAX_STREAM_MIPI;
else
stream_num = RKCIF_SINGLE_STREAM;
linked_sensor.lanes = sensor->lanes;
if (sensor->mbus.type == V4L2_MBUS_CCP2) {
linked_sensor.sd = &dev->lvds_subdev.sd;
dev->lvds_subdev.sensor_self.sd = &dev->lvds_subdev.sd;
dev->lvds_subdev.sensor_self.lanes = sensor->lanes;
memcpy(&dev->lvds_subdev.sensor_self.mbus, &sensor->mbus,
sizeof(struct v4l2_mbus_config));
} else {
stream_num = RKCIF_MAX_STREAM_MIPI;
linked_sensor.sd = sensor->sd;
}
/* sensor links(or mipi-phy) */
for (s = 0; s < dev->num_sensors; ++s) {
struct rkcif_sensor_info *sensor = &dev->sensors[s];
struct rkcif_sensor_info linked_sensor;
struct media_entity *source_entity, *sink_entity;
memcpy(&linked_sensor.mbus, &sensor->mbus,
sizeof(struct v4l2_mbus_config));
linked_sensor.lanes = sensor->lanes;
for (pad = 0; pad < linked_sensor.sd->entity.num_pads; pad++) {
if (linked_sensor.sd->entity.pads[pad].flags &
MEDIA_PAD_FL_SOURCE) {
if (pad == linked_sensor.sd->entity.num_pads) {
dev_err(dev->dev,
"failed to find src pad for %s\n",
linked_sensor.sd->name);
if (sensor->mbus.type == V4L2_MBUS_CCP2) {
linked_sensor.sd = &dev->lvds_subdev.sd;
dev->lvds_subdev.sensor_self.sd = &dev->lvds_subdev.sd;
dev->lvds_subdev.sensor_self.lanes = sensor->lanes;
memcpy(&dev->lvds_subdev.sensor_self.mbus, &sensor->mbus,
sizeof(struct v4l2_mbus_config));
} else {
linked_sensor.sd = sensor->sd;
}
break;
}
memcpy(&linked_sensor.mbus, &sensor->mbus,
sizeof(struct v4l2_mbus_config));
if ((linked_sensor.mbus.type == V4L2_MBUS_BT656 ||
linked_sensor.mbus.type == V4L2_MBUS_PARALLEL) &&
(dev->chip_id == CHIP_RK1808_CIF)) {
source_entity = &linked_sensor.sd->entity;
sink_entity = &dev->stream[RKCIF_STREAM_CIF].vnode.vdev.entity;
for (pad = 0; pad < linked_sensor.sd->entity.num_pads; pad++) {
if (linked_sensor.sd->entity.pads[pad].flags &
MEDIA_PAD_FL_SOURCE) {
if (pad == linked_sensor.sd->entity.num_pads) {
dev_err(dev->dev,
"failed to find src pad for %s\n",
ret = media_create_pad_link(source_entity,
pad,
sink_entity,
0,
MEDIA_LNK_FL_ENABLED);
if (ret)
dev_err(dev->dev, "failed to create link for %s\n",
linked_sensor.sd->name);
break;
}
if ((linked_sensor.mbus.type == V4L2_MBUS_BT656 ||
linked_sensor.mbus.type == V4L2_MBUS_PARALLEL) &&
(dev->chip_id >= CHIP_RV1126_CIF)) {
source_entity = &linked_sensor.sd->entity;
sink_entity = &dev->stream[pad].vnode.vdev.entity;
ret = media_create_pad_link(source_entity,
pad,
sink_entity,
0,
MEDIA_LNK_FL_ENABLED);
if (ret)
dev_err(dev->dev, "failed to create link for %s pad[%d]\n",
linked_sensor.sd->name, pad);
continue;
}
for (id = 0; id < stream_num; id++) {
source_entity = &linked_sensor.sd->entity;
sink_entity = &dev->stream[id].vnode.vdev.entity;
if ((dev->chip_id < CHIP_RK1808_CIF) ||
(id == pad - 1 && !(*mipi_lvds_linked)))
flags = MEDIA_LNK_FL_ENABLED;
else
flags = 0;
ret = media_create_pad_link(source_entity,
pad,
sink_entity,
0,
flags);
if (ret) {
dev_err(dev->dev,
"failed to create link for %s\n",
linked_sensor.sd->name);
break;
}
if ((linked_sensor.mbus.type == V4L2_MBUS_BT656 ||
linked_sensor.mbus.type == V4L2_MBUS_PARALLEL) &&
(dev->chip_id == CHIP_RK1808_CIF)) {
source_entity = &linked_sensor.sd->entity;
sink_entity = &dev->stream[RKCIF_STREAM_CIF].vnode.vdev.entity;
ret = media_create_pad_link(source_entity,
pad,
sink_entity,
0,
MEDIA_LNK_FL_ENABLED);
if (ret)
dev_err(dev->dev, "failed to create link for %s\n",
linked_sensor.sd->name);
break;
}
if ((linked_sensor.mbus.type == V4L2_MBUS_BT656 ||
linked_sensor.mbus.type == V4L2_MBUS_PARALLEL) &&
(dev->chip_id >= CHIP_RV1126_CIF)) {
source_entity = &linked_sensor.sd->entity;
sink_entity = &dev->stream[pad].vnode.vdev.entity;
ret = media_create_pad_link(source_entity,
pad,
sink_entity,
0,
MEDIA_LNK_FL_ENABLED);
if (ret)
dev_err(dev->dev, "failed to create link for %s pad[%d]\n",
linked_sensor.sd->name, pad);
continue;
}
}
if (dev->chip_id == CHIP_RK3588_CIF) {
for (id = 0; id < stream_num; id++) {
source_entity = &linked_sensor.sd->entity;
sink_entity = &dev->stream[id].vnode.vdev.entity;
sink_entity = &dev->scale_vdev[id].vnode.vdev.entity;
if ((dev->chip_id != CHIP_RK1808_CIF &&
dev->chip_id != CHIP_RV1126_CIF &&
dev->chip_id != CHIP_RV1126_CIF_LITE &&
dev->chip_id != CHIP_RK3568_CIF) ||
(id == pad - 1 && !mipi_lvds_linked))
if ((id + stream_num) == pad - 1 && !(*mipi_lvds_linked))
flags = MEDIA_LNK_FL_ENABLED;
else
flags = 0;
@@ -691,24 +1037,49 @@ static int rkcif_create_links(struct rkcif_device *dev)
}
}
}
}
if (sensor->mbus.type == V4L2_MBUS_CCP2) {
source_entity = &sensor->sd->entity;
sink_entity = &linked_sensor.sd->entity;
ret = media_create_pad_link(source_entity,
1,
sink_entity,
0,
MEDIA_LNK_FL_ENABLED);
if (ret)
dev_err(dev->dev, "failed to create link between %s and %s\n",
linked_sensor.sd->name,
sensor->sd->name);
}
if (sensor->mbus.type == V4L2_MBUS_CCP2) {
source_entity = &sensor->sd->entity;
sink_entity = &linked_sensor.sd->entity;
ret = media_create_pad_link(source_entity,
1,
sink_entity,
0,
MEDIA_LNK_FL_ENABLED);
if (ret)
dev_err(dev->dev, "failed to create link between %s and %s\n",
linked_sensor.sd->name,
sensor->sd->name);
}
if (linked_sensor.mbus.type != V4L2_MBUS_BT656 &&
linked_sensor.mbus.type != V4L2_MBUS_PARALLEL)
mipi_lvds_linked = true;
if (linked_sensor.mbus.type != V4L2_MBUS_BT656 &&
linked_sensor.mbus.type != V4L2_MBUS_PARALLEL)
*mipi_lvds_linked = true;
return ret;
}
/***************************** media controller *******************************/
static int rkcif_create_links(struct rkcif_device *dev)
{
u32 s = 0;
u32 stream_num = 0;
bool mipi_lvds_linked = false;
if (dev->chip_id < CHIP_RV1126_CIF) {
if (dev->inf_id == RKCIF_MIPI_LVDS)
stream_num = RKCIF_MAX_STREAM_MIPI;
else
stream_num = RKCIF_SINGLE_STREAM;
} else {
stream_num = RKCIF_MAX_STREAM_MIPI;
}
/* sensor links(or mipi-phy) */
for (s = 0; s < dev->num_sensors; ++s) {
struct rkcif_sensor_info *sensor = &dev->sensors[s];
rkcif_create_link(dev, sensor, stream_num, &mipi_lvds_linked);
}
return 0;
@@ -762,7 +1133,8 @@ static int subdev_notifier_complete(struct v4l2_async_notifier *notifier)
}
if (sensor->mbus.type == V4L2_MBUS_CCP2 ||
sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) {
sensor->mbus.type == V4L2_MBUS_CSI2_DPHY ||
sensor->mbus.type == V4L2_MBUS_CSI2_CPHY) {
switch (sensor->mbus.flags & V4L2_MBUS_CSI2_LANES) {
case V4L2_MBUS_CSI2_1_LANE:
@@ -870,12 +1242,14 @@ static int rkcif_fwnode_parse(struct device *dev,
if (vep->bus_type != V4L2_MBUS_BT656 &&
vep->bus_type != V4L2_MBUS_PARALLEL &&
vep->bus_type != V4L2_MBUS_CSI2_DPHY &&
vep->bus_type != V4L2_MBUS_CSI2_CPHY &&
vep->bus_type != V4L2_MBUS_CCP2)
return 0;
rk_asd->mbus.type = vep->bus_type;
if (vep->bus_type == V4L2_MBUS_CSI2_DPHY) {
if (vep->bus_type == V4L2_MBUS_CSI2_DPHY ||
vep->bus_type == V4L2_MBUS_CSI2_CPHY) {
rk_asd->mbus.flags = vep->bus.mipi_csi2.flags;
rk_asd->lanes = vep->bus.mipi_csi2.num_data_lanes;
} else if (vep->bus_type == V4L2_MBUS_CCP2) {
@@ -942,6 +1316,14 @@ static int rkcif_register_platform_subdevs(struct rkcif_device *cif_dev)
return -EINVAL;
}
if (cif_dev->chip_id == CHIP_RK3588_CIF) {
ret = rkcif_register_scale_vdevs(cif_dev, RKCIF_MAX_SCALE_CH, true);
if (ret < 0) {
dev_err(cif_dev->dev, "cif register scale_vdev[%d] failed!\n", stream_num);
goto err_unreg_stream_vdev;
}
}
ret = cif_subdev_notifier(cif_dev);
if (ret < 0) {
v4l2_err(&cif_dev->v4l2_dev,
@@ -952,17 +1334,22 @@ static int rkcif_register_platform_subdevs(struct rkcif_device *cif_dev)
return 0;
err_unreg_stream_vdev:
rkcif_unregister_stream_vdevs(cif_dev, stream_num);
if (cif_dev->chip_id == CHIP_RK3588_CIF)
rkcif_unregister_scale_vdevs(cif_dev, RKCIF_MAX_SCALE_CH);
return ret;
}
static irqreturn_t rkcif_irq_handler(int irq, struct rkcif_device *cif_dev)
{
if (cif_dev->workmode == RKCIF_WORKMODE_PINGPONG)
rkcif_irq_pingpong(cif_dev);
else
if (cif_dev->workmode == RKCIF_WORKMODE_PINGPONG) {
if (cif_dev->chip_id < CHIP_RK3588_CIF)
rkcif_irq_pingpong(cif_dev);
else
rkcif_irq_pingpong_v1(cif_dev);
} else {
rkcif_irq_oneframe(cif_dev);
}
return IRQ_HANDLED;
}
@@ -1149,10 +1536,11 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int
struct v4l2_device *v4l2_dev;
int ret;
cif_dev->hdr.mode = NO_HDR;
cif_dev->hdr.hdr_mode = NO_HDR;
cif_dev->inf_id = inf_id;
mutex_init(&cif_dev->stream_lock);
mutex_init(&cif_dev->scale_lock);
spin_lock_init(&cif_dev->hdr_lock);
spin_lock_init(&cif_dev->reset_watchdog_timer.timer_lock);
spin_lock_init(&cif_dev->reset_watchdog_timer.csi2_err_lock);
@@ -1164,6 +1552,7 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int
cif_dev->pipe.close = rkcif_pipeline_close;
cif_dev->pipe.set_stream = rkcif_pipeline_set_stream;
cif_dev->isr_hdl = rkcif_irq_handler;
cif_dev->id_use_cnt = 0;
if (cif_dev->chip_id == CHIP_RV1126_CIF_LITE)
cif_dev->isr_hdl = rkcif_irq_lite_handler;
@@ -1184,6 +1573,13 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int
rkcif_stream_init(cif_dev, RKCIF_STREAM_MIPI_ID3);
}
if (cif_dev->chip_id == CHIP_RK3588_CIF) {
rkcif_init_scale_vdev(cif_dev, RKCIF_SCALE_CH0);
rkcif_init_scale_vdev(cif_dev, RKCIF_SCALE_CH1);
rkcif_init_scale_vdev(cif_dev, RKCIF_SCALE_CH2);
rkcif_init_scale_vdev(cif_dev, RKCIF_SCALE_CH3);
}
#if defined(CONFIG_ROCKCHIP_CIF_WORKMODE_PINGPONG)
cif_dev->workmode = RKCIF_WORKMODE_PINGPONG;
#elif defined(CONFIG_ROCKCHIP_CIF_WORKMODE_ONEFRAME)
@@ -1200,6 +1596,9 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int
strlcpy(cif_dev->media_dev.model, dev_name(dev),
sizeof(cif_dev->media_dev.model));
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;
cif_dev->media_dev.dev = dev;
v4l2_dev = &cif_dev->v4l2_dev;
v4l2_dev->mdev = &cif_dev->media_dev;
@@ -1328,6 +1727,9 @@ static int rkcif_plat_probe(struct platform_device *pdev)
dev_set_drvdata(dev, cif_dev);
cif_dev->dev = dev;
if (sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp))
return -ENODEV;
rkcif_attach_hw(cif_dev);
rkcif_parse_dts(cif_dev);
@@ -1338,9 +1740,6 @@ static int rkcif_plat_probe(struct platform_device *pdev)
return ret;
}
if (sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp))
return -ENODEV;
if (rkcif_proc_init(cif_dev))
dev_warn(dev, "dev:%s create proc failed\n", dev_name(dev));

View File

@@ -17,6 +17,7 @@
#include <media/v4l2-mc.h>
#include <linux/workqueue.h>
#include <linux/rk-camera-module.h>
#include <linux/rkcif-config.h>
#include "regs.h"
#include "version.h"
@@ -46,6 +47,9 @@
#define CIF_DVP_ID2_VDEV_NAME CIF_VIDEODEVICE_NAME "_dvp_id2"
#define CIF_DVP_ID3_VDEV_NAME CIF_VIDEODEVICE_NAME "_dvp_id3"
#define RKCIF_PLANE_Y 0
#define RKCIF_PLANE_CBCR 1
/*
* RK1808 support 5 channel inputs simultaneously:
* dvp + 4 mipi virtual channels;
@@ -69,10 +73,13 @@
#define RKCIF_DEFAULT_HEIGHT 480
#define RKCIF_FS_DETECTED_NUM 2
#define RKCIF_RX_BUF_MAX 8
/*
* for HDR mode sync buf
*/
#define RDBK_MAX 3
#define RDBK_TOISP_MAX 2
#define RDBK_L 0
#define RDBK_M 1
#define RDBK_S 2
@@ -89,6 +96,13 @@ enum rkcif_workmode {
RKCIF_WORKMODE_LINELOOP = 0x02
};
enum rkcif_stream_mode {
RKCIF_STREAM_MODE_NONE = 0x0,
RKCIF_STREAM_MODE_CAPTURE = 0x01,
RKCIF_STREAM_MODE_TOISP = 0x02,
RKCIF_STREAM_MODE_TOSCALE = 0x04
};
enum rkcif_yuvaddr_state {
RKCIF_YUV_ADDR_STATE_UPDATE = 0x0,
RKCIF_YUV_ADDR_STATE_INIT = 0x1
@@ -171,9 +185,17 @@ struct rkcif_buffer {
};
struct rkcif_dummy_buffer {
void *vaddr;
struct list_head list;
struct dma_buf *dbuf;
dma_addr_t dma_addr;
struct page **pages;
void *mem_priv;
void *vaddr;
u32 size;
int dma_fd;
bool is_need_vaddr;
bool is_need_dbuf;
bool is_need_dmafd;
};
extern int rkcif_debug;
@@ -322,10 +344,13 @@ struct rkcif_readout_stats {
struct rkcif_irq_stats {
u64 csi_overflow_cnt;
u64 csi_bwidth_lack_cnt;
u64 csi_size_err_cnt;
u64 dvp_bus_err_cnt;
u64 dvp_overflow_cnt;
u64 dvp_line_err_cnt;
u64 dvp_pix_err_cnt;
u64 dvp_size_err_cnt;
u64 dvp_bwidth_lack_cnt;
u64 all_frm_end_cnt;
u64 all_err_cnt;
};
@@ -394,6 +419,22 @@ struct rkcif_extend_info {
bool is_extended;
};
enum rkcif_capture_mode {
RKCIF_TO_DDR = 0,
RKCIF_TO_ISP_DDR,
RKCIF_TO_ISP_DMA,
};
struct rkcif_rx_buffer {
struct rkisp_rx_buf dbufs;
struct rkcif_dummy_buffer dummy;
};
enum rkcif_dma_en_mode {
RKCIF_DMAEN_BY_VICAP = 0x1,
RKCIF_DMAEN_BY_ISP = 0x2,
};
/*
* struct rkcif_stream - Stream states TODO
*
@@ -421,6 +462,8 @@ struct rkcif_stream {
struct list_head buf_head;
struct rkcif_buffer *curr_buf;
struct rkcif_buffer *next_buf;
struct rkcif_rx_buffer *curr_buf_toisp;
struct rkcif_rx_buffer *next_buf_toisp;
spinlock_t vbq_lock; /* vfd lock */
spinlock_t fps_lock;
@@ -435,6 +478,15 @@ struct rkcif_stream {
struct rkcif_extend_info extend_line;
struct rkcif_readout_stats readout;
unsigned int fs_cnt_in_single_frame;
unsigned int capture_mode;
struct rkcif_scale_vdev *scale_vdev;
int dma_en;
int to_en_dma;
int to_stop_dma;
unsigned int cur_stream_mode;
struct rkcif_rx_buffer rx_buf[RKCIF_RX_BUF_MAX];
struct list_head rx_buf_head;
int buf_num_toisp;
u64 line_int_cnt;
int vc;
bool stopping;
@@ -499,6 +551,110 @@ static inline struct vb2_queue *to_vb2_queue(struct file *file)
return &vnode->buf_queue;
}
#define SCALE_DRIVER_NAME "rkcif_scale"
#define RKCIF_SCALE_CH0 0
#define RKCIF_SCALE_CH1 1
#define RKCIF_SCALE_CH2 2
#define RKCIF_SCALE_CH3 3
#define RKCIF_MAX_SCALE_CH 4
#define CIF_SCALE_CH0_VDEV_NAME CIF_DRIVER_NAME "_scale_ch0"
#define CIF_SCALE_CH1_VDEV_NAME CIF_DRIVER_NAME "_scale_ch1"
#define CIF_SCALE_CH2_VDEV_NAME CIF_DRIVER_NAME "_scale_ch2"
#define CIF_SCALE_CH3_VDEV_NAME CIF_DRIVER_NAME "_scale_ch3"
#define RKCIF_SCALE_ENUM_SIZE_MAX 3
enum scale_ch_sw {
SCALE_MIPI0_ID0,
SCALE_MIPI0_ID1,
SCALE_MIPI0_ID2,
SCALE_MIPI0_ID3,
SCALE_MIPI1_ID0,
SCALE_MIPI1_ID1,
SCALE_MIPI1_ID2,
SCALE_MIPI1_ID3,
SCALE_MIPI2_ID0,
SCALE_MIPI2_ID1,
SCALE_MIPI2_ID2,
SCALE_MIPI2_ID3,
SCALE_MIPI3_ID0,
SCALE_MIPI3_ID1,
SCALE_MIPI3_ID2,
SCALE_MIPI3_ID3,
SCALE_MIPI4_ID0,
SCALE_MIPI4_ID1,
SCALE_MIPI4_ID2,
SCALE_MIPI4_ID3,
SCALE_MIPI5_ID0,
SCALE_MIPI5_ID1,
SCALE_MIPI5_ID2,
SCALE_MIPI5_ID3,
SCALE_DVP,
SCALE_CH_MAX,
};
enum scale_mode {
SCALE_8TIMES,
SCALE_16TIMES,
SCALE_32TIMES,
};
struct rkcif_scale_ch_info {
u32 width;
u32 height;
u32 vir_width;
};
struct rkcif_scale_src_res {
u32 width;
u32 height;
};
/*
* struct rkcif_scale_vdev - CIF Capture device
*
* @irq_lock: buffer queue lock
* @stat: stats buffer list
* @readout_wq: workqueue for statistics information read
*/
struct rkcif_scale_vdev {
unsigned int ch:3;
struct rkcif_device *cifdev;
struct rkcif_vdev_node vnode;
struct rkcif_stream *stream;
struct list_head buf_head;
spinlock_t vbq_lock; /* vfd lock */
wait_queue_head_t wq_stopped;
struct v4l2_pix_format_mplane pixm;
const struct cif_output_fmt *scale_out_fmt;
struct rkcif_scale_ch_info ch_info;
struct rkcif_scale_src_res src_res;
struct rkcif_buffer *curr_buf;
struct rkcif_buffer *next_buf;
struct bayer_blc blc;
enum rkcif_state state;
unsigned int ch_src;
unsigned int scale_mode;
int frame_phase;
unsigned int frame_idx;
bool stopping;
};
static inline
struct rkcif_scale_vdev *to_rkcif_scale_vdev(struct rkcif_vdev_node *vnode)
{
return container_of(vnode, struct rkcif_scale_vdev, vnode);
}
void rkcif_init_scale_vdev(struct rkcif_device *cif_dev, u32 ch);
int rkcif_register_scale_vdevs(struct rkcif_device *cif_dev,
int stream_num,
bool is_multi_input);
void rkcif_unregister_scale_vdevs(struct rkcif_device *cif_dev,
int stream_num);
/*
* struct rkcif_device - ISP platform device
* @base_addr: base register address
@@ -518,6 +674,7 @@ struct rkcif_device {
struct rkcif_sensor_info terminal_sensor;
struct rkcif_stream stream[RKCIF_MULTI_STREAMS_NUM];
struct rkcif_scale_vdev scale_vdev[RKCIF_MULTI_STREAMS_NUM];
struct rkcif_pipeline pipe;
struct csi_channel_info channels[RKCIF_MAX_CSI_CHANNEL];
@@ -526,9 +683,10 @@ struct rkcif_device {
atomic_t stream_cnt;
atomic_t fh_cnt;
struct mutex stream_lock; /* lock between streams */
struct mutex scale_lock; /* lock between scale dev */
enum rkcif_workmode workmode;
bool can_be_reset;
struct rkcif_hdr hdr;
struct rkmodule_hdr_cfg hdr;
struct rkcif_buffer *rdbk_buf[RDBK_MAX];
struct rkcif_luma_vdev luma_vdev;
struct rkcif_lvds_subdev lvds_subdev;
@@ -545,6 +703,8 @@ struct rkcif_device {
unsigned int buf_wake_up_cnt;
struct notifier_block reset_notifier; /* reset for mipi csi crc err */
struct rkcif_work_struct reset_work;
int id_use_cnt;
unsigned int csi_host_idx;
unsigned int dvp_sof_in_oneframe;
unsigned int wait_line;
unsigned int wait_line_bak;
@@ -557,6 +717,17 @@ struct rkcif_device {
};
extern struct platform_driver rkcif_plat_drv;
int rkcif_do_start_stream(struct rkcif_stream *stream,
enum rkcif_stream_mode mode);
void rkcif_do_stop_stream(struct rkcif_stream *stream,
enum rkcif_stream_mode mode);
void rkcif_irq_handle_scale(struct rkcif_device *cif_dev,
unsigned int intstat_glb);
const struct
cif_input_fmt *get_input_fmt(struct v4l2_subdev *sd,
struct v4l2_rect *rect,
u32 pad_id, int *vc);
void rkcif_write_register(struct rkcif_device *dev,
enum cif_reg_index index, u32 val);
@@ -579,6 +750,9 @@ void rkcif_stream_init(struct rkcif_device *dev, u32 id);
void rkcif_set_default_fmt(struct rkcif_device *cif_dev);
void rkcif_irq_oneframe(struct rkcif_device *cif_dev);
void rkcif_irq_pingpong(struct rkcif_device *cif_dev);
void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev);
unsigned int rkcif_irq_global(struct rkcif_device *cif_dev);
void rkcif_irq_handle_toisp(struct rkcif_device *cif_dev, unsigned int intstat_glb);
void rkcif_soft_reset(struct rkcif_device *cif_dev,
bool is_rst_iommu);
int rkcif_register_lvds_subdev(struct rkcif_device *dev);
@@ -597,4 +771,16 @@ void rkcif_config_dvp_clk_sampling_edge(struct rkcif_device *dev,
enum rkcif_clk_edge edge);
void rkcif_enable_dvp_clk_dual_edge(struct rkcif_device *dev, bool on);
void rkcif_reset_work(struct work_struct *work);
int rkcif_init_rx_buf(struct rkcif_stream *stream, int buf_num);
void rkcif_free_rx_buf(struct rkcif_stream *stream, int buf_num);
void rkcif_set_fmt(struct rkcif_stream *stream,
struct v4l2_pix_format_mplane *pixm,
bool try);
u32 rkcif_mbus_pixelcode_to_v4l2(u32 pixelcode);
extern const struct vb2_mem_ops vb2_rdma_sg_memops;
#endif

View File

@@ -18,6 +18,7 @@
#include <linux/pinctrl/consumer.h>
#include <linux/regmap.h>
#include <media/videobuf2-dma-contig.h>
#include <media/videobuf2-dma-sg.h>
#include <media/v4l2-fwnode.h>
#include <linux/iommu.h>
#include <dt-bindings/soc/rockchip-system-status.h>
@@ -25,6 +26,7 @@
#include <linux/io.h>
#include <linux/mfd/syscon.h>
#include "dev.h"
#include "common.h"
static const struct cif_reg px30_cif_regs[] = {
[CIF_REG_DVP_CTRL] = CIF_REG(CIF_CTRL),
@@ -597,6 +599,128 @@ static const struct cif_reg rk3568_cif_regs[] = {
[CIF_REG_GRF_CIFIO_CON1] = CIF_REG(CIF_GRF_VI_CON1),
};
static const char * const rk3588_cif_clks[] = {
"aclk_cif",
"hclk_cif",
"dclk_cif",
};
static const char * const rk3588_cif_rsts[] = {
"rst_cif_a",
"rst_cif_h",
"rst_cif_d",
};
static const struct cif_reg rk3588_cif_regs[] = {
[CIF_REG_DVP_CTRL] = CIF_REG(DVP_CTRL),
[CIF_REG_DVP_INTEN] = CIF_REG(DVP_INTEN),
[CIF_REG_DVP_INTSTAT] = CIF_REG(DVP_INTSTAT),
[CIF_REG_DVP_FOR] = CIF_REG(DVP_FOR),
[CIF_REG_DVP_MULTI_ID] = CIF_REG(DVP_MULTI_ID),
[CIF_REG_DVP_SAV_EAV] = CIF_REG(DVP_SAV_EAV),
[CIF_REG_DVP_FRM0_ADDR_Y] = CIF_REG(DVP_FRM0_ADDR_Y_ID0),
[CIF_REG_DVP_FRM0_ADDR_UV] = CIF_REG(DVP_FRM0_ADDR_UV_ID0),
[CIF_REG_DVP_FRM1_ADDR_Y] = CIF_REG(DVP_FRM1_ADDR_Y_ID0),
[CIF_REG_DVP_FRM1_ADDR_UV] = CIF_REG(DVP_FRM1_ADDR_UV_ID0),
[CIF_REG_DVP_FRM0_ADDR_Y_ID1] = CIF_REG(DVP_FRM0_ADDR_Y_ID1),
[CIF_REG_DVP_FRM0_ADDR_UV_ID1] = CIF_REG(DVP_FRM0_ADDR_UV_ID1),
[CIF_REG_DVP_FRM1_ADDR_Y_ID1] = CIF_REG(DVP_FRM1_ADDR_Y_ID1),
[CIF_REG_DVP_FRM1_ADDR_UV_ID1] = CIF_REG(DVP_FRM1_ADDR_UV_ID1),
[CIF_REG_DVP_FRM0_ADDR_Y_ID2] = CIF_REG(DVP_FRM0_ADDR_Y_ID2),
[CIF_REG_DVP_FRM0_ADDR_UV_ID2] = CIF_REG(DVP_FRM0_ADDR_UV_ID2),
[CIF_REG_DVP_FRM1_ADDR_Y_ID2] = CIF_REG(DVP_FRM1_ADDR_Y_ID2),
[CIF_REG_DVP_FRM1_ADDR_UV_ID2] = CIF_REG(DVP_FRM1_ADDR_UV_ID2),
[CIF_REG_DVP_FRM0_ADDR_Y_ID3] = CIF_REG(DVP_FRM0_ADDR_Y_ID3),
[CIF_REG_DVP_FRM0_ADDR_UV_ID3] = CIF_REG(DVP_FRM0_ADDR_UV_ID3),
[CIF_REG_DVP_FRM1_ADDR_Y_ID3] = CIF_REG(DVP_FRM1_ADDR_Y_ID3),
[CIF_REG_DVP_FRM1_ADDR_UV_ID3] = CIF_REG(DVP_FRM1_ADDR_UV_ID3),
[CIF_REG_DVP_VIR_LINE_WIDTH] = CIF_REG(DVP_VIR_LINE_WIDTH),
[CIF_REG_DVP_SET_SIZE] = CIF_REG(DVP_CROP_SIZE),
[CIF_REG_DVP_LINE_INT_NUM] = CIF_REG(DVP_LINE_INT_NUM_01),
[CIF_REG_DVP_LINE_INT_NUM1] = CIF_REG(DVP_LINE_INT_NUM_23),
[CIF_REG_DVP_LINE_CNT] = CIF_REG(DVP_LINE_INT_NUM_01),
[CIF_REG_DVP_LINE_CNT1] = CIF_REG(DVP_LINE_INT_NUM_23),
[CIF_REG_MIPI_LVDS_ID0_CTRL0] = CIF_REG(CSI_MIPI0_ID0_CTRL0),
[CIF_REG_MIPI_LVDS_ID0_CTRL1] = CIF_REG(CSI_MIPI0_ID0_CTRL1),
[CIF_REG_MIPI_LVDS_ID1_CTRL0] = CIF_REG(CSI_MIPI0_ID1_CTRL0),
[CIF_REG_MIPI_LVDS_ID1_CTRL1] = CIF_REG(CSI_MIPI0_ID1_CTRL1),
[CIF_REG_MIPI_LVDS_ID2_CTRL0] = CIF_REG(CSI_MIPI0_ID2_CTRL0),
[CIF_REG_MIPI_LVDS_ID2_CTRL1] = CIF_REG(CSI_MIPI0_ID2_CTRL1),
[CIF_REG_MIPI_LVDS_ID3_CTRL0] = CIF_REG(CSI_MIPI0_ID3_CTRL0),
[CIF_REG_MIPI_LVDS_ID3_CTRL1] = CIF_REG(CSI_MIPI0_ID3_CTRL1),
[CIF_REG_MIPI_LVDS_CTRL] = CIF_REG(CSI_MIPI0_CTRL),
[CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0] = CIF_REG(CSI_MIPI0_FRM0_ADDR_Y_ID0),
[CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0] = CIF_REG(CSI_MIPI0_FRM1_ADDR_Y_ID0),
[CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0] = CIF_REG(CSI_MIPI0_FRM0_ADDR_UV_ID0),
[CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0] = CIF_REG(CSI_MIPI0_FRM1_ADDR_UV_ID0),
[CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0] = CIF_REG(CSI_MIPI0_VLW_ID0),
[CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID1] = CIF_REG(CSI_MIPI0_FRM0_ADDR_Y_ID1),
[CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID1] = CIF_REG(CSI_MIPI0_FRM1_ADDR_Y_ID1),
[CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID1] = CIF_REG(CSI_MIPI0_FRM0_ADDR_UV_ID1),
[CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID1] = CIF_REG(CSI_MIPI0_FRM1_ADDR_UV_ID1),
[CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID1] = CIF_REG(CSI_MIPI0_VLW_ID1),
[CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID2] = CIF_REG(CSI_MIPI0_FRM0_ADDR_Y_ID2),
[CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID2] = CIF_REG(CSI_MIPI0_FRM1_ADDR_Y_ID2),
[CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID2] = CIF_REG(CSI_MIPI0_FRM0_ADDR_UV_ID2),
[CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID2] = CIF_REG(CSI_MIPI0_FRM1_ADDR_UV_ID2),
[CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID2] = CIF_REG(CSI_MIPI0_VLW_ID2),
[CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID3] = CIF_REG(CSI_MIPI0_FRM0_ADDR_Y_ID3),
[CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID3] = CIF_REG(CSI_MIPI0_FRM1_ADDR_Y_ID3),
[CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID3] = CIF_REG(CSI_MIPI0_FRM0_ADDR_UV_ID3),
[CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID3] = CIF_REG(CSI_MIPI0_FRM1_ADDR_UV_ID3),
[CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID3] = CIF_REG(CSI_MIPI0_VLW_ID3),
[CIF_REG_MIPI_LVDS_INTEN] = CIF_REG(CSI_MIPI0_INTEN),
[CIF_REG_MIPI_LVDS_INTSTAT] = CIF_REG(CSI_MIPI0_INTSTAT),
[CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1] = CIF_REG(CSI_MIPI0_LINE_INT_NUM_ID0_1),
[CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3] = CIF_REG(CSI_MIPI0_LINE_INT_NUM_ID2_3),
[CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1] = CIF_REG(CSI_MIPI0_LINE_CNT_ID0_1),
[CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID2_3] = CIF_REG(CSI_MIPI0_LINE_CNT_ID2_3),
[CIF_REG_MIPI_LVDS_ID0_CROP_START] = CIF_REG(CSI_MIPI0_ID0_CROP_START),
[CIF_REG_MIPI_LVDS_ID1_CROP_START] = CIF_REG(CSI_MIPI0_ID1_CROP_START),
[CIF_REG_MIPI_LVDS_ID2_CROP_START] = CIF_REG(CSI_MIPI0_ID2_CROP_START),
[CIF_REG_MIPI_LVDS_ID3_CROP_START] = CIF_REG(CSI_MIPI0_ID3_CROP_START),
[CIF_REG_MIPI_FRAME_NUM_VC0] = CIF_REG(CSI_MIPI0_FRAME_NUM_VC0),
[CIF_REG_MIPI_FRAME_NUM_VC1] = CIF_REG(CSI_MIPI0_FRAME_NUM_VC1),
[CIF_REG_MIPI_FRAME_NUM_VC2] = CIF_REG(CSI_MIPI0_FRAME_NUM_VC2),
[CIF_REG_MIPI_FRAME_NUM_VC3] = CIF_REG(CSI_MIPI0_FRAME_NUM_VC3),
[CIF_REG_MIPI_EFFECT_CODE_ID0] = CIF_REG(CSI_MIPI0_EFFECT_CODE_ID0),
[CIF_REG_MIPI_EFFECT_CODE_ID1] = CIF_REG(CSI_MIPI0_EFFECT_CODE_ID1),
[CIF_REG_MIPI_EFFECT_CODE_ID2] = CIF_REG(CSI_MIPI0_EFFECT_CODE_ID2),
[CIF_REG_MIPI_EFFECT_CODE_ID3] = CIF_REG(CSI_MIPI0_EFFECT_CODE_ID3),
[CIF_REG_MIPI_ON_PAD] = CIF_REG(CSI_MIPI0_ON_PAD),
[CIF_REG_GLB_CTRL] = CIF_REG(GLB_CTRL),
[CIF_REG_GLB_INTEN] = CIF_REG(GLB_INTEN),
[CIF_REG_GLB_INTST] = CIF_REG(GLB_INTST),
[CIF_REG_SCL_CH_CTRL] = CIF_REG(SCL_CH_CTRL),
[CIF_REG_SCL_CTRL] = CIF_REG(SCL_CTRL),
[CIF_REG_SCL_FRM0_ADDR_CH0] = CIF_REG(SCL_FRM0_ADDR_CH0),
[CIF_REG_SCL_FRM1_ADDR_CH0] = CIF_REG(SCL_FRM1_ADDR_CH0),
[CIF_REG_SCL_VLW_CH0] = CIF_REG(SCL_VLW_CH0),
[CIF_REG_SCL_FRM0_ADDR_CH1] = CIF_REG(SCL_FRM0_ADDR_CH1),
[CIF_REG_SCL_FRM1_ADDR_CH1] = CIF_REG(SCL_FRM1_ADDR_CH1),
[CIF_REG_SCL_VLW_CH1] = CIF_REG(SCL_VLW_CH1),
[CIF_REG_SCL_FRM0_ADDR_CH2] = CIF_REG(SCL_FRM0_ADDR_CH2),
[CIF_REG_SCL_FRM1_ADDR_CH2] = CIF_REG(SCL_FRM1_ADDR_CH2),
[CIF_REG_SCL_VLW_CH2] = CIF_REG(SCL_VLW_CH2),
[CIF_REG_SCL_FRM0_ADDR_CH3] = CIF_REG(SCL_FRM0_ADDR_CH3),
[CIF_REG_SCL_FRM1_ADDR_CH3] = CIF_REG(SCL_FRM1_ADDR_CH3),
[CIF_REG_SCL_VLW_CH3] = CIF_REG(SCL_VLW_CH3),
[CIF_REG_SCL_BLC_CH0] = CIF_REG(SCL_BLC_CH0),
[CIF_REG_SCL_BLC_CH1] = CIF_REG(SCL_BLC_CH1),
[CIF_REG_SCL_BLC_CH2] = CIF_REG(SCL_BLC_CH2),
[CIF_REG_SCL_BLC_CH3] = CIF_REG(SCL_BLC_CH3),
[CIF_REG_TOISP0_CTRL] = CIF_REG(TOISP0_CH_CTRL),
[CIF_REG_TOISP0_SIZE] = CIF_REG(TOISP0_CROP_SIZE),
[CIF_REG_TOISP0_CROP] = CIF_REG(TOISP0_CROP),
[CIF_REG_TOISP1_CTRL] = CIF_REG(TOISP1_CH_CTRL),
[CIF_REG_TOISP1_SIZE] = CIF_REG(TOISP1_CROP_SIZE),
[CIF_REG_TOISP1_CROP] = CIF_REG(TOISP1_CROP),
[CIF_REG_GRF_CIFIO_CON] = CIF_REG(CIF_GRF_SOC_CON2),
};
static const struct rkcif_hw_match_data px30_cif_match_data = {
.chip_id = CHIP_PX30_CIF,
.clks = px30_cif_clks,
@@ -678,6 +802,14 @@ static const struct rkcif_hw_match_data rk3568_cif_match_data = {
.cif_regs = rk3568_cif_regs,
};
static const struct rkcif_hw_match_data rk3588_cif_match_data = {
.chip_id = CHIP_RK3588_CIF,
.clks = rk3588_cif_clks,
.clks_num = ARRAY_SIZE(rk3588_cif_clks),
.rsts = rk3588_cif_rsts,
.rsts_num = ARRAY_SIZE(rk3588_cif_rsts),
.cif_regs = rk3588_cif_regs,
};
static const struct of_device_id rkcif_plat_of_match[] = {
{
@@ -708,6 +840,10 @@ static const struct of_device_id rkcif_plat_of_match[] = {
.compatible = "rockchip,rk3568-cif",
.data = &rk3568_cif_match_data,
},
{
.compatible = "rockchip,rk3588-cif",
.data = &rk3588_cif_match_data,
},
{
.compatible = "rockchip,rv1126-cif",
.data = &rv1126_cif_match_data,
@@ -723,11 +859,17 @@ static irqreturn_t rkcif_irq_handler(int irq, void *ctx)
{
struct device *dev = ctx;
struct rkcif_hw *cif_hw = dev_get_drvdata(dev);
unsigned int intstat_glb = 0;
int i;
if (cif_hw->chip_id == CHIP_RK3588_CIF)
intstat_glb = rkcif_irq_global(cif_hw->cif_dev[0]);
for (i = 0; i < cif_hw->dev_num; i++) {
if (cif_hw->cif_dev[i]->isr_hdl)
if (cif_hw->cif_dev[i]->isr_hdl) {
cif_hw->cif_dev[i]->isr_hdl(irq, cif_hw->cif_dev[i]);
if (cif_hw->chip_id == CHIP_RK3588_CIF && intstat_glb)
rkcif_irq_handle_toisp(cif_hw->cif_dev[i], intstat_glb);
}
}
return IRQ_HANDLED;
@@ -825,6 +967,7 @@ static int rkcif_plat_hw_probe(struct platform_device *pdev)
const struct rkcif_hw_match_data *data;
struct resource *res;
int i, ret, irq;
bool is_mem_reserved = false;
match = of_match_node(rkcif_plat_of_match, node);
if (IS_ERR(match))
@@ -853,10 +996,7 @@ static int rkcif_plat_hw_probe(struct platform_device *pdev)
cif_hw->irq = irq;
cif_hw->match_data = data;
cif_hw->chip_id = data->chip_id;
if (data->chip_id == CHIP_RK1808_CIF ||
data->chip_id == CHIP_RV1126_CIF ||
data->chip_id == CHIP_RV1126_CIF_LITE ||
data->chip_id == CHIP_RK3568_CIF) {
if (data->chip_id >= CHIP_RK1808_CIF) {
res = platform_get_resource_byname(pdev,
IORESOURCE_MEM,
"cif_regs");
@@ -915,17 +1055,30 @@ static int rkcif_plat_hw_probe(struct platform_device *pdev)
cif_hw->cif_regs = data->cif_regs;
cif_hw->is_dma_contig = true;
cif_hw->is_dma_sg_ops = false;
mutex_init(&cif_hw->dev_lock);
cif_hw->iommu_en = is_iommu_enable(dev);
if (!cif_hw->iommu_en) {
ret = of_reserved_mem_device_init(dev);
if (ret)
ret = of_reserved_mem_device_init(dev);
if (ret) {
is_mem_reserved = false;
if (!cif_hw->iommu_en)
dev_info(dev, "No reserved memory region assign to CIF\n");
else
cif_hw->is_dma_contig = false;
}
if (is_mem_reserved) {
cif_hw->mem_ops = &vb2_rdma_sg_memops;
cif_hw->is_dma_sg_ops = true;
} else if (cif_hw->iommu_en) {
cif_hw->mem_ops = &vb2_dma_sg_memops;
cif_hw->is_dma_sg_ops = true;
} else {
cif_hw->mem_ops = &vb2_dma_contig_memops;
}
if (data->chip_id != CHIP_RK1808_CIF &&
data->chip_id != CHIP_RV1126_CIF &&
data->chip_id != CHIP_RV1126_CIF_LITE &&
data->chip_id != CHIP_RK3568_CIF) {
if (data->chip_id < CHIP_RK1808_CIF) {
cif_dev = devm_kzalloc(dev, sizeof(*cif_dev), GFP_KERNEL);
if (!cif_dev)
return -ENOMEM;
@@ -946,9 +1099,8 @@ static int rkcif_plat_hw_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
if (data->chip_id == CHIP_RK1808_CIF ||
data->chip_id == CHIP_RV1126_CIF ||
data->chip_id == CHIP_RK3568_CIF) {
if (data->chip_id >= CHIP_RK1808_CIF &&
data->chip_id != CHIP_RV1126_CIF_LITE) {
platform_driver_register(&rkcif_plat_drv);
platform_driver_register(&rkcif_subdev_driver);
}
@@ -965,10 +1117,7 @@ static int rkcif_plat_remove(struct platform_device *pdev)
rkcif_iommu_cleanup(cif_hw);
mutex_destroy(&cif_hw->dev_lock);
if (cif_hw->chip_id != CHIP_RK1808_CIF &&
cif_hw->chip_id != CHIP_RV1126_CIF &&
cif_hw->chip_id != CHIP_RV1126_CIF_LITE &&
cif_hw->chip_id != CHIP_RK3568_CIF)
if (cif_hw->chip_id < CHIP_RK1808_CIF)
rkcif_plat_uninit(cif_hw->cif_dev[0]);
return 0;

View File

@@ -19,7 +19,7 @@
#include "regs.h"
#include "version.h"
#define RKCIF_DEV_MAX 2
#define RKCIF_DEV_MAX 7
#define RKCIF_HW_DRIVER_NAME "rkcifhw"
#define RKCIF_MAX_BUS_CLK 8
#define RKCIF_MAX_RESET 15
@@ -47,6 +47,7 @@ enum rkcif_chip_id {
CHIP_RV1126_CIF,
CHIP_RV1126_CIF_LITE,
CHIP_RK3568_CIF,
CHIP_RK3588_CIF,
};
struct rkcif_hw_match_data {
@@ -72,17 +73,19 @@ struct rkcif_hw {
struct regmap *grf;
struct clk *clks[RKCIF_MAX_BUS_CLK];
int clk_size;
bool iommu_en;
struct iommu_domain *domain;
struct reset_control *cif_rst[RKCIF_MAX_RESET];
int chip_id;
const struct cif_reg *cif_regs;
const struct vb2_mem_ops *mem_ops;
bool iommu_en;
bool can_be_reset;
bool is_dma_sg_ops;
bool is_dma_contig;
struct rkcif_device *cif_dev[RKCIF_DEV_MAX];
int dev_num;
struct rkcif_device *cif_dev[RKCIF_DEV_MAX];
int dev_num;
atomic_t power_cnt;
atomic_t power_cnt;
const struct rkcif_hw_match_data *match_data;
struct mutex dev_lock;
};

View File

@@ -31,9 +31,10 @@ MODULE_PARM_DESC(debug_csi2, "Debug level (0-1)");
* the 4 virtual channel output pads
*/
#define CSI2_SINK_PAD 0
#define CSI2_NUM_SINK_PADS 1
#define CSI2_NUM_SRC_PADS 4
#define CSI2_NUM_SINK_PADS 4
#define CSI2_NUM_SRC_PADS 8
#define CSI2_NUM_PADS 5
#define CSI2_NUM_PADS_MAX 9
#define CSI2_NUM_PADS_SINGLE_LINK 2
#define MAX_CSI2_SENSORS 2
@@ -60,6 +61,7 @@ enum rkcsi2_chip_id {
CHIP_RK3288_CSI2,
CHIP_RV1126_CSI2,
CHIP_RK3568_CSI2,
CHIP_RK3588_CSI2,
};
enum csi2_pads {
@@ -103,7 +105,7 @@ struct csi2_err_stats {
struct csi2_dev {
struct device *dev;
struct v4l2_subdev sd;
struct media_pad pad[CSI2_NUM_PADS];
struct media_pad pad[CSI2_NUM_PADS_MAX];
struct clk_bulk_data *clks_bulk;
int clks_num;
struct reset_control *rsts_bulk;
@@ -277,25 +279,36 @@ static void csi2_disable(struct csi2_dev *csi2)
write_csihost_reg(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,
enum host_type_t host_type)
{
void __iomem *base = csi2->base;
int lanes = csi2->bus.num_data_lanes;
struct v4l2_mbus_config mbus;
u32 val = 0;
csi2_g_mbus_config(&csi2->sd, 0, &mbus);
if (mbus.type == V4L2_MBUS_CSI2_DPHY)
val = SW_CPHY_EN(0);
else if (mbus.type == V4L2_MBUS_CSI2_CPHY)
val = SW_CPHY_EN(1);
write_csihost_reg(base, CSIHOST_N_LANES, lanes - 1);
if (host_type == RK_DSI_RXHOST) {
write_csihost_reg(base, CSIHOST_CONTROL,
SW_CPHY_EN(0) | SW_DSI_EN(1) |
SW_DATATYPE_FS(0x01) | SW_DATATYPE_FE(0x11) |
SW_DATATYPE_LS(0x21) | SW_DATATYPE_LE(0x31));
val |= SW_DSI_EN(1) | SW_DATATYPE_FS(0x01) |
SW_DATATYPE_FE(0x11) | SW_DATATYPE_LS(0x21) |
SW_DATATYPE_LE(0x31);
write_csihost_reg(base, CSIHOST_CONTROL, val);
/* Disable some error interrupt when HOST work on DSI RX mode */
write_csihost_reg(base, CSIHOST_MSK1, 0xe00000f0);
write_csihost_reg(base, CSIHOST_MSK2, 0xff00);
} else {
write_csihost_reg(base, CSIHOST_CONTROL,
SW_CPHY_EN(0) | SW_DSI_EN(0));
val |= SW_DSI_EN(0);
write_csihost_reg(base, CSIHOST_CONTROL, val);
write_csihost_reg(base, CSIHOST_MSK1, 0);
write_csihost_reg(base, CSIHOST_MSK2, 0xf000);
}
@@ -889,6 +902,11 @@ static const struct csi2_match_data rk3568_csi2_match_data = {
.num_pads = CSI2_NUM_PADS,
};
static const struct csi2_match_data rk3588_csi2_match_data = {
.chip_id = CHIP_RK3588_CSI2,
.num_pads = CSI2_NUM_PADS_MAX,
};
static const struct of_device_id csi2_dt_ids[] = {
{
.compatible = "rockchip,rk1808-mipi-csi2",
@@ -906,6 +924,10 @@ static const struct of_device_id csi2_dt_ids[] = {
.compatible = "rockchip,rv1126-mipi-csi2",
.data = &rv1126_csi2_match_data,
},
{
.compatible = "rockchip,rk3588-mipi-csi2",
.data = &rk3588_csi2_match_data,
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, csi2_dt_ids);

View File

@@ -272,7 +272,8 @@ static void rkcif_show_format(struct rkcif_device *dev, struct seq_file *f)
mbus_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH ? "high active" : "low active");
} else {
seq_printf(f, "\tinterface:%s\n",
sensor->mbus.type == V4L2_MBUS_CSI2_DPHY ? "mipi csi2" :
sensor->mbus.type == V4L2_MBUS_CSI2_DPHY ? "mipi csi2 dphy" :
sensor->mbus.type == V4L2_MBUS_CSI2_CPHY ? "mipi csi2 cphy" :
sensor->mbus.type == V4L2_MBUS_CCP2 ? "lvds" : "unknown");
seq_printf(f, "\tlanes:%d\n", sensor->lanes);
seq_puts(f, "\tvc channel:");
@@ -288,8 +289,8 @@ static void rkcif_show_format(struct rkcif_device *dev, struct seq_file *f)
}
seq_printf(f, "\thdr mode: %s\n",
dev->hdr.mode == NO_HDR ? "normal" :
dev->hdr.mode == HDR_X2 ? "hdr_x2" : "hdr_x3");
dev->hdr.hdr_mode == NO_HDR ? "normal" :
dev->hdr.hdr_mode == HDR_X2 ? "hdr_x2" : "hdr_x3");
seq_printf(f, "\tformat:%s/%ux%u@%d\n",
rkcif_pixelcode_to_string(stream->cif_fmt_in->mbus_code),
@@ -318,7 +319,7 @@ static void rkcif_show_format(struct rkcif_device *dev, struct seq_file *f)
if (dev->inf_id == RKCIF_MIPI_LVDS) {
time_val = div_u64(stream->readout.early_time, 1000000);
seq_printf(f, "\tearly:%u ms\n", time_val);
if (dev->hdr.mode == NO_HDR) {
if (dev->hdr.hdr_mode == NO_HDR) {
time_val = div_u64(stream->readout.readout_time, 1000000);
seq_printf(f, "\treadout:%u ms\n", time_val);
} else {
@@ -341,10 +342,12 @@ static void rkcif_show_format(struct rkcif_device *dev, struct seq_file *f)
seq_printf(f, "\t\t\tdvp pix err:%llu\n", dev->irq_stats.dvp_pix_err_cnt);
seq_printf(f, "\t\t\tdvp line err:%llu\n", dev->irq_stats.dvp_line_err_cnt);
seq_printf(f, "\t\t\tdvp over flow:%llu\n", dev->irq_stats.dvp_overflow_cnt);
seq_printf(f, "\t\t\tdvp bandwidth lack:%llu\n", dev->irq_stats.dvp_bwidth_lack_cnt);
seq_printf(f, "\t\t\tdvp size err:%llu\n", dev->irq_stats.dvp_size_err_cnt);
} else {
seq_printf(f, "\t\t\tcsi over flow:%llu\n", dev->irq_stats.csi_overflow_cnt);
seq_printf(f, "\t\t\tcsi bandwidth lack:%llu\n", dev->irq_stats.csi_bwidth_lack_cnt);
seq_printf(f, "\t\t\tcsi size err:%llu\n", dev->irq_stats.csi_size_err_cnt);
}
seq_printf(f, "\t\t\tall err count:%llu\n", dev->irq_stats.all_err_cnt);
seq_printf(f, "\t\t\tframe dma end:%llu\n", dev->irq_stats.all_frm_end_cnt);

View File

@@ -61,6 +61,9 @@ enum cif_reg_index {
CIF_REG_DVP_FRM0_ADDR_UV_ID3,
CIF_REG_DVP_FRM1_ADDR_Y_ID3,
CIF_REG_DVP_FRM1_ADDR_UV_ID3,
CIF_REG_DVP_SAV_EAV,
CIF_REG_DVP_LINE_CNT1,
CIF_REG_DVP_LINE_INT_NUM1,
/* mipi & lvds registers index */
CIF_REG_MIPI_LVDS_ID0_CTRL0,
CIF_REG_MIPI_LVDS_ID0_CTRL1,
@@ -134,6 +137,12 @@ enum cif_reg_index {
CIF_REG_LVDS_SAV_EAV_BLK0_ID3,
CIF_REG_LVDS_SAV_EAV_ACT1_ID3,
CIF_REG_LVDS_SAV_EAV_BLK1_ID3,
CIF_REG_MIPI_EFFECT_CODE_ID0,
CIF_REG_MIPI_EFFECT_CODE_ID1,
CIF_REG_MIPI_EFFECT_CODE_ID2,
CIF_REG_MIPI_EFFECT_CODE_ID3,
CIF_REG_MIPI_ON_PAD,
CIF_REG_Y_STAT_CONTROL,
CIF_REG_Y_STAT_VALUE,
CIF_REG_MMU_DTE_ADDR,
@@ -149,6 +158,34 @@ enum cif_reg_index {
/* reg belowed is in grf */
CIF_REG_GRF_CIFIO_CON,
CIF_REG_GRF_CIFIO_CON1,
/* reg global control */
CIF_REG_GLB_CTRL,
CIF_REG_GLB_INTEN,
CIF_REG_GLB_INTST,
CIF_REG_SCL_CH_CTRL,
CIF_REG_SCL_CTRL,
CIF_REG_SCL_FRM0_ADDR_CH0,
CIF_REG_SCL_FRM1_ADDR_CH0,
CIF_REG_SCL_VLW_CH0,
CIF_REG_SCL_FRM0_ADDR_CH1,
CIF_REG_SCL_FRM1_ADDR_CH1,
CIF_REG_SCL_VLW_CH1,
CIF_REG_SCL_FRM0_ADDR_CH2,
CIF_REG_SCL_FRM1_ADDR_CH2,
CIF_REG_SCL_VLW_CH2,
CIF_REG_SCL_FRM0_ADDR_CH3,
CIF_REG_SCL_FRM1_ADDR_CH3,
CIF_REG_SCL_VLW_CH3,
CIF_REG_SCL_BLC_CH0,
CIF_REG_SCL_BLC_CH1,
CIF_REG_SCL_BLC_CH2,
CIF_REG_SCL_BLC_CH3,
CIF_REG_TOISP0_CTRL,
CIF_REG_TOISP0_SIZE,
CIF_REG_TOISP0_CROP,
CIF_REG_TOISP1_CTRL,
CIF_REG_TOISP1_SIZE,
CIF_REG_TOISP1_CROP,
CIF_REG_INDEX_MAX
};
@@ -298,6 +335,116 @@ enum cif_reg_index {
#define CIF_MMU_INT_STATUS 0x820
#define CIF_MMU_AUTO_GATING 0x824
/* RK3588 DVP Registers Offset */
#define DVP_CTRL 0x10
#define DVP_INTEN 0x14
#define DVP_INTSTAT 0x18
#define DVP_FOR 0x1C
#define DVP_MULTI_ID 0x20
#define DVP_SAV_EAV 0x24
#define DVP_CROP_SIZE 0x28
#define DVP_CROP 0x2C
#define DVP_FRM0_ADDR_Y_ID0 0x30
#define DVP_FRM0_ADDR_UV_ID0 0x34
#define DVP_FRM1_ADDR_Y_ID0 0x38
#define DVP_FRM1_ADDR_UV_ID0 0x3C
#define DVP_FRM0_ADDR_Y_ID1 0x40
#define DVP_FRM0_ADDR_UV_ID1 0x44
#define DVP_FRM1_ADDR_Y_ID1 0x48
#define DVP_FRM1_ADDR_UV_ID1 0x4C
#define DVP_FRM0_ADDR_Y_ID2 0x50
#define DVP_FRM0_ADDR_UV_ID2 0x54
#define DVP_FRM1_ADDR_Y_ID2 0x58
#define DVP_FRM1_ADDR_UV_ID2 0x5C
#define DVP_FRM0_ADDR_Y_ID3 0x60
#define DVP_FRM0_ADDR_UV_ID3 0x64
#define DVP_FRM1_ADDR_Y_ID3 0x68
#define DVP_FRM1_ADDR_UV_ID3 0x6C
#define DVP_VIR_LINE_WIDTH 0x70
#define DVP_LINE_INT_NUM_01 0x74
#define DVP_LINE_INT_NUM_23 0x78
#define DVP_LINE_CNT_01 0x7C
#define DVP_LINE_CNT_23 0x80
/* RK3588 CSI Registers Offset */
#define CSI_MIPI0_ID0_CTRL0 0x100
#define CSI_MIPI0_ID0_CTRL1 0x104
#define CSI_MIPI0_ID1_CTRL0 0x108
#define CSI_MIPI0_ID1_CTRL1 0x10C
#define CSI_MIPI0_ID2_CTRL0 0x110
#define CSI_MIPI0_ID2_CTRL1 0x114
#define CSI_MIPI0_ID3_CTRL0 0x118
#define CSI_MIPI0_ID3_CTRL1 0x11C
#define CSI_MIPI0_CTRL 0x120
#define CSI_MIPI0_FRM0_ADDR_Y_ID0 0x124
#define CSI_MIPI0_FRM1_ADDR_Y_ID0 0x128
#define CSI_MIPI0_FRM0_ADDR_UV_ID0 0x12C
#define CSI_MIPI0_FRM1_ADDR_UV_ID0 0x130
#define CSI_MIPI0_VLW_ID0 0x134
#define CSI_MIPI0_FRM0_ADDR_Y_ID1 0x138
#define CSI_MIPI0_FRM1_ADDR_Y_ID1 0x13C
#define CSI_MIPI0_FRM0_ADDR_UV_ID1 0x140
#define CSI_MIPI0_FRM1_ADDR_UV_ID1 0x144
#define CSI_MIPI0_VLW_ID1 0x148
#define CSI_MIPI0_FRM0_ADDR_Y_ID2 0x14C
#define CSI_MIPI0_FRM1_ADDR_Y_ID2 0x150
#define CSI_MIPI0_FRM0_ADDR_UV_ID2 0x154
#define CSI_MIPI0_FRM1_ADDR_UV_ID2 0x158
#define CSI_MIPI0_VLW_ID2 0x15C
#define CSI_MIPI0_FRM0_ADDR_Y_ID3 0x160
#define CSI_MIPI0_FRM1_ADDR_Y_ID3 0x164
#define CSI_MIPI0_FRM0_ADDR_UV_ID3 0x168
#define CSI_MIPI0_FRM1_ADDR_UV_ID3 0x16C
#define CSI_MIPI0_VLW_ID3 0x170
#define CSI_MIPI0_INTEN 0x174
#define CSI_MIPI0_INTSTAT 0x178
#define CSI_MIPI0_LINE_INT_NUM_ID0_1 0x17C
#define CSI_MIPI0_LINE_INT_NUM_ID2_3 0x180
#define CSI_MIPI0_LINE_CNT_ID0_1 0x184
#define CSI_MIPI0_LINE_CNT_ID2_3 0x188
#define CSI_MIPI0_ID0_CROP_START 0x18C
#define CSI_MIPI0_ID1_CROP_START 0x190
#define CSI_MIPI0_ID2_CROP_START 0x194
#define CSI_MIPI0_ID3_CROP_START 0x198
#define CSI_MIPI0_FRAME_NUM_VC0 0x19C
#define CSI_MIPI0_FRAME_NUM_VC1 0x1A0
#define CSI_MIPI0_FRAME_NUM_VC2 0x1A4
#define CSI_MIPI0_FRAME_NUM_VC3 0x1A8
#define CSI_MIPI0_EFFECT_CODE_ID0 0x1AC
#define CSI_MIPI0_EFFECT_CODE_ID1 0x1B0
#define CSI_MIPI0_EFFECT_CODE_ID2 0x1B4
#define CSI_MIPI0_EFFECT_CODE_ID3 0x1B8
#define CSI_MIPI0_ON_PAD 0x1BC
/* RK3588 CONTROL Registers Offset */
#define GLB_CTRL 0X000
#define GLB_INTEN 0X004
#define GLB_INTST 0X008
#define SCL_CH_CTRL 0x700
#define SCL_CTRL 0x704
#define SCL_FRM0_ADDR_CH0 0x708
#define SCL_FRM1_ADDR_CH0 0x70C
#define SCL_VLW_CH0 0x710
#define SCL_FRM0_ADDR_CH1 0x714
#define SCL_FRM1_ADDR_CH1 0x718
#define SCL_VLW_CH1 0x71C
#define SCL_FRM0_ADDR_CH2 0x720
#define SCL_FRM1_ADDR_CH2 0x724
#define SCL_VLW_CH2 0x728
#define SCL_FRM0_ADDR_CH3 0x72C
#define SCL_FRM1_ADDR_CH3 0x730
#define SCL_VLW_CH3 0x734
#define SCL_BLC_CH0 0x738
#define SCL_BLC_CH1 0x73C
#define SCL_BLC_CH2 0x740
#define SCL_BLC_CH3 0x744
#define TOISP0_CH_CTRL 0x780
#define TOISP0_CROP_SIZE 0x784
#define TOISP0_CROP 0x788
#define TOISP1_CH_CTRL 0x78C
#define TOISP1_CROP_SIZE 0x790
#define TOISP1_CROP 0x794
/* The key register bit description */
/* CIF_CTRL Reg */
@@ -307,6 +454,13 @@ enum cif_reg_index {
#define MODE_PINGPONG (0x1 << 1)
#define MODE_LINELOOP (0x2 << 1)
#define AXI_BURST_16 (0xF << 12)
#define DVP_PRESS_EN (0x1 << 12)
#define DVP_HURRY_EN (0x1 << 8)
#define DVP_DMA_EN (0x1 << 1)
#define DVP_SW_WATER_LINE_75 (0x0 << 5)
#define DVP_SW_WATER_LINE_50 (0x1 << 5)
#define DVP_SW_WATER_LINE_25 (0x2 << 5)
#define DVP_SW_WATER_LINE_00 (0x3 << 5)
/* CIF_INTEN */
#define INTEN_DISABLE (0x0 << 0)
@@ -337,6 +491,22 @@ enum cif_reg_index {
#define INTSTAT_ERR (0xFC)
#define DVP_ALL_OVERFLOW (IFIFO_OVERFLOW | DFIFO_OVERFLOW)
#define DVP_FIFO_OVERFLOW (0x01 << 16)
#define DVP_BANDWIDTH_LACK (0x01 << 17)
#define DVP_SIZE_ERR_ID0 (0x1 << 22)
#define DVP_SIZE_ERR_ID1 (0x1 << 23)
#define DVP_SIZE_ERR_ID2 (0x1 << 24)
#define DVP_SIZE_ERR_ID3 (0x1 << 25)
#define DVP_SIZE_ERR (DVP_SIZE_ERR_ID0 |\
DVP_SIZE_ERR_ID1 |\
DVP_SIZE_ERR_ID2 |\
DVP_SIZE_ERR_ID3)
#define DVP_SW_PRESS_VALUE(val) (((val) & 0x7) << 13)
#define DVP_SW_HURRY_VALUE(val) (((val) & 0x7) << 9)
#define DVP_DMA_END_INTEN(id) \
({ \
unsigned int mask; \
@@ -351,7 +521,7 @@ enum cif_reg_index {
mask; \
})
#define DVP_LINE_INTEN (0x01 << 10)
#define DVP_LINE_INTEN (0x01 << 10)
#define DVP_DMA_END_INTSTAT(id) \
({ \
@@ -367,8 +537,8 @@ enum cif_reg_index {
mask; \
})
#define DVP_PST_INTSTAT PST_INF_FRAME_END
#define DVP_LINE_INTSTAT (0x01 << 10)
#define DVP_PST_INTSTAT PST_INF_FRAME_END
#define DVP_LINE_INTSTAT (0x01 << 10)
/* FRAME STATUS */
#define FRAME_STAT_CLS 0x00
@@ -433,6 +603,19 @@ enum cif_reg_index {
#define BT656_1120_MULTI_ID_2_MASK ~(0x03 << 20)
#define BT656_1120_MULTI_ID_3_MASK ~(0x03 << 28)
#define CIF_HIGH_ALIGN (0x01 << 18)
#define CIF_HIGH_ALIGN_RK3588 (0x01 << 21)
#define BT1120_CLOCK_SINGLE_EDGES_RK3588 (0x00 << 11)
#define BT1120_CLOCK_DOUBLE_EDGES_RK3588 (0x01 << 11)
#define TRANSMIT_INTERFACE_RK3588 (0x01 << 9)
#define TRANSMIT_PROGRESS_RK3588 (0x00 << 9)
#define BT1120_YC_SWAP_RK3588 (0x01 << 12)
#define INPUT_BT601_YUV422 (0x00 << 2)
#define INPUT_BT601_RAW (0x01 << 2)
#define INPUT_BT656_YUV422 (0x02 << 2)
#define INPUT_BT1120_YUV422 (0x03 << 2)
#define INPUT_SONY_RAW (0x04 << 2)
/* CIF_SCL_CTRL */
#define ENABLE_SCL_DOWN (0x01 << 0)
@@ -460,11 +643,33 @@ enum cif_reg_index {
#define DVP_CHANNEL3_F1_READY (0x01 << 13)
#define DVP_CHANNEL3_FRM_READ (DVP_CHANNEL3_F0_READY | DVP_CHANNEL3_F1_READY)
#define DVP_FRAME0_START_ID0 (0x1 << 0)
#define DVP_FRAME1_START_ID0 (0x1 << 1)
#define DVP_FRAME_END_ID0 (0x1 << 0)
#define DVP_FRAME_END_ID1 (0x1 << 11)
#define DVP_FRAME_END_ID2 (0x1 << 12)
#define DVP_FRAME_END_ID3 (0x1 << 13)
#define DVP_FRAME0_END_ID0 (0x1 << 8)
#define DVP_FRAME1_END_ID0 (0x1 << 9)
#define DVP_ALL_END_ID0 (DVP_FRAME0_END_ID0 | DVP_FRAME1_END_ID0)
#define DVP_FRAME0_END_ID1 (0x1 << 10)
#define DVP_FRAME1_END_ID1 (0x1 << 11)
#define DVP_ALL_END_ID1 (DVP_FRAME0_END_ID1 | DVP_FRAME1_END_ID1)
#define DVP_FRAME0_END_ID2 (0x1 << 12)
#define DVP_FRAME1_END_ID2 (0x1 << 13)
#define DVP_ALL_END_ID2 (DVP_FRAME0_END_ID2 | DVP_FRAME1_END_ID2)
#define DVP_FRAME0_END_ID3 (0x1 << 14)
#define DVP_FRAME1_END_ID3 (0x1 << 15)
#define DVP_ALL_END_ID3 (DVP_FRAME0_END_ID3 | DVP_FRAME1_END_ID3)
#define DVP_ALIGN_MSB (0x01 << 21)
#define DVP_ALIGN_LSB (0x00 << 21)
#define DVP_FRM_STS_ID0(x) (((x) & (0x3 << 0)) >> 0)
#define DVP_FRM_STS_ID1(x) (((x) & (0x3 << 4)) >> 4)
#define DVP_FRM_STS_ID2(x) (((x) & (0x3 << 8)) >> 8)
@@ -497,6 +702,21 @@ enum cif_reg_index {
#define CIF_CROP_Y_SHIFT 16
#define CIF_CROP_X_SHIFT 0
/* CIF SCALE*/
#define SCALE_END_INTSTAT(ch) (0x3 << ((ch + 1) * 2))
#define SCALE_FIFO_OVERFLOW(ch) (1 << (10 + ch))
#define SCALE_TOISP_AXI0_ERR (1 << 0)
#define SCALE_TOISP_AXI1_ERR (1 << 1)
#define CIF_SCALE_SW_PRESS_VALUE(val) (((val) & 0x7) << 13)
#define CIF_SCALE_SW_PRESS_ENABLE (0x1 << 12)
#define CIF_SCALE_SW_HURRY_VALUE(val) (((val) & 0x7) << 5)
#define CIF_SCALE_SW_HURRY_ENABLE (0x1 << 4)
#define CIF_SCALE_SW_WATER_LINE(val) (val << 1)
#define CIF_SCALE_SW_SRC_CH(val, ch) ((val & 0x1f) << (3 + ch * 8))
#define CIF_SCALE_SW_MODE(val, ch) ((val & 0x3) << (1 + ch * 8))
#define CIF_SCALE_EN(ch) (1 << (ch * 8))
#define SW_SCALE_END(intstat, ch) ((intstat >> ((ch + 1) * 2)) & 0x3)
/* CIF_CSI_ID_CTRL0 */
#define CSI_DISABLE_CAPTURE (0x0 << 0)
#define CSI_ENABLE_CAPTURE (0x1 << 0)
@@ -511,12 +731,38 @@ enum cif_reg_index {
#define CSI_ENABLE_COMMAND_MODE (0x1 << 4)
#define CSI_DISABLE_CROP (0x0 << 5)
#define CSI_ENABLE_CROP (0x1 << 5)
#define CSI_DISABLE_CROP_V1 (0x0 << 4)
#define CSI_ENABLE_CROP_V1 (0x1 << 4)
#define CSI_ENABLE_MIPI_COMPACT (0x1 << 6)
#define CSI_YUV_INPUT_ORDER_UYVY (0x0 << 16)
#define CSI_YUV_INPUT_ORDER_VYUY (0x1 << 16)
#define CSI_YUV_INPUT_ORDER_YUYV (0x2 << 16)
#define CSI_YUV_INPUT_ORDER_YVYU (0x3 << 16)
#define CSI_ENABLE_MIPI_HIGH_ALIGN (0x1 << 31)
#define CSI_HIGH_ALIGN (0x1 << 31)
#define CSI_HIGH_ALIGN_RK3588 (0x1 << 27)
#define CSI_YUV_OUTPUT_ORDER_UYVY (0x0 << 18)
#define CSI_YUV_OUTPUT_ORDER_VYUY (0x1 << 18)
#define CSI_YUV_OUTPUT_ORDER_YUYV (0x2 << 18)
#define CSI_YUV_OUTPUT_ORDER_YVYU (0x3 << 18)
#define CSI_WRDDR_TYPE_RAW_COMPACT (0x0 << 5)
#define CSI_WRDDR_TYPE_RAW_UNCOMPACT (0x1 << 5)
#define CSI_WRDDR_TYPE_YUV_PACKET (0x2 << 5)
#define CSI_WRDDR_TYPE_YUV400_RK3588 (0x3 << 5)
#define CSI_WRDDR_TYPE_YUV422SP_RK3588 (0x4 << 5)
#define CSI_WRDDR_TYPE_YUV420SP_RK3588 (0x5 << 5)
#define CSI_ALIGN_MSB (0x01 << 27)
#define CSI_ALIGN_LSB (0x0 << 27)
#define CSI_DMA_ENABLE (0x1 << 28)
#define CSI_NO_HDR (0X0 << 22)
#define CSI_HDR2 (0X1 << 22)
#define CSI_HDR3 (0X2 << 22)
#define CSI_HDR_MODE_VC (0x0 << 20)
#define CSI_HDR_MODE_LINE_CNT (0x1 << 20)
#define CSI_HDR_MODE_LINE_INFO (0x2 << 20)
#define CSI_HDR_VC_MODE_PROTECT (0x1 << 29)
#define LVDS_ENABLE_CAPTURE (0x1 << 16)
#define LVDS_MODE(mode) (((mode) & 0x7) << 17)
@@ -561,14 +807,17 @@ enum cif_reg_index {
#define CSI_ALL_FRAME_START_INTEN (0xff << 0)
#define CSI_ALL_FRAME_END_INTEN (0xff << 8)
#define CSI_ALL_ERROR_INTEN (0x1f << 16)
#define CSI_ALL_ERROR_INTEN_V1 (0xf0f << 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_LINE_INTEN_RK3588(id) (0x1 << ((id) + 20))
#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))
#define CSI_LINE_INTSTAT_V1(id) (0x1 << ((id) + 20))
/* CIF_CSI_INTSTAT */
#define CSI_FRAME0_START_ID0 (0x1 << 0)
@@ -598,51 +847,72 @@ enum cif_reg_index {
#define CSI_LINE_ID3_INTST (0x1 << 24)
#define CSI_DMA_LVDS_ID2_FIFO_OVERFLOW (0x1 << 25)
#define CSI_DMA_LVDS_ID3_FIFO_OVERFLOW (0x1 << 26)
#define CSI_SIZE_ERR_ID0 (0x1 << 24)
#define CSI_SIZE_ERR_ID1 (0x1 << 25)
#define CSI_SIZE_ERR_ID2 (0x1 << 26)
#define CSI_SIZE_ERR_ID3 (0x1 << 27)
#define CSI_FRAME_START_ID0 (CSI_FRAME0_START_ID0 |\
CSI_FRAME1_START_ID0)
#define CSI_FRAME_START_ID1 (CSI_FRAME0_START_ID1 |\
CSI_FRAME1_START_ID1)
#define CSI_FRAME_START_ID2 (CSI_FRAME0_START_ID2 |\
CSI_FRAME1_START_ID2)
#define CSI_FRAME_START_ID3 (CSI_FRAME0_START_ID3 |\
CSI_FRAME1_START_ID3)
#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 |\
CSI_RX_FIFO_OVERFLOW |\
CSI_DMA_LVDS_ID2_FIFO_OVERFLOW |\
CSI_DMA_LVDS_ID3_FIFO_OVERFLOW)
/*mask for rk3588*/
#define CSI_RX_FIFO_OVERFLOW_V1 (0x1 << 19)
#define CSI_BANDWIDTH_LACK_V1 (0x1 << 18)
#define CSI_ALL_ERROR_INTEN_V1 (0xf0f << 16)
#define CSI_FIFO_OVERFLOW_V1 (CSI_DMA_Y_FIFO_OVERFLOW |\
CSI_DMA_UV_FIFO_OVERFLOW |\
CSI_RX_FIFO_OVERFLOW_V1)
#define CSI_SIZE_ERR (CSI_SIZE_ERR_ID0 |\
CSI_SIZE_ERR_ID1 |\
CSI_SIZE_ERR_ID2 |\
CSI_SIZE_ERR_ID3)
#define CSI_FRAME_START_ID0 (CSI_FRAME0_START_ID0 |\
CSI_FRAME1_START_ID0)
#define CSI_FRAME_START_ID1 (CSI_FRAME0_START_ID1 |\
CSI_FRAME1_START_ID1)
#define CSI_FRAME_START_ID2 (CSI_FRAME0_START_ID2 |\
CSI_FRAME1_START_ID2)
#define CSI_FRAME_START_ID3 (CSI_FRAME0_START_ID3 |\
CSI_FRAME1_START_ID3)
#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 | \
CSI_RX_FIFO_OVERFLOW | \
CSI_DMA_LVDS_ID2_FIFO_OVERFLOW | \
CSI_DMA_LVDS_ID3_FIFO_OVERFLOW)
/* CIF_MIPI_LVDS_CTRL */
#define CIF_MIPI_LVDS_SW_DMA_IDLE (0x1 << 16)
#define CIF_MIPI_LVDS_SW_PRESS_VALUE(val) (((val) & 0x3) << 13)
#define CIF_MIPI_LVDS_SW_PRESS_ENABLE (0x1 << 12)
#define CIF_MIPI_LVDS_SW_LVDS_WIDTH_8BITS (0x0 << 9)
#define CIF_MIPI_LVDS_SW_LVDS_WIDTH_10BITS (0x1 << 9)
#define CIF_MIPI_LVDS_SW_LVDS_WIDTH_12BITS (0x2 << 9)
#define CIF_MIPI_LVDS_SW_SEL_LVDS (0x1 << 8)
#define CIF_MIPI_LVDS_SW_HURRY_VALUE(val) (((val) & 0x3) << 5)
#define CIF_MIPI_LVDS_SW_HURRY_ENABLE (0x1 << 4)
#define CIF_MIPI_LVDS_SW_WATER_LINE_75 (0x0 << 1)
#define CIF_MIPI_LVDS_SW_WATER_LINE_50 (0x1 << 1)
#define CIF_MIPI_LVDS_SW_WATER_LINE_25 (0x2 << 1)
#define CIF_MIPI_LVDS_SW_WATER_LINE_00 (0x3 << 1)
#define CIF_MIPI_LVDS_SW_WATER_LINE_ENABLE (0x1 << 0)
#define CIF_MIPI_LVDS_SW_DMA_IDLE_RK1808 (0x1 << 24)
#define CIF_MIPI_LVDS_SW_DMA_IDLE (0x1 << 16)
#define CIF_MIPI_LVDS_SW_PRESS_VALUE(val) (((val) & 0x3) << 13)
#define CIF_MIPI_LVDS_SW_PRESS_VALUE_RK3588(val) (((val) & 0x7) << 13)
#define CIF_MIPI_LVDS_SW_PRESS_ENABLE (0x1 << 12)
#define CIF_MIPI_LVDS_SW_LVDS_WIDTH_8BITS (0x0 << 9)
#define CIF_MIPI_LVDS_SW_LVDS_WIDTH_10BITS (0x1 << 9)
#define CIF_MIPI_LVDS_SW_LVDS_WIDTH_12BITS (0x2 << 9)
#define CIF_MIPI_LVDS_SW_SEL_LVDS (0x1 << 8)
#define CIF_MIPI_LVDS_SW_HURRY_VALUE(val) (((val) & 0x3) << 5)
#define CIF_MIPI_LVDS_SW_HURRY_VALUE_RK3588(val) (((val) & 0x7) << 5)
#define CIF_MIPI_LVDS_SW_HURRY_ENABLE (0x1 << 4)
#define CIF_MIPI_LVDS_SW_WATER_LINE_75 (0x0 << 1)
#define CIF_MIPI_LVDS_SW_WATER_LINE_50 (0x1 << 1)
#define CIF_MIPI_LVDS_SW_WATER_LINE_25 (0x2 << 1)
#define CIF_MIPI_LVDS_SW_WATER_LINE_00 (0x3 << 1)
#define CIF_MIPI_LVDS_SW_WATER_LINE_ENABLE (0x1 << 0)
#define CIF_MIPI_LVDS_SW_DMA_IDLE_RK1808 (0x1 << 24)
#define CIF_MIPI_LVDS_SW_HURRY_VALUE_RK1808(val) (((val) & 0x3) << 17)
#define CIF_MIPI_LVDS_SW_HURRY_ENABLE_RK1808 (0x1 << 16)
#define CIF_MIPI_LVDS_SW_WATER_LINE_75_RK1808 (0x0 << 0)
#define CIF_MIPI_LVDS_SW_WATER_LINE_50_RK1808 (0x1 << 0)
#define CIF_MIPI_LVDS_SW_WATER_LINE_25_RK1808 (0x2 << 0)
#define CIF_MIPI_LVDS_SW_WATER_LINE_00_RK1808 (0x3 << 0)
#define CIF_MIPI_LVDS_SW_HURRY_ENABLE_RK1808 (0x1 << 16)
#define CIF_MIPI_LVDS_SW_WATER_LINE_75_RK1808 (0x0 << 0)
#define CIF_MIPI_LVDS_SW_WATER_LINE_50_RK1808 (0x1 << 0)
#define CIF_MIPI_LVDS_SW_WATER_LINE_25_RK1808 (0x2 << 0)
#define CIF_MIPI_LVDS_SW_WATER_LINE_00_RK1808 (0x3 << 0)
#define CIF_MIPI_LVDS_SW_WATER_LINE_ENABLE_RK1808 (0x1 << 4)
/* CSI Host Registers Define */
@@ -688,5 +958,16 @@ enum cif_reg_index {
#define RK3568_CIF_PCLK_SAMPLING_EDGE_FALLING (0x10001000)
#define RK3568_CIF_PCLK_SINGLE_EDGE (0x02000000)
#define RK3568_CIF_PCLK_DUAL_EDGE (0x02000200)
#define CIF_GRF_SOC_CON2 (0x308)
#define RK3588_CIF_PCLK_SAMPLING_EDGE_RISING (0x00100000)
#define RK3588_CIF_PCLK_SAMPLING_EDGE_FALLING (0x00100010)
#define RK3588_CIF_PCLK_SINGLE_EDGE (0x00200000)
#define RK3588_CIF_PCLK_DUAL_EDGE (0x00200020)
/*toisp*/
#define TOISP_END_CH0(index) (0x1 << (20 + index * 3))
#define TOISP_END_CH1(index) (0x1 << (21 + index * 3))
#define TOISP_END_CH2(index) (0x1 << (22 + index * 3))
#endif

View File

@@ -20,12 +20,36 @@
#include <media/videobuf2-dma-contig.h>
#include <media/v4l2-fwnode.h>
#include "dev.h"
#include <linux/regulator/consumer.h>
static inline struct sditf_priv *to_sditf_priv(struct v4l2_subdev *subdev)
{
return container_of(subdev, struct sditf_priv, sd);
}
static void sditf_get_hdr_mode(struct sditf_priv *priv)
{
struct rkcif_device *cif_dev = priv->cif_dev;
struct rkmodule_hdr_cfg hdr_cfg;
int ret = 0;
if (!cif_dev->terminal_sensor.sd)
rkcif_update_sensor_info(&cif_dev->stream[0]);
if (cif_dev->terminal_sensor.sd) {
ret = v4l2_subdev_call(cif_dev->terminal_sensor.sd,
core, ioctl,
RKMODULE_GET_HDR_CFG,
&hdr_cfg);
if (!ret)
priv->hdr_cfg = hdr_cfg;
else
priv->hdr_cfg.hdr_mode = NO_HDR;
} else {
priv->hdr_cfg.hdr_mode = NO_HDR;
}
}
static int sditf_g_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_frame_interval *fi)
{
@@ -69,12 +93,15 @@ static int sditf_get_set_fmt(struct v4l2_subdev *sd,
struct sditf_priv *priv = to_sditf_priv(sd);
struct rkcif_device *cif_dev = priv->cif_dev;
struct v4l2_subdev_selection input_sel;
struct v4l2_pix_format_mplane pixm;
int ret = -EINVAL;
if (!cif_dev->terminal_sensor.sd)
rkcif_update_sensor_info(&cif_dev->stream[0]);
if (cif_dev->terminal_sensor.sd) {
sditf_get_hdr_mode(priv);
fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(cif_dev->terminal_sensor.sd, pad, get_fmt, NULL, fmt);
if (ret) {
v4l2_err(&priv->sd,
@@ -83,6 +110,8 @@ static int sditf_get_set_fmt(struct v4l2_subdev *sd,
}
input_sel.target = V4L2_SEL_TGT_CROP_BOUNDS;
input_sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
input_sel.pad = 0;
ret = v4l2_subdev_call(cif_dev->terminal_sensor.sd,
pad, get_selection, NULL,
&input_sel);
@@ -90,11 +119,57 @@ static int sditf_get_set_fmt(struct v4l2_subdev *sd,
fmt->format.width = input_sel.r.width;
fmt->format.height = input_sel.r.height;
}
priv->cap_info.width = fmt->format.width;
priv->cap_info.height = fmt->format.height;
pixm.pixelformat = rkcif_mbus_pixelcode_to_v4l2(fmt->format.code);
pixm.width = priv->cap_info.width;
pixm.height = priv->cap_info.height;
v4l2_dbg(3, rkcif_debug, &cif_dev->v4l2_dev,
"%s, width %d, height %d, hdr mode %d\n",
__func__, fmt->format.width, fmt->format.width, priv->hdr_cfg.hdr_mode);
if (priv->hdr_cfg.hdr_mode == NO_HDR) {
rkcif_set_fmt(&cif_dev->stream[0], &pixm, false);
} else if (priv->hdr_cfg.hdr_mode == HDR_X2) {
rkcif_set_fmt(&cif_dev->stream[0], &pixm, false);
rkcif_set_fmt(&cif_dev->stream[1], &pixm, false);
} else if (priv->hdr_cfg.hdr_mode == HDR_X3) {
rkcif_set_fmt(&cif_dev->stream[0], &pixm, false);
rkcif_set_fmt(&cif_dev->stream[1], &pixm, false);
rkcif_set_fmt(&cif_dev->stream[2], &pixm, false);
}
}
return 0;
}
static int sditf_init_buf(struct sditf_priv *priv)
{
struct rkcif_device *cif_dev = priv->cif_dev;
int ret = 0;
if (priv->hdr_cfg.hdr_mode == HDR_X2) {
ret = rkcif_init_rx_buf(&cif_dev->stream[0], priv->buf_num);
} else if (priv->hdr_cfg.hdr_mode == HDR_X3) {
ret = rkcif_init_rx_buf(&cif_dev->stream[0], priv->buf_num);
ret |= rkcif_init_rx_buf(&cif_dev->stream[1], priv->buf_num);
} else {
ret = -EINVAL;
}
return ret;
}
static void sditf_free_buf(struct sditf_priv *priv)
{
struct rkcif_device *cif_dev = priv->cif_dev;
if (priv->hdr_cfg.hdr_mode == HDR_X2) {
rkcif_free_rx_buf(&cif_dev->stream[0], priv->buf_num);
} else if (priv->hdr_cfg.hdr_mode == HDR_X3) {
rkcif_free_rx_buf(&cif_dev->stream[0], priv->buf_num);
rkcif_free_rx_buf(&cif_dev->stream[1], priv->buf_num);
}
}
static int sditf_get_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
@@ -102,18 +177,49 @@ static int sditf_get_selection(struct v4l2_subdev *sd,
return -EINVAL;
}
static void sditf_reinit_mode(struct sditf_priv *priv, struct rkisp_vicap_mode *mode)
{
if (mode->is_rdbk) {
priv->toisp_inf.link_mode = TOISP_NONE;
} else {
if (strstr(mode->name, RKISP0_DEVNAME))
priv->toisp_inf.link_mode = TOISP0;
else if (strstr(mode->name, RKISP1_DEVNAME))
priv->toisp_inf.link_mode = TOISP1;
else if (strstr(mode->name, RKISP_UNITE_DEVNAME))
priv->toisp_inf.link_mode = TOISP_UNITE;
else
v4l2_err(&priv->cif_dev->v4l2_dev,
"%s, mode name err, mode name: %s\n",
__func__, mode->name);
}
v4l2_dbg(3, rkcif_debug, &priv->cif_dev->v4l2_dev,
"%s, mode->is_rdbk %d, mode->name %s, link_mode %d\n",
__func__, mode->is_rdbk, mode->name, priv->toisp_inf.link_mode);
}
static long sditf_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct sditf_priv *priv = to_sditf_priv(sd);
struct rkcif_device *cif_dev = priv->cif_dev;
struct v4l2_subdev *sensor_sd;
struct rkisp_vicap_mode *mode;
struct v4l2_subdev_format fmt;
int *pbuf_num = NULL;
int ret = 0;
if (!cif_dev->terminal_sensor.sd)
rkcif_update_sensor_info(&cif_dev->stream[0]);
if (cif_dev->terminal_sensor.sd) {
sensor_sd = cif_dev->terminal_sensor.sd;
return v4l2_subdev_call(sensor_sd, core, ioctl, cmd, arg);
switch (cmd) {
case RKISP_VICAP_CMD_MODE:
mode = (struct rkisp_vicap_mode *)arg;
memcpy(&priv->mode, mode, sizeof(*mode));
sditf_reinit_mode(priv, &priv->mode);
return 0;
case RKISP_VICAP_CMD_INIT_BUF:
pbuf_num = (int *)arg;
priv->buf_num = *pbuf_num;
sditf_get_set_fmt(&priv->sd, NULL, &fmt);
ret = sditf_init_buf(priv);
return ret;
default:
break;
}
return -EINVAL;
@@ -123,9 +229,36 @@ static long sditf_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
static long sditf_compat_ioctl32(struct v4l2_subdev *sd,
unsigned int cmd, unsigned long arg)
{
void __user *up = compat_ptr(arg);
struct sditf_priv *priv = to_sditf_priv(sd);
struct rkcif_device *cif_dev = priv->cif_dev;
struct v4l2_subdev *sensor_sd;
struct rkisp_vicap_mode *mode;
int buf_num;
int ret = 0;
switch (cmd) {
case RKISP_VICAP_CMD_MODE:
mode = kzalloc(sizeof(*mode), GFP_KERNEL);
if (!mode) {
ret = -ENOMEM;
return ret;
}
if (copy_from_user(mode, up, sizeof(*mode))) {
kfree(mode);
return -EFAULT;
}
ret = sditf_ioctl(sd, cmd, mode);
kfree(mode);
return ret;
case RKISP_VICAP_CMD_INIT_BUF:
if (copy_from_user(&buf_num, up, sizeof(int)))
return -EFAULT;
ret = sditf_ioctl(sd, cmd, &buf_num);
return ret;
default:
break;
}
if (!cif_dev->terminal_sensor.sd)
rkcif_update_sensor_info(&cif_dev->stream[0]);
@@ -139,6 +272,180 @@ static long sditf_compat_ioctl32(struct v4l2_subdev *sd,
}
#endif
static int sditf_channel_enable(struct sditf_priv *priv, int user)
{
struct rkcif_device *cif_dev = priv->cif_dev;
unsigned int ch0 = 0, ch1 = 0, ch2 = 0;
unsigned int ctrl_val = 0;
unsigned int int_en = 0;
unsigned int offset_x = 0;
unsigned int offset_y = 0;
unsigned int width = priv->cap_info.width;
unsigned int height = priv->cap_info.height;
if (priv->hdr_cfg.hdr_mode == NO_HDR) {
if (cif_dev->inf_id == RKCIF_MIPI_LVDS)
ch0 = cif_dev->csi_host_idx * 4;
else
ch0 = 24;//dvp
ctrl_val = (ch0 << 3) | 0x1;
if (user == 0)
int_en = 0x04104003;
else
int_en = 0x08820003;
priv->toisp_inf.ch_info[0].is_valid = true;
priv->toisp_inf.ch_info[0].id = ch0;
} else if (priv->hdr_cfg.hdr_mode == HDR_X2) {
ch0 = cif_dev->csi_host_idx * 4 + 1;
ch1 = cif_dev->csi_host_idx * 4;
ctrl_val = (ch0 << 3) | 0x1;
ctrl_val |= (ch1 << 11) | 0x100;
if (user == 0)
int_en = 0x0430c003;
else
int_en = 0x09860003;
priv->toisp_inf.ch_info[0].is_valid = true;
priv->toisp_inf.ch_info[0].id = ch0;
priv->toisp_inf.ch_info[1].is_valid = true;
priv->toisp_inf.ch_info[1].id = ch1;
} else if (priv->hdr_cfg.hdr_mode == HDR_X3) {
ch0 = cif_dev->csi_host_idx * 4 + 2;
ch1 = cif_dev->csi_host_idx * 4 + 1;
ch2 = cif_dev->csi_host_idx * 4;
ctrl_val = (ch0 << 3) | 0x1;
ctrl_val |= (ch1 << 11) | 0x100;
ctrl_val |= (ch2 << 19) | 0x10000;
if (user == 0)
int_en = 0x0471c003;
else
int_en = 0x0b8e0003;
priv->toisp_inf.ch_info[0].is_valid = true;
priv->toisp_inf.ch_info[0].id = ch0;
priv->toisp_inf.ch_info[1].is_valid = true;
priv->toisp_inf.ch_info[1].id = ch1;
priv->toisp_inf.ch_info[2].is_valid = true;
priv->toisp_inf.ch_info[2].id = ch2;
}
if (user == 0) {
if (priv->toisp_inf.link_mode == TOISP_UNITE)
width = priv->cap_info.width / 2 + 256;
rkcif_write_register_or(cif_dev, CIF_REG_TOISP0_CTRL, ctrl_val);
if (width && height) {
rkcif_write_register(cif_dev, CIF_REG_TOISP0_CROP,
offset_x | (offset_y << 16));
rkcif_write_register(cif_dev, CIF_REG_TOISP0_SIZE,
width | (height << 16));
} else {
return -EINVAL;
}
rkcif_write_register_or(cif_dev, CIF_REG_GLB_INTEN, int_en);
} else {
if (priv->toisp_inf.link_mode == TOISP_UNITE) {
offset_x = priv->cap_info.width / 2 - 256;
width = priv->cap_info.width / 2 + 256;
}
rkcif_write_register_or(cif_dev, CIF_REG_TOISP1_CTRL, ctrl_val);
if (width && height) {
rkcif_write_register(cif_dev, CIF_REG_TOISP1_CROP,
offset_x | (offset_y << 16));
rkcif_write_register(cif_dev, CIF_REG_TOISP1_SIZE,
width | (height << 16));
} else {
return -EINVAL;
}
rkcif_write_register_or(cif_dev, CIF_REG_GLB_INTEN, int_en);
}
return 0;
}
static __maybe_unused void sditf_channel_disable(struct sditf_priv *priv, int user)
{
struct rkcif_device *cif_dev = priv->cif_dev;
unsigned int ctrl_val = 0;
if (priv->hdr_cfg.hdr_mode == NO_HDR)
ctrl_val = 0x01;
else if (priv->hdr_cfg.hdr_mode == HDR_X2)
ctrl_val = 0x101;
else if (priv->hdr_cfg.hdr_mode == HDR_X3)
ctrl_val = 0x10101;
if (user == 0)
rkcif_write_register_and(cif_dev, CIF_REG_TOISP0_CTRL, ~ctrl_val);
else
rkcif_write_register_and(cif_dev, CIF_REG_TOISP1_CTRL, ~ctrl_val);
priv->toisp_inf.ch_info[0].is_valid = false;
priv->toisp_inf.ch_info[1].is_valid = false;
priv->toisp_inf.ch_info[2].is_valid = false;
}
static int sditf_start_stream(struct sditf_priv *priv)
{
struct rkcif_device *cif_dev = priv->cif_dev;
struct v4l2_subdev_format fmt;
sditf_get_set_fmt(&priv->sd, NULL, &fmt);
if (priv->toisp_inf.link_mode == TOISP0) {
sditf_channel_enable(priv, 0);
} else if (priv->toisp_inf.link_mode == TOISP1) {
sditf_channel_enable(priv, 1);
} else if (priv->toisp_inf.link_mode == TOISP_UNITE) {
sditf_channel_enable(priv, 0);
sditf_channel_enable(priv, 1);
}
if (priv->hdr_cfg.hdr_mode == NO_HDR) {
rkcif_do_start_stream(&cif_dev->stream[0], RKCIF_STREAM_MODE_TOISP);
} else if (priv->hdr_cfg.hdr_mode == HDR_X2) {
rkcif_do_start_stream(&cif_dev->stream[0], RKCIF_STREAM_MODE_TOISP);
rkcif_do_start_stream(&cif_dev->stream[1], RKCIF_STREAM_MODE_TOISP);
} else if (priv->hdr_cfg.hdr_mode == HDR_X3) {
rkcif_do_start_stream(&cif_dev->stream[0], RKCIF_STREAM_MODE_TOISP);
rkcif_do_start_stream(&cif_dev->stream[1], RKCIF_STREAM_MODE_TOISP);
rkcif_do_start_stream(&cif_dev->stream[2], RKCIF_STREAM_MODE_TOISP);
}
return 0;
}
static int sditf_stop_stream(struct sditf_priv *priv)
{
struct rkcif_device *cif_dev = priv->cif_dev;
if (priv->hdr_cfg.hdr_mode == NO_HDR) {
rkcif_do_stop_stream(&cif_dev->stream[0], RKCIF_STREAM_MODE_TOISP);
} else if (priv->hdr_cfg.hdr_mode == HDR_X2) {
rkcif_do_stop_stream(&cif_dev->stream[1], RKCIF_STREAM_MODE_TOISP);
rkcif_do_stop_stream(&cif_dev->stream[0], RKCIF_STREAM_MODE_TOISP);
} else if (priv->hdr_cfg.hdr_mode == HDR_X3) {
rkcif_do_stop_stream(&cif_dev->stream[2], RKCIF_STREAM_MODE_TOISP);
rkcif_do_stop_stream(&cif_dev->stream[1], RKCIF_STREAM_MODE_TOISP);
rkcif_do_stop_stream(&cif_dev->stream[0], RKCIF_STREAM_MODE_TOISP);
}
return 0;
}
static int sditf_s_stream(struct v4l2_subdev *sd, int on)
{
struct sditf_priv *priv = to_sditf_priv(sd);
struct rkcif_device *cif_dev = priv->cif_dev;
int ret = 0;
if (cif_dev->chip_id >= CHIP_RK3588_CIF) {
if (priv->toisp_inf.link_mode == TOISP_NONE)
return 0;
v4l2_dbg(3, rkcif_debug, &cif_dev->v4l2_dev,
"%s, toisp mode %d, hdr %d, stream on %d\n",
__func__, priv->toisp_inf.link_mode, priv->hdr_cfg.hdr_mode, on);
if (on) {
ret = sditf_start_stream(priv);
} else {
ret = sditf_stop_stream(priv);
sditf_free_buf(priv);
}
}
return ret;
}
static const struct v4l2_subdev_pad_ops sditf_subdev_pad_ops = {
.set_fmt = sditf_get_set_fmt,
.get_fmt = sditf_get_set_fmt,
@@ -148,6 +455,7 @@ static const struct v4l2_subdev_pad_ops sditf_subdev_pad_ops = {
static const struct v4l2_subdev_video_ops sditf_video_ops = {
.g_frame_interval = sditf_g_frame_interval,
.s_stream = sditf_s_stream,
};
static const struct v4l2_subdev_core_ops sditf_core_ops = {
@@ -206,7 +514,13 @@ static int rkcif_subdev_media_init(struct sditf_priv *priv)
return ret;
strncpy(priv->sd.name, dev_name(cif_dev->dev), sizeof(priv->sd.name));
priv->cap_info.width = 0;
priv->cap_info.height = 0;
priv->mode.is_rdbk = 0;
priv->toisp_inf.link_mode = TOISP_NONE;
priv->toisp_inf.ch_info[0].is_valid = false;
priv->toisp_inf.ch_info[1].is_valid = false;
priv->toisp_inf.ch_info[2].is_valid = false;
return 0;
}

View File

@@ -17,12 +17,51 @@
#include <media/v4l2-mc.h>
#include <linux/rk-camera-module.h>
#include "hw.h"
#include "../isp/isp_external.h"
#define RKISP0_DEVNAME "rkisp0"
#define RKISP1_DEVNAME "rkisp1"
#define RKISP_UNITE_DEVNAME "rkisp_unite"
#define RKCIF_TOISP_CH0 0
#define RKCIF_TOISP_CH1 1
#define RKCIF_TOISP_CH2 2
#define TOISP_CH_MAX 3
struct capture_info {
unsigned int offset_x;
unsigned int offset_y;
unsigned int width;
unsigned int height;
};
enum toisp_link_mode {
TOISP_NONE,
TOISP0,
TOISP1,
TOISP_UNITE,
};
struct toisp_ch_info {
bool is_valid;
int id;
};
struct toisp_info {
struct toisp_ch_info ch_info[TOISP_CH_MAX];
enum toisp_link_mode link_mode;
};
struct sditf_priv {
struct device *dev;
struct v4l2_subdev sd;
struct media_pad pads;
struct rkcif_device *cif_dev;
struct rkmodule_hdr_cfg hdr_cfg;
struct capture_info cap_info;
struct rkisp_vicap_mode mode;
struct toisp_info toisp_inf;
int buf_num;
};
extern struct platform_driver rkcif_subdev_driver;

View File

@@ -17,6 +17,12 @@
#define RKCIF_CMD_SET_CSI_MEMORY_MODE \
_IOW('V', BASE_VIDIOC_PRIVATE + 1, int)
#define RKCIF_CMD_GET_SCALE_BLC \
_IOR('V', BASE_VIDIOC_PRIVATE + 2, struct bayer_blc)
#define RKCIF_CMD_SET_SCALE_BLC \
_IOW('V', BASE_VIDIOC_PRIVATE + 3, struct bayer_blc)
/* cif memory mode
* 0: raw12/raw10/raw8 8bit memory compact
* 1: raw12/raw10 16bit memory one pixel
@@ -38,4 +44,14 @@ enum cif_csi_lvds_memory {
CSI_LVDS_MEM_WORD_HIGH_ALIGN = 2,
};
/* black level for scale image
* The sequence of pattern00~03 is the same as the output of sensor bayer
*/
struct bayer_blc {
u8 pattern00;
u8 pattern01;
u8 pattern02;
u8 pattern03;
};
#endif