diff --git a/drivers/media/platform/rockchip/cif/Makefile b/drivers/media/platform/rockchip/cif/Makefile index bd05e586986e..d43cad36a272 100644 --- a/drivers/media/platform/rockchip/cif/Makefile +++ b/drivers/media/platform/rockchip/cif/Makefile @@ -9,4 +9,5 @@ video_rkcif-objs += dev.o \ procfs.o \ cif-scale.o \ common.o \ - cif-tools.o + cif-tools.o \ + cif-rockit.o diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 0ac8786e02cf..45525eae2a7b 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -2604,6 +2604,285 @@ static int rkcif_assign_new_buffer_pingpong(struct rkcif_stream *stream, return ret; } +static void rkcif_assign_new_buffer_init_rockit(struct rkcif_stream *stream, + int channel_id) +{ + struct rkcif_device *dev = stream->cifdev; + struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; + u32 frm0_addr_y, frm0_addr_uv; + u32 frm1_addr_y, frm1_addr_uv; + unsigned long flags; + struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf; + struct csi_channel_info *channel = &dev->channels[channel_id]; + + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || + mbus_cfg->type == V4L2_MBUS_CCP2) { + frm0_addr_y = get_reg_index_of_frm0_y_addr(channel_id); + frm0_addr_uv = get_reg_index_of_frm0_uv_addr(channel_id); + frm1_addr_y = get_reg_index_of_frm1_y_addr(channel_id); + frm1_addr_uv = get_reg_index_of_frm1_uv_addr(channel_id); + } else { + frm0_addr_y = get_dvp_reg_index_of_frm0_y_addr(channel_id); + frm0_addr_uv = get_dvp_reg_index_of_frm0_uv_addr(channel_id); + frm1_addr_y = get_dvp_reg_index_of_frm1_y_addr(channel_id); + frm1_addr_uv = get_dvp_reg_index_of_frm1_uv_addr(channel_id); + } + + spin_lock_irqsave(&stream->vbq_lock, flags); + + if (!stream->curr_buf_rockit) { + if (!list_empty(&stream->rockit_buf_head)) { + stream->curr_buf_rockit = list_first_entry(&stream->rockit_buf_head, + struct rkcif_buffer, + queue); + list_del(&stream->curr_buf_rockit->queue); + } + } + + if (stream->curr_buf_rockit) { + rkcif_write_register(dev, frm0_addr_y, + stream->curr_buf_rockit->buff_addr[RKCIF_PLANE_Y]); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm0_addr_uv, + stream->curr_buf_rockit->buff_addr[RKCIF_PLANE_CBCR]); + } else { + if (dummy_buf->vaddr) { + rkcif_write_register(dev, frm0_addr_y, dummy_buf->dma_addr); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm0_addr_uv, dummy_buf->dma_addr); + } else { + if (stream->lack_buf_cnt < 2) + stream->lack_buf_cnt++; + } + } + + if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) { + stream->next_buf_rockit = stream->curr_buf_rockit; + if (stream->next_buf_rockit) { + rkcif_write_register(dev, frm1_addr_y, + stream->next_buf_rockit->buff_addr[RKCIF_PLANE_Y] + (channel->virtual_width / 2)); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm1_addr_uv, + stream->next_buf_rockit->buff_addr[RKCIF_PLANE_CBCR] + (channel->virtual_width / 2)); + } + } else { + if (!stream->next_buf_rockit) { + if (!list_empty(&stream->rockit_buf_head)) { + stream->next_buf_rockit = list_first_entry(&stream->rockit_buf_head, + struct rkcif_buffer, queue); + list_del(&stream->next_buf_rockit->queue); + } + } + + if (stream->next_buf_rockit) { + rkcif_write_register(dev, frm1_addr_y, + stream->next_buf_rockit->buff_addr[RKCIF_PLANE_Y]); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm1_addr_uv, + stream->next_buf_rockit->buff_addr[RKCIF_PLANE_CBCR]); + } else { + if (dummy_buf->vaddr) { + rkcif_write_register(dev, frm1_addr_y, dummy_buf->dma_addr); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm1_addr_uv, dummy_buf->dma_addr); + } else { + if (stream->curr_buf_rockit) { + stream->next_buf_rockit = stream->curr_buf_rockit; + rkcif_write_register(dev, frm1_addr_y, + stream->next_buf_rockit->buff_addr[RKCIF_PLANE_Y]); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm1_addr_uv, + stream->next_buf_rockit->buff_addr[RKCIF_PLANE_CBCR]); + } + if (stream->lack_buf_cnt < 2) + stream->lack_buf_cnt++; + } + } + } + spin_unlock_irqrestore(&stream->vbq_lock, flags); + + stream->is_dvp_yuv_addr_init = true; + + /* for BT.656/BT.1120 multi channels function, + * yuv addr of unused channel must be set + */ + if (mbus_cfg->type == V4L2_MBUS_BT656) { + int ch_id; + + for (ch_id = 0; ch_id < RKCIF_MAX_STREAM_DVP; ch_id++) { + if (dev->stream[ch_id].is_dvp_yuv_addr_init) + continue; + if (dummy_buf->dma_addr) { + rkcif_write_register(dev, + get_dvp_reg_index_of_frm0_y_addr(ch_id), + dummy_buf->dma_addr); + rkcif_write_register(dev, + get_dvp_reg_index_of_frm0_uv_addr(ch_id), + dummy_buf->dma_addr); + rkcif_write_register(dev, + get_dvp_reg_index_of_frm1_y_addr(ch_id), + dummy_buf->dma_addr); + rkcif_write_register(dev, + get_dvp_reg_index_of_frm1_uv_addr(ch_id), + dummy_buf->dma_addr); + } + } + } + stream->buf_owner = RKCIF_DMAEN_BY_ROCKIT; +} + +static int rkcif_assign_new_buffer_update_rockit(struct rkcif_stream *stream, + int channel_id) +{ + struct rkcif_device *dev = stream->cifdev; + struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf; + struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; + struct rkcif_buffer *buffer = NULL; + u32 frm_addr_y, frm_addr_uv; + struct csi_channel_info *channel = &dev->channels[channel_id]; + int ret = 0; + unsigned long flags; + + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || + mbus_cfg->type == V4L2_MBUS_CCP2) { + frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ? + get_reg_index_of_frm0_y_addr(channel_id) : + get_reg_index_of_frm1_y_addr(channel_id); + frm_addr_uv = stream->frame_phase & CIF_CSI_FRAME0_READY ? + get_reg_index_of_frm0_uv_addr(channel_id) : + get_reg_index_of_frm1_uv_addr(channel_id); + } else { + frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ? + get_dvp_reg_index_of_frm0_y_addr(channel_id) : + get_dvp_reg_index_of_frm1_y_addr(channel_id); + frm_addr_uv = stream->frame_phase & CIF_CSI_FRAME0_READY ? + get_dvp_reg_index_of_frm0_uv_addr(channel_id) : + get_dvp_reg_index_of_frm1_uv_addr(channel_id); + } + + spin_lock_irqsave(&stream->vbq_lock, flags); + if (!list_empty(&stream->rockit_buf_head)) { + + if (!dummy_buf->vaddr && + stream->curr_buf_rockit == stream->next_buf_rockit && + stream->cif_fmt_in->field != V4L2_FIELD_INTERLACED) + ret = -EINVAL; + + if (stream->frame_phase == CIF_CSI_FRAME0_READY) { + if (!stream->curr_buf_rockit) + ret = -EINVAL; + stream->curr_buf_rockit = list_first_entry(&stream->rockit_buf_head, + struct rkcif_buffer, queue); + if (stream->curr_buf_rockit) { + list_del(&stream->curr_buf_rockit->queue); + buffer = stream->curr_buf_rockit; + } + } else if (stream->frame_phase == CIF_CSI_FRAME1_READY) { + if (!stream->next_buf_rockit) + ret = -EINVAL; + if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) { + if (stream->next_buf_rockit != stream->curr_buf_rockit) { + stream->next_buf_rockit = stream->curr_buf_rockit; + buffer = stream->next_buf_rockit; + } else { + buffer = NULL; + } + + } else { + stream->next_buf_rockit = list_first_entry(&stream->rockit_buf_head, + struct rkcif_buffer, queue); + if (stream->next_buf_rockit) { + list_del(&stream->next_buf_rockit->queue); + buffer = stream->next_buf_rockit; + } + } + } + } else { + buffer = NULL; + if (dummy_buf->vaddr) { + if (stream->frame_phase == CIF_CSI_FRAME0_READY) { + stream->curr_buf_rockit = NULL; + } else if (stream->frame_phase == CIF_CSI_FRAME1_READY) { + if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) { + stream->next_buf_rockit = stream->curr_buf_rockit; + buffer = stream->next_buf_rockit; + } else { + stream->next_buf_rockit = NULL; + } + } + } else if (stream->curr_buf_rockit && stream->next_buf_rockit && + stream->curr_buf_rockit != stream->next_buf_rockit) { + if (stream->frame_phase == CIF_CSI_FRAME0_READY) { + stream->curr_buf_rockit = stream->next_buf_rockit; + buffer = stream->next_buf_rockit; + } else if (stream->frame_phase == CIF_CSI_FRAME1_READY) { + stream->next_buf_rockit = stream->curr_buf_rockit; + buffer = stream->curr_buf_rockit; + } + if (stream->lack_buf_cnt < 2) + stream->lack_buf_cnt++; + } else { + if (stream->lack_buf_cnt < 2) + stream->lack_buf_cnt++; + } + } + stream->frame_phase_cache = stream->frame_phase; + + if (buffer) { + if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED && + stream->frame_phase == CIF_CSI_FRAME1_READY) { + rkcif_write_register(dev, frm_addr_y, + buffer->buff_addr[RKCIF_PLANE_Y] + (channel->virtual_width / 2)); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, + buffer->buff_addr[RKCIF_PLANE_CBCR] + (channel->virtual_width / 2)); + } else { + rkcif_write_register(dev, frm_addr_y, + buffer->buff_addr[RKCIF_PLANE_Y]); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, + buffer->buff_addr[RKCIF_PLANE_CBCR]); + } + } else { + if (dummy_buf->vaddr) { + rkcif_write_register(dev, frm_addr_y, dummy_buf->dma_addr); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, dummy_buf->dma_addr); + v4l2_info(&dev->v4l2_dev, + "not active buffer, use dummy buffer, %s stream[%d]\n", + (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || + mbus_cfg->type == V4L2_MBUS_CCP2) ? "mipi/lvds" : "dvp", + stream->id); + } else { + ret = -EINVAL; + v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, + "not active buffer, lack_buf_cnt %d, stop capture, %s stream[%d]\n", + stream->lack_buf_cnt, + (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || + mbus_cfg->type == V4L2_MBUS_CCP2) ? "mipi/lvds" : "dvp", + stream->id); + } + } + spin_unlock_irqrestore(&stream->vbq_lock, flags); + return ret; +} + +static int rkcif_assign_new_buffer_pingpong_rockit(struct rkcif_stream *stream, + int init, int channel_id) +{ + int ret = 0; + + if (init) + rkcif_assign_new_buffer_init_rockit(stream, channel_id); + else + ret = rkcif_assign_new_buffer_update_rockit(stream, channel_id); + return ret; +} + static void rkcif_csi_get_vc_num(struct rkcif_device *dev, unsigned int mbus_flags) { @@ -3241,6 +3520,10 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, rkcif_assign_new_buffer_pingpong_toisp(stream, RKCIF_YUV_ADDR_STATE_INIT, channel->id); + else if (mode == RKCIF_STREAM_MODE_ROCKIT) + rkcif_assign_new_buffer_pingpong_rockit(stream, + RKCIF_YUV_ADDR_STATE_INIT, + channel->id); if (stream->lack_buf_cnt == 2) stream->dma_en = 0; @@ -3350,6 +3633,8 @@ static int rkcif_csi_stream_start(struct rkcif_stream *stream, unsigned int mode stream->dma_en |= RKCIF_DMAEN_BY_ISP; else if (dev->hdr.hdr_mode == HDR_X3 && (stream->id == 0 || stream->id == 1)) stream->dma_en |= RKCIF_DMAEN_BY_ISP; + } else if (mode == RKCIF_STREAM_MODE_ROCKIT) { + stream->dma_en |= RKCIF_DMAEN_BY_ROCKIT; } if (stream->cifdev->chip_id < CHIP_RK3588_CIF) rkcif_csi_channel_set(stream, channel, mbus_type); @@ -3370,6 +3655,8 @@ static int rkcif_csi_stream_start(struct rkcif_stream *stream, unsigned int mode (stream->id == 0 || stream->id == 1) && (!stream->dma_en)) stream->to_en_dma = RKCIF_DMAEN_BY_ISP; + } else if (mode == RKCIF_STREAM_MODE_ROCKIT) { + stream->to_en_dma = RKCIF_DMAEN_BY_ROCKIT; } } } @@ -5540,6 +5827,7 @@ void rkcif_stream_init(struct rkcif_device *dev, u32 id) INIT_LIST_HEAD(&stream->buf_head); INIT_LIST_HEAD(&stream->rx_buf_head); INIT_LIST_HEAD(&stream->rx_buf_head_vicap); + INIT_LIST_HEAD(&stream->rockit_buf_head); spin_lock_init(&stream->vbq_lock); spin_lock_init(&stream->fps_lock); stream->state = RKCIF_STATE_READY; @@ -7888,6 +8176,51 @@ static void rkcif_update_stream_toisp(struct rkcif_device *cif_dev, mipi_id); } +static void rkcif_update_stream_rockit(struct rkcif_device *cif_dev, + struct rkcif_stream *stream, + int mipi_id) +{ + struct rkcif_buffer *active_buf = NULL; + unsigned long flags; + int ret = 0; + + if (stream->frame_phase == (CIF_CSI_FRAME0_READY | CIF_CSI_FRAME1_READY)) { + + v4l2_err(&cif_dev->v4l2_dev, "stream[%d], frm0/frm1 end simultaneously,frm id:%d\n", + stream->id, stream->frame_idx); + return; + } + if (!stream->is_line_wake_up) { + + spin_lock_irqsave(&stream->fps_lock, flags); + if (stream->frame_phase & CIF_CSI_FRAME0_READY) { + if (stream->curr_buf_rockit) + active_buf = stream->curr_buf_rockit; + stream->fps_stats.frm0_timestamp = ktime_get_ns(); + } else if (stream->frame_phase & CIF_CSI_FRAME1_READY) { + if (stream->next_buf_rockit) + active_buf = stream->next_buf_rockit; + stream->fps_stats.frm1_timestamp = ktime_get_ns(); + } + spin_unlock_irqrestore(&stream->fps_lock, flags); + } + + if (cif_dev->inf_id == RKCIF_MIPI_LVDS) + rkcif_deal_readout_time(stream); + + ret = rkcif_assign_new_buffer_pingpong_rockit(stream, + RKCIF_YUV_ADDR_STATE_UPDATE, + mipi_id); + if (ret) + return; + + if (active_buf) { + active_buf->vb.vb2_buf.timestamp = stream->readout.fs_timestamp; + active_buf->vb.sequence = stream->frame_idx - 1; + rkcif_rockit_buf_done(stream, active_buf); + } +} + static u32 rkcif_get_sof(struct rkcif_device *cif_dev) { u32 val = 0x0; @@ -9221,7 +9554,10 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) rkcif_update_stream(cif_dev, stream, mipi_id); } else if (stream->dma_en & RKCIF_DMAEN_BY_ISP) { rkcif_update_stream_toisp(cif_dev, stream, mipi_id); + } else if (stream->dma_en & RKCIF_DMAEN_BY_ROCKIT) { + rkcif_update_stream_rockit(cif_dev, stream, mipi_id); } + if (cif_dev->chip_id >= CHIP_RV1106_CIF) rkcif_modify_frame_skip_config(stream); if (stream->is_change_toisp) { diff --git a/drivers/media/platform/rockchip/cif/cif-rockit.c b/drivers/media/platform/rockchip/cif/cif-rockit.c new file mode 100644 index 000000000000..1c6505791299 --- /dev/null +++ b/drivers/media/platform/rockchip/cif/cif-rockit.c @@ -0,0 +1,402 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2022 Rockchip Electronics Co., Ltd */ + +#define pr_fmt(fmt) "isp_rockit: %s:%d " fmt, __func__, __LINE__ + +#include +#include +#include + +#include "dev.h" + +static struct rockit_rkcif_cfg *rockit_rkcif_cfg; + +struct rkcif_rockit_buffer { + struct rkcif_buffer cif_buf; + struct dma_buf *dmabuf; + void *mpi_mem; + void *mpi_buf; + struct list_head queue; + int buf_id; + union { + u32 buff_addr; + void *vaddr; + }; +}; + +static struct rkcif_stream *rkcif_rockit_get_stream(struct rockit_rkcif_cfg *input_rockit_cfg) +{ + struct rkcif_device *cif_dev = NULL; + struct rkcif_stream *stream = NULL; + u8 i; + + if (!rockit_rkcif_cfg) { + pr_err("rockit_rkcif_cfg is null get stream failed\n"); + return NULL; + } + if (!input_rockit_cfg) { + pr_err("input is null get stream failed\n"); + return NULL; + } + + for (i = 0; i < rockit_rkcif_cfg->cif_num; i++) { + if (!strcmp(rockit_rkcif_cfg->rkcif_dev_cfg[i].cif_name, + input_rockit_cfg->cur_name)) { + cif_dev = rockit_rkcif_cfg->rkcif_dev_cfg[i].cif_dev; + break; + } + } + + if (cif_dev == NULL) { + pr_err("Can not find cif_dev!"); + return NULL; + } + + switch (input_rockit_cfg->nick_id) { + case 0: + stream = &cif_dev->stream[RKCIF_STREAM_MIPI_ID0]; + break; + case 1: + stream = &cif_dev->stream[RKCIF_STREAM_MIPI_ID1]; + break; + case 2: + stream = &cif_dev->stream[RKCIF_STREAM_MIPI_ID2]; + break; + case 3: + stream = &cif_dev->stream[RKCIF_STREAM_MIPI_ID3]; + break; + default: + stream = NULL; + break; + } + + return stream; +} + +int rkcif_rockit_buf_queue(struct rockit_rkcif_cfg *input_rockit_cfg) +{ + struct rkcif_stream *stream = NULL; + struct rkcif_rockit_buffer *rkcif_buf = NULL; + struct rkcif_device *cif_dev = NULL; + const struct vb2_mem_ops *g_ops = NULL; + int i, ret, offset, dev_id; + struct rkcif_stream_cfg *stream_cfg = NULL; + void *mem = NULL; + struct sg_table *sg_tbl; + unsigned long lock_flags = 0; + + stream = rkcif_rockit_get_stream(input_rockit_cfg); + + if (stream == NULL) { + pr_err("the stream is NULL"); + return -EINVAL; + } + + cif_dev = stream->cifdev; + dev_id = cif_dev->csi_host_idx; + g_ops = cif_dev->hw_dev->mem_ops; + + if (stream->id >= RKCIF_MAX_STREAM_MIPI) + return -EINVAL; + + stream_cfg = &rockit_rkcif_cfg->rkcif_dev_cfg[dev_id].rkcif_stream_cfg[stream->id]; + + stream_cfg->node = input_rockit_cfg->node; + + if (!input_rockit_cfg->buf) + return -EINVAL; + + for (i = 0; i < ROCKIT_BUF_NUM_MAX; i++) { + if (stream_cfg->buff_id[i] == input_rockit_cfg->mpi_id) { + input_rockit_cfg->is_alloc = 0; + break; + } + } + + if (input_rockit_cfg->is_alloc) { + for (i = 0; i < ROCKIT_BUF_NUM_MAX; i++) { + if (stream_cfg->buff_id[i] == 0) { + stream_cfg->rkcif_buff[i] = + kzalloc(sizeof(struct rkcif_rockit_buffer), GFP_KERNEL); + if (stream_cfg->rkcif_buff[i] == NULL) { + pr_err("rkisp_buff alloc failed!\n"); + return -EINVAL; + } + stream_cfg->buff_id[i] = input_rockit_cfg->mpi_id; + break; + } + } + if (i == ROCKIT_BUF_NUM_MAX) + return -EINVAL; + + rkcif_buf = stream_cfg->rkcif_buff[i]; + rkcif_buf->mpi_buf = input_rockit_cfg->mpibuf; + + mem = g_ops->attach_dmabuf(stream->cifdev->hw_dev->dev, + input_rockit_cfg->buf, + input_rockit_cfg->buf->size, + DMA_BIDIRECTIONAL); + if (IS_ERR(mem)) + pr_err("the g_ops->attach_dmabuf is error!\n"); + + rkcif_buf->mpi_mem = mem; + rkcif_buf->dmabuf = input_rockit_cfg->buf; + + ret = g_ops->map_dmabuf(mem); + if (ret) + pr_err("the g_ops->map_dmabuf is error!\n"); + + if (stream->cifdev->hw_dev->is_dma_sg_ops) { + sg_tbl = (struct sg_table *)g_ops->cookie(mem); + rkcif_buf->buff_addr = sg_dma_address(sg_tbl->sgl); + } else { + rkcif_buf->buff_addr = *((u32 *)g_ops->cookie(mem)); + } + get_dma_buf(input_rockit_cfg->buf); + } else { + for (i = 0; i < ROCKIT_BUF_NUM_MAX; i++) { + rkcif_buf = stream_cfg->rkcif_buff[i]; + if (stream_cfg->buff_id[i] == input_rockit_cfg->mpi_id) + break; + } + } + + for (i = 0; i < stream->cif_fmt_out->mplanes; i++) + rkcif_buf->cif_buf.buff_addr[i] = rkcif_buf->buff_addr; + + if (stream->cif_fmt_out->mplanes == 1) { + for (i = 0; i < stream->cif_fmt_out->cplanes - 1; i++) { + offset = stream->pixm.plane_fmt[i].bytesperline * stream->pixm.height; + rkcif_buf->cif_buf.buff_addr[i + 1] = + rkcif_buf->cif_buf.buff_addr[i] + offset; + } + } + + v4l2_dbg(2, rkcif_debug, &cif_dev->v4l2_dev, + "stream:%d rockit_queue buf:0x%x\n", + stream->id, rkcif_buf->cif_buf.buff_addr[0]); + + if (stream_cfg->is_discard) + return -EINVAL; + + spin_lock_irqsave(&stream->vbq_lock, lock_flags); + list_add_tail(&rkcif_buf->cif_buf.queue, &stream->rockit_buf_head); + spin_unlock_irqrestore(&stream->vbq_lock, lock_flags); + + return 0; +} + +int rkcif_rockit_buf_done(struct rkcif_stream *stream, struct rkcif_buffer *buf) +{ + struct rkcif_device *dev = stream->cifdev; + struct rkcif_rockit_buffer *rkcif_buf = NULL; + struct rkcif_stream_cfg *stream_cfg = NULL; + u32 dev_id = stream->cifdev->csi_host_idx; + + if (!rockit_rkcif_cfg || + !rockit_rkcif_cfg->rkcif_rockit_mpibuf_done || + stream->id >= RKCIF_MAX_STREAM_MIPI) + return -EINVAL; + + stream_cfg = &rockit_rkcif_cfg->rkcif_dev_cfg[dev_id].rkcif_stream_cfg[stream->id]; + rkcif_buf = + container_of(buf, struct rkcif_rockit_buffer, cif_buf); + + rockit_rkcif_cfg->mpibuf = rkcif_buf->mpi_buf; + rockit_rkcif_cfg->buf = rkcif_buf->dmabuf; + + rockit_rkcif_cfg->frame.u64PTS = buf->vb.vb2_buf.timestamp; + + rockit_rkcif_cfg->frame.u32TimeRef = buf->vb.sequence; + + rockit_rkcif_cfg->frame.u32Height = stream->pixm.height; + + rockit_rkcif_cfg->frame.u32Width = stream->pixm.width; + + rockit_rkcif_cfg->frame.enPixelFormat = stream->pixm.pixelformat; + + rockit_rkcif_cfg->frame.u32VirWidth = stream->pixm.width; + + rockit_rkcif_cfg->frame.u32VirHeight = stream->pixm.height; + + rockit_rkcif_cfg->cur_name = dev_name(dev->dev); + + rockit_rkcif_cfg->node = stream_cfg->node; + + if (list_empty(&stream->rockit_buf_head)) + rockit_rkcif_cfg->is_empty = true; + else + rockit_rkcif_cfg->is_empty = false; + + if (rockit_rkcif_cfg->rkcif_rockit_mpibuf_done) + rockit_rkcif_cfg->rkcif_rockit_mpibuf_done(rockit_rkcif_cfg); + + return 0; +} + +static int rkcif_rockit_buf_free(struct rkcif_stream *stream) +{ + struct rkcif_rockit_buffer *rkcif_buf = NULL; + u32 i = 0, dev_id = stream->cifdev->csi_host_idx; + const struct vb2_mem_ops *g_ops = stream->cifdev->hw_dev->mem_ops; + struct rkcif_stream_cfg *stream_cfg = NULL; + + if (!rockit_rkcif_cfg || stream->id >= RKCIF_MAX_STREAM_MIPI) + return -EINVAL; + + stream_cfg = &rockit_rkcif_cfg->rkcif_dev_cfg[dev_id].rkcif_stream_cfg[stream->id]; + stream_cfg->is_discard = false; + for (i = 0; i < ROCKIT_BUF_NUM_MAX; i++) { + if (stream_cfg->rkcif_buff[i]) { + rkcif_buf = (struct rkcif_rockit_buffer *)stream_cfg->rkcif_buff[i]; + if (rkcif_buf->mpi_mem) { + g_ops->unmap_dmabuf(rkcif_buf->mpi_mem); + g_ops->detach_dmabuf(rkcif_buf->mpi_mem); + dma_buf_put(rkcif_buf->dmabuf); + } + kfree(stream_cfg->rkcif_buff[i]); + stream_cfg->rkcif_buff[i] = NULL; + stream_cfg->buff_id[i] = 0; + } + } + stream->curr_buf_rockit = NULL; + stream->next_buf_rockit = NULL; + INIT_LIST_HEAD(&stream->rockit_buf_head); + return 0; +} + +int rkcif_rockit_pause_stream(struct rockit_rkcif_cfg *input_rockit_cfg) +{ + struct rkcif_stream *stream = NULL; + + stream = rkcif_rockit_get_stream(input_rockit_cfg); + + if (stream == NULL) { + pr_err("the stream is NULL"); + return -EINVAL; + } + + rkcif_do_stop_stream(stream, RKCIF_STREAM_MODE_ROCKIT); + rkcif_rockit_buf_free(stream); + return 0; +} +EXPORT_SYMBOL(rkcif_rockit_pause_stream); + +int rkcif_rockit_config_stream(struct rockit_rkcif_cfg *input_rockit_cfg, + int width, int height, int v4l2_fmt) +{ + struct rkcif_stream *stream = NULL; + int ret; + + stream = rkcif_rockit_get_stream(input_rockit_cfg); + + if (stream == NULL) { + pr_err("the stream is NULL"); + return -EINVAL; + } + stream->pixm.pixelformat = v4l2_fmt; + stream->pixm.width = width; + stream->pixm.height = height; + stream->pixm.plane_fmt[0].bytesperline = 0; + ret = rkcif_set_fmt(stream, &stream->pixm, false); + if (ret < 0) { + pr_err("stream id %d config failed\n", stream->id); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL(rkcif_rockit_config_stream); + +int rkcif_rockit_resume_stream(struct rockit_rkcif_cfg *input_rockit_cfg) +{ + struct rkcif_stream *stream = NULL; + int ret = 0; + + stream = rkcif_rockit_get_stream(input_rockit_cfg); + + if (stream == NULL) { + pr_err("the stream is NULL"); + return -EINVAL; + } + + ret = rkcif_do_start_stream(stream, RKCIF_STREAM_MODE_ROCKIT); + if (ret < 0) { + pr_err("stream id %d start failed\n", stream->id); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL(rkcif_rockit_resume_stream); + +void rkcif_rockit_dev_init(struct rkcif_device *dev) +{ + int i; + + if (rockit_rkcif_cfg == NULL) { + rockit_rkcif_cfg = kzalloc(sizeof(struct rockit_rkcif_cfg), GFP_KERNEL); + if (rockit_rkcif_cfg == NULL) + return; + } + rockit_rkcif_cfg->cif_num = dev->hw_dev->dev_num; + for (i = 0; i < rockit_rkcif_cfg->cif_num; i++) { + if (dev->hw_dev->cif_dev[i]) { + rockit_rkcif_cfg->rkcif_dev_cfg[i].cif_name = dev_name(dev->hw_dev->cif_dev[i]->dev); + rockit_rkcif_cfg->rkcif_dev_cfg[i].cif_dev = + dev->hw_dev->cif_dev[i]; + } + } +} + +void rkcif_rockit_dev_deinit(void) +{ + kfree(rockit_rkcif_cfg); + rockit_rkcif_cfg = NULL; +} + +void *rkcif_rockit_function_register(void *function, int cmd) +{ + if (rockit_rkcif_cfg == NULL) { + pr_err("rockit_cfg is null function register failed"); + return NULL; + } + + switch (cmd) { + case ROCKIT_BUF_QUE: + function = rkcif_rockit_buf_queue; + break; + case ROCKIT_MPIBUF_DONE: + rockit_rkcif_cfg->rkcif_rockit_mpibuf_done = function; + if (!rockit_rkcif_cfg->rkcif_rockit_mpibuf_done) + pr_err("get rkcif_rockit_mpibuf_done failed!"); + break; + default: + break; + } + return function; +} +EXPORT_SYMBOL(rkcif_rockit_function_register); + +int rkcif_rockit_get_cifdev(char **name) +{ + int i = 0; + + if (rockit_rkcif_cfg == NULL) { + pr_err("rockit_cfg is null"); + return -EINVAL; + } + + if (name == NULL) { + pr_err("the name is null"); + return -EINVAL; + } + + for (i = 0; i < rockit_rkcif_cfg->cif_num; i++) + name[i] = (char *)rockit_rkcif_cfg->rkcif_dev_cfg[i].cif_name; + if (name[0] == NULL) + return -EINVAL; + else + return 0; +} +EXPORT_SYMBOL(rkcif_rockit_get_cifdev); diff --git a/drivers/media/platform/rockchip/cif/dev.c b/drivers/media/platform/rockchip/cif/dev.c index b34785b4a83b..8ebaf794bce4 100644 --- a/drivers/media/platform/rockchip/cif/dev.c +++ b/drivers/media/platform/rockchip/cif/dev.c @@ -2023,6 +2023,8 @@ int rkcif_plat_uninit(struct rkcif_device *cif_dev) } rkcif_unregister_stream_vdevs(cif_dev, stream_num); + if (cif_dev->chip_id == CHIP_RV1106_CIF) + rkcif_rockit_dev_deinit(); return 0; } @@ -2137,6 +2139,8 @@ static int rkcif_plat_probe(struct platform_device *pdev) dev_warn(dev, "dev:%s create proc failed\n", dev_name(dev)); rkcif_init_reset_monitor(cif_dev); + if (cif_dev->chip_id == CHIP_RV1106_CIF) + rkcif_rockit_dev_init(cif_dev); pm_runtime_enable(&pdev->dev); return 0; diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index b3e7d1cab3c9..a88dbb236880 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -101,11 +101,12 @@ enum rkcif_workmode { }; enum rkcif_stream_mode { - RKCIF_STREAM_MODE_NONE = 0x0, - RKCIF_STREAM_MODE_CAPTURE = 0x01, - RKCIF_STREAM_MODE_TOISP = 0x02, - RKCIF_STREAM_MODE_TOSCALE = 0x04, - RKCIF_STREAM_MODE_TOISP_RDBK = 0x08 + RKCIF_STREAM_MODE_NONE = 0x0, + RKCIF_STREAM_MODE_CAPTURE = 0x01, + RKCIF_STREAM_MODE_TOISP = 0x02, + RKCIF_STREAM_MODE_TOSCALE = 0x04, + RKCIF_STREAM_MODE_TOISP_RDBK = 0x08, + RKCIF_STREAM_MODE_ROCKIT = 0x10 }; enum rkcif_yuvaddr_state { @@ -445,6 +446,7 @@ enum rkcif_dma_en_mode { RKCIF_DMAEN_BY_ISP = 0x2, RKCIF_DMAEN_BY_VICAP_TO_ISP = 0x4, RKCIF_DMAEN_BY_ISP_TO_VICAP = 0x8, + RKCIF_DMAEN_BY_ROCKIT = 0x10, }; struct rkcif_skip_info { @@ -484,6 +486,9 @@ struct rkcif_stream { struct rkcif_buffer *next_buf; struct rkcif_rx_buffer *curr_buf_toisp; struct rkcif_rx_buffer *next_buf_toisp; + struct list_head rockit_buf_head; + struct rkcif_buffer *curr_buf_rockit; + struct rkcif_buffer *next_buf_rockit; spinlock_t vbq_lock; /* vfd lock */ spinlock_t fps_lock; @@ -909,5 +914,9 @@ int rkcif_clr_unready_dev(void); const struct cif_output_fmt *rkcif_find_output_fmt(struct rkcif_stream *stream, u32 pixelfmt); +/* Rockit */ +int rkcif_rockit_buf_done(struct rkcif_stream *stream, struct rkcif_buffer *buf); +void rkcif_rockit_dev_init(struct rkcif_device *dev); +void rkcif_rockit_dev_deinit(void); #endif