mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 04:10:18 +09:00
media: rockchip: isp1: add dmarx patch
support read 8/16bit bayer raw and yuv422 format from memory to isp. Change-Id: I771a1a9c366a6721323815e811668472996a3355 Signed-off-by: Cai YiWei <cyw@rock-chips.com>
This commit is contained in:
@@ -6,4 +6,5 @@ video_rkisp1-objs += rkisp1.o \
|
||||
regs.o \
|
||||
isp_stats.o \
|
||||
isp_params.o \
|
||||
capture.o
|
||||
capture.o \
|
||||
dmarx.o
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
* @xsubs: horizontal color samples in a 4*4 matrix, for yuv
|
||||
* @ysubs: vertical color samples in a 4*4 matrix, for yuv
|
||||
*/
|
||||
static int fcc_xysubs(u32 fcc, u32 *xsubs, u32 *ysubs)
|
||||
int fcc_xysubs(u32 fcc, u32 *xsubs, u32 *ysubs)
|
||||
{
|
||||
switch (fcc) {
|
||||
case V4L2_PIX_FMT_GREY:
|
||||
@@ -915,15 +915,12 @@ static int raw_config_mi(struct rkisp1_stream *stream)
|
||||
{
|
||||
void __iomem *base = stream->ispdev->base_addr;
|
||||
struct rkisp1_device *dev = stream->ispdev;
|
||||
struct v4l2_mbus_framefmt *in_frm =
|
||||
&dev->active_sensor->fmt.format;
|
||||
struct v4l2_mbus_framefmt *in_frm;
|
||||
u32 in_size;
|
||||
|
||||
v4l2_dbg(1, rkisp1_debug, &dev->v4l2_dev,
|
||||
"stream:%d input %dx%d\n",
|
||||
stream->id, in_frm->width, in_frm->height);
|
||||
|
||||
if (dev->active_sensor->mbus.type != V4L2_MBUS_CSI2) {
|
||||
if (!dev->active_sensor ||
|
||||
(dev->active_sensor &&
|
||||
dev->active_sensor->mbus.type != V4L2_MBUS_CSI2)) {
|
||||
if (stream->id == RKISP1_STREAM_RAW)
|
||||
v4l2_err(&dev->v4l2_dev,
|
||||
"only mipi sensor support raw path\n");
|
||||
@@ -933,6 +930,12 @@ static int raw_config_mi(struct rkisp1_stream *stream)
|
||||
if (dev->stream[RKISP1_STREAM_RAW].streaming)
|
||||
return 0;
|
||||
|
||||
in_frm = &dev->active_sensor->fmt.format;
|
||||
|
||||
v4l2_dbg(1, rkisp1_debug, &dev->v4l2_dev,
|
||||
"stream:%d input %dx%d\n",
|
||||
stream->id, in_frm->width, in_frm->height);
|
||||
|
||||
/* raw output size equal to sensor input size */
|
||||
if (stream->id == RKISP1_STREAM_RAW) {
|
||||
in_size = stream->out_fmt.plane_fmt[0].sizeimage;
|
||||
@@ -1183,7 +1186,8 @@ static void rkisp1_stream_stop(struct rkisp1_stream *stream)
|
||||
|
||||
stream->stopping = true;
|
||||
stream->ops->stop_mi(stream);
|
||||
if (dev->isp_state == ISP_START) {
|
||||
if (dev->isp_state == ISP_START &&
|
||||
dev->isp_inp != INP_DMARX_ISP) {
|
||||
ret = wait_event_timeout(stream->done,
|
||||
!stream->streaming,
|
||||
msecs_to_jiffies(1000));
|
||||
@@ -1382,9 +1386,10 @@ static int rkisp1_create_dummy_buf(struct rkisp1_stream *stream)
|
||||
stream->out_fmt.height,
|
||||
stream->out_fmt.plane_fmt[1].sizeimage,
|
||||
stream->out_fmt.plane_fmt[2].sizeimage);
|
||||
if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2 &&
|
||||
(dev->isp_ver == ISP_V12 ||
|
||||
dev->isp_ver == ISP_V13)) {
|
||||
if (dev->active_sensor &&
|
||||
dev->active_sensor->mbus.type == V4L2_MBUS_CSI2 &&
|
||||
(dev->isp_ver == ISP_V12 ||
|
||||
dev->isp_ver == ISP_V13)) {
|
||||
u32 in_size;
|
||||
struct rkisp1_stream *raw = &dev->stream[RKISP1_STREAM_RAW];
|
||||
|
||||
@@ -1504,7 +1509,8 @@ rkisp1_start_streaming(struct vb2_queue *queue, unsigned int count)
|
||||
if (WARN_ON(stream->streaming))
|
||||
return -EBUSY;
|
||||
|
||||
if (!dev->active_sensor) {
|
||||
if (!dev->active_sensor &&
|
||||
dev->isp_inp != INP_DMARX_ISP) {
|
||||
ret = rkisp1_update_sensor_info(dev);
|
||||
if (ret < 0) {
|
||||
v4l2_err(v4l2_dev,
|
||||
@@ -1734,7 +1740,7 @@ static void rkisp1_dma_detach_device(struct rkisp1_device *rkisp1_dev)
|
||||
iommu_detach_device(domain, dev);
|
||||
}
|
||||
|
||||
static int rkisp1_fh_open(struct file *filp)
|
||||
int rkisp1_fh_open(struct file *filp)
|
||||
{
|
||||
struct rkisp1_stream *stream = video_drvdata(filp);
|
||||
struct rkisp1_device *dev = stream->ispdev;
|
||||
@@ -1749,7 +1755,7 @@ static int rkisp1_fh_open(struct file *filp)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rkisp1_fop_release(struct file *file)
|
||||
int rkisp1_fop_release(struct file *file)
|
||||
{
|
||||
struct rkisp1_stream *stream = video_drvdata(file);
|
||||
struct rkisp1_device *dev = stream->ispdev;
|
||||
@@ -2132,6 +2138,9 @@ void rkisp1_mi_isr(u32 mis_val, struct rkisp1_device *dev)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (mis_val & CIF_MI_DMA_READY)
|
||||
rkisp1_dmarx_isr(mis_val, dev);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dev->stream); ++i) {
|
||||
struct rkisp1_stream *stream = &dev->stream[i];
|
||||
|
||||
|
||||
@@ -92,6 +92,10 @@ struct rkisp1_stream_raw {
|
||||
u8 pre_stop;
|
||||
};
|
||||
|
||||
struct rkisp1_stream_dmarx {
|
||||
int y_stride;
|
||||
};
|
||||
|
||||
/* Different config between selfpath and mainpath */
|
||||
struct stream_config {
|
||||
const struct capture_fmt *fmts;
|
||||
@@ -191,12 +195,14 @@ struct rkisp1_stream {
|
||||
struct rkisp1_buffer *next_buf;
|
||||
bool streaming;
|
||||
bool stopping;
|
||||
bool frame_end;
|
||||
wait_queue_head_t done;
|
||||
unsigned int burst;
|
||||
union {
|
||||
struct rkisp1_stream_sp sp;
|
||||
struct rkisp1_stream_mp mp;
|
||||
struct rkisp1_stream_raw raw;
|
||||
struct rkisp1_stream_dmarx dmarx;
|
||||
} u;
|
||||
};
|
||||
|
||||
@@ -207,5 +213,7 @@ void rkisp1_stream_init(struct rkisp1_device *dev, u32 id);
|
||||
void rkisp1_set_stream_def_fmt(struct rkisp1_device *dev, u32 id,
|
||||
u32 width, u32 height, u32 pixelformat);
|
||||
void rkisp1_mipi_dmatx0_end(u32 status, struct rkisp1_device *dev);
|
||||
|
||||
int fcc_xysubs(u32 fcc, u32 *xsubs, u32 *ysubs);
|
||||
int rkisp1_fh_open(struct file *filp);
|
||||
int rkisp1_fop_release(struct file *file);
|
||||
#endif /* _RKISP1_PATH_VIDEO_H */
|
||||
|
||||
@@ -92,6 +92,9 @@ static int __isp_pipeline_prepare(struct rkisp1_pipeline *p,
|
||||
p->num_subdevs = 0;
|
||||
memset(p->subdevs, 0, sizeof(p->subdevs));
|
||||
|
||||
if (dev->isp_inp == INP_DMARX_ISP)
|
||||
return 0;
|
||||
|
||||
while (1) {
|
||||
struct media_pad *pad = NULL;
|
||||
|
||||
@@ -117,6 +120,10 @@ static int __isp_pipeline_prepare(struct rkisp1_pipeline *p,
|
||||
if (me->num_pads == 1)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!p->num_subdevs)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -169,6 +176,11 @@ static int __isp_pipeline_s_isp_clk(struct rkisp1_pipeline *p)
|
||||
u64 data_rate;
|
||||
int i;
|
||||
|
||||
if (dev->isp_inp == INP_DMARX_ISP) {
|
||||
clk_set_rate(dev->clks[0], 400 * 1000000UL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* find the subdev of active sensor */
|
||||
sd = p->subdevs[0];
|
||||
for (i = 0; i < p->num_subdevs; i++) {
|
||||
@@ -221,11 +233,11 @@ static int rkisp1_pipeline_open(struct rkisp1_pipeline *p,
|
||||
return 0;
|
||||
|
||||
/* go through media graphic and get subdevs */
|
||||
if (prepare)
|
||||
__isp_pipeline_prepare(p, me);
|
||||
|
||||
if (!p->num_subdevs)
|
||||
return -EINVAL;
|
||||
if (prepare) {
|
||||
ret = __isp_pipeline_prepare(p, me);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = __isp_pipeline_s_isp_clk(p);
|
||||
if (ret < 0)
|
||||
@@ -594,10 +606,14 @@ static int rkisp1_register_platform_subdevs(struct rkisp1_device *dev)
|
||||
if (ret < 0)
|
||||
goto err_unreg_isp_subdev;
|
||||
|
||||
ret = rkisp1_register_stats_vdev(&dev->stats_vdev, &dev->v4l2_dev, dev);
|
||||
ret = rkisp1_register_dmarx_vdev(dev);
|
||||
if (ret < 0)
|
||||
goto err_unreg_stream_vdev;
|
||||
|
||||
ret = rkisp1_register_stats_vdev(&dev->stats_vdev, &dev->v4l2_dev, dev);
|
||||
if (ret < 0)
|
||||
goto err_unreg_dmarx_vdev;
|
||||
|
||||
ret = rkisp1_register_params_vdev(&dev->params_vdev, &dev->v4l2_dev,
|
||||
dev);
|
||||
if (ret < 0)
|
||||
@@ -615,6 +631,8 @@ err_unreg_params_vdev:
|
||||
rkisp1_unregister_params_vdev(&dev->params_vdev);
|
||||
err_unreg_stats_vdev:
|
||||
rkisp1_unregister_stats_vdev(&dev->stats_vdev);
|
||||
err_unreg_dmarx_vdev:
|
||||
rkisp1_unregister_dmarx_vdev(dev);
|
||||
err_unreg_stream_vdev:
|
||||
rkisp1_unregister_stream_vdevs(dev);
|
||||
err_unreg_isp_subdev:
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#define _RKISP1_DEV_H
|
||||
|
||||
#include "capture.h"
|
||||
#include "dmarx.h"
|
||||
#include "rkisp1.h"
|
||||
#include "isp_params.h"
|
||||
#include "isp_stats.h"
|
||||
@@ -52,6 +53,7 @@
|
||||
#define GRP_ID_ISP BIT(2)
|
||||
#define GRP_ID_ISP_MP BIT(3)
|
||||
#define GRP_ID_ISP_SP BIT(4)
|
||||
#define GRP_ID_ISP_DMARX BIT(5)
|
||||
|
||||
#define RKISP1_MAX_BUS_CLK 8
|
||||
#define RKISP1_MAX_SENSOR 2
|
||||
@@ -77,6 +79,13 @@ enum rkisp1_isp_state {
|
||||
ISP_ERROR
|
||||
};
|
||||
|
||||
enum rkisp1_isp_inp {
|
||||
INP_INVAL = 0,
|
||||
INP_CSI,
|
||||
INP_DVP,
|
||||
INP_DMARX_ISP,
|
||||
};
|
||||
|
||||
/*
|
||||
* struct rkisp1_pipeline - An ISP hardware pipeline
|
||||
*
|
||||
@@ -138,6 +147,7 @@ struct rkisp1_device {
|
||||
struct rkisp1_stream stream[RKISP1_MAX_STREAM];
|
||||
struct rkisp1_isp_stats_vdev stats_vdev;
|
||||
struct rkisp1_isp_params_vdev params_vdev;
|
||||
struct rkisp1_dmarx_device dmarx_dev;
|
||||
struct rkisp1_pipeline pipe;
|
||||
struct vb2_alloc_ctx *alloc_ctx;
|
||||
struct iommu_domain *domain;
|
||||
@@ -154,6 +164,7 @@ struct rkisp1_device {
|
||||
struct v4l2_subdev *hdr_sensor;
|
||||
enum rkisp1_isp_state isp_state;
|
||||
unsigned int isp_err_cnt;
|
||||
enum rkisp1_isp_inp isp_inp;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
700
drivers/media/platform/rockchip/isp1/dmarx.c
Normal file
700
drivers/media/platform/rockchip/isp1/dmarx.c
Normal file
@@ -0,0 +1,700 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-event.h>
|
||||
#include <media/v4l2-fh.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
#include <media/videobuf2-dma-contig.h>
|
||||
#include <linux/dma-iommu.h>
|
||||
#include "dev.h"
|
||||
#include "regs.h"
|
||||
|
||||
#define CIF_ISP_REQ_BUFS_MIN 1
|
||||
|
||||
static const struct capture_fmt dmarx_fmts[] = {
|
||||
/* bayer raw */
|
||||
{
|
||||
.fourcc = V4L2_PIX_FMT_SRGGB8,
|
||||
.mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
|
||||
.fmt_type = FMT_BAYER,
|
||||
.bpp = { 8 },
|
||||
.mplanes = 1,
|
||||
.write_format = CIF_MI_DMA_CTRL_READ_FMT_PACKED,
|
||||
.output_format = CIF_MI_DMA_CTRL_RGB_BAYER_8BIT,
|
||||
}, {
|
||||
.fourcc = V4L2_PIX_FMT_SGRBG8,
|
||||
.mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
|
||||
.fmt_type = FMT_BAYER,
|
||||
.bpp = { 8 },
|
||||
.mplanes = 1,
|
||||
.write_format = CIF_MI_DMA_CTRL_READ_FMT_PACKED,
|
||||
.output_format = CIF_MI_DMA_CTRL_RGB_BAYER_8BIT,
|
||||
}, {
|
||||
.fourcc = V4L2_PIX_FMT_SGBRG8,
|
||||
.mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
|
||||
.fmt_type = FMT_BAYER,
|
||||
.bpp = { 8 },
|
||||
.mplanes = 1,
|
||||
.write_format = CIF_MI_DMA_CTRL_READ_FMT_PACKED,
|
||||
.output_format = CIF_MI_DMA_CTRL_RGB_BAYER_8BIT,
|
||||
}, {
|
||||
.fourcc = V4L2_PIX_FMT_SBGGR8,
|
||||
.mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
|
||||
.fmt_type = FMT_BAYER,
|
||||
.bpp = { 8 },
|
||||
.mplanes = 1,
|
||||
.write_format = CIF_MI_DMA_CTRL_READ_FMT_PACKED,
|
||||
.output_format = CIF_MI_DMA_CTRL_RGB_BAYER_8BIT,
|
||||
}, { /* 12bit used, 4 lower bits of LSB unused */
|
||||
.fourcc = V4L2_PIX_FMT_SBGGR16,
|
||||
.mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
|
||||
.fmt_type = FMT_BAYER,
|
||||
.bpp = { 16 },
|
||||
.mplanes = 1,
|
||||
.write_format = CIF_MI_DMA_CTRL_READ_FMT_PACKED,
|
||||
.output_format = CIF_MI_DMA_CTRL_RGB_BAYER_16BIT,
|
||||
}, {
|
||||
.fourcc = V4L2_PIX_FMT_YUYV,
|
||||
.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
|
||||
.fmt_type = FMT_YUV,
|
||||
.bpp = { 16 },
|
||||
.cplanes = 1,
|
||||
.mplanes = 1,
|
||||
.uv_swap = 0,
|
||||
.write_format = CIF_MI_DMA_CTRL_READ_FMT_PACKED,
|
||||
.output_format = CIF_MI_DMA_CTRL_FMT_YUV422,
|
||||
}, {
|
||||
.fourcc = V4L2_PIX_FMT_YVYU,
|
||||
.mbus_code = MEDIA_BUS_FMT_YVYU8_2X8,
|
||||
.fmt_type = FMT_YUV,
|
||||
.bpp = { 16 },
|
||||
.cplanes = 1,
|
||||
.mplanes = 1,
|
||||
.uv_swap = 0,
|
||||
.write_format = CIF_MI_DMA_CTRL_READ_FMT_PACKED,
|
||||
.output_format = CIF_MI_DMA_CTRL_FMT_YUV422,
|
||||
}, {
|
||||
.fourcc = V4L2_PIX_FMT_UYVY,
|
||||
.mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
|
||||
.fmt_type = FMT_YUV,
|
||||
.bpp = { 16 },
|
||||
.cplanes = 1,
|
||||
.mplanes = 1,
|
||||
.uv_swap = 0,
|
||||
.write_format = CIF_MI_DMA_CTRL_READ_FMT_PACKED,
|
||||
.output_format = CIF_MI_DMA_CTRL_FMT_YUV422,
|
||||
}, {
|
||||
.fourcc = V4L2_PIX_FMT_VYUY,
|
||||
.mbus_code = MEDIA_BUS_FMT_VYUY8_2X8,
|
||||
.fmt_type = FMT_YUV,
|
||||
.bpp = { 16 },
|
||||
.cplanes = 1,
|
||||
.mplanes = 1,
|
||||
.uv_swap = 0,
|
||||
.write_format = CIF_MI_DMA_CTRL_READ_FMT_PACKED,
|
||||
.output_format = CIF_MI_DMA_CTRL_FMT_YUV422,
|
||||
}
|
||||
};
|
||||
|
||||
static struct stream_config rkisp1_dmarx_stream_config = {
|
||||
.fmts = dmarx_fmts,
|
||||
.fmt_size = ARRAY_SIZE(dmarx_fmts),
|
||||
.mi = {
|
||||
.y_size_init = CIF_MI_DMA_Y_PIC_SIZE,
|
||||
.y_base_ad_init = CIF_MI_DMA_Y_PIC_START_AD,
|
||||
.cb_base_ad_init = CIF_MI_DMA_CB_PIC_START_AD,
|
||||
.cr_base_ad_init = CIF_MI_DMA_CR_PIC_START_AD,
|
||||
},
|
||||
};
|
||||
|
||||
static const
|
||||
struct capture_fmt *find_fmt(struct rkisp1_stream *stream,
|
||||
const u32 pixelfmt)
|
||||
{
|
||||
const struct capture_fmt *fmt;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < stream->config->fmt_size; i++) {
|
||||
fmt = &stream->config->fmts[i];
|
||||
if (fmt->fourcc == pixelfmt)
|
||||
return fmt;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int dmarx_config_mi(struct rkisp1_stream *stream)
|
||||
{
|
||||
struct rkisp1_device *dev = stream->ispdev;
|
||||
void __iomem *base = dev->base_addr;
|
||||
struct capture_fmt *dmarx_in_fmt = &stream->out_isp_fmt;
|
||||
|
||||
v4l2_dbg(1, rkisp1_debug, &dev->v4l2_dev,
|
||||
"%s %dx%x y_stride:%d\n", __func__,
|
||||
stream->out_fmt.width,
|
||||
stream->out_fmt.height,
|
||||
stream->u.dmarx.y_stride);
|
||||
|
||||
mi_set_y_size(stream, stream->out_fmt.width *
|
||||
stream->out_fmt.height);
|
||||
dmarx_set_y_width(base, stream->out_fmt.width);
|
||||
dmarx_set_y_line_length(base, stream->u.dmarx.y_stride);
|
||||
|
||||
mi_dmarx_ready_enable(stream);
|
||||
if (dmarx_in_fmt->uv_swap)
|
||||
dmarx_set_uv_swap(base);
|
||||
|
||||
dmarx_ctrl(base,
|
||||
dmarx_in_fmt->write_format |
|
||||
dmarx_in_fmt->output_format |
|
||||
CIF_MI_DMA_CTRL_BURST_LEN_LUM_16 |
|
||||
CIF_MI_DMA_CTRL_BURST_LEN_CHROM_16);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void update_dmarx(struct rkisp1_stream *stream)
|
||||
{
|
||||
void __iomem *base = stream->ispdev->base_addr;
|
||||
|
||||
if (stream->curr_buf) {
|
||||
mi_set_y_addr(stream,
|
||||
stream->curr_buf->buff_addr[RKISP1_PLANE_Y]);
|
||||
mi_set_cb_addr(stream,
|
||||
stream->curr_buf->buff_addr[RKISP1_PLANE_CB]);
|
||||
mi_set_cr_addr(stream,
|
||||
stream->curr_buf->buff_addr[RKISP1_PLANE_CR]);
|
||||
mi_dmarx_start(base);
|
||||
stream->frame_end = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void dmarx_stop_mi(struct rkisp1_stream *stream)
|
||||
{
|
||||
mi_dmarx_ready_disable(stream);
|
||||
}
|
||||
|
||||
static struct streams_ops rkisp1_dmarx_streams_ops = {
|
||||
.config_mi = dmarx_config_mi,
|
||||
.stop_mi = dmarx_stop_mi,
|
||||
.update_mi = update_dmarx,
|
||||
};
|
||||
|
||||
static int dmarx_frame_end(struct rkisp1_stream *stream)
|
||||
{
|
||||
unsigned long lock_flags = 0;
|
||||
|
||||
if (stream->curr_buf) {
|
||||
vb2_buffer_done(&stream->curr_buf->vb.vb2_buf,
|
||||
VB2_BUF_STATE_DONE);
|
||||
stream->curr_buf = NULL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&stream->vbq_lock, lock_flags);
|
||||
if (!list_empty(&stream->buf_queue)) {
|
||||
stream->curr_buf =
|
||||
list_first_entry(&stream->buf_queue,
|
||||
struct rkisp1_buffer,
|
||||
queue);
|
||||
list_del(&stream->curr_buf->queue);
|
||||
}
|
||||
spin_unlock_irqrestore(&stream->vbq_lock, lock_flags);
|
||||
|
||||
stream->ops->update_mi(stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************** vb2 operations*******************************/
|
||||
|
||||
static void dmarx_stop(struct rkisp1_stream *stream)
|
||||
{
|
||||
struct rkisp1_device *dev = stream->ispdev;
|
||||
struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
|
||||
int ret = 0;
|
||||
|
||||
stream->stopping = true;
|
||||
if (dev->isp_state == ISP_START &&
|
||||
!stream->frame_end) {
|
||||
ret = wait_event_timeout(stream->done,
|
||||
!stream->streaming,
|
||||
msecs_to_jiffies(500));
|
||||
if (!ret)
|
||||
v4l2_warn(v4l2_dev,
|
||||
"dmarx:%d waiting on event return error %d\n",
|
||||
stream->id, ret);
|
||||
}
|
||||
if (stream->ops->stop_mi)
|
||||
stream->ops->stop_mi(stream);
|
||||
stream->stopping = false;
|
||||
stream->streaming = false;
|
||||
stream->frame_end = false;
|
||||
}
|
||||
|
||||
static int dmarx_start(struct rkisp1_stream *stream)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = stream->ops->config_mi(stream);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
stream->curr_buf = NULL;
|
||||
dmarx_frame_end(stream);
|
||||
stream->streaming = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rkisp1_queue_setup(struct vb2_queue *queue,
|
||||
const void *parg,
|
||||
unsigned int *num_buffers,
|
||||
unsigned int *num_planes,
|
||||
unsigned int sizes[],
|
||||
void *alloc_ctxs[])
|
||||
{
|
||||
struct rkisp1_stream *stream = queue->drv_priv;
|
||||
struct rkisp1_device *dev = stream->ispdev;
|
||||
const struct v4l2_format *pfmt = parg;
|
||||
const struct v4l2_pix_format_mplane *pixm = NULL;
|
||||
const struct capture_fmt *isp_fmt = NULL;
|
||||
u32 i;
|
||||
|
||||
if (pfmt) {
|
||||
pixm = &pfmt->fmt.pix_mp;
|
||||
isp_fmt = find_fmt(stream, pixm->pixelformat);
|
||||
} else {
|
||||
pixm = &stream->out_fmt;
|
||||
isp_fmt = &stream->out_isp_fmt;
|
||||
}
|
||||
|
||||
*num_planes = isp_fmt->mplanes;
|
||||
|
||||
for (i = 0; i < isp_fmt->mplanes; i++) {
|
||||
const struct v4l2_plane_pix_format *plane_fmt;
|
||||
|
||||
plane_fmt = &pixm->plane_fmt[i];
|
||||
sizes[i] = plane_fmt->sizeimage;
|
||||
alloc_ctxs[i] = dev->alloc_ctx;
|
||||
}
|
||||
|
||||
v4l2_dbg(1, rkisp1_debug, &dev->v4l2_dev, "%s count %d, size %d\n",
|
||||
v4l2_type_names[queue->type], *num_buffers, sizes[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The vb2_buffer are stored in rkisp1_buffer, in order to unify
|
||||
* mplane buffer and none-mplane buffer.
|
||||
*/
|
||||
static void rkisp1_buf_queue(struct vb2_buffer *vb)
|
||||
{
|
||||
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
|
||||
struct rkisp1_buffer *ispbuf = to_rkisp1_buffer(vbuf);
|
||||
struct vb2_queue *queue = vb->vb2_queue;
|
||||
struct rkisp1_stream *stream = queue->drv_priv;
|
||||
unsigned long lock_flags = 0;
|
||||
struct v4l2_pix_format_mplane *pixm = &stream->out_fmt;
|
||||
struct capture_fmt *isp_fmt = &stream->out_isp_fmt;
|
||||
int i;
|
||||
|
||||
memset(ispbuf->buff_addr, 0, sizeof(ispbuf->buff_addr));
|
||||
for (i = 0; i < isp_fmt->mplanes; i++)
|
||||
ispbuf->buff_addr[i] = vb2_dma_contig_plane_dma_addr(vb, i);
|
||||
|
||||
/*
|
||||
* NOTE: plane_fmt[0].sizeimage is total size of all planes for single
|
||||
* memory plane formats, so calculate the size explicitly.
|
||||
*/
|
||||
if (isp_fmt->mplanes == 1) {
|
||||
for (i = 0; i < isp_fmt->cplanes - 1; i++) {
|
||||
ispbuf->buff_addr[i + 1] = (i == 0) ?
|
||||
ispbuf->buff_addr[i] +
|
||||
pixm->plane_fmt[i].bytesperline *
|
||||
pixm->height :
|
||||
ispbuf->buff_addr[i] +
|
||||
pixm->plane_fmt[i].sizeimage;
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&stream->vbq_lock, lock_flags);
|
||||
if (stream->streaming &&
|
||||
list_empty(&stream->buf_queue) &&
|
||||
!stream->curr_buf) {
|
||||
stream->curr_buf = ispbuf;
|
||||
stream->ops->update_mi(stream);
|
||||
} else {
|
||||
list_add_tail(&ispbuf->queue, &stream->buf_queue);
|
||||
}
|
||||
spin_unlock_irqrestore(&stream->vbq_lock, lock_flags);
|
||||
}
|
||||
|
||||
static void dmarx_stop_streaming(struct vb2_queue *queue)
|
||||
{
|
||||
struct rkisp1_stream *stream = queue->drv_priv;
|
||||
struct rkisp1_buffer *buf;
|
||||
unsigned long lock_flags = 0;
|
||||
|
||||
dmarx_stop(stream);
|
||||
|
||||
spin_lock_irqsave(&stream->vbq_lock, lock_flags);
|
||||
if (stream->curr_buf) {
|
||||
list_add_tail(&stream->curr_buf->queue, &stream->buf_queue);
|
||||
stream->curr_buf = NULL;
|
||||
}
|
||||
while (!list_empty(&stream->buf_queue)) {
|
||||
buf = list_first_entry(&stream->buf_queue,
|
||||
struct rkisp1_buffer, queue);
|
||||
list_del(&buf->queue);
|
||||
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
|
||||
}
|
||||
spin_unlock_irqrestore(&stream->vbq_lock, lock_flags);
|
||||
}
|
||||
|
||||
static int dmarx_start_streaming(struct vb2_queue *queue,
|
||||
unsigned int count)
|
||||
{
|
||||
struct rkisp1_stream *stream = queue->drv_priv;
|
||||
struct rkisp1_device *dev = stream->ispdev;
|
||||
struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
|
||||
int ret = 0;
|
||||
|
||||
if (atomic_read(&dev->open_cnt) < 2) {
|
||||
v4l2_err(v4l2_dev,
|
||||
"other stream should enable first\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (WARN_ON(stream->streaming))
|
||||
return -EBUSY;
|
||||
|
||||
ret = dmarx_start(stream);
|
||||
if (ret < 0)
|
||||
v4l2_err(v4l2_dev,
|
||||
"start dmarx stream:%d failed\n",
|
||||
stream->id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct vb2_ops dmarx_vb2_ops = {
|
||||
.queue_setup = rkisp1_queue_setup,
|
||||
.buf_queue = rkisp1_buf_queue,
|
||||
.wait_prepare = vb2_ops_wait_prepare,
|
||||
.wait_finish = vb2_ops_wait_finish,
|
||||
.stop_streaming = dmarx_stop_streaming,
|
||||
.start_streaming = dmarx_start_streaming,
|
||||
};
|
||||
|
||||
static int rkisp_init_vb2_queue(struct vb2_queue *q,
|
||||
struct rkisp1_stream *stream,
|
||||
enum v4l2_buf_type buf_type)
|
||||
{
|
||||
struct rkisp1_vdev_node *node;
|
||||
|
||||
node = queue_to_node(q);
|
||||
|
||||
q->type = buf_type;
|
||||
q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_USERPTR;
|
||||
q->drv_priv = stream;
|
||||
q->ops = &dmarx_vb2_ops;
|
||||
q->mem_ops = &vb2_dma_contig_memops;
|
||||
q->buf_struct_size = sizeof(struct rkisp1_buffer);
|
||||
q->min_buffers_needed = CIF_ISP_REQ_BUFS_MIN;
|
||||
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
|
||||
q->lock = &node->vlock;
|
||||
|
||||
return vb2_queue_init(q);
|
||||
}
|
||||
|
||||
static int rkisp1_set_fmt(struct rkisp1_stream *stream,
|
||||
struct v4l2_pix_format_mplane *pixm,
|
||||
bool try)
|
||||
{
|
||||
const struct capture_fmt *fmt;
|
||||
unsigned int imagsize = 0;
|
||||
unsigned int planes;
|
||||
u32 xsubs = 1, ysubs = 1;
|
||||
unsigned int i;
|
||||
|
||||
fmt = find_fmt(stream, pixm->pixelformat);
|
||||
if (!fmt) {
|
||||
v4l2_err(&stream->ispdev->v4l2_dev,
|
||||
"nonsupport pixelformat:%c%c%c%c\n",
|
||||
pixm->pixelformat,
|
||||
pixm->pixelformat >> 8,
|
||||
pixm->pixelformat >> 16,
|
||||
pixm->pixelformat >> 24);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pixm->num_planes = fmt->mplanes;
|
||||
pixm->field = V4L2_FIELD_NONE;
|
||||
if (!pixm->quantization)
|
||||
pixm->quantization = V4L2_QUANTIZATION_FULL_RANGE;
|
||||
|
||||
/* calculate size */
|
||||
fcc_xysubs(fmt->fourcc, &xsubs, &ysubs);
|
||||
planes = fmt->cplanes ? fmt->cplanes : fmt->mplanes;
|
||||
for (i = 0; i < planes; i++) {
|
||||
struct v4l2_plane_pix_format *plane_fmt;
|
||||
unsigned int width, height, bytesperline;
|
||||
|
||||
plane_fmt = pixm->plane_fmt + i;
|
||||
|
||||
if (i == 0) {
|
||||
width = pixm->width;
|
||||
height = pixm->height;
|
||||
} else {
|
||||
width = pixm->width / xsubs;
|
||||
height = pixm->height / ysubs;
|
||||
}
|
||||
|
||||
bytesperline = width * DIV_ROUND_UP(fmt->bpp[i], 8);
|
||||
/* stride is only available for sp stream and y plane */
|
||||
if (i != 0 ||
|
||||
plane_fmt->bytesperline < bytesperline)
|
||||
plane_fmt->bytesperline = bytesperline;
|
||||
|
||||
plane_fmt->sizeimage = plane_fmt->bytesperline * height;
|
||||
|
||||
imagsize += plane_fmt->sizeimage;
|
||||
}
|
||||
|
||||
/* convert to non-MPLANE format.
|
||||
* it's important since we want to unify none-MPLANE
|
||||
* and MPLANE.
|
||||
*/
|
||||
if (fmt->mplanes == 1)
|
||||
pixm->plane_fmt[0].sizeimage = imagsize;
|
||||
|
||||
if (!try) {
|
||||
stream->out_isp_fmt = *fmt;
|
||||
stream->out_fmt = *pixm;
|
||||
|
||||
stream->u.dmarx.y_stride =
|
||||
pixm->plane_fmt[0].bytesperline /
|
||||
DIV_ROUND_UP(fmt->bpp[0], 8);
|
||||
|
||||
v4l2_dbg(1, rkisp1_debug, &stream->ispdev->v4l2_dev,
|
||||
"%s: stream: %d req(%d, %d) out(%d, %d)\n", __func__,
|
||||
stream->id, pixm->width, pixm->height,
|
||||
stream->out_fmt.width, stream->out_fmt.height);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/************************* v4l2_file_operations***************************/
|
||||
|
||||
static const struct v4l2_file_operations rkisp1_fops = {
|
||||
.open = rkisp1_fh_open,
|
||||
.release = rkisp1_fop_release,
|
||||
.unlocked_ioctl = video_ioctl2,
|
||||
.poll = vb2_fop_poll,
|
||||
.mmap = vb2_fop_mmap,
|
||||
};
|
||||
|
||||
static int rkisp1_try_fmt_vid_out_mplane(struct file *file, void *fh,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct rkisp1_stream *stream = video_drvdata(file);
|
||||
|
||||
return rkisp1_set_fmt(stream, &f->fmt.pix_mp, true);
|
||||
}
|
||||
|
||||
static int rkisp1_enum_fmt_vid_out_mplane(struct file *file, void *priv,
|
||||
struct v4l2_fmtdesc *f)
|
||||
{
|
||||
struct rkisp1_stream *stream = video_drvdata(file);
|
||||
const struct capture_fmt *fmt = NULL;
|
||||
|
||||
if (f->index >= stream->config->fmt_size)
|
||||
return -EINVAL;
|
||||
|
||||
fmt = &stream->config->fmts[f->index];
|
||||
f->pixelformat = fmt->fourcc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rkisp1_s_fmt_vid_out_mplane(struct file *file,
|
||||
void *priv, struct v4l2_format *f)
|
||||
{
|
||||
struct rkisp1_stream *stream = video_drvdata(file);
|
||||
struct video_device *vdev = &stream->vnode.vdev;
|
||||
struct rkisp1_vdev_node *node = vdev_to_node(vdev);
|
||||
struct rkisp1_device *dev = stream->ispdev;
|
||||
|
||||
if (vb2_is_busy(&node->buf_queue)) {
|
||||
v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return rkisp1_set_fmt(stream, &f->fmt.pix_mp, false);
|
||||
}
|
||||
|
||||
static int rkisp1_g_fmt_vid_out_mplane(struct file *file, void *fh,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct rkisp1_stream *stream = video_drvdata(file);
|
||||
|
||||
f->fmt.pix_mp = stream->out_fmt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rkisp1_querycap(struct file *file, void *priv,
|
||||
struct v4l2_capability *cap)
|
||||
{
|
||||
struct rkisp1_stream *stream = video_drvdata(file);
|
||||
struct device *dev = stream->ispdev->dev;
|
||||
struct video_device *vdev = video_devdata(file);
|
||||
|
||||
strlcpy(cap->card, vdev->name, sizeof(cap->card));
|
||||
snprintf(cap->driver, sizeof(cap->driver),
|
||||
"%s_v%d", dev->driver->name,
|
||||
stream->ispdev->isp_ver >> 4);
|
||||
snprintf(cap->bus_info, sizeof(cap->bus_info),
|
||||
"platform:%s", dev_name(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_ioctl_ops rkisp1_dmarx_ioctl = {
|
||||
.vidioc_reqbufs = vb2_ioctl_reqbufs,
|
||||
.vidioc_querybuf = vb2_ioctl_querybuf,
|
||||
.vidioc_create_bufs = vb2_ioctl_create_bufs,
|
||||
.vidioc_qbuf = vb2_ioctl_qbuf,
|
||||
.vidioc_expbuf = vb2_ioctl_expbuf,
|
||||
.vidioc_dqbuf = vb2_ioctl_dqbuf,
|
||||
.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
|
||||
.vidioc_streamon = vb2_ioctl_streamon,
|
||||
.vidioc_streamoff = vb2_ioctl_streamoff,
|
||||
.vidioc_try_fmt_vid_out_mplane = rkisp1_try_fmt_vid_out_mplane,
|
||||
.vidioc_enum_fmt_vid_out_mplane = rkisp1_enum_fmt_vid_out_mplane,
|
||||
.vidioc_s_fmt_vid_out_mplane = rkisp1_s_fmt_vid_out_mplane,
|
||||
.vidioc_g_fmt_vid_out_mplane = rkisp1_g_fmt_vid_out_mplane,
|
||||
.vidioc_querycap = rkisp1_querycap,
|
||||
};
|
||||
|
||||
static void rkisp1_unregister_dmarx_video(struct rkisp1_stream *stream)
|
||||
{
|
||||
media_entity_cleanup(&stream->vnode.vdev.entity);
|
||||
video_unregister_device(&stream->vnode.vdev);
|
||||
}
|
||||
|
||||
static int rkisp1_register_dmarx_video(struct rkisp1_stream *stream)
|
||||
{
|
||||
struct rkisp1_device *dev = stream->ispdev;
|
||||
struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
|
||||
struct video_device *vdev = &stream->vnode.vdev;
|
||||
struct rkisp1_vdev_node *node;
|
||||
int ret = 0;
|
||||
|
||||
node = vdev_to_node(vdev);
|
||||
mutex_init(&node->vlock);
|
||||
|
||||
vdev->release = video_device_release_empty;
|
||||
vdev->fops = &rkisp1_fops;
|
||||
vdev->minor = -1;
|
||||
vdev->v4l2_dev = v4l2_dev;
|
||||
vdev->lock = &node->vlock;
|
||||
video_set_drvdata(vdev, stream);
|
||||
|
||||
vdev->ioctl_ops = &rkisp1_dmarx_ioctl;
|
||||
vdev->device_caps = V4L2_CAP_VIDEO_OUTPUT_MPLANE |
|
||||
V4L2_CAP_STREAMING;
|
||||
vdev->vfl_dir = VFL_DIR_TX;
|
||||
node->pad.flags = MEDIA_PAD_FL_SOURCE;
|
||||
|
||||
rkisp_init_vb2_queue(&node->buf_queue, stream,
|
||||
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
|
||||
vdev->queue = &node->buf_queue;
|
||||
|
||||
ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
|
||||
if (ret < 0) {
|
||||
v4l2_err(v4l2_dev,
|
||||
"video register failed with error %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = media_entity_init(&vdev->entity, 1, &node->pad, 0);
|
||||
if (ret < 0)
|
||||
goto unreg;
|
||||
|
||||
return 0;
|
||||
unreg:
|
||||
video_unregister_device(vdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**************** Interrupter Handler ****************/
|
||||
|
||||
void rkisp1_dmarx_isr(u32 mis_val, struct rkisp1_device *dev)
|
||||
{
|
||||
void __iomem *base = dev->base_addr;
|
||||
struct rkisp1_stream *stream;
|
||||
|
||||
if (mis_val & CIF_MI_DMA_READY) {
|
||||
stream = &dev->dmarx_dev.stream[RKISP1_STREAM_DMARX];
|
||||
stream->frame_end = true;
|
||||
writel(CIF_MI_DMA_READY, base + CIF_MI_ICR);
|
||||
|
||||
if (stream->stopping) {
|
||||
stream->stopping = false;
|
||||
stream->streaming = false;
|
||||
wake_up(&stream->done);
|
||||
} else {
|
||||
dmarx_frame_end(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int rkisp1_register_dmarx_vdev(struct rkisp1_device *dev)
|
||||
{
|
||||
struct rkisp1_dmarx_device *dmarx_dev = &dev->dmarx_dev;
|
||||
struct rkisp1_stream *stream;
|
||||
struct video_device *vdev;
|
||||
struct media_entity *source, *sink;
|
||||
int ret = 0;
|
||||
|
||||
memset(dmarx_dev, 0, sizeof(*dmarx_dev));
|
||||
dmarx_dev->ispdev = dev;
|
||||
|
||||
if (dev->isp_ver <= ISP_V13) {
|
||||
stream = &dmarx_dev->stream[RKISP1_STREAM_DMARX];
|
||||
INIT_LIST_HEAD(&stream->buf_queue);
|
||||
init_waitqueue_head(&stream->done);
|
||||
spin_lock_init(&stream->vbq_lock);
|
||||
stream->id = RKISP1_STREAM_DMARX;
|
||||
stream->ispdev = dev;
|
||||
stream->ops = &rkisp1_dmarx_streams_ops;
|
||||
stream->config = &rkisp1_dmarx_stream_config;
|
||||
vdev = &stream->vnode.vdev;
|
||||
strlcpy(vdev->name, DMA_VDEV_NAME, sizeof(vdev->name));
|
||||
ret = rkisp1_register_dmarx_video(stream);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* dmarx links -> isp subdev */
|
||||
source = &vdev->entity;
|
||||
sink = &dev->isp_sdev.sd.entity;
|
||||
media_entity_create_link(source, 0,
|
||||
sink, RKISP1_ISP_PAD_SINK, 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rkisp1_unregister_dmarx_vdev(struct rkisp1_device *dev)
|
||||
{
|
||||
struct rkisp1_dmarx_device *dmarx_dev = &dev->dmarx_dev;
|
||||
struct rkisp1_stream *stream;
|
||||
|
||||
if (dev->isp_ver <= ISP_V13) {
|
||||
stream = &dmarx_dev->stream[RKISP1_STREAM_DMARX];
|
||||
rkisp1_unregister_dmarx_video(stream);
|
||||
}
|
||||
}
|
||||
29
drivers/media/platform/rockchip/isp1/dmarx.h
Normal file
29
drivers/media/platform/rockchip/isp1/dmarx.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */
|
||||
|
||||
#ifndef _RKISP1_DMARX_H
|
||||
#define _RKISP1_DMARX_H
|
||||
|
||||
#include "capture.h"
|
||||
#include "common.h"
|
||||
|
||||
#define RKISP1_STREAM_DMARX 0
|
||||
#define RKISP1_MAX_DMARX_STREAM 1
|
||||
|
||||
struct rkisp1_dmarx_device;
|
||||
|
||||
enum rkisp1_dmarx_pad {
|
||||
RKISP1_DMARX_PAD_SINK,
|
||||
RKISP1_DMARX_PAD_SOURCE,
|
||||
RKISP1_DMARX_PAD_MAX
|
||||
};
|
||||
|
||||
struct rkisp1_dmarx_device {
|
||||
struct rkisp1_device *ispdev;
|
||||
struct rkisp1_stream stream[RKISP1_MAX_DMARX_STREAM];
|
||||
};
|
||||
|
||||
void rkisp1_dmarx_isr(u32 mis_val, struct rkisp1_device *dev);
|
||||
void rkisp1_unregister_dmarx_vdev(struct rkisp1_device *dev);
|
||||
int rkisp1_register_dmarx_vdev(struct rkisp1_device *dev);
|
||||
#endif /* _RKISP1_DMARX_H */
|
||||
@@ -91,6 +91,8 @@
|
||||
#define CIF_ISP_ACQ_PROP_IN_SEL_10B_MSB (2 << 12)
|
||||
#define CIF_ISP_ACQ_PROP_IN_SEL_8B_ZERO (3 << 12)
|
||||
#define CIF_ISP_ACQ_PROP_IN_SEL_8B_MSB (4 << 12)
|
||||
#define CIF_ISP_ACQ_PROP_DMA_RGB BIT(15)
|
||||
#define CIF_ISP_ACQ_PROP_DMA_YUV BIT(16)
|
||||
|
||||
/* VI_DPCL */
|
||||
#define CIF_VI_DPCL_DMA_JPEG (0 << 0)
|
||||
@@ -232,17 +234,17 @@
|
||||
#define CIF_MI_STATUS_SP_Y_FIFO_FULL BIT(4)
|
||||
|
||||
/* MI_DMA_CTRL */
|
||||
#define CIF_MI_DMA_CTRL_BURST_LEN_LUM_16 (0 << 0)
|
||||
#define CIF_MI_DMA_CTRL_BURST_LEN_LUM_32 (1 << 0)
|
||||
#define CIF_MI_DMA_CTRL_BURST_LEN_LUM_64 (2 << 0)
|
||||
#define CIF_MI_DMA_CTRL_BURST_LEN_CHROM_16 (0 << 2)
|
||||
#define CIF_MI_DMA_CTRL_BURST_LEN_CHROM_32 (1 << 2)
|
||||
#define CIF_MI_DMA_CTRL_BURST_LEN_CHROM_64 (2 << 2)
|
||||
#define CIF_MI_DMA_CTRL_BURST_LEN_LUM_4 (0 << 0)
|
||||
#define CIF_MI_DMA_CTRL_BURST_LEN_LUM_8 BIT(0)
|
||||
#define CIF_MI_DMA_CTRL_BURST_LEN_LUM_16 BIT(1)
|
||||
#define CIF_MI_DMA_CTRL_BURST_LEN_CHROM_4 (0 << 2)
|
||||
#define CIF_MI_DMA_CTRL_BURST_LEN_CHROM_8 BIT(2)
|
||||
#define CIF_MI_DMA_CTRL_BURST_LEN_CHROM_16 BIT(3)
|
||||
#define CIF_MI_DMA_CTRL_READ_FMT_PLANAR (0 << 4)
|
||||
#define CIF_MI_DMA_CTRL_READ_FMT_SPLANAR (1 << 4)
|
||||
#define CIF_MI_DMA_CTRL_READ_FMT_PACKED (2 << 4)
|
||||
#define CIF_MI_DMA_CTRL_FMT_YUV400 (0 << 6)
|
||||
#define CIF_MI_DMA_CTRL_FMT_YUV420 (1 << 6)
|
||||
#define CIF_MI_DMA_CTRL_READ_FMT_PACKED (2 << 4)
|
||||
#define CIF_MI_DMA_CTRL_FMT_YUV422 (2 << 6)
|
||||
#define CIF_MI_DMA_CTRL_FMT_YUV444 (3 << 6)
|
||||
#define CIF_MI_DMA_CTRL_BYTE_SWAP BIT(8)
|
||||
@@ -1941,4 +1943,52 @@ static inline void mi_ctrl2(void __iomem *base, u32 val)
|
||||
writel(val, base + CIF_MI_CTRL2);
|
||||
}
|
||||
|
||||
static inline void mi_dmarx_ready_enable(struct rkisp1_stream *stream)
|
||||
{
|
||||
void __iomem *base = stream->ispdev->base_addr;
|
||||
void __iomem *addr = base + CIF_MI_IMSC;
|
||||
|
||||
writel(CIF_MI_DMA_READY | readl(addr), addr);
|
||||
}
|
||||
|
||||
static inline void mi_dmarx_ready_disable(struct rkisp1_stream *stream)
|
||||
{
|
||||
void __iomem *base = stream->ispdev->base_addr;
|
||||
void __iomem *addr = base + CIF_MI_IMSC;
|
||||
|
||||
writel(~CIF_MI_DMA_READY & readl(addr), addr);
|
||||
}
|
||||
|
||||
static inline void dmarx_set_uv_swap(void __iomem *base)
|
||||
{
|
||||
void __iomem *addr = base + CIF_MI_XTD_FORMAT_CTRL;
|
||||
u32 reg = readl(addr) & ~BIT(2);
|
||||
|
||||
writel(reg | CIF_MI_XTD_FMT_CTRL_DMA_CB_CR_SWAP, addr);
|
||||
}
|
||||
|
||||
static inline void dmarx_set_y_width(void __iomem *base, u32 val)
|
||||
{
|
||||
writel(val, base + CIF_MI_DMA_Y_PIC_WIDTH);
|
||||
}
|
||||
|
||||
static inline void dmarx_set_y_line_length(void __iomem *base, u32 val)
|
||||
{
|
||||
writel(val, base + CIF_MI_DMA_Y_LLENGTH);
|
||||
}
|
||||
|
||||
static inline void dmarx_ctrl(void __iomem *base, u32 val)
|
||||
{
|
||||
void __iomem *addr = base + CIF_MI_DMA_CTRL;
|
||||
|
||||
writel(val | readl(addr), addr);
|
||||
}
|
||||
|
||||
static inline void mi_dmarx_start(void __iomem *base)
|
||||
{
|
||||
void __iomem *addr = base + CIF_MI_DMA_START;
|
||||
|
||||
writel(CIF_MI_DMA_START_ENABLE, addr);
|
||||
}
|
||||
|
||||
#endif /* _RKISP1_REGS_H */
|
||||
|
||||
@@ -254,6 +254,7 @@ static int rkisp1_config_isp(struct rkisp1_device *dev)
|
||||
u32 irq_mask = 0;
|
||||
u32 signal = 0;
|
||||
u32 acq_mult = 0;
|
||||
u32 acq_prop = 0;
|
||||
|
||||
sensor = dev->active_sensor;
|
||||
in_frm = &dev->isp_sdev.in_frm;
|
||||
@@ -265,7 +266,7 @@ static int rkisp1_config_isp(struct rkisp1_device *dev)
|
||||
if (in_fmt->fmt_type == FMT_BAYER) {
|
||||
acq_mult = 1;
|
||||
if (out_fmt->fmt_type == FMT_BAYER) {
|
||||
if (sensor->mbus.type == V4L2_MBUS_BT656)
|
||||
if (sensor && sensor->mbus.type == V4L2_MBUS_BT656)
|
||||
isp_ctrl =
|
||||
CIF_ISP_CTRL_ISP_MODE_RAW_PICT_ITU656;
|
||||
else
|
||||
@@ -283,17 +284,20 @@ static int rkisp1_config_isp(struct rkisp1_device *dev)
|
||||
writel(CIF_ISP_DEMOSAIC_TH(0xc),
|
||||
base + CIF_ISP_DEMOSAIC);
|
||||
|
||||
if (sensor->mbus.type == V4L2_MBUS_BT656)
|
||||
if (sensor && sensor->mbus.type == V4L2_MBUS_BT656)
|
||||
isp_ctrl = CIF_ISP_CTRL_ISP_MODE_BAYER_ITU656;
|
||||
else
|
||||
isp_ctrl = CIF_ISP_CTRL_ISP_MODE_BAYER_ITU601;
|
||||
}
|
||||
|
||||
if (dev->isp_inp == INP_DMARX_ISP)
|
||||
acq_prop = CIF_ISP_ACQ_PROP_DMA_RGB;
|
||||
} else if (in_fmt->fmt_type == FMT_YUV) {
|
||||
acq_mult = 2;
|
||||
if (sensor->mbus.type == V4L2_MBUS_CSI2) {
|
||||
if (sensor && sensor->mbus.type == V4L2_MBUS_CSI2) {
|
||||
isp_ctrl = CIF_ISP_CTRL_ISP_MODE_ITU601;
|
||||
} else {
|
||||
if (sensor->mbus.type == V4L2_MBUS_BT656)
|
||||
if (sensor && sensor->mbus.type == V4L2_MBUS_BT656)
|
||||
isp_ctrl = CIF_ISP_CTRL_ISP_MODE_ITU656;
|
||||
else
|
||||
isp_ctrl = CIF_ISP_CTRL_ISP_MODE_ITU601;
|
||||
@@ -301,17 +305,19 @@ static int rkisp1_config_isp(struct rkisp1_device *dev)
|
||||
}
|
||||
|
||||
irq_mask |= CIF_ISP_DATA_LOSS;
|
||||
if (dev->isp_inp == INP_DMARX_ISP)
|
||||
acq_prop = CIF_ISP_ACQ_PROP_DMA_YUV;
|
||||
}
|
||||
|
||||
/* Set up input acquisition properties */
|
||||
if (sensor->mbus.type == V4L2_MBUS_BT656 ||
|
||||
sensor->mbus.type == V4L2_MBUS_PARALLEL) {
|
||||
if (sensor && (sensor->mbus.type == V4L2_MBUS_BT656 ||
|
||||
sensor->mbus.type == V4L2_MBUS_PARALLEL)) {
|
||||
if (sensor->mbus.flags &
|
||||
V4L2_MBUS_PCLK_SAMPLE_RISING)
|
||||
signal = CIF_ISP_ACQ_PROP_POS_EDGE;
|
||||
}
|
||||
|
||||
if (sensor->mbus.type == V4L2_MBUS_PARALLEL) {
|
||||
if (sensor && sensor->mbus.type == V4L2_MBUS_PARALLEL) {
|
||||
if (sensor->mbus.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
|
||||
signal |= CIF_ISP_ACQ_PROP_VSYNC_LOW;
|
||||
|
||||
@@ -320,9 +326,10 @@ static int rkisp1_config_isp(struct rkisp1_device *dev)
|
||||
}
|
||||
|
||||
writel(isp_ctrl, base + CIF_ISP_CTRL);
|
||||
writel(signal | in_fmt->yuv_seq |
|
||||
CIF_ISP_ACQ_PROP_BAYER_PAT(in_fmt->bayer_pat) |
|
||||
CIF_ISP_ACQ_PROP_FIELD_SEL_ALL, base + CIF_ISP_ACQ_PROP);
|
||||
acq_prop |= signal | in_fmt->yuv_seq |
|
||||
CIF_ISP_ACQ_PROP_BAYER_PAT(in_fmt->bayer_pat) |
|
||||
CIF_ISP_ACQ_PROP_FIELD_SEL_ALL;
|
||||
writel(acq_prop, base + CIF_ISP_ACQ_PROP);
|
||||
writel(0, base + CIF_ISP_ACQ_NR_FRAMES);
|
||||
|
||||
/* Acquisition Size */
|
||||
@@ -551,13 +558,17 @@ static int rkisp1_config_path(struct rkisp1_device *dev)
|
||||
struct rkisp1_sensor_info *sensor = dev->active_sensor;
|
||||
u32 dpcl = readl(dev->base_addr + CIF_VI_DPCL);
|
||||
|
||||
if (sensor->mbus.type == V4L2_MBUS_BT656 ||
|
||||
sensor->mbus.type == V4L2_MBUS_PARALLEL) {
|
||||
if (sensor && (sensor->mbus.type == V4L2_MBUS_BT656 ||
|
||||
sensor->mbus.type == V4L2_MBUS_PARALLEL)) {
|
||||
ret = rkisp1_config_dvp(dev);
|
||||
dpcl |= CIF_VI_DPCL_IF_SEL_PARALLEL;
|
||||
} else if (sensor->mbus.type == V4L2_MBUS_CSI2) {
|
||||
dev->isp_inp = INP_DVP;
|
||||
} else if (sensor && sensor->mbus.type == V4L2_MBUS_CSI2) {
|
||||
ret = rkisp1_config_mipi(dev);
|
||||
dpcl |= CIF_VI_DPCL_IF_SEL_MIPI;
|
||||
dev->isp_inp = INP_CSI;
|
||||
} else if (dev->isp_inp == INP_DMARX_ISP) {
|
||||
dpcl |= CIF_VI_DPCL_DMA_SW_ISP;
|
||||
}
|
||||
|
||||
writel(dpcl, dev->base_addr + CIF_VI_DPCL);
|
||||
@@ -712,7 +723,7 @@ static int rkisp1_isp_start(struct rkisp1_device *dev)
|
||||
dev->stream[RKISP1_STREAM_MP].streaming);
|
||||
|
||||
/* Activate MIPI */
|
||||
if (sensor->mbus.type == V4L2_MBUS_CSI2) {
|
||||
if (sensor && sensor->mbus.type == V4L2_MBUS_CSI2) {
|
||||
#if RKISP1_RK3326_USE_OLDMIPI
|
||||
if (dev->isp_ver == ISP_V13) {
|
||||
#else
|
||||
@@ -1369,6 +1380,24 @@ static int rkisp1_isp_sd_s_power(struct v4l2_subdev *sd, int on)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rkisp1_subdev_link_setup(struct media_entity *entity,
|
||||
const struct media_pad *local,
|
||||
const struct media_pad *remote,
|
||||
u32 flags)
|
||||
{
|
||||
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
|
||||
struct rkisp1_device *dev = sd_to_isp_dev(sd);
|
||||
|
||||
if (!strcmp(remote->entity->name, DMA_VDEV_NAME)) {
|
||||
if (flags & MEDIA_LNK_FL_ENABLED)
|
||||
dev->isp_inp = INP_DMARX_ISP;
|
||||
else
|
||||
dev->isp_inp = INP_INVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rkisp1_subdev_link_validate(struct media_link *link)
|
||||
{
|
||||
if (link->source->index == RKISP1_ISP_PAD_SINK_PARAMS)
|
||||
@@ -1427,6 +1456,7 @@ static const struct v4l2_subdev_pad_ops rkisp1_isp_sd_pad_ops = {
|
||||
};
|
||||
|
||||
static const struct media_entity_operations rkisp1_isp_sd_media_ops = {
|
||||
.link_setup = rkisp1_subdev_link_setup,
|
||||
.link_validate = rkisp1_subdev_link_validate,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user