diff --git a/drivers/media/platform/rockchip/isp/csi.c b/drivers/media/platform/rockchip/isp/csi.c index a0395a697c58..319188ea490b 100644 --- a/drivers/media/platform/rockchip/isp/csi.c +++ b/drivers/media/platform/rockchip/isp/csi.c @@ -12,6 +12,7 @@ #include #include #include "dev.h" +#include "isp_external.h" #include "regs.h" static void get_remote_mipi_sensor(struct rkisp_device *dev, @@ -436,6 +437,10 @@ int rkisp_csi_config_patch(struct rkisp_device *dev) } else { if (dev->isp_inp & INP_CIF) { struct rkmodule_hdr_cfg hdr_cfg; + struct rkisp_vicap_mode mode = { + .name = dev->name, + .is_rdbk = true, + }; get_remote_mipi_sensor(dev, &mipi_sensor, MEDIA_ENT_F_PROC_VIDEO_COMPOSER); dev->hdr.op_mode = HDR_NORMAL; @@ -454,6 +459,30 @@ int rkisp_csi_config_patch(struct rkisp_device *dev) /* normal read back mode */ if (dev->hdr.op_mode == HDR_NORMAL) dev->hdr.op_mode = HDR_RDBK_FRAME1; + + if (dev->isp_inp == INP_CIF && dev->hw_dev->is_single) + mode.is_rdbk = false; + v4l2_subdev_call(mipi_sensor, core, ioctl, + RKISP_VICAP_CMD_MODE, &mode); + /* vicap direct to isp */ + if (dev->isp_ver == ISP_V30 && dev->hw_dev->is_single) { + switch (dev->hdr.op_mode) { + case HDR_RDBK_FRAME3: + dev->hdr.op_mode = HDR_LINEX3_DDR; + break; + case HDR_RDBK_FRAME2: + dev->hdr.op_mode = HDR_LINEX2_DDR; + break; + default: + dev->hdr.op_mode = HDR_NORMAL; + } + if (dev->hdr.op_mode != HDR_NORMAL && mipi_sensor) { + int cnt = RKISP_VICAP_BUF_CNT; + + v4l2_subdev_call(mipi_sensor, core, ioctl, + RKISP_VICAP_CMD_INIT_BUF, &cnt); + } + } } else { switch (dev->isp_inp & 0x7) { case INP_RAWRD2 | INP_RAWRD0: @@ -467,15 +496,26 @@ int rkisp_csi_config_patch(struct rkisp_device *dev) } } - if (dev->hdr.op_mode == HDR_RDBK_FRAME2) - val = SW_HDRMGE_EN | SW_HDRMGE_MODE_FRAMEX2; - else if (dev->hdr.op_mode == HDR_RDBK_FRAME3) - val = SW_HDRMGE_EN | SW_HDRMGE_MODE_FRAMEX3; - if (!dev->hw_dev->is_mi_update) rkisp_write(dev, CSI2RX_CTRL0, SW_IBUF_OP_MODE(dev->hdr.op_mode), true); + /* hdr merge */ + switch (dev->hdr.op_mode) { + case HDR_RDBK_FRAME2: + case HDR_FRAMEX2_DDR: + case HDR_LINEX2_DDR: + case HDR_LINEX2_NO_DDR: + val = SW_HDRMGE_EN | SW_HDRMGE_MODE_FRAMEX2; + break; + case HDR_RDBK_FRAME3: + case HDR_FRAMEX3_DDR: + case HDR_LINEX3_DDR: + val = SW_HDRMGE_EN | SW_HDRMGE_MODE_FRAMEX3; + break; + default: + val = 0; + } if (is_feature_on) { if ((ISP2X_MODULE_HDRMGE & ~iq_feature) && (val & SW_HDRMGE_EN)) { v4l2_err(&dev->v4l2_dev, "hdrmge is not supported\n"); diff --git a/drivers/media/platform/rockchip/isp/dev.c b/drivers/media/platform/rockchip/isp/dev.c index d3afca1fe6d8..971b485170d6 100644 --- a/drivers/media/platform/rockchip/isp/dev.c +++ b/drivers/media/platform/rockchip/isp/dev.c @@ -126,7 +126,7 @@ static int __isp_pipeline_prepare(struct rkisp_pipeline *p, p->num_subdevs = 0; memset(p->subdevs, 0, sizeof(p->subdevs)); - if (!(dev->isp_inp & (INP_CSI | INP_DVP | INP_LVDS))) + if (!(dev->isp_inp & (INP_CSI | INP_DVP | INP_LVDS | INP_CIF))) return 0; while (1) { @@ -259,8 +259,13 @@ static int rkisp_pipeline_open(struct rkisp_pipeline *p, static int rkisp_pipeline_close(struct rkisp_pipeline *p) { + struct rkisp_device *dev = container_of(p, struct rkisp_device, pipe); + atomic_dec(&p->power_cnt); + if (dev->isp_ver == ISP_V30 && !atomic_read(&p->power_cnt)) + rkisp_rx_buf_pool_free(dev); + return 0; } diff --git a/drivers/media/platform/rockchip/isp/dev.h b/drivers/media/platform/rockchip/isp/dev.h index ee350e9fbdcb..15b5d5bcd888 100644 --- a/drivers/media/platform/rockchip/isp/dev.h +++ b/drivers/media/platform/rockchip/isp/dev.h @@ -45,6 +45,7 @@ #include "isp_stats.h" #include "isp_mipi_luma.h" #include "procfs.h" +#include "isp_external.h" #define DRIVER_NAME "rkisp" #define ISP_VDEV_NAME DRIVER_NAME "_ispdev" @@ -227,5 +228,7 @@ struct rkisp_device { int rdbk_cnt_x3; u32 rd_mode; u8 filt_state[RDBK_F_MAX]; + + struct rkisp_rx_buf_pool pv_pool[RKISP_RX_BUF_POOL_MAX]; }; #endif diff --git a/drivers/media/platform/rockchip/isp/isp_external.h b/drivers/media/platform/rockchip/isp/isp_external.h new file mode 100644 index 000000000000..655c4b943835 --- /dev/null +++ b/drivers/media/platform/rockchip/isp/isp_external.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2021 Fuzhou Rockchip Electronics Co., Ltd. */ + +#ifndef _RKISP_EXTERNAL_H +#define _RKISP_EXTERNAL_H + + +#define RKISP_VICAP_CMD_MODE \ + _IOW('V', BASE_VIDIOC_PRIVATE + 0, struct rkisp_vicap_mode) + +#define RKISP_VICAP_CMD_INIT_BUF \ + _IOW('V', BASE_VIDIOC_PRIVATE + 1, int) + +#define RKISP_VICAP_BUF_CNT 1 +#define RKISP_RX_BUF_POOL_MAX (RKISP_VICAP_BUF_CNT * 3) + +struct rkisp_vicap_mode { + char *name; + bool is_rdbk; +}; + +enum rx_buf_type { + BUF_SHORT, + BUF_MIDDLE, + BUF_LONG, +}; + +struct rkisp_rx_buf_pool { + struct rkisp_rx_buf *dbufs; + void *mem_priv; + dma_addr_t dma; + void *vaddr; +}; + +struct rkisp_rx_buf { + struct list_head list; + struct dma_buf *dbuf; + enum rx_buf_type type; + u64 timestamp; + u32 sequence; + bool is_init; +}; + +#endif diff --git a/drivers/media/platform/rockchip/isp/rkisp.c b/drivers/media/platform/rockchip/isp/rkisp.c index 105470c97323..cfeb7ca3bdc1 100644 --- a/drivers/media/platform/rockchip/isp/rkisp.c +++ b/drivers/media/platform/rockchip/isp/rkisp.c @@ -49,6 +49,7 @@ #include #include "common.h" +#include "isp_external.h" #include "regs.h" #include "rkisp_tb_helper.h" @@ -2324,6 +2325,107 @@ static int rkisp_isp_sd_s_stream(struct v4l2_subdev *sd, int on) return 0; } +void rkisp_rx_buf_pool_free(struct rkisp_device *dev) +{ + const struct vb2_mem_ops *g_ops = dev->hw_dev->mem_ops; + struct rkisp_rx_buf_pool *pool; + int i; + + for (i = 0; i < RKISP_RX_BUF_POOL_MAX; i++) { + pool = &dev->pv_pool[i]; + if (!pool->dbufs) + break; + if (pool->mem_priv) { + g_ops->unmap_dmabuf(pool->mem_priv); + g_ops->detach_dmabuf(pool->mem_priv); + dma_buf_put(pool->dbufs->dbuf); + pool->mem_priv = NULL; + } + pool->dbufs = NULL; + } +} + +static int rkisp_rx_buf_pool_init(struct rkisp_device *dev, + struct rkisp_rx_buf *dbufs) +{ + const struct vb2_mem_ops *g_ops = dev->hw_dev->mem_ops; + struct rkisp_stream *stream; + struct rkisp_rx_buf_pool *pool; + struct sg_table *sg_tbl; + int i, ret; + void *mem; + + for (i = 0; i < RKISP_RX_BUF_POOL_MAX; i++) { + pool = &dev->pv_pool[i]; + if (!pool->dbufs) + break; + } + + pool->dbufs = dbufs; + v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev, + "%s type:0x%x dbufs[%d]:%p", __func__, dbufs->type, i, dbufs); + + mem = g_ops->attach_dmabuf(dev->hw_dev->dev, dbufs->dbuf, + dbufs->dbuf->size, DMA_BIDIRECTIONAL); + if (IS_ERR(mem)) { + ret = PTR_ERR(mem); + goto err; + } + pool->mem_priv = mem; + ret = g_ops->map_dmabuf(mem); + if (ret) + goto err; + if (dev->hw_dev->is_dma_sg_ops) { + sg_tbl = (struct sg_table *)g_ops->cookie(mem); + pool->dma = sg_dma_address(sg_tbl->sgl); + } else { + pool->dma = *((dma_addr_t *)g_ops->cookie(mem)); + } + get_dma_buf(dbufs->dbuf); + pool->vaddr = g_ops->vaddr(mem); + dbufs->is_init = true; + + switch (dbufs->type) { + case BUF_SHORT: + stream = &dev->dmarx_dev.stream[RKISP_STREAM_RAWRD2]; + break; + case BUF_MIDDLE: + stream = &dev->dmarx_dev.stream[RKISP_STREAM_RAWRD0]; + break; + case BUF_LONG: + default: + stream = &dev->dmarx_dev.stream[RKISP_STREAM_RAWRD1]; + + } + stream->ops->config_mi(stream); + rkisp_write(dev, stream->config->mi.y_base_ad_init, pool->dma, false); + v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev, + "%s dma:0x%x vaddr:%p", __func__, (u32)pool->dma, pool->vaddr); + return 0; +err: + rkisp_rx_buf_pool_free(dev); + return ret; +} + +static int rkisp_sd_s_rx_buffer(struct v4l2_subdev *sd, + void *buf, unsigned int *size) +{ + struct rkisp_device *dev = sd_to_isp_dev(sd); + struct rkisp_rx_buf *dbufs; + int ret = 0; + + if (!buf) + return -EINVAL; + + dbufs = buf; + if (!dbufs->is_init) + ret = rkisp_rx_buf_pool_init(dev, dbufs); + + /* TODO qbuf/debuf for more buffer */ + + return ret; +} + static int rkisp_isp_sd_s_power(struct v4l2_subdev *sd, int on) { struct rkisp_device *isp_dev = sd_to_isp_dev(sd); @@ -2463,6 +2565,19 @@ static int rkisp_subdev_link_setup(struct media_entity *entity, else dev->dmarx_dev.trigger = T_AUTO; + if (dev->isp_inp & INP_CIF) { + struct v4l2_subdev *remote = get_remote_sensor(sd); + struct rkisp_vicap_mode mode; + + mode.name = dev->name; + mode.is_rdbk = !!(dev->isp_inp & rawrd); + /* read back mode only */ + if (dev->isp_ver < ISP_V30 || !dev->hw_dev->is_single) + mode.is_rdbk = true; + v4l2_subdev_call(remote, core, ioctl, + RKISP_VICAP_CMD_MODE, &mode); + } + v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev, "isp input:0x%x\n", dev->isp_inp); return 0; @@ -2724,6 +2839,7 @@ static const struct media_entity_operations rkisp_isp_sd_media_ops = { static const struct v4l2_subdev_video_ops rkisp_isp_sd_video_ops = { .s_stream = rkisp_isp_sd_s_stream, + .s_rx_buffer = rkisp_sd_s_rx_buffer, }; static const struct v4l2_subdev_core_ops rkisp_isp_core_ops = { diff --git a/drivers/media/platform/rockchip/isp/rkisp.h b/drivers/media/platform/rockchip/isp/rkisp.h index c667f73e816d..db1a8167df15 100644 --- a/drivers/media/platform/rockchip/isp/rkisp.h +++ b/drivers/media/platform/rockchip/isp/rkisp.h @@ -172,6 +172,8 @@ void rkisp_trigger_read_back(struct rkisp_device *dev, u8 dma2frm, u32 mode, boo int rkisp_rdbk_trigger_event(struct rkisp_device *dev, u32 cmd, void *arg); +void rkisp_rx_buf_pool_free(struct rkisp_device *dev); + static inline struct ispsd_out_fmt *rkisp_get_ispsd_out_fmt(struct rkisp_isp_subdev *isp_sdev) {