diff --git a/drivers/media/platform/rockchip/isp/Makefile b/drivers/media/platform/rockchip/isp/Makefile index 03cc0bd0783e..71b352f93318 100644 --- a/drivers/media/platform/rockchip/isp/Makefile +++ b/drivers/media/platform/rockchip/isp/Makefile @@ -13,5 +13,5 @@ video_rkisp-objs += rkisp.o \ capture.o \ dmarx.o \ csi.o \ - mpfbc.o \ + bridge.o \ isp_mipi_luma.o diff --git a/drivers/media/platform/rockchip/isp/bridge.c b/drivers/media/platform/rockchip/isp/bridge.c new file mode 100644 index 000000000000..614192241935 --- /dev/null +++ b/drivers/media/platform/rockchip/isp/bridge.c @@ -0,0 +1,772 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dev.h" +#include "regs.h" + +static inline +struct rkisp_bridge_buf *to_bridge_buf(struct rkisp_ispp_buf *dbufs) +{ + return container_of(dbufs, struct rkisp_bridge_buf, dbufs); +} + +static void update_mi(struct rkisp_bridge_device *dev) +{ + void __iomem *base = dev->ispdev->base_addr; + struct rkisp_bridge_buf *buf; + u32 val; + + if (dev->nxt_buf) { + buf = to_bridge_buf(dev->nxt_buf); + val = buf->dummy[GROUP_BUF_PIC].dma_addr; + writel(val, base + dev->cfg->reg.y0_base); + val += dev->cfg->offset; + writel(val, base + dev->cfg->reg.uv0_base); + val = buf->dummy[GROUP_BUF_GAIN].dma_addr; + writel(val, base + dev->cfg->reg.g0_base); + } + + v4l2_dbg(3, rkisp_debug, &dev->sd, + "%s pic(shd:0x%x base:0x%x) gain(shd:0x%x base:0x%x)\n", + __func__, + readl(base + dev->cfg->reg.y0_base_shd), + readl(base + dev->cfg->reg.y0_base), + readl(base + dev->cfg->reg.g0_base_shd), + readl(base + dev->cfg->reg.g0_base)); +} + +static int frame_end(struct rkisp_bridge_device *dev) +{ + struct v4l2_subdev *sd = v4l2_get_subdev_hostdata(&dev->sd); + unsigned long lock_flags = 0; + + if (dev->cur_buf && dev->nxt_buf) { + dev->cur_buf->frame_id = rkisp_dmarx_get_frame_id(dev->ispdev) + 1; + v4l2_subdev_call(sd, video, s_rx_buffer, dev->cur_buf, NULL); + dev->cur_buf = NULL; + } + + if (dev->nxt_buf) { + dev->cur_buf = dev->nxt_buf; + dev->nxt_buf = NULL; + } + + spin_lock_irqsave(&dev->buf_lock, lock_flags); + if (!list_empty(&dev->list)) { + dev->nxt_buf = list_first_entry(&dev->list, + struct rkisp_ispp_buf, list); + list_del(&dev->nxt_buf->list); + } + spin_unlock_irqrestore(&dev->buf_lock, lock_flags); + + update_mi(dev); + + return 0; +} + +static int config_gain(struct rkisp_bridge_device *dev) +{ + void __iomem *base = dev->ispdev->base_addr; + struct rkisp_bridge_buf *buf; + u32 val; + + dev->cur_buf = list_first_entry(&dev->list, + struct rkisp_ispp_buf, list); + list_del(&dev->cur_buf->list); + if (!list_empty(&dev->list)) { + dev->nxt_buf = list_first_entry(&dev->list, + struct rkisp_ispp_buf, list); + list_del(&dev->nxt_buf->list); + } + + if (dev->nxt_buf && (dev->work_mode & ISP_ISPP_QUICK)) { + buf = to_bridge_buf(dev->nxt_buf); + val = buf->dummy[GROUP_BUF_GAIN].dma_addr; + writel(val, base + dev->cfg->reg.g1_base); + mi_wr_ctrl2(base, SW_GAIN_WR_PINGPONG); + } + + buf = to_bridge_buf(dev->cur_buf); + val = buf->dummy[GROUP_BUF_GAIN].dma_addr; + writel(val, base + dev->cfg->reg.g0_base); + + val = dev->cur_buf->dbuf[GROUP_BUF_GAIN]->size; + writel(val, base + MI_GAIN_WR_SIZE); + val = ALIGN((dev->crop.width + 3) >> 2, 16); + writel(val, base + MI_GAIN_WR_LENGTH); + mi_wr_ctrl2(base, SW_GAIN_WR_AUTOUPD); + + return 0; +} + +static int config_mpfbc(struct rkisp_bridge_device *dev) +{ + void __iomem *base = dev->ispdev->base_addr; + struct rkisp_bridge_buf *buf; + u32 h = ALIGN(dev->crop.height, 16); + u32 val, ctrl = 0; + + if (dev->work_mode & ISP_ISPP_QUICK) { + isp_set_bits(base + CTRL_SWS_CFG, + 0, SW_ISP2PP_PIPE_EN); + ctrl = SW_MPFBC_MAINISP_MODE; + if (dev->nxt_buf) { + ctrl |= SW_MPFBC_PINGPONG_EN; + buf = to_bridge_buf(dev->nxt_buf); + val = buf->dummy[GROUP_BUF_PIC].dma_addr; + writel(val, base + dev->cfg->reg.y1_base); + val += dev->cfg->offset; + writel(val, base + dev->cfg->reg.uv1_base); + } + } + + buf = to_bridge_buf(dev->cur_buf); + val = buf->dummy[GROUP_BUF_PIC].dma_addr; + writel(val, base + dev->cfg->reg.y0_base); + val += dev->cfg->offset; + writel(val, base + dev->cfg->reg.uv0_base); + + writel(0, base + ISP_MPFBC_VIR_WIDTH); + writel(h, base + ISP_MPFBC_VIR_HEIGHT); + + mp_set_data_path(base); + isp_set_bits(base + MI_WR_CTRL, 0, + CIF_MI_CTRL_INIT_BASE_EN | + CIF_MI_CTRL_INIT_OFFSET_EN); + isp_set_bits(base + MI_IMSC, 0, + dev->cfg->frame_end_id); + + ctrl |= (dev->work_mode & ISP_ISPP_422) | SW_MPFBC_EN; + writel(ctrl, base + ISP_MPFBC_BASE); + return 0; +} + +static void disable_mpfbc(void __iomem *base) +{ + isp_clear_bits(base + ISP_MPFBC_BASE, SW_MPFBC_EN); +} + +static struct rkisp_bridge_ops mpfbc_ops = { + .config = config_mpfbc, + .disable = disable_mpfbc, + .is_stopped = is_mpfbc_stopped, +}; + +static struct rkisp_bridge_config mpfbc_cfg = { + .frame_end_id = MI_MPFBC_FRAME, + .reg = { + .y0_base = ISP_MPFBC_HEAD_PTR, + .uv0_base = ISP_MPFBC_PAYL_PTR, + .y1_base = ISP_MPFBC_HEAD_PTR2, + .uv1_base = ISP_MPFBC_PAYL_PTR2, + .g0_base = MI_GAIN_WR_BASE, + .g1_base = MI_GAIN_WR_BASE2, + + .y0_base_shd = ISP_MPFBC_HEAD_PTR, + .uv0_base_shd = ISP_MPFBC_PAYL_PTR, + .g0_base_shd = MI_GAIN_WR_BASE_SHD, + }, +}; + +static int config_mp(struct rkisp_bridge_device *dev) +{ + void __iomem *base = dev->ispdev->base_addr; + struct rkisp_bridge_buf *buf; + u32 val; + + if (dev->work_mode & ISP_ISPP_QUICK) { + isp_set_bits(base + CTRL_SWS_CFG, 0, + SW_ISP2PP_PIPE_EN); + if (dev->nxt_buf) { + buf = to_bridge_buf(dev->nxt_buf); + val = buf->dummy[GROUP_BUF_PIC].dma_addr; + writel(val, base + dev->cfg->reg.y1_base); + val += dev->cfg->offset; + writel(val, base + dev->cfg->reg.uv1_base); + isp_set_bits(base + CIF_MI_CTRL, 0, + CIF_MI_MP_PINGPONG_ENABLE); + } + } + + buf = to_bridge_buf(dev->cur_buf); + val = buf->dummy[GROUP_BUF_PIC].dma_addr; + writel(val, base + dev->cfg->reg.y0_base); + val += dev->cfg->offset; + writel(val, base + dev->cfg->reg.uv0_base); + writel(dev->cfg->offset, base + CIF_MI_MP_Y_SIZE_INIT); + val = dev->cur_buf->dbuf[GROUP_BUF_PIC]->size - dev->cfg->offset; + writel(val, base + CIF_MI_MP_CB_SIZE_INIT); + writel(0, base + CIF_MI_MP_CR_SIZE_INIT); + writel(0, base + CIF_MI_MP_Y_OFFS_CNT_INIT); + writel(0, base + CIF_MI_MP_CB_OFFS_CNT_INIT); + writel(0, base + CIF_MI_MP_CR_OFFS_CNT_INIT); + + mp_set_data_path(base); + mp_mi_ctrl_set_format(base, MI_CTRL_MP_WRITE_YUV_SPLA); + writel(dev->work_mode & ISP_ISPP_422, base + ISP_MPFBC_BASE); + isp_set_bits(base + MI_WR_CTRL, 0, + CIF_MI_CTRL_INIT_BASE_EN | + CIF_MI_CTRL_INIT_OFFSET_EN); + isp_set_bits(base + MI_IMSC, 0, + dev->cfg->frame_end_id); + mi_ctrl_mpyuv_enable(base); + mp_mi_ctrl_autoupdate_en(base); + return 0; +} + +static void disable_mp(void __iomem *base) +{ + mi_ctrl_mp_disable(base); +} + +static struct rkisp_bridge_ops mp_ops = { + .config = config_mp, + .disable = disable_mp, + .is_stopped = mp_is_stream_stopped, +}; + +static struct rkisp_bridge_config mp_cfg = { + .frame_end_id = MI_MP_FRAME, + .reg = { + .y0_base = MI_MP_WR_Y_BASE, + .uv0_base = MI_MP_WR_CB_BASE, + .y1_base = MI_MP_WR_Y_BASE2, + .uv1_base = MI_MP_WR_CB_BASE2, + .g0_base = MI_GAIN_WR_BASE, + .g1_base = MI_GAIN_WR_BASE2, + + .y0_base_shd = MI_MP_WR_Y_BASE_SHD, + .uv0_base_shd = MI_MP_WR_CB_BASE_SHD, + .g0_base_shd = MI_GAIN_WR_BASE_SHD, + }, +}; + +static void free_bridge_buf(struct rkisp_bridge_device *dev) +{ + struct rkisp_bridge_buf *buf; + struct rkisp_ispp_buf *dbufs; + int i, j; + + if (dev->cur_buf) { + list_add_tail(&dev->cur_buf->list, &dev->list); + if (dev->cur_buf == dev->nxt_buf) + dev->nxt_buf = NULL; + dev->cur_buf = NULL; + } + + if (dev->nxt_buf) { + list_add_tail(&dev->nxt_buf->list, &dev->list); + dev->nxt_buf = NULL; + } + + while (!list_empty(&dev->list)) { + dbufs = list_first_entry(&dev->list, + struct rkisp_ispp_buf, list); + list_del(&dbufs->list); + } + + for (i = 0; i < BRIDGE_BUF_MAX; i++) { + buf = &dev->bufs[i]; + for (j = 0; j < GROUP_BUF_MAX; j++) + rkisp_free_buffer(dev->ispdev->dev, &buf->dummy[j]); + } +} + +static int init_buf(struct rkisp_bridge_device *dev) +{ + struct v4l2_subdev *sd = v4l2_get_subdev_hostdata(&dev->sd); + struct rkisp_bridge_buf *buf; + struct rkisp_dummy_buffer *dummy; + u32 width = dev->crop.width; + u32 height = dev->crop.height; + u32 offset = width * height; + u32 pic_size = 0, gain_size; + int i, j, ret = 0; + + gain_size = ALIGN(width, 64) * ALIGN(height, 128) >> 4; + if (dev->work_mode & ISP_ISPP_FBC) { + width = ALIGN(width, 16); + height = ALIGN(height, 16); + offset = width * height >> 4; + pic_size = offset; + } + if (dev->work_mode & ISP_ISPP_422) + pic_size += width * height * 2; + else + pic_size += width * height * 3 >> 1; + dev->cfg->offset = offset; + + for (i = 0; i < dev->buf_num; i++) { + buf = &dev->bufs[i]; + for (j = 0; j < GROUP_BUF_MAX; j++) { + dummy = &buf->dummy[j]; + dummy->is_need_dbuf = true; + dummy->size = !j ? pic_size : gain_size; + ret = rkisp_alloc_buffer(dev->ispdev->dev, dummy); + if (ret) + goto err; + buf->dbufs.dbuf[j] = dummy->dbuf; + } + list_add_tail(&buf->dbufs.list, &dev->list); + ret = v4l2_subdev_call(sd, video, s_rx_buffer, &buf->dbufs, NULL); + if (ret) + goto err; + } + + return 0; +err: + free_bridge_buf(dev); + v4l2_err(&dev->sd, "%s fail:%d\n", __func__, ret); + return ret; +} + +static int config_mode(struct rkisp_bridge_device *dev) +{ + if (dev->work_mode == ISP_ISPP_INIT_FAIL) { + free_bridge_buf(dev); + return 0; + } + + if (!dev->linked || !dev->ispdev->isp_inp) { + v4l2_err(&dev->sd, + "invalid: link:%d or isp input:0x%x\n", + dev->linked, + dev->ispdev->isp_inp); + return -EINVAL; + } + + v4l2_dbg(1, rkisp_debug, &dev->sd, + "work mode:0x%x buf num:%d\n", + dev->work_mode, dev->buf_num); + + if (dev->work_mode & ISP_ISPP_FBC) { + dev->ops = &mpfbc_ops; + dev->cfg = &mpfbc_cfg; + } else { + dev->ops = &mp_ops; + dev->cfg = &mp_cfg; + } + + return init_buf(dev); +} + +static void crop_on(struct rkisp_bridge_device *dev) +{ + struct rkisp_device *ispdev = dev->ispdev; + void __iomem *base = ispdev->base_addr; + u32 src_w = ispdev->isp_sdev.out_crop.width; + u32 src_h = ispdev->isp_sdev.out_crop.height; + u32 dest_w = dev->crop.width; + u32 dest_h = dev->crop.height; + u32 left = dev->crop.left; + u32 top = dev->crop.top; + u32 ctrl; + + if (src_w == dest_w && src_h == dest_h) + return; + + writel(left, base + CIF_DUAL_CROP_M_H_OFFS); + writel(top, base + CIF_DUAL_CROP_M_V_OFFS); + writel(dest_w, base + CIF_DUAL_CROP_M_H_SIZE); + writel(dest_h, base + CIF_DUAL_CROP_M_V_SIZE); + ctrl = readl(base + CIF_DUAL_CROP_CTRL); + ctrl |= CIF_DUAL_CROP_MP_MODE_YUV | CIF_DUAL_CROP_CFG_UPD; + writel(ctrl, base + CIF_DUAL_CROP_CTRL); +} + +static void crop_off(struct rkisp_bridge_device *dev) +{ + struct rkisp_device *ispdev = dev->ispdev; + void __iomem *base = ispdev->base_addr; + u32 src_w = ispdev->isp_sdev.out_crop.width; + u32 src_h = ispdev->isp_sdev.out_crop.height; + u32 dest_w = dev->crop.width; + u32 dest_h = dev->crop.height; + u32 ctrl; + + if (src_w == dest_w && src_h == dest_h) + return; + + ctrl = readl(base + CIF_DUAL_CROP_CTRL); + ctrl &= ~(CIF_DUAL_CROP_MP_MODE_YUV | + CIF_DUAL_CROP_MP_MODE_RAW); + ctrl |= CIF_DUAL_CROP_GEN_CFG_UPD; + writel(ctrl, base + CIF_DUAL_CROP_CTRL); +} + +static int bridge_start(struct rkisp_bridge_device *dev) +{ + void __iomem *base = dev->ispdev->base_addr; + + crop_on(dev); + config_gain(dev); + dev->ops->config(dev); + + force_cfg_update(base); + + if (!(dev->work_mode & ISP_ISPP_QUICK)) + update_mi(dev); + + dev->en = true; + return 0; +} + +static int bridge_stop(struct rkisp_bridge_device *dev) +{ + void __iomem *base = dev->ispdev->base_addr; + int ret; + + dev->stopping = true; + dev->ops->disable(base); + hdr_stop_dmatx(dev->ispdev); + ret = wait_event_timeout(dev->done, !dev->en, + msecs_to_jiffies(1000)); + if (!ret) + v4l2_warn(&dev->sd, + "%s timeout ret:%d\n", __func__, ret); + crop_off(dev); + isp_clear_bits(base + MI_IMSC, dev->cfg->frame_end_id); + dev->stopping = false; + dev->en = false; + + /* make sure ispp last frame done */ + if (dev->work_mode & ISP_ISPP_QUICK) + usleep_range(20000, 25000); + return 0; +} + +static int bridge_start_stream(struct v4l2_subdev *sd) +{ + struct rkisp_bridge_device *dev = v4l2_get_subdevdata(sd); + int ret; + + if (WARN_ON(dev->en)) + return -EBUSY; + + if (dev->ispdev->isp_inp & INP_CSI || + dev->ispdev->isp_inp & INP_DVP) { + /* Always update sensor info in case media topology changed */ + ret = rkisp_update_sensor_info(dev->ispdev); + if (ret < 0) { + v4l2_err(sd, "update sensor info failed %d\n", ret); + goto free_buf; + } + } + + /* enable clocks/power-domains */ + ret = dev->ispdev->pipe.open(&dev->ispdev->pipe, &sd->entity, true); + if (ret < 0) + goto free_buf; + + hdr_config_dmatx(dev->ispdev); + ret = bridge_start(dev); + if (ret) + goto close_pipe; + hdr_update_dmatx_buf(dev->ispdev); + + /* start sub-devices */ + ret = dev->ispdev->pipe.set_stream(&dev->ispdev->pipe, true); + if (ret < 0) + goto stop_bridge; + + ret = media_pipeline_start(&sd->entity, &dev->ispdev->pipe.pipe); + if (ret < 0) + goto pipe_stream_off; + + return 0; +pipe_stream_off: + dev->ispdev->pipe.set_stream(&dev->ispdev->pipe, false); +stop_bridge: + bridge_stop(dev); +close_pipe: + dev->ispdev->pipe.close(&dev->ispdev->pipe); + hdr_destroy_buf(dev->ispdev); +free_buf: + free_bridge_buf(dev); + v4l2_err(&dev->sd, "%s fail:%d\n", __func__, ret); + return ret; +} + +static void bridge_destroy_buf(struct rkisp_bridge_device *dev) +{ + free_bridge_buf(dev); + hdr_destroy_buf(dev->ispdev); +} + +static int bridge_stop_stream(struct v4l2_subdev *sd) +{ + struct rkisp_bridge_device *dev = v4l2_get_subdevdata(sd); + + bridge_stop(dev); + media_pipeline_stop(&sd->entity); + dev->ispdev->pipe.set_stream(&dev->ispdev->pipe, false); + dev->ispdev->pipe.close(&dev->ispdev->pipe); + bridge_destroy_buf(dev); + return 0; +} + +static int bridge_get_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct rkisp_bridge_device *dev = v4l2_get_subdevdata(sd); + + if (!fmt) + return -EINVAL; + + /* get isp out format */ + fmt->pad = RKISP_ISP_PAD_SOURCE_PATH; + fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE; + return v4l2_subdev_call(&dev->ispdev->isp_sdev.sd, + pad, get_fmt, NULL, fmt); +} + +static int bridge_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct rkisp_bridge_device *dev = v4l2_get_subdevdata(sd); + struct rkisp_isp_subdev *isp_sd = &dev->ispdev->isp_sdev; + u32 src_w = isp_sd->out_crop.width; + u32 src_h = isp_sd->out_crop.height; + struct v4l2_rect *crop; + + if (!sel) + return -EINVAL; + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + crop = &sel->r; + crop->left = clamp_t(u32, crop->left, 0, src_w); + crop->top = clamp_t(u32, crop->top, 0, src_h); + crop->width = clamp_t(u32, crop->width, + CIF_ISP_OUTPUT_W_MIN, src_w - crop->left); + crop->height = clamp_t(u32, crop->height, + CIF_ISP_OUTPUT_H_MIN, src_h - crop->top); + + dev->crop = *crop; + return 0; +} + +static int bridge_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct rkisp_bridge_device *dev = v4l2_get_subdevdata(sd); + struct rkisp_isp_subdev *isp_sd = &dev->ispdev->isp_sdev; + struct v4l2_rect *crop; + + if (!sel) + return -EINVAL; + + crop = &sel->r; + switch (sel->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + *crop = isp_sd->out_crop; + break; + case V4L2_SEL_TGT_CROP: + *crop = dev->crop; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int bridge_s_rx_buffer(struct v4l2_subdev *sd, + void *buf, unsigned int *size) +{ + struct rkisp_bridge_device *dev = v4l2_get_subdevdata(sd); + struct rkisp_ispp_buf *dbufs = buf; + unsigned long lock_flags = 0; + + /* size isn't using now */ + if (!dbufs) + return -EINVAL; + + spin_lock_irqsave(&dev->buf_lock, lock_flags); + list_add_tail(&dbufs->list, &dev->list); + spin_unlock_irqrestore(&dev->buf_lock, lock_flags); + return 0; +} + +static int bridge_s_stream(struct v4l2_subdev *sd, int on) +{ + struct rkisp_bridge_device *dev = v4l2_get_subdevdata(sd); + int ret = 0; + + v4l2_dbg(1, rkisp_debug, sd, + "%s %d\n", __func__, on); + + if (on) { + atomic_inc(&dev->ispdev->cap_dev.refcnt); + ret = bridge_start_stream(sd); + } else if (dev->en) { + ret = bridge_stop_stream(sd); + } + + if (!on) + atomic_dec(&dev->ispdev->cap_dev.refcnt); + return ret; +} + +static int bridge_s_power(struct v4l2_subdev *sd, int on) +{ + int ret = 0; + + v4l2_dbg(1, rkisp_debug, sd, + "%s %d\n", __func__, on); + + if (on) + ret = v4l2_pipeline_pm_use(&sd->entity, 1); + else + ret = v4l2_pipeline_pm_use(&sd->entity, 0); + + return ret; +} + +static long bridge_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct rkisp_bridge_device *dev = v4l2_get_subdevdata(sd); + struct rkisp_ispp_mode *mode; + long ret = 0; + + switch (cmd) { + case RKISP_ISPP_CMD_SET_MODE: + mode = arg; + dev->work_mode = mode->work_mode; + dev->buf_num = mode->buf_num; + ret = config_mode(dev); + break; + default: + ret = -ENOIOCTLCMD; + } + + return ret; +} + +static const struct v4l2_subdev_pad_ops bridge_pad_ops = { + .set_fmt = bridge_get_set_fmt, + .get_fmt = bridge_get_set_fmt, + .get_selection = bridge_get_selection, + .set_selection = bridge_set_selection, +}; + +static const struct v4l2_subdev_video_ops bridge_video_ops = { + .s_rx_buffer = bridge_s_rx_buffer, + .s_stream = bridge_s_stream, +}; + +static const struct v4l2_subdev_core_ops bridge_core_ops = { + .s_power = bridge_s_power, + .ioctl = bridge_ioctl, +}; + +static struct v4l2_subdev_ops bridge_v4l2_ops = { + .core = &bridge_core_ops, + .video = &bridge_video_ops, + .pad = &bridge_pad_ops, +}; + +void rkisp_bridge_isr(u32 *mis_val, struct rkisp_device *dev) +{ + struct rkisp_bridge_device *bridge = &dev->br_dev; + void __iomem *base = dev->base_addr; + + if (!bridge->en || !bridge->cfg || + (bridge->cfg && + !(*mis_val & bridge->cfg->frame_end_id))) + return; + + *mis_val &= ~bridge->cfg->frame_end_id; + writel(bridge->cfg->frame_end_id, base + CIF_MI_ICR); + + if (bridge->stopping) { + if (bridge->ops->is_stopped(base)) { + bridge->en = false; + bridge->stopping = false; + wake_up(&bridge->done); + } + } else if (!(bridge->work_mode & ISP_ISPP_QUICK)) { + frame_end(bridge); + } +} + +int rkisp_register_bridge_subdev(struct rkisp_device *dev, + struct v4l2_device *v4l2_dev) +{ + struct rkisp_bridge_device *bridge = &dev->br_dev; + struct v4l2_subdev *sd; + struct media_entity *source, *sink; + int ret; + + memset(bridge, 0, sizeof(*bridge)); + if (dev->isp_ver != ISP_V20) + return 0; + + bridge->ispdev = dev; + sd = &bridge->sd; + v4l2_subdev_init(sd, &bridge_v4l2_ops); + //sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->entity.obj_type = 0; + snprintf(sd->name, sizeof(sd->name), BRIDGE_DEV_NAME); + bridge->pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&sd->entity, 1, &bridge->pad); + if (ret < 0) + return ret; + sd->owner = THIS_MODULE; + v4l2_set_subdevdata(sd, bridge); + sd->grp_id = GRP_ID_ISP_BRIDGE; + ret = v4l2_device_register_subdev(v4l2_dev, sd); + if (ret < 0) { + v4l2_err(sd, "Failed to register subdev\n"); + goto free_media; + } + bridge->crop = dev->isp_sdev.out_crop; + /* bridge links */ + bridge->linked = true; + source = &dev->isp_sdev.sd.entity; + sink = &sd->entity; + ret = media_create_pad_link(source, RKISP_ISP_PAD_SOURCE_PATH, + sink, 0, bridge->linked); + init_waitqueue_head(&bridge->done); + spin_lock_init(&bridge->buf_lock); + INIT_LIST_HEAD(&bridge->list); + return ret; + +free_media: + media_entity_cleanup(&sd->entity); + return ret; +} + +void rkisp_unregister_bridge_subdev(struct rkisp_device *dev) +{ + struct v4l2_subdev *sd = &dev->br_dev.sd; + + if (dev->isp_ver != ISP_V20) + return; + v4l2_device_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); +} + +void rkisp_get_bridge_sd(struct platform_device *dev, + struct v4l2_subdev **sd) +{ + struct rkisp_device *isp_dev = platform_get_drvdata(dev); + + if (isp_dev) + *sd = &isp_dev->br_dev.sd; + else + *sd = NULL; +} diff --git a/drivers/media/platform/rockchip/isp/bridge.h b/drivers/media/platform/rockchip/isp/bridge.h new file mode 100644 index 000000000000..a5e1681da05e --- /dev/null +++ b/drivers/media/platform/rockchip/isp/bridge.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */ + +#ifndef _RKISP_BRIDGE_H +#define _RKISP_BRIDGE_H + +#include "linux/platform_device.h" +#include "isp_ispp.h" + +#define BRIDGE_DEV_NAME DRIVER_NAME "-bridge-ispp" +#define BRIDGE_BUF_MAX (RKISP_ISPP_BUF_MAX + 1) + +struct rkisp_bridge_device; + +struct rkisp_bridge_ops { + int (*config)(struct rkisp_bridge_device *dev); + void (*disable)(void __iomem *base); + bool (*is_stopped)(void __iomem *base); +}; + +struct rkisp_bridge_config { + const int frame_end_id; + u32 offset; + struct { + u32 y0_base; + u32 uv0_base; + u32 y1_base; + u32 uv1_base; + u32 g0_base; + u32 g1_base; + + u32 y0_base_shd; + u32 uv0_base_shd; + u32 g0_base_shd; + } reg; +}; + +struct rkisp_bridge_buf { + struct rkisp_ispp_buf dbufs; + struct rkisp_dummy_buffer dummy[GROUP_BUF_MAX]; +}; + +struct rkisp_bridge_device { + struct rkisp_device *ispdev; + struct v4l2_subdev sd; + struct v4l2_rect crop; + struct media_pad pad; + wait_queue_head_t done; + spinlock_t buf_lock; + struct list_head list; + struct rkisp_bridge_buf bufs[BRIDGE_BUF_MAX]; + struct rkisp_ispp_buf *cur_buf; + struct rkisp_ispp_buf *nxt_buf; + struct rkisp_bridge_ops *ops; + struct rkisp_bridge_config *cfg; + u8 work_mode; + u8 buf_num; + bool pingpong; + bool stopping; + bool linked; + bool en; +}; + +int rkisp_register_bridge_subdev(struct rkisp_device *dev, + struct v4l2_device *v4l2_dev); +void rkisp_unregister_bridge_subdev(struct rkisp_device *dev); +void rkisp_bridge_isr(u32 *mis_val, struct rkisp_device *dev); +void rkisp_get_bridge_sd(struct platform_device *dev, + struct v4l2_subdev **sd); +#endif diff --git a/drivers/media/platform/rockchip/isp/capture.c b/drivers/media/platform/rockchip/isp/capture.c index 2ce8c0a1ad08..e36b635f7572 100644 --- a/drivers/media/platform/rockchip/isp/capture.c +++ b/drivers/media/platform/rockchip/isp/capture.c @@ -782,7 +782,7 @@ static int rkisp_config_rsz(struct rkisp_stream *stream, bool async) u32 xsubs_out = 1, ysubs_out = 1; if (input_isp_fmt->fmt_type == FMT_BAYER || - dev->mpfbc_dev.en) + dev->br_dev.en) goto disable; /* set input and output sizes for scale calculation */ @@ -1901,16 +1901,14 @@ static void rkisp_stream_stop(struct rkisp_stream *stream) ret = wait_event_timeout(stream->done, !stream->streaming, msecs_to_jiffies(1000)); - if (!ret) { - v4l2_warn(v4l2_dev, "waiting on event return error %d\n", ret); - stream->stopping = false; - stream->streaming = false; - } - } else { - stream->stopping = false; - stream->streaming = false; + if (!ret) + v4l2_warn(v4l2_dev, "%s id:%d timeout\n", + __func__, stream->id); } + stream->stopping = false; + stream->streaming = false; + if (stream->id == RKISP_STREAM_MP || stream->id == RKISP_STREAM_SP) { disable_dcrop(stream, true); @@ -1979,7 +1977,7 @@ static int rkisp_start(struct rkisp_stream *stream) * also required because the sencond FE maybe corrupt especially * when run at 120fps. */ - if (is_update && !dev->mpfbc_dev.en) { + if (is_update && !dev->br_dev.en) { rkisp_stats_first_ddr_config(&dev->stats_vdev); force_cfg_update(base); mi_frame_end(stream); @@ -2563,7 +2561,8 @@ void rkisp_set_stream_def_fmt(struct rkisp_device *dev, u32 id, struct v4l2_pix_format_mplane pixm; memset(&pixm, 0, sizeof(pixm)); - pixm.pixelformat = pixelformat; + if (pixelformat) + pixm.pixelformat = pixelformat; pixm.width = width; pixm.height = height; rkisp_set_fmt(stream, &pixm, false); @@ -2937,7 +2936,7 @@ static int rkisp_stream_init(struct rkisp_device *dev, u32 id) init_waitqueue_head(&stream->done); spin_lock_init(&stream->vbq_lock); - /* isp2 disable MP/SP, enable MPFBC default */ + /* isp2 disable MP/SP, enable BRIDGE default */ if ((id == RKISP_STREAM_SP || id == RKISP_STREAM_MP) && dev->isp_ver == ISP_V20) stream->linked = false; @@ -3111,8 +3110,8 @@ void rkisp_mi_isr(u32 mis_val, struct rkisp_device *dev) v4l2_dbg(3, rkisp_debug, &dev->v4l2_dev, "mi isr:0x%x\n", mis_val); - if (mis_val & MI_MPFBC_FRAME) - rkisp_mpfbc_isr(mis_val, dev); + rkisp_bridge_isr(&mis_val, dev); + if (mis_val & CIF_MI_DMA_READY) rkisp_dmarx_isr(mis_val, dev); diff --git a/drivers/media/platform/rockchip/isp/common.h b/drivers/media/platform/rockchip/isp/common.h index dd5541981ff8..a181c9c83955 100644 --- a/drivers/media/platform/rockchip/isp/common.h +++ b/drivers/media/platform/rockchip/isp/common.h @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -103,9 +104,13 @@ struct rkisp_buffer { struct rkisp_dummy_buffer { struct list_head queue; - void *vaddr; + struct dma_buf *dbuf; dma_addr_t dma_addr; + void *mem_priv; + void *vaddr; u32 size; + bool is_need_vaddr; + bool is_need_dbuf; }; extern int rkisp_debug; @@ -136,6 +141,9 @@ static inline struct vb2_queue *to_vb2_queue(struct file *file) static inline int rkisp_alloc_buffer(struct device *dev, struct rkisp_dummy_buffer *buf) { + const struct vb2_mem_ops *ops = &vb2_dma_contig_memops; + unsigned long attrs = buf->is_need_vaddr ? 0 : DMA_ATTR_NO_KERNEL_MAPPING; + void *mem_priv; int ret = 0; if (!buf->size) { @@ -143,13 +151,19 @@ static inline int rkisp_alloc_buffer(struct device *dev, goto err; } - buf->vaddr = dma_alloc_coherent(dev, buf->size, - &buf->dma_addr, GFP_KERNEL); - if (!buf->vaddr) { + mem_priv = ops->alloc(dev, attrs, buf->size, + DMA_BIDIRECTIONAL, GFP_KERNEL); + if (IS_ERR_OR_NULL(mem_priv)) { ret = -ENOMEM; goto err; } + buf->mem_priv = mem_priv; + buf->dma_addr = *((dma_addr_t *)ops->cookie(mem_priv)); + if (!attrs) + buf->vaddr = ops->vaddr(mem_priv); + if (buf->is_need_dbuf) + buf->dbuf = ops->get_dmabuf(mem_priv, O_RDWR); if (rkisp_debug) dev_info(dev, "%s buf:0x%x~0x%x size:%d\n", __func__, (u32)buf->dma_addr, (u32)buf->dma_addr + buf->size, buf->size); @@ -163,14 +177,21 @@ err: static inline void rkisp_free_buffer(struct device *dev, struct rkisp_dummy_buffer *buf) { - if (buf && buf->vaddr && buf->size) { + const struct vb2_mem_ops *ops = &vb2_dma_contig_memops; + + if (buf && buf->mem_priv) { if (rkisp_debug) dev_info(dev, "%s buf:0x%x~0x%x\n", __func__, (u32)buf->dma_addr, (u32)buf->dma_addr + buf->size); - dma_free_coherent(dev, buf->size, - buf->vaddr, buf->dma_addr); + if (buf->dbuf) + dma_buf_put(buf->dbuf); + 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; } } diff --git a/drivers/media/platform/rockchip/isp/dev.c b/drivers/media/platform/rockchip/isp/dev.c index 3c14f456b4ce..0f30096045bd 100644 --- a/drivers/media/platform/rockchip/isp/dev.c +++ b/drivers/media/platform/rockchip/isp/dev.c @@ -509,13 +509,13 @@ static int rkisp_register_platform_subdevs(struct rkisp_device *dev) if (ret < 0) goto err_unreg_isp_subdev; - ret = rkisp_register_mpfbc_subdev(dev, &dev->v4l2_dev); + ret = rkisp_register_bridge_subdev(dev, &dev->v4l2_dev); if (ret < 0) goto err_unreg_csi_subdev; ret = rkisp_register_stream_vdevs(dev); if (ret < 0) - goto err_unreg_mpfbc_subdev; + goto err_unreg_bridge_subdev; ret = rkisp_register_dmarx_vdev(dev); if (ret < 0) @@ -555,8 +555,8 @@ err_unreg_dmarx_vdev: rkisp_unregister_dmarx_vdev(dev); err_unreg_stream_vdev: rkisp_unregister_stream_vdevs(dev); -err_unreg_mpfbc_subdev: - rkisp_unregister_mpfbc_subdev(dev); +err_unreg_bridge_subdev: + rkisp_unregister_bridge_subdev(dev); err_unreg_csi_subdev: rkisp_unregister_csi_subdev(dev); err_unreg_isp_subdev: @@ -1108,7 +1108,7 @@ static int rkisp_plat_remove(struct platform_device *pdev) rkisp_unregister_params_vdev(&isp_dev->params_vdev); rkisp_unregister_stats_vdev(&isp_dev->stats_vdev); rkisp_unregister_stream_vdevs(isp_dev); - rkisp_unregister_mpfbc_subdev(isp_dev); + rkisp_unregister_bridge_subdev(isp_dev); rkisp_unregister_csi_subdev(isp_dev); rkisp_unregister_isp_subdev(isp_dev); media_device_cleanup(&isp_dev->media_dev); diff --git a/drivers/media/platform/rockchip/isp/dev.h b/drivers/media/platform/rockchip/isp/dev.h index 2e2a6a35d511..6610d3ccafcf 100644 --- a/drivers/media/platform/rockchip/isp/dev.h +++ b/drivers/media/platform/rockchip/isp/dev.h @@ -38,7 +38,7 @@ #include "capture.h" #include "csi.h" #include "dmarx.h" -#include "mpfbc.h" +#include "bridge.h" #include "rkisp.h" #include "isp_params.h" #include "isp_stats.h" @@ -69,7 +69,7 @@ #define GRP_ID_ISP_MP BIT(3) #define GRP_ID_ISP_SP BIT(4) #define GRP_ID_ISP_DMARX BIT(5) -#define GRP_ID_ISP_MPFBC BIT(6) +#define GRP_ID_ISP_BRIDGE BIT(6) #define GRP_ID_CSI BIT(7) #define RKISP_MAX_BUS_CLK 8 @@ -171,7 +171,7 @@ struct rkisp_hdr { * @params_vdev: ISP input parameters device * @dmarx_dev: image input device * @csi_dev: mipi csi device - * @mpfbc_dev: mpfbc output device + * @br_dev: bridge of isp and ispp device */ struct rkisp_device { struct list_head list; @@ -195,7 +195,7 @@ struct rkisp_device { struct rkisp_isp_params_vdev params_vdev; struct rkisp_dmarx_device dmarx_dev; struct rkisp_csi_device csi_dev; - struct rkisp_mpfbc_device mpfbc_dev; + struct rkisp_bridge_device br_dev; struct rkisp_luma_vdev luma_vdev; struct rkisp_pipeline pipe; struct iommu_domain *domain; diff --git a/drivers/media/platform/rockchip/isp/isp_ispp.h b/drivers/media/platform/rockchip/isp/isp_ispp.h index 69a25a3d235a..4998560cdd53 100644 --- a/drivers/media/platform/rockchip/isp/isp_ispp.h +++ b/drivers/media/platform/rockchip/isp/isp_ispp.h @@ -7,16 +7,44 @@ #include #include +#define RKISP_ISPP_BUF_MAX 4 +#define RKISP_ISPP_CMD_SET_MODE \ + _IOW('V', BASE_VIDIOC_PRIVATE + 0, struct rkisp_ispp_mode) + +enum rkisp_ispp_buf_group { + GROUP_BUF_PIC = 0, + GROUP_BUF_GAIN, + GROUP_BUF_MAX, +}; + +enum rkisp_ispp_work_mode { + ISP_ISPP_FBC = BIT(0), + ISP_ISPP_422 = BIT(1), + ISP_ISPP_QUICK = BIT(2), + ISP_ISPP_INIT_FAIL = BIT(7), +}; + +struct rkisp_ispp_mode { + u8 work_mode; + u8 buf_num; +}; + +struct rkisp_ispp_buf { + struct list_head list; + struct dma_buf *dbuf[GROUP_BUF_MAX]; + u32 frame_id; +}; + #if IS_BUILTIN(CONFIG_VIDEO_ROCKCHIP_ISP) && IS_BUILTIN(CONFIG_VIDEO_ROCKCHIP_ISPP) int __init rkispp_plat_drv_init(void); #endif #if defined(CONFIG_VIDEO_ROCKCHIP_ISP) -void rkisp_get_mpfbc_sd(struct platform_device *dev, - struct v4l2_subdev **sd); +void rkisp_get_bridge_sd(struct platform_device *dev, + struct v4l2_subdev **sd); #else -static inline void rkisp_get_mpfbc_sd(struct platform_device *dev, - struct v4l2_subdev **sd) +static inline void rkisp_get_bridge_sd(struct platform_device *dev, + struct v4l2_subdev **sd) { *sd = NULL; } diff --git a/drivers/media/platform/rockchip/isp/isp_params_v2x.c b/drivers/media/platform/rockchip/isp/isp_params_v2x.c index 7eb0302a2c97..fbaae5a520db 100644 --- a/drivers/media/platform/rockchip/isp/isp_params_v2x.c +++ b/drivers/media/platform/rockchip/isp/isp_params_v2x.c @@ -4183,6 +4183,7 @@ int rkisp_init_params_vdev_v2x(struct rkisp_isp_params_vdev *params_vdev) priv_val->buf_3dlut_idx = 0; for (i = 0; i < RKISP_PARAM_3DLUT_BUF_NUM; i++) { + priv_val->buf_3dlut[i].is_need_vaddr = true; priv_val->buf_3dlut[i].size = RKISP_PARAM_3DLUT_BUF_SIZE; ret = rkisp_alloc_buffer(dev, &priv_val->buf_3dlut[i]); if (ret) { @@ -4193,6 +4194,7 @@ int rkisp_init_params_vdev_v2x(struct rkisp_isp_params_vdev *params_vdev) priv_val->buf_lsclut_idx = 0; for (i = 0; i < RKISP_PARAM_LSC_LUT_BUF_NUM; i++) { + priv_val->buf_lsclut[i].is_need_vaddr = true; priv_val->buf_lsclut[i].size = RKISP_PARAM_LSC_LUT_BUF_SIZE; ret = rkisp_alloc_buffer(dev, &priv_val->buf_lsclut[i]); if (ret) { @@ -4203,6 +4205,7 @@ int rkisp_init_params_vdev_v2x(struct rkisp_isp_params_vdev *params_vdev) priv_val->buf_ldch_idx = 0; for (i = 0; i < RKISP_PARAM_LDCH_BUF_NUM; i++) { + priv_val->buf_ldch[i].is_need_vaddr = true; priv_val->buf_ldch[i].size = ISP2X_LDCH_MESH_XY_NUM * sizeof(u16); ret = rkisp_alloc_buffer(dev, &priv_val->buf_ldch[i]); if (ret) { diff --git a/drivers/media/platform/rockchip/isp/isp_stats_v2x.c b/drivers/media/platform/rockchip/isp/isp_stats_v2x.c index a090ea33243a..81004dcbf5b1 100644 --- a/drivers/media/platform/rockchip/isp/isp_stats_v2x.c +++ b/drivers/media/platform/rockchip/isp/isp_stats_v2x.c @@ -1508,6 +1508,7 @@ void rkisp_init_stats_vdev_v2x(struct rkisp_isp_stats_vdev *stats_vdev) stats_vdev->rd_buf_idx = 0; stats_vdev->wr_buf_idx = 0; for (i = 0; i < RKISP_STATS_DDR_BUF_NUM; i++) { + stats_vdev->stats_buf[i].is_need_vaddr = true; stats_vdev->stats_buf[i].size = RKISP_RD_STATS_BUF_SIZE; rkisp_alloc_buffer(stats_vdev->dev->dev, &stats_vdev->stats_buf[i]); } diff --git a/drivers/media/platform/rockchip/isp/mpfbc.c b/drivers/media/platform/rockchip/isp/mpfbc.c deleted file mode 100644 index 7a9f50955c56..000000000000 --- a/drivers/media/platform/rockchip/isp/mpfbc.c +++ /dev/null @@ -1,505 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dev.h" -#include "regs.h" - -static int mpfbc_get_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct rkisp_mpfbc_device *mpfbc_dev = v4l2_get_subdevdata(sd); - struct rkisp_device *dev = mpfbc_dev->ispdev; - - if (!fmt) - return -EINVAL; - - /* get isp out format */ - fmt->pad = RKISP_ISP_PAD_SOURCE_PATH; - fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE; - return v4l2_subdev_call(&dev->isp_sdev.sd, pad, get_fmt, NULL, fmt); -} - -static int mpfbc_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct rkisp_mpfbc_device *mpfbc_dev = v4l2_get_subdevdata(sd); - struct rkisp_isp_subdev *isp_sd = &mpfbc_dev->ispdev->isp_sdev; - u32 src_w = isp_sd->out_crop.width; - u32 src_h = isp_sd->out_crop.height; - struct v4l2_rect *crop; - - if (!sel) - return -EINVAL; - if (sel->target != V4L2_SEL_TGT_CROP) - return -EINVAL; - - crop = &sel->r; - crop->left = clamp_t(u32, crop->left, 0, src_w); - crop->top = clamp_t(u32, crop->top, 0, src_h); - crop->width = clamp_t(u32, crop->width, - CIF_ISP_OUTPUT_W_MIN, src_w - crop->left); - crop->height = clamp_t(u32, crop->height, - CIF_ISP_OUTPUT_H_MIN, src_h - crop->top); - - mpfbc_dev->crop = *crop; - return 0; -} - -static int mpfbc_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct rkisp_mpfbc_device *mpfbc_dev = v4l2_get_subdevdata(sd); - struct rkisp_isp_subdev *isp_sd = &mpfbc_dev->ispdev->isp_sdev; - struct v4l2_rect *crop; - - if (!sel) - return -EINVAL; - - crop = &sel->r; - switch (sel->target) { - case V4L2_SEL_TGT_CROP_BOUNDS: - *crop = isp_sd->out_crop; - break; - case V4L2_SEL_TGT_CROP: - *crop = mpfbc_dev->crop; - break; - default: - return -EINVAL; - } - - return 0; -} - -static void mpfbc_crop_on(struct rkisp_mpfbc_device *mpfbc_dev) -{ - struct rkisp_device *dev = mpfbc_dev->ispdev; - void __iomem *base = dev->base_addr; - u32 src_w = dev->isp_sdev.out_crop.width; - u32 src_h = dev->isp_sdev.out_crop.height; - u32 dest_w = mpfbc_dev->crop.width; - u32 dest_h = mpfbc_dev->crop.height; - u32 left = mpfbc_dev->crop.left; - u32 top = mpfbc_dev->crop.top; - u32 ctrl; - - if (src_w == dest_w && src_h == dest_h) - return; - - writel(left, base + CIF_DUAL_CROP_M_H_OFFS); - writel(top, base + CIF_DUAL_CROP_M_V_OFFS); - writel(dest_w, base + CIF_DUAL_CROP_M_H_SIZE); - writel(dest_h, base + CIF_DUAL_CROP_M_V_SIZE); - ctrl = readl(base + CIF_DUAL_CROP_CTRL); - ctrl |= CIF_DUAL_CROP_MP_MODE_YUV | CIF_DUAL_CROP_CFG_UPD; - writel(ctrl, base + CIF_DUAL_CROP_CTRL); -} - -static void mpfbc_crop_off(struct rkisp_mpfbc_device *mpfbc_dev) -{ - struct rkisp_device *dev = mpfbc_dev->ispdev; - void __iomem *base = dev->base_addr; - u32 src_w = dev->isp_sdev.out_crop.width; - u32 src_h = dev->isp_sdev.out_crop.height; - u32 dest_w = mpfbc_dev->crop.width; - u32 dest_h = mpfbc_dev->crop.height; - u32 ctrl; - - if (src_w == dest_w && src_h == dest_h) - return; - - ctrl = readl(base + CIF_DUAL_CROP_CTRL); - ctrl &= ~(CIF_DUAL_CROP_MP_MODE_YUV | - CIF_DUAL_CROP_MP_MODE_RAW); - ctrl |= CIF_DUAL_CROP_GEN_CFG_UPD; - writel(ctrl, base + CIF_DUAL_CROP_CTRL); -} - -static void free_dma_buf(struct rkisp_dma_buf *buf) -{ - const struct vb2_mem_ops *ops = &vb2_dma_contig_memops; - - if (!buf) - return; - - ops->unmap_dmabuf(buf->mem_priv); - ops->detach_dmabuf(buf->mem_priv); - dma_buf_put(buf->dbuf); - kfree(buf); -} - -static void mpfbc_free_dma_buf(struct rkisp_mpfbc_device *dev) -{ - free_dma_buf(dev->pic_cur); - dev->pic_cur = NULL; - free_dma_buf(dev->pic_nxt); - dev->pic_nxt = NULL; - free_dma_buf(dev->gain_cur); - dev->gain_cur = NULL; - free_dma_buf(dev->gain_nxt); - dev->gain_nxt = NULL; -} - -static int mpfbc_s_rx_buffer(struct v4l2_subdev *sd, - void *dbuf, unsigned int *size) -{ - struct rkisp_mpfbc_device *mpfbc_dev = v4l2_get_subdevdata(sd); - struct rkisp_device *dev = mpfbc_dev->ispdev; - void __iomem *base = dev->base_addr; - const struct vb2_mem_ops *ops = &vb2_dma_contig_memops; - struct rkisp_dma_buf *buf; - dma_addr_t dma_addr; - u32 w = ALIGN(mpfbc_dev->crop.width, 16); - u32 h = ALIGN(mpfbc_dev->crop.height, 16); - u32 sizes = (w * h >> 4) + w * h * 2; - u32 w_tmp; - int ret = 0; - - if (!dbuf || !size) - return -EINVAL; - - buf = kzalloc(sizeof(*buf), GFP_KERNEL); - if (!buf) { - ret = -ENOMEM; - goto err; - } - - buf->dbuf = dbuf; - buf->mem_priv = ops->attach_dmabuf(dev->dev, dbuf, - *size, DMA_BIDIRECTIONAL); - if (IS_ERR(buf->mem_priv)) { - ret = PTR_ERR(buf->mem_priv); - goto err; - } - - ret = ops->map_dmabuf(buf->mem_priv); - if (ret) { - ops->detach_dmabuf(buf->mem_priv); - goto err; - } - - dma_addr = *((dma_addr_t *)ops->cookie(buf->mem_priv)); - - v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev, - "%s buf:0x%x size:%d\n", - __func__, (u32)dma_addr, *size); - - /* picture or gain buffer */ - if (*size == sizes) { - if (mpfbc_dev->pic_cur) { - mpfbc_dev->pic_nxt = buf; - writel(dma_addr, base + ISP_MPFBC_HEAD_PTR2); - writel(dma_addr + (w * h >> 4), - base + ISP_MPFBC_PAYL_PTR2); - mpfbc_dev->pingpong = true; - } else { - mpfbc_dev->pic_cur = buf; - writel(dma_addr, base + ISP_MPFBC_HEAD_PTR); - writel(dma_addr + (w * h >> 4), - base + ISP_MPFBC_PAYL_PTR); - mpfbc_dev->pingpong = false; - } - } else { - if (mpfbc_dev->gain_cur) { - mpfbc_dev->gain_nxt = buf; - writel(dma_addr, base + MI_GAIN_WR_BASE2); - mi_wr_ctrl2(base, SW_GAIN_WR_PINGPONG); - } else { - mpfbc_dev->gain_cur = buf; - writel(dma_addr, base + MI_GAIN_WR_BASE); - isp_clear_bits(base + MI_WR_CTRL2, - SW_GAIN_WR_PINGPONG); - } - writel(*size, base + MI_GAIN_WR_SIZE); - - w_tmp = (mpfbc_dev->crop.width + 3) / 4; - w_tmp = ALIGN(w_tmp, 16); - writel(w_tmp, base + MI_GAIN_WR_LENGTH); - mi_wr_ctrl2(base, SW_GAIN_WR_AUTOUPD); - } - - return 0; -err: - kfree(buf); - dma_buf_put(dbuf); - mpfbc_free_dma_buf(mpfbc_dev); - return ret; -} - -static int mpfbc_start(struct rkisp_mpfbc_device *mpfbc_dev) -{ - struct rkisp_device *dev = mpfbc_dev->ispdev; - void __iomem *base = dev->base_addr; - u32 h = ALIGN(mpfbc_dev->crop.height, 16); - - mpfbc_crop_on(mpfbc_dev); - writel(mpfbc_dev->pingpong << 4 | SW_MPFBC_YUV_MODE(1) | - SW_MPFBC_MAINISP_MODE | SW_MPFBC_EN, - base + ISP_MPFBC_BASE); - writel(0, base + ISP_MPFBC_VIR_WIDTH); - writel(h, base + ISP_MPFBC_VIR_HEIGHT); - isp_set_bits(base + CTRL_SWS_CFG, 0, SW_ISP2PP_PIPE_EN); - isp_set_bits(base + MI_IMSC, 0, MI_MPFBC_FRAME); - isp_set_bits(base + MI_WR_CTRL, 0, CIF_MI_CTRL_INIT_BASE_EN); - mp_set_data_path(base); - force_cfg_update(base); - mpfbc_dev->en = true; - return 0; -} - -static int mpfbc_stop(struct rkisp_mpfbc_device *mpfbc_dev) -{ - struct rkisp_device *dev = mpfbc_dev->ispdev; - void __iomem *base = dev->base_addr; - int ret; - - mpfbc_dev->stopping = true; - isp_clear_bits(base + ISP_MPFBC_BASE, SW_MPFBC_EN); - hdr_stop_dmatx(dev); - ret = wait_event_timeout(mpfbc_dev->done, - !mpfbc_dev->en, - msecs_to_jiffies(1000)); - if (!ret) - v4l2_warn(&mpfbc_dev->sd, - "waiting on event return error %d\n", ret); - mpfbc_crop_off(mpfbc_dev); - mpfbc_dev->stopping = false; - isp_clear_bits(base + MI_IMSC, MI_MPFBC_FRAME); - mpfbc_dev->en = false; - return 0; -} - -static int mpfbc_start_stream(struct v4l2_subdev *sd) -{ - struct rkisp_mpfbc_device *mpfbc_dev = v4l2_get_subdevdata(sd); - struct rkisp_device *dev = mpfbc_dev->ispdev; - int ret; - - if (!mpfbc_dev->linked || !dev->isp_inp) { - v4l2_err(&dev->v4l2_dev, - "mpfbc no linked or isp inval input\n"); - return -EINVAL; - } - - if (WARN_ON(mpfbc_dev->en)) - return -EBUSY; - - if (dev->isp_inp & INP_CSI || - dev->isp_inp & INP_DVP) { - /* Always update sensor info in case media topology changed */ - ret = rkisp_update_sensor_info(dev); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, - "update sensor info failed %d\n", - ret); - return -EBUSY; - } - } - - /* enable clocks/power-domains */ - ret = dev->pipe.open(&dev->pipe, &sd->entity, true); - if (ret < 0) - return ret; - - hdr_config_dmatx(dev); - ret = mpfbc_start(mpfbc_dev); - if (ret < 0) - goto close_pipe; - hdr_update_dmatx_buf(dev); - - /* start sub-devices */ - ret = dev->pipe.set_stream(&dev->pipe, true); - if (ret < 0) - goto stop_mpfbc; - - ret = media_pipeline_start(&sd->entity, &dev->pipe.pipe); - if (ret < 0) - goto pipe_stream_off; - - return 0; -pipe_stream_off: - dev->pipe.set_stream(&dev->pipe, false); -stop_mpfbc: - mpfbc_stop(mpfbc_dev); - hdr_destroy_buf(dev); -close_pipe: - dev->pipe.close(&dev->pipe); - return ret; -} - -static void mpfbc_destroy_buf(struct rkisp_device *dev) -{ - mpfbc_free_dma_buf(&dev->mpfbc_dev); - hdr_destroy_buf(dev); -} - -static int mpfbc_stop_stream(struct v4l2_subdev *sd) -{ - struct rkisp_mpfbc_device *mpfbc_dev = v4l2_get_subdevdata(sd); - struct rkisp_device *dev = mpfbc_dev->ispdev; - - mpfbc_stop(mpfbc_dev); - media_pipeline_stop(&sd->entity); - dev->pipe.set_stream(&dev->pipe, false); - dev->pipe.close(&dev->pipe); - mpfbc_destroy_buf(dev); - return 0; -} - -static int mpfbc_s_stream(struct v4l2_subdev *sd, int on) -{ - struct rkisp_mpfbc_device *mpfbc_dev = v4l2_get_subdevdata(sd); - struct rkisp_device *dev = mpfbc_dev->ispdev; - int ret = 0; - - v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev, - "%s %d\n", __func__, on); - - if (on) { - atomic_inc(&dev->cap_dev.refcnt); - ret = mpfbc_start_stream(sd); - } else if (mpfbc_dev->en) { - ret = mpfbc_stop_stream(sd); - } - - if (!on) - atomic_dec(&dev->cap_dev.refcnt); - return ret; -} - -static int mpfbc_s_power(struct v4l2_subdev *sd, int on) -{ - struct rkisp_mpfbc_device *mpfbc_dev = v4l2_get_subdevdata(sd); - struct rkisp_device *dev = mpfbc_dev->ispdev; - int ret = 0; - - v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev, - "%s %d\n", __func__, on); - - if (on) - ret = v4l2_pipeline_pm_use(&sd->entity, 1); - else - ret = v4l2_pipeline_pm_use(&sd->entity, 0); - - return ret; -} - -void rkisp_mpfbc_isr(u32 mis_val, struct rkisp_device *dev) -{ - struct rkisp_mpfbc_device *mpfbc_dev = &dev->mpfbc_dev; - void __iomem *base = dev->base_addr; - - writel(MI_MPFBC_FRAME, base + CIF_MI_ICR); - - if (mpfbc_dev->stopping) { - if (is_mpfbc_stopped(base)) { - mpfbc_dev->en = false; - mpfbc_dev->stopping = false; - wake_up(&mpfbc_dev->done); - } - } -} - -static const struct v4l2_subdev_pad_ops mpfbc_pad_ops = { - .set_fmt = mpfbc_get_set_fmt, - .get_fmt = mpfbc_get_set_fmt, - .get_selection = mpfbc_get_selection, - .set_selection = mpfbc_set_selection, -}; - -static const struct v4l2_subdev_video_ops mpfbc_video_ops = { - .s_rx_buffer = mpfbc_s_rx_buffer, - .s_stream = mpfbc_s_stream, -}; - -static const struct v4l2_subdev_core_ops mpfbc_core_ops = { - .s_power = mpfbc_s_power, -}; - -static struct v4l2_subdev_ops mpfbc_v4l2_ops = { - .core = &mpfbc_core_ops, - .video = &mpfbc_video_ops, - .pad = &mpfbc_pad_ops, -}; - -int rkisp_register_mpfbc_subdev(struct rkisp_device *dev, - struct v4l2_device *v4l2_dev) -{ - struct rkisp_mpfbc_device *mpfbc_dev = &dev->mpfbc_dev; - struct v4l2_subdev *sd; - struct media_entity *source, *sink; - int ret; - - memset(mpfbc_dev, 0, sizeof(*mpfbc_dev)); - if (dev->isp_ver != ISP_V20) - return 0; - - mpfbc_dev->ispdev = dev; - sd = &mpfbc_dev->sd; - - v4l2_subdev_init(sd, &mpfbc_v4l2_ops); - //sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - sd->entity.obj_type = 0; - snprintf(sd->name, sizeof(sd->name), MPFBC_DEV_NAME); - - mpfbc_dev->pad.flags = MEDIA_PAD_FL_SINK; - - ret = media_entity_pads_init(&sd->entity, 1, &mpfbc_dev->pad); - if (ret < 0) - return ret; - sd->owner = THIS_MODULE; - v4l2_set_subdevdata(sd, mpfbc_dev); - sd->grp_id = GRP_ID_ISP_MPFBC; - ret = v4l2_device_register_subdev(v4l2_dev, sd); - if (ret < 0) { - v4l2_err(v4l2_dev, "Failed to register mpfbc subdev\n"); - goto free_media; - } - mpfbc_dev->crop = dev->isp_sdev.out_crop; - /* mpfbc links */ - mpfbc_dev->linked = true; - source = &dev->isp_sdev.sd.entity; - sink = &sd->entity; - ret = media_create_pad_link(source, RKISP_ISP_PAD_SOURCE_PATH, - sink, 0, mpfbc_dev->linked); - - init_waitqueue_head(&mpfbc_dev->done); - return ret; - -free_media: - media_entity_cleanup(&sd->entity); - return ret; -} - -void rkisp_unregister_mpfbc_subdev(struct rkisp_device *dev) -{ - struct v4l2_subdev *sd = &dev->mpfbc_dev.sd; - - if (dev->isp_ver != ISP_V20) - return; - v4l2_device_unregister_subdev(sd); - media_entity_cleanup(&sd->entity); -} - -void rkisp_get_mpfbc_sd(struct platform_device *dev, - struct v4l2_subdev **sd) -{ - struct rkisp_device *isp_dev = platform_get_drvdata(dev); - - if (isp_dev) - *sd = &isp_dev->mpfbc_dev.sd; - else - *sd = NULL; -} diff --git a/drivers/media/platform/rockchip/isp/mpfbc.h b/drivers/media/platform/rockchip/isp/mpfbc.h deleted file mode 100644 index 3660b91f0c00..000000000000 --- a/drivers/media/platform/rockchip/isp/mpfbc.h +++ /dev/null @@ -1,40 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */ - -#ifndef _RKISP_mpfbc_H -#define _RKISP_mpfbc_H - -#include "linux/platform_device.h" - -#define MPFBC_DEV_NAME DRIVER_NAME "-mpfbc-subdev" - -struct rkisp_mpfbc_device; - -struct rkisp_dma_buf { - struct dma_buf *dbuf; - void *mem_priv; -}; - -struct rkisp_mpfbc_device { - struct rkisp_device *ispdev; - struct v4l2_subdev sd; - struct v4l2_rect crop; - struct media_pad pad; - wait_queue_head_t done; - struct rkisp_dma_buf *pic_cur; - struct rkisp_dma_buf *pic_nxt; - struct rkisp_dma_buf *gain_cur; - struct rkisp_dma_buf *gain_nxt; - u8 pingpong; - u8 stopping; - u8 en; - bool linked; -}; - -int rkisp_register_mpfbc_subdev(struct rkisp_device *dev, - struct v4l2_device *v4l2_dev); -void rkisp_unregister_mpfbc_subdev(struct rkisp_device *dev); -void rkisp_mpfbc_isr(u32 mis_val, struct rkisp_device *dev); -void rkisp_get_mpfbc_sd(struct platform_device *dev, - struct v4l2_subdev **sd); -#endif diff --git a/drivers/media/platform/rockchip/isp/regs.h b/drivers/media/platform/rockchip/isp/regs.h index 5e9721e1522e..16f14eba7cbb 100644 --- a/drivers/media/platform/rockchip/isp/regs.h +++ b/drivers/media/platform/rockchip/isp/regs.h @@ -151,8 +151,8 @@ #define CIF_MI_SP_Y_FULL_YUV2RGB BIT(8) #define CIF_MI_SP_CBCR_FULL_YUV2RGB BIT(9) #define CIF_MI_SP_422NONCOSITEED BIT(10) -#define CIF_MI_MP_PINGPONG_ENABEL BIT(11) -#define CIF_MI_SP_PINGPONG_ENABEL BIT(12) +#define CIF_MI_MP_PINGPONG_ENABLE BIT(11) +#define CIF_MI_SP_PINGPONG_ENABLE BIT(12) #define CIF_MI_MP_AUTOUPDATE_ENABLE BIT(13) #define CIF_MI_SP_AUTOUPDATE_ENABLE BIT(14) #define CIF_MI_LAST_PIXEL_SIG_ENABLE BIT(15) diff --git a/drivers/media/platform/rockchip/isp/rkisp.c b/drivers/media/platform/rockchip/isp/rkisp.c index a200502fc68b..cebb22fd145c 100644 --- a/drivers/media/platform/rockchip/isp/rkisp.c +++ b/drivers/media/platform/rockchip/isp/rkisp.c @@ -1438,7 +1438,7 @@ static int rkisp_isp_sd_set_selection(struct v4l2_subdev *sd, isp_sd->out_crop = *crop; isp_sd->out_crop.left = 0; isp_sd->out_crop.top = 0; - dev->mpfbc_dev.crop = isp_sd->out_crop; + dev->br_dev.crop = isp_sd->out_crop; } } else { if (dev->isp_ver == ISP_V20) @@ -1446,16 +1446,14 @@ static int rkisp_isp_sd_set_selection(struct v4l2_subdev *sd, isp_sd->out_crop = *crop; } - /* change fmt&size of MP/SP */ + /* change size of MP/SP */ rkisp_set_stream_def_fmt(dev, RKISP_STREAM_MP, isp_sd->out_crop.width, - isp_sd->out_crop.height, - V4L2_PIX_FMT_YUYV); + isp_sd->out_crop.height, 0); if (dev->isp_ver != ISP_V10_1) rkisp_set_stream_def_fmt(dev, RKISP_STREAM_SP, isp_sd->out_crop.width, - isp_sd->out_crop.height, - V4L2_PIX_FMT_YUYV); + isp_sd->out_crop.height, 0); return 0; err: return -EINVAL; @@ -1636,19 +1634,19 @@ static int rkisp_subdev_link_setup(struct media_entity *entity, } else if (!strcmp(remote->entity->name, SP_VDEV_NAME)) { stream = &dev->cap_dev.stream[RKISP_STREAM_SP]; if (flags & MEDIA_LNK_FL_ENABLED && - dev->mpfbc_dev.linked) + dev->br_dev.linked) goto err; } else if (!strcmp(remote->entity->name, MP_VDEV_NAME)) { stream = &dev->cap_dev.stream[RKISP_STREAM_MP]; if (flags & MEDIA_LNK_FL_ENABLED && - dev->mpfbc_dev.linked) + dev->br_dev.linked) goto err; - } else if (!strcmp(remote->entity->name, MPFBC_DEV_NAME)) { + } else if (!strcmp(remote->entity->name, BRIDGE_DEV_NAME)) { if (flags & MEDIA_LNK_FL_ENABLED && (dev->cap_dev.stream[RKISP_STREAM_SP].linked || dev->cap_dev.stream[RKISP_STREAM_MP].linked)) goto err; - dev->mpfbc_dev.linked = flags & MEDIA_LNK_FL_ENABLED; + dev->br_dev.linked = flags & MEDIA_LNK_FL_ENABLED; } else { if (flags & MEDIA_LNK_FL_ENABLED) { if (dev->isp_inp & ~(INP_DVP | rawrd)) @@ -1673,7 +1671,7 @@ err: v4l2_err(sd, "link error %s -> %s\n" "\tdmaread can't work with other input\n" "\tcsi dvp can't work together\n" - "\tmpfbc can't work with mainpath/selfpath\n", + "\tbridge can't work with mainpath/selfpath\n", local->entity->name, remote->entity->name); return -EINVAL; } diff --git a/drivers/media/platform/rockchip/ispp/common.c b/drivers/media/platform/rockchip/ispp/common.c index 98b61cb58a09..b44737c945da 100644 --- a/drivers/media/platform/rockchip/ispp/common.c +++ b/drivers/media/platform/rockchip/ispp/common.c @@ -44,6 +44,7 @@ int rkispp_allow_buffer(struct rkispp_device *dev, struct rkispp_dummy_buffer *buf) { const struct vb2_mem_ops *ops = &vb2_dma_contig_memops; + unsigned long attrs = buf->is_need_vaddr ? 0 : DMA_ATTR_NO_KERNEL_MAPPING; void *mem_priv; int ret = 0; @@ -52,8 +53,8 @@ int rkispp_allow_buffer(struct rkispp_device *dev, goto err; } - mem_priv = ops->alloc(dev->dev, 0, buf->size, - DMA_BIDIRECTIONAL, GFP_KERNEL); + mem_priv = ops->alloc(dev->dev, attrs, buf->size, + DMA_BIDIRECTIONAL, GFP_KERNEL); if (IS_ERR_OR_NULL(mem_priv)) { ret = -ENOMEM; goto err; @@ -61,7 +62,10 @@ int rkispp_allow_buffer(struct rkispp_device *dev, buf->mem_priv = mem_priv; buf->dma_addr = *((dma_addr_t *)ops->cookie(mem_priv)); - buf->vaddr = ops->vaddr(mem_priv); + if (!attrs) + buf->vaddr = ops->vaddr(mem_priv); + if (buf->is_need_dbuf) + buf->dbuf = ops->get_dmabuf(mem_priv, O_RDWR); v4l2_dbg(1, rkispp_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); @@ -80,9 +84,14 @@ void rkispp_free_buffer(struct rkispp_device *dev, v4l2_dbg(1, rkispp_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); 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; } } diff --git a/drivers/media/platform/rockchip/ispp/common.h b/drivers/media/platform/rockchip/ispp/common.h index ef2256d856ef..6bac59d2400f 100644 --- a/drivers/media/platform/rockchip/ispp/common.h +++ b/drivers/media/platform/rockchip/ispp/common.h @@ -40,11 +40,15 @@ struct rkispp_buffer { }; struct rkispp_dummy_buffer { - struct list_head queue; + struct list_head list; + struct dma_buf *dbuf; dma_addr_t dma_addr; + void *mem_priv; void *vaddr; u32 size; - void *mem_priv; + u32 id; + bool is_need_vaddr; + bool is_need_dbuf; }; extern int rkispp_debug; diff --git a/drivers/media/platform/rockchip/ispp/dev.c b/drivers/media/platform/rockchip/ispp/dev.c index 273f37047ecc..5b046f77dc15 100644 --- a/drivers/media/platform/rockchip/ispp/dev.c +++ b/drivers/media/platform/rockchip/ispp/dev.c @@ -40,6 +40,10 @@ int rkispp_debug; module_param_named(debug, rkispp_debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level (0-3)"); +static int rkisp_ispp_mode = ISP_ISPP_422 | ISP_ISPP_FBC; +module_param_named(mode, rkisp_ispp_mode, int, 0644); +MODULE_PARM_DESC(mode, "isp->ispp mode: bit0 fbc, bit1 yuv422, bit2 quick"); + static char rkispp_version[RKISPP_VERNO_LEN]; module_param_string(version, rkispp_version, RKISPP_VERNO_LEN, 0444); MODULE_PARM_DESC(version, "version number"); @@ -82,13 +86,12 @@ static void get_remote_node_dev(struct rkispp_device *ispp_dev) of_node_full_name(remote)); continue; } else { - rkisp_get_mpfbc_sd(remote_dev, &sd); + rkisp_get_bridge_sd(remote_dev, &sd); if (!sd) { - dev_err(dev, "Failed to get remote mpfbc sd\n"); + dev_err(dev, "Failed to get isp bridge sd\n"); } else { ispp_dev->ispp_sdev.remote_sd = sd; - dev_info(dev, "get remote mpfbc sd:%s\n", - sd->name); + v4l2_set_subdev_hostdata(sd, &ispp_dev->ispp_sdev.sd); break; } } @@ -225,6 +228,7 @@ static int rkispp_enable_sys_clk(struct rkispp_device *ispp_dev) { int i, ret = -EINVAL; + ispp_dev->isp_mode = rkisp_ispp_mode; for (i = 0; i < ispp_dev->clks_num; i++) { ret = clk_prepare_enable(ispp_dev->clks[i]); if (ret < 0) diff --git a/drivers/media/platform/rockchip/ispp/dev.h b/drivers/media/platform/rockchip/ispp/dev.h index d170272b36d3..07194ce96494 100644 --- a/drivers/media/platform/rockchip/ispp/dev.h +++ b/drivers/media/platform/rockchip/ispp/dev.h @@ -52,5 +52,6 @@ struct rkispp_device { /* lock for fec and ispp irq */ spinlock_t irq_lock; enum rkispp_input inp; + u32 isp_mode; }; #endif diff --git a/drivers/media/platform/rockchip/ispp/ispp.c b/drivers/media/platform/rockchip/ispp/ispp.c index 456482e836d0..3deebb7eb30d 100644 --- a/drivers/media/platform/rockchip/ispp/ispp.c +++ b/drivers/media/platform/rockchip/ispp/ispp.c @@ -12,6 +12,27 @@ #include "dev.h" #include "regs.h" +void rkispp_free_pool(struct rkispp_stream_vdev *vdev) +{ + const struct vb2_mem_ops *ops = &vb2_dma_contig_memops; + struct rkispp_isp_buf_pool *buf; + int i, j; + + for (i = 0; i < RKISPP_BUF_POOL_MAX; i++) { + buf = &vdev->pool[i]; + if (!buf->dbufs) + break; + for (j = 0; j < GROUP_BUF_MAX; j++) { + if (buf->mem_priv[j]) { + ops->unmap_dmabuf(buf->mem_priv[j]); + ops->detach_dmabuf(buf->mem_priv[j]); + buf->mem_priv[j] = NULL; + } + } + buf->dbufs = NULL; + } +} + u32 cal_fec_mesh(u32 width, u32 height, u32 mode) { u32 mesh_size, mesh_left_height; @@ -232,92 +253,73 @@ err: return -EINVAL; } -static int rkispp_s_rx_buffer(struct rkispp_subdev *ispp_sdev) -{ - const struct vb2_mem_ops *ops = &vb2_dma_contig_memops; - struct rkispp_device *dev = ispp_sdev->dev; - struct rkispp_stream_vdev *vdev = &dev->stream_vdev; - struct rkispp_dummy_buffer *buf; - struct dma_buf *dbuf; - void *size; - int ret; - - if (vdev->module_ens & ISPP_MODULE_TNR) { - buf = &vdev->tnr_buf.pic_cur; - size = &buf->size; - dbuf = ops->get_dmabuf(buf->mem_priv, O_RDWR); - ret = v4l2_subdev_call(ispp_sdev->remote_sd, - video, s_rx_buffer, dbuf, size); - if (ret) - return ret; - - buf = &vdev->tnr_buf.gain_cur; - size = &buf->size; - dbuf = ops->get_dmabuf(buf->mem_priv, O_RDWR); - if ((vdev->module_ens & ISPP_MODULE_TNR_3TO1) == - ISPP_MODULE_TNR_3TO1) { - ret = v4l2_subdev_call(ispp_sdev->remote_sd, - video, s_rx_buffer, dbuf, size); - if (ret) - return ret; - buf = &vdev->tnr_buf.pic_next; - size = &buf->size; - dbuf = ops->get_dmabuf(buf->mem_priv, O_RDWR); - ret = v4l2_subdev_call(ispp_sdev->remote_sd, - video, s_rx_buffer, dbuf, size); - if (ret) - return ret; - buf = &vdev->tnr_buf.gain_next; - size = &buf->size; - dbuf = ops->get_dmabuf(buf->mem_priv, O_RDWR); - } - } else { - buf = &vdev->nr_buf.pic_cur; - size = &buf->size; - dbuf = ops->get_dmabuf(buf->mem_priv, O_RDWR); - ret = v4l2_subdev_call(ispp_sdev->remote_sd, - video, s_rx_buffer, dbuf, size); - if (ret) - return ret; - buf = &vdev->nr_buf.gain_cur; - size = &buf->size; - dbuf = ops->get_dmabuf(buf->mem_priv, O_RDWR); - } - - return v4l2_subdev_call(ispp_sdev->remote_sd, - video, s_rx_buffer, dbuf, size); -} - static int rkispp_sd_s_stream(struct v4l2_subdev *sd, int on) { struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd); struct rkispp_device *dev = ispp_sdev->dev; - struct rkispp_stream *stream; - int ret, i; - - for (i = 0; i < STREAM_MAX; i++) { - stream = &dev->stream_vdev.stream[i]; - if (stream->streaming) - break; - } - - if (i == STREAM_MAX) { - v4l2_err(&dev->v4l2_dev, - "no video start before subdev stream on\n"); - return -EINVAL; - } + int ret; v4l2_dbg(1, rkispp_debug, &ispp_sdev->dev->v4l2_dev, "s_stream on:%d\n", on); - if (on) { - ret = rkispp_s_rx_buffer(ispp_sdev); - if (ret) - return ret; + ret = v4l2_subdev_call(ispp_sdev->remote_sd, + video, s_stream, on); + if (!ret) + ispp_sdev->state = on; + if ((on && ret) || (!on && !ret)) + rkispp_free_pool(&dev->stream_vdev); + return ret; +} + +static int rkispp_sd_s_rx_buffer(struct v4l2_subdev *sd, + void *buf, unsigned int *size) +{ + const struct vb2_mem_ops *ops = &vb2_dma_contig_memops; + struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd); + struct rkispp_device *dev = ispp_sdev->dev; + struct rkispp_stream_vdev *vdev = &dev->stream_vdev; + struct rkisp_ispp_buf *dbufs = buf; + struct rkispp_isp_buf_pool *pool; + u32 i, val = (vdev->module_ens & ISPP_MODULE_TNR) ? + ISPP_MODULE_TNR : ISPP_MODULE_NR; + int ret = 0; + void *mem; + + /* size isn't using now */ + if (!dbufs) + return -EINVAL; + + if (ispp_sdev->state == ISPP_START) { + rkispp_module_work_event(dev, dbufs, NULL, val, false); + return ret; } - return v4l2_subdev_call(ispp_sdev->remote_sd, - video, s_stream, on); + /* init dma buf pool */ + for (i = 0; i < RKISPP_BUF_POOL_MAX; i++) { + pool = &vdev->pool[i]; + if (!pool->dbufs) + break; + } + pool->dbufs = dbufs; + for (i = 0; i < GROUP_BUF_MAX; i++) { + mem = ops->attach_dmabuf(dev->dev, dbufs->dbuf[i], + dbufs->dbuf[i]->size, DMA_BIDIRECTIONAL); + if (IS_ERR(mem)) { + ret = PTR_ERR(mem); + goto err; + } + pool->mem_priv[i] = mem; + ret = ops->map_dmabuf(mem); + if (ret) + goto err; + pool->dma[i] = *((dma_addr_t *)ops->cookie(mem)); + v4l2_dbg(1, rkispp_debug, sd, + "dma[%d]:0x%x\n", i, pool->dma[i]); + } + return 0; +err: + rkispp_free_pool(vdev); + return ret; } static int rkispp_sd_s_power(struct v4l2_subdev *sd, int on) @@ -348,8 +350,8 @@ static int rkispp_sd_s_power(struct v4l2_subdev *sd, int on) writel(SW_FEC2DDR_DIS, base + RKISPP_FEC_CORE_CTRL); writel(0xfffffff, base + RKISPP_CTRL_INT_MSK); writel(GATE_DIS_ALL, base + RKISPP_CTRL_CLKGATE); - //usleep_range(1000, 1200); - //writel(0, base + RKISPP_CTRL_CLKGATE); + usleep_range(100, 120); + writel(GATE_DIS_NR, base + RKISPP_CTRL_CLKGATE); if (ispp_dev->inp == INP_ISP) { struct v4l2_subdev_format fmt; struct v4l2_subdev_selection sel; @@ -402,6 +404,7 @@ static int rkispp_sd_s_power(struct v4l2_subdev *sd, int on) v4l2_err(&ispp_dev->v4l2_dev, "%s runtime put failed:%d\n", __func__, ret); + ispp_sdev->state = ISPP_STOP; } return ret; @@ -424,6 +427,7 @@ static const struct v4l2_subdev_pad_ops rkispp_sd_pad_ops = { static const struct v4l2_subdev_video_ops rkispp_sd_video_ops = { .s_stream = rkispp_sd_s_stream, + .s_rx_buffer = rkispp_sd_s_rx_buffer, }; static const struct v4l2_subdev_core_ops rkispp_sd_core_ops = { @@ -446,7 +450,7 @@ int rkispp_register_subdev(struct rkispp_device *dev, memset(ispp_sdev, 0, sizeof(*ispp_sdev)); ispp_sdev->dev = dev; sd = &ispp_sdev->sd; - + ispp_sdev->state = ISPP_STOP; v4l2_subdev_init(sd, &rkispp_sd_ops); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; sd->entity.ops = &rkispp_sd_media_ops; diff --git a/drivers/media/platform/rockchip/ispp/ispp.h b/drivers/media/platform/rockchip/ispp/ispp.h index ec183ed79717..c6e53eeccfdc 100644 --- a/drivers/media/platform/rockchip/ispp/ispp.h +++ b/drivers/media/platform/rockchip/ispp/ispp.h @@ -16,6 +16,11 @@ enum rkispp_pad { RKISPP_PAD_MAX }; +enum rkispp_state { + ISPP_STOP = 0, + ISPP_START, +}; + struct isppsd_fmt { u32 mbus_code; u32 fourcc; @@ -32,6 +37,7 @@ struct rkispp_subdev { struct v4l2_mbus_framefmt in_fmt; struct isppsd_fmt out_fmt; atomic_t frm_sync_seq; + enum rkispp_state state; }; u32 cal_fec_mesh(u32 width, u32 height, u32 mode); diff --git a/drivers/media/platform/rockchip/ispp/regs.h b/drivers/media/platform/rockchip/ispp/regs.h index b61b6d1f2f31..fb1131844a5e 100644 --- a/drivers/media/platform/rockchip/ispp/regs.h +++ b/drivers/media/platform/rockchip/ispp/regs.h @@ -114,6 +114,8 @@ #define RKISPP_TNR_CORE_SCALE_CL1 (RKISPP_TNR + 0x0150) #define RKISPP_TNR_CORE_SCALE_CL2 (RKISPP_TNR + 0x0154) #define RKISPP_TNR_CORE_WEIGHT (RKISPP_TNR + 0x0158) +#define RKISPP_TNR_TILE_CNT (RKISPP_TNR + 0x01c0) +#define RKISPP_TNR_STATE (RKISPP_TNR + 0x01c4) #define RKISPP_NR 0x0400 #define RKISPP_NR_CTRL (RKISPP_NR + 0x0000) @@ -199,6 +201,8 @@ #define RKISPP_NR_YNR_HSTV_Y_16 (RKISPP_NR + 0x01E0) #define RKISPP_NR_YNR_ST_SCALE_LV1_LV2 (RKISPP_NR + 0x01E4) #define RKISPP_NR_YNR_ST_SCALE_LV3 (RKISPP_NR + 0x01E8) +#define RKISPP_NR_BLOCK_CNT (RKISPP_NR + 0x01f0) +#define RKISPP_NR_BUFFER_READY (RKISPP_NR + 0x01f4) #define RKISPP_SHARP 0x0600 #define RKISPP_SHARP_CTRL (RKISPP_SHARP + 0x0000) diff --git a/drivers/media/platform/rockchip/ispp/stats.c b/drivers/media/platform/rockchip/ispp/stats.c index 877c54fa9e83..20c9f4729b86 100644 --- a/drivers/media/platform/rockchip/ispp/stats.c +++ b/drivers/media/platform/rockchip/ispp/stats.c @@ -28,7 +28,7 @@ static void update_addr(struct rkispp_stats_vdev *stats_vdev) if (!stats_vdev->next_buf) { dummy_buf = &stats_vdev->dummy_buf; - if (!dummy_buf->vaddr) + if (!dummy_buf->mem_priv) return; writel(dummy_buf->dma_addr, base + RKISPP_ORB_WR_BASE); diff --git a/drivers/media/platform/rockchip/ispp/stream.c b/drivers/media/platform/rockchip/ispp/stream.c index 5f55b087294b..9eb20c1d58c6 100644 --- a/drivers/media/platform/rockchip/ispp/stream.c +++ b/drivers/media/platform/rockchip/ispp/stream.c @@ -213,106 +213,74 @@ struct capture_fmt *find_fmt(struct rkispp_stream *stream, static void check_to_force_update(struct rkispp_device *dev, u32 mis_val) { struct rkispp_stream_vdev *vdev = &dev->stream_vdev; - struct rkispp_stream *stream = &vdev->stream[STREAM_MB]; - void __iomem *base = dev->base_addr; - u32 reg_y, reg_uv, is_switch = false; + struct rkispp_stream *stream; + u32 i, mask = NR_INT | SHP_INT; + bool is_fec_en = (vdev->module_ens & ISPP_MODULE_FEC); - if (!stream->streaming) + if (mis_val & TNR_INT) + rkispp_module_work_event(dev, NULL, NULL, + ISPP_MODULE_TNR, true); + if (mis_val & FEC_INT) + rkispp_module_work_event(dev, NULL, NULL, + ISPP_MODULE_FEC, true); + + /* wait nr_shp/fec/scl idle */ + for (i = STREAM_S0; i < STREAM_MAX; i++) { + stream = &vdev->stream[i]; + if (stream->is_upd && + (!is_fec_en || !vdev->fec.is_end)) + mask |= stream->config->frame_end_id; + } + + vdev->irq_ends |= (mis_val & mask); + v4l2_dbg(3, rkispp_debug, &dev->v4l2_dev, + "irq_ends:0x%x mask:0x%x\n", + vdev->irq_ends, mask); + if (vdev->irq_ends != mask) return; + vdev->irq_ends = 0; + rkispp_module_work_event(dev, NULL, NULL, + ISPP_MODULE_NR, true); - /* nr or fec input buffer is pingpong when work on frame mode - * need to keep address static after force update - */ - if (dev->inp == INP_DDR && - (!(vdev->module_ens & ISPP_MODULE_TNR) || - vdev->module_ens == ISPP_MODULE_FEC)) - is_switch = true; - - if ((stream->last_module == ISPP_MODULE_SHP || - stream->last_module == ISPP_MODULE_NR) && - mis_val & NR_INT) { - if (is_switch) { - reg_y = readl(base + RKISPP_NR_ADDR_BASE_Y); - reg_uv = readl(base + RKISPP_NR_ADDR_BASE_UV); - - writel(readl(base + RKISPP_NR_ADDR_BASE_Y_SHD), - base + RKISPP_NR_ADDR_BASE_Y); - writel(readl(base + RKISPP_NR_ADDR_BASE_UV_SHD), - base + RKISPP_NR_ADDR_BASE_UV); - } - - writel(OTHER_FORCE_UPD, base + RKISPP_CTRL_UPDATE); - - if (is_switch) { - writel(reg_y, base + RKISPP_NR_ADDR_BASE_Y); - writel(reg_uv, base + RKISPP_NR_ADDR_BASE_UV); - } - } else if (stream->last_module == ISPP_MODULE_FEC && - mis_val & FEC_INT) { - if (is_switch) { - reg_y = readl(base + RKISPP_FEC_RD_Y_BASE); - reg_uv = readl(base + RKISPP_FEC_RD_UV_BASE); - - writel(readl(base + RKISPP_FEC_RD_Y_BASE_SHD), - base + RKISPP_FEC_RD_Y_BASE); - writel(readl(base + RKISPP_FEC_RD_UV_BASE_SHD), - base + RKISPP_FEC_RD_UV_BASE); - } - - writel(FEC_FORCE_UPD, base + RKISPP_CTRL_UPDATE); - - if (is_switch) { - writel(reg_y, base + RKISPP_FEC_RD_Y_BASE); - writel(reg_uv, base + RKISPP_FEC_RD_UV_BASE); - } + for (i = STREAM_MB; i < STREAM_MAX; i++) { + stream = &vdev->stream[i]; + if (stream->streaming) + stream->is_upd = true; } } static void update_mi(struct rkispp_stream *stream) { - struct rkispp_stream_vdev *vdev = &stream->isppdev->stream_vdev; - void __iomem *base = stream->isppdev->base_addr; + struct rkispp_device *dev = stream->isppdev; + struct rkispp_stream_vdev *vdev = &dev->stream_vdev; + void __iomem *base = dev->base_addr; struct rkispp_dummy_buffer *dummy_buf; - u8 en = 0; + u32 val; - if (stream->next_buf) { - set_y_addr(stream, - stream->next_buf->buff_addr[RKISPP_PLANE_Y]); - set_uv_addr(stream, - stream->next_buf->buff_addr[RKISPP_PLANE_UV]); - if (stream->type == STREAM_INPUT && stream->curr_buf) { - if (vdev->module_ens & ISPP_MODULE_FEC) - en = FEC_ST; - if (vdev->module_ens & - (ISPP_MODULE_NR | ISPP_MODULE_SHP)) - en = NR_SHP_ST; - if (vdev->module_ens & ISPP_MODULE_TNR) - en = TNR_ST; - writel(en, base + RKISPP_CTRL_STRT); - } + if (stream->curr_buf) { + val = stream->curr_buf->buff_addr[RKISPP_PLANE_Y]; + set_y_addr(stream, val); + val = stream->curr_buf->buff_addr[RKISPP_PLANE_UV]; + set_uv_addr(stream, val); } if (stream->type == STREAM_OUTPUT && - !stream->next_buf) { + !stream->curr_buf) { dummy_buf = &stream->dummy_buf; - if (!dummy_buf->vaddr) - return; set_y_addr(stream, dummy_buf->dma_addr); set_uv_addr(stream, dummy_buf->dma_addr); } - if (vdev->is_update_manual && - stream->type == STREAM_OUTPUT) - stream->curr_buf = stream->next_buf; - - if (stream->id == STREAM_MB && - stream->isppdev->inp == INP_DDR && - stream->last_module == ISPP_MODULE_TNR) { - writel(readl(base + RKISPP_TNR_WR_Y_BASE_SHD), - base + RKISPP_TNR_IIR_Y_BASE); - writel(readl(base + RKISPP_TNR_WR_UV_BASE_SHD), - base + RKISPP_TNR_IIR_UV_BASE); + if (stream->type == STREAM_INPUT && stream->streaming) { + if (vdev->module_ens & ISPP_MODULE_TNR) + val = ISPP_MODULE_TNR; + else if (vdev->module_ens & (ISPP_MODULE_NR | ISPP_MODULE_SHP)) + val = ISPP_MODULE_NR; + else + val = ISPP_MODULE_FEC; + rkispp_module_work_event(dev, NULL, NULL, val, false); } + v4l2_dbg(2, rkispp_debug, &stream->isppdev->v4l2_dev, "%s stream:%d CUR(Y:0x%x UV:0x%x) SHD(Y:0x%x UV:0x%x)\n", __func__, stream->id, @@ -346,13 +314,12 @@ static int rkispp_frame_end(struct rkispp_stream *stream) stream->curr_buf = NULL; } - stream->curr_buf = stream->next_buf; - stream->next_buf = NULL; spin_lock_irqsave(&stream->vbq_lock, lock_flags); - if (!list_empty(&stream->buf_queue)) { - stream->next_buf = list_first_entry(&stream->buf_queue, - struct rkispp_buffer, queue); - list_del(&stream->next_buf->queue); + if (!list_empty(&stream->buf_queue) && !stream->curr_buf) { + stream->curr_buf = + list_first_entry(&stream->buf_queue, + struct rkispp_buffer, queue); + list_del(&stream->curr_buf->queue); } spin_unlock_irqrestore(&stream->vbq_lock, lock_flags); @@ -360,25 +327,161 @@ static int rkispp_frame_end(struct rkispp_stream *stream) return 0; } +static void *get_pool_buf(struct rkispp_stream_vdev *vdev, + struct rkisp_ispp_buf *dbufs) +{ + int i; + + for (i = 0; i < RKISPP_BUF_POOL_MAX; i++) + if (vdev->pool[i].dbufs == dbufs) + return &vdev->pool[i]; + + return NULL; +} + +static void *dbuf_to_dummy(struct dma_buf *dbuf, + struct rkispp_dummy_buffer *pool, + int num) +{ + int i; + + for (i = 0; i < num; i++) { + if (pool->dbuf == dbuf) + return pool; + pool++; + } + + return NULL; +} + +static void *get_list_buf(struct list_head *list, bool is_isp_ispp) +{ + void *buf = NULL; + + if (!list_empty(list)) { + if (is_isp_ispp) { + buf = list_first_entry(list, + struct rkisp_ispp_buf, list); + list_del(&((struct rkisp_ispp_buf *)buf)->list); + } else { + buf = list_first_entry(list, + struct rkispp_dummy_buffer, list); + list_del(&((struct rkispp_dummy_buffer *)buf)->list); + } + } + return buf; +} + +static void tnr_free_buf(struct rkispp_device *dev) +{ + struct rkispp_stream_vdev *vdev = &dev->stream_vdev; + struct rkisp_ispp_buf *dbufs; + struct list_head *list; + int i; + + list = &vdev->tnr.list_rd; + if (vdev->tnr.cur_rd) { + list_add_tail(&vdev->tnr.cur_rd->list, list); + if (vdev->tnr.nxt_rd == vdev->tnr.cur_rd) + vdev->tnr.nxt_rd = NULL; + vdev->tnr.cur_rd = NULL; + } + if (vdev->tnr.nxt_rd) { + list_add_tail(&vdev->tnr.nxt_rd->list, list); + vdev->tnr.nxt_rd = NULL; + } + while (!list_empty(list)) + get_list_buf(list, true); + + list = &vdev->tnr.list_wr; + if (vdev->tnr.cur_wr) { + list_add_tail(&vdev->tnr.cur_wr->list, list); + vdev->tnr.cur_wr = NULL; + } + while (!list_empty(list)) { + dbufs = get_list_buf(list, true); + kfree(dbufs); + } + + for (i = 0; i < sizeof(vdev->tnr.buf) / + sizeof(struct rkispp_dummy_buffer); i++) + rkispp_free_buffer(dev, &vdev->tnr.buf.iir + i); +} + +static int tnr_init_buf(struct rkispp_device *dev, + u32 pic_size, u32 gain_size) +{ + struct rkispp_stream_vdev *vdev = &dev->stream_vdev; + struct rkisp_ispp_buf *dbufs; + struct rkispp_dummy_buffer *buf; + int i, j, ret, cnt = RKISP_ISPP_BUF_MAX; + + if (dev->inp == INP_ISP && dev->isp_mode & ISP_ISPP_QUICK) + cnt = 1; + for (i = 0; i < cnt; i++) { + dbufs = kzalloc(sizeof(*dbufs), GFP_KERNEL); + if (!dbufs) { + ret = -ENOMEM; + goto err; + } + for (j = 0; j < GROUP_BUF_MAX; j++) { + buf = &vdev->tnr.buf.wr[i][j]; + buf->is_need_dbuf = true; + buf->size = !j ? pic_size : gain_size; + ret = rkispp_allow_buffer(dev, buf); + if (ret) { + kfree(dbufs); + goto err; + } + dbufs->dbuf[j] = buf->dbuf; + } + list_add_tail(&dbufs->list, &vdev->tnr.list_wr); + } + + if (dev->inp == INP_ISP && dev->isp_mode & ISP_ISPP_QUICK) { + buf = &vdev->tnr.buf.iir; + buf->size = pic_size; + ret = rkispp_allow_buffer(dev, buf); + if (ret < 0) + goto err; + } + + buf = &vdev->tnr.buf.gain_kg; + buf->size = gain_size * 4; + ret = rkispp_allow_buffer(dev, buf); + if (ret < 0) + goto err; + return 0; +err: + tnr_free_buf(dev); + v4l2_err(&dev->v4l2_dev, "%s failed\n", __func__); + return ret; +} + static int config_tnr(struct rkispp_device *dev) { struct rkispp_stream_vdev *vdev; struct rkispp_stream *stream = NULL; void __iomem *base = dev->base_addr; int ret, mult = 1; - u32 i, width, height, fmt; - u32 pic_size, gain_size, kg_size; - u32 addr_offs, w, h; + u32 width, height, fmt; + u32 pic_size, gain_size; + u32 addr_offs, w, h, val; vdev = &dev->stream_vdev; + vdev->tnr.is_end = true; + vdev->tnr.is_3to1 = + ((vdev->module_ens & ISPP_MODULE_TNR_3TO1) == + ISPP_MODULE_TNR_3TO1); if (!(vdev->module_ens & ISPP_MODULE_TNR)) return 0; if (dev->inp == INP_DDR) { + vdev->tnr.is_3to1 = false; stream = &vdev->stream[STREAM_II]; fmt = stream->out_cap_fmt.wr_fmt; } else { - fmt = dev->ispp_sdev.out_fmt.wr_fmt | FMT_FBC; + fmt = dev->isp_mode & (FMT_YUV422 | FMT_FBC); } width = dev->ispp_sdev.out_fmt.width; @@ -387,102 +490,56 @@ static int config_tnr(struct rkispp_device *dev) h = (fmt & FMT_FBC) ? ALIGN(height, 16) : height; addr_offs = (fmt & FMT_FBC) ? w * h >> 4 : w * h; pic_size = (fmt & FMT_YUV422) ? w * h * 2 : w * h * 3 >> 1; + vdev->tnr.uv_offset = addr_offs; if (fmt & FMT_FBC) pic_size += w * h >> 4; gain_size = ALIGN(width, 64) * ALIGN(height, 128) >> 4; - kg_size = gain_size * 4; if (fmt & FMT_YUYV) mult = 2; if (vdev->module_ens & (ISPP_MODULE_NR | ISPP_MODULE_SHP)) { - struct rkispp_dummy_buffer *buf; - - if (dev->inp == INP_ISP) { + ret = tnr_init_buf(dev, pic_size, gain_size); + if (ret) + return ret; + if (dev->inp == INP_ISP && + dev->isp_mode & ISP_ISPP_QUICK) { rkispp_set_bits(base + RKISPP_CTRL_QUICK, GLB_QUICK_MODE_MASK, GLB_QUICK_MODE(0)); - buf = &vdev->tnr_buf.pic_cur; - buf->size = pic_size; - ret = rkispp_allow_buffer(dev, buf); - if (ret < 0) - goto err; - writel(buf->dma_addr, - base + RKISPP_TNR_CUR_Y_BASE); - writel(buf->dma_addr + addr_offs, - base + RKISPP_TNR_CUR_UV_BASE); + val = vdev->pool[0].dma[GROUP_BUF_PIC]; + writel(val, base + RKISPP_TNR_CUR_Y_BASE); + writel(val + addr_offs, base + RKISPP_TNR_CUR_UV_BASE); - buf = &vdev->tnr_buf.gain_cur; - buf->size = gain_size; - ret = rkispp_allow_buffer(dev, buf); - if (ret < 0) - goto err; - writel(buf->dma_addr, - base + RKISPP_TNR_GAIN_CUR_Y_BASE); + val = vdev->pool[0].dma[GROUP_BUF_GAIN]; + writel(val, base + RKISPP_TNR_GAIN_CUR_Y_BASE); - buf = &vdev->tnr_buf.iir; - buf->size = pic_size; - ret = rkispp_allow_buffer(dev, buf); - if (ret < 0) - goto err; - - if ((vdev->module_ens & ISPP_MODULE_TNR_3TO1) == - ISPP_MODULE_TNR_3TO1) { - buf = &vdev->tnr_buf.pic_next; - buf->size = pic_size; - ret = rkispp_allow_buffer(dev, buf); - if (ret < 0) - goto err; - writel(buf->dma_addr, - base + RKISPP_TNR_NXT_Y_BASE); - writel(buf->dma_addr + addr_offs, - base + RKISPP_TNR_NXT_UV_BASE); - buf = &vdev->tnr_buf.gain_next; - buf->size = gain_size; - ret = rkispp_allow_buffer(dev, buf); - if (ret < 0) - goto err; - writel(buf->dma_addr, - base + RKISPP_TNR_GAIN_NXT_Y_BASE); + if (vdev->tnr.is_3to1) { + val = vdev->pool[1].dma[GROUP_BUF_PIC]; + writel(val, base + RKISPP_TNR_NXT_Y_BASE); + writel(val + addr_offs, base + RKISPP_TNR_NXT_UV_BASE); + val = vdev->pool[1].dma[GROUP_BUF_GAIN]; + writel(val, base + RKISPP_TNR_GAIN_NXT_Y_BASE); } } - buf = &vdev->tnr_buf.gain_kg; - buf->size = kg_size; - ret = rkispp_allow_buffer(dev, buf); - if (ret < 0) - goto err; - writel(buf->dma_addr, - base + RKISPP_TNR_GAIN_KG_Y_BASE); - buf = &vdev->tnr_buf.pic_wr; - buf->size = pic_size; - ret = rkispp_allow_buffer(dev, buf); - if (ret < 0) - goto err; - writel(buf->dma_addr, - base + RKISPP_TNR_WR_Y_BASE); - writel(buf->dma_addr + addr_offs, - base + RKISPP_TNR_WR_UV_BASE); - if (vdev->tnr_buf.iir.vaddr) - buf = &vdev->tnr_buf.iir; - writel(buf->dma_addr, - base + RKISPP_TNR_IIR_Y_BASE); - writel(buf->dma_addr + addr_offs, - base + RKISPP_TNR_IIR_UV_BASE); + val = vdev->tnr.buf.gain_kg.dma_addr; + writel(val, base + RKISPP_TNR_GAIN_KG_Y_BASE); - buf = &vdev->tnr_buf.gain_wr; - buf->size = gain_size; - ret = rkispp_allow_buffer(dev, buf); - if (ret < 0) - goto err; - writel(buf->dma_addr, - base + RKISPP_TNR_GAIN_WR_Y_BASE); + val = vdev->tnr.buf.wr[0][GROUP_BUF_PIC].dma_addr; + writel(val, base + RKISPP_TNR_WR_Y_BASE); + writel(val + addr_offs, base + RKISPP_TNR_WR_UV_BASE); + if (vdev->tnr.buf.iir.mem_priv) + val = vdev->tnr.buf.iir.dma_addr; + writel(val, base + RKISPP_TNR_IIR_Y_BASE); + writel(val + addr_offs, base + RKISPP_TNR_IIR_UV_BASE); - writel(ALIGN(width * mult, 16) >> 2, - base + RKISPP_TNR_WR_VIR_STRIDE); - writel(fmt << 4 | SW_TNR_1ST_FRM, - base + RKISPP_TNR_CTRL); + val = vdev->tnr.buf.wr[0][GROUP_BUF_GAIN].dma_addr; + writel(val, base + RKISPP_TNR_GAIN_WR_Y_BASE); + + writel(ALIGN(width * mult, 16) >> 2, base + RKISPP_TNR_WR_VIR_STRIDE); + writel(fmt << 4 | SW_TNR_1ST_FRM, base + RKISPP_TNR_CTRL); } if (stream) { @@ -507,9 +564,7 @@ static int config_tnr(struct rkispp_device *dev) base + RKISPP_TNR_NXT_VIR_STRIDE); } rkispp_set_bits(base + RKISPP_TNR_CORE_CTRL, SW_TNR_MODE, - ((vdev->module_ens & ISPP_MODULE_TNR_3TO1) == - ISPP_MODULE_TNR_3TO1 && - dev->inp == INP_ISP) ? SW_TNR_MODE : 0); + vdev->tnr.is_3to1 ? SW_TNR_MODE : 0); writel(ALIGN(width, 64) >> 4, base + RKISPP_TNR_GAIN_CUR_VIR_STRIDE); writel(ALIGN(width, 64) >> 4, @@ -528,12 +583,66 @@ static int config_tnr(struct rkispp_device *dev) readl(base + RKISPP_TNR_CTRL), readl(base + RKISPP_TNR_CORE_CTRL)); return 0; -err: - for (i = 0; i < sizeof(vdev->tnr_buf) / +} + +static void nr_free_buf(struct rkispp_device *dev) +{ + struct rkispp_stream_vdev *vdev = &dev->stream_vdev; + struct rkisp_ispp_buf *dbufs; + struct list_head *list; + int i; + + list = &vdev->nr.list_rd; + if (vdev->nr.cur_rd) { + list_add_tail(&vdev->nr.cur_rd->list, list); + vdev->nr.cur_rd = NULL; + } + while (!list_empty(list)) { + dbufs = get_list_buf(list, true); + if (vdev->module_ens & ISPP_MODULE_TNR) + kfree(dbufs); + } + + list = &vdev->nr.list_wr; + if (vdev->nr.cur_wr) + vdev->nr.cur_wr = NULL; + while (!list_empty(list)) + get_list_buf(list, false); + + for (i = 0; i < sizeof(vdev->nr.buf) / sizeof(struct rkispp_dummy_buffer); i++) - rkispp_free_buffer(dev, &vdev->tnr_buf.pic_cur + i); - v4l2_err(&dev->v4l2_dev, - "%s Failed to allocate buffer\n", __func__); + rkispp_free_buffer(dev, &vdev->nr.buf.tmp_yuv + i); +} + +static int nr_init_buf(struct rkispp_device *dev, u32 size) +{ + struct rkispp_stream_vdev *vdev = &dev->stream_vdev; + struct rkispp_dummy_buffer *buf; + int i, ret, cnt = 1; + + if (vdev->module_ens & ISPP_MODULE_FEC) + cnt = RKISP_ISPP_BUF_MAX; + for (i = 0; i < cnt; i++) { + buf = &vdev->nr.buf.wr[i]; + buf->size = size; + ret = rkispp_allow_buffer(dev, buf); + if (ret) + goto err; + list_add_tail(&buf->list, &vdev->nr.list_wr); + } + + if (dev->inp == INP_ISP && dev->isp_mode & ISP_ISPP_QUICK) + vdev->nr.cur_wr = get_list_buf(&vdev->nr.list_wr, false); + + buf = &vdev->nr.buf.tmp_yuv; + buf->size = size >> 4; + ret = rkispp_allow_buffer(dev, buf); + if (ret) + goto err; + return 0; +err: + nr_free_buf(dev); + v4l2_err(&dev->v4l2_dev, "%s failed\n", __func__); return ret; } @@ -542,13 +651,13 @@ static int config_nr_shp(struct rkispp_device *dev) struct rkispp_stream_vdev *vdev; struct rkispp_stream *stream = NULL; void __iomem *base = dev->base_addr; - struct rkispp_dummy_buffer *buf; u32 width, height, fmt; - u32 pic_size, gain_size; - u32 i, addr_offs, w, h; + u32 pic_size, addr_offs; + u32 w, h, val; int ret, mult = 1; vdev = &dev->stream_vdev; + vdev->nr.is_end = true; if (!(vdev->module_ens & (ISPP_MODULE_NR | ISPP_MODULE_SHP))) return 0; @@ -556,7 +665,7 @@ static int config_nr_shp(struct rkispp_device *dev) stream = &vdev->stream[STREAM_II]; fmt = stream->out_cap_fmt.wr_fmt; } else { - fmt = dev->ispp_sdev.out_fmt.wr_fmt | FMT_FBC; + fmt = dev->isp_mode & (FMT_YUV422 | FMT_FBC); } width = dev->ispp_sdev.out_fmt.width; @@ -565,13 +674,17 @@ static int config_nr_shp(struct rkispp_device *dev) h = (fmt & FMT_FBC) ? ALIGN(height, 16) : height; addr_offs = (fmt & FMT_FBC) ? w * h >> 4 : w * h; pic_size = (fmt & FMT_YUV422) ? w * h * 2 : w * h * 3 >> 1; + vdev->nr.uv_offset = addr_offs; if (fmt & FMT_FBC) pic_size += w * h >> 4; - gain_size = ALIGN(width, 64) * ALIGN(height, 128) >> 4; if (fmt & FMT_YUYV) mult = 2; + ret = nr_init_buf(dev, pic_size); + if (ret) + return ret; + if (vdev->module_ens & ISPP_MODULE_TNR) { writel(readl(base + RKISPP_TNR_WR_Y_BASE), base + RKISPP_NR_ADDR_BASE_Y); @@ -589,20 +702,11 @@ static int config_nr_shp(struct rkispp_device *dev) GLB_QUICK_MODE_MASK, GLB_QUICK_MODE(2)); - buf = &vdev->nr_buf.pic_cur; - buf->size = pic_size; - ret = rkispp_allow_buffer(dev, buf); - if (ret < 0) - goto err; - writel(buf->dma_addr, base + RKISPP_NR_ADDR_BASE_Y); - writel(buf->dma_addr + addr_offs, - base + RKISPP_NR_ADDR_BASE_UV); - buf = &vdev->nr_buf.gain_cur; - buf->size = gain_size; - ret = rkispp_allow_buffer(dev, buf); - if (ret < 0) - goto err; - writel(buf->dma_addr, base + RKISPP_NR_ADDR_BASE_GAIN); + val = vdev->pool[0].dma[GROUP_BUF_PIC]; + writel(val, base + RKISPP_NR_ADDR_BASE_Y); + writel(val + addr_offs, base + RKISPP_NR_ADDR_BASE_UV); + val = vdev->pool[0].dma[GROUP_BUF_GAIN]; + writel(val, base + RKISPP_NR_ADDR_BASE_GAIN); rkispp_clear_bits(base + RKISPP_CTRL_QUICK, GLB_NR_SD32_TNR); } else if (stream) { stream->config->frame_end_id = NR_INT; @@ -615,31 +719,21 @@ static int config_nr_shp(struct rkispp_device *dev) rkispp_clear_bits(base + RKISPP_CTRL_QUICK, GLB_FEC2SCL_EN); if (vdev->module_ens & ISPP_MODULE_FEC) { - pic_size = (fmt & FMT_YUV422) ? width * height * 2 : - width * height * 3 >> 1; addr_offs = width * height; - buf = &vdev->nr_buf.pic_wr; - buf->size = pic_size; - ret = rkispp_allow_buffer(dev, buf); - if (ret < 0) - goto err; - writel(buf->dma_addr, base + RKISPP_SHARP_WR_Y_BASE); - writel(buf->dma_addr + addr_offs, - base + RKISPP_SHARP_WR_UV_BASE); - + vdev->fec.uv_offset = addr_offs; + val = vdev->nr.buf.wr[0].dma_addr; + writel(val, base + RKISPP_SHARP_WR_Y_BASE); + val += addr_offs; + writel(val, base + RKISPP_SHARP_WR_UV_BASE); writel(ALIGN(width * mult, 16) >> 2, - base + RKISPP_SHARP_WR_VIR_STRIDE); + base + RKISPP_SHARP_WR_VIR_STRIDE); rkispp_set_bits(base + RKISPP_SHARP_CTRL, SW_SHP_WR_FORMAT_MASK, fmt & (~FMT_FBC)); rkispp_clear_bits(base + RKISPP_SHARP_CORE_CTRL, SW_SHP_DMA_DIS); } - buf = &vdev->nr_buf.tmp_yuv; - buf->size = width * 42; - ret = rkispp_allow_buffer(dev, buf); - if (ret < 0) - goto err; - writel(buf->dma_addr, base + RKISPP_SHARP_TMP_YUV_BASE); + val = vdev->nr.buf.tmp_yuv.dma_addr; + writel(val, base + RKISPP_SHARP_TMP_YUV_BASE); /* fix to use new nr algorithm */ rkispp_set_bits(base + RKISPP_NR_CTRL, NR_NEW_ALGO, NR_NEW_ALGO); @@ -663,13 +757,22 @@ static int config_nr_shp(struct rkispp_device *dev) readl(base + RKISPP_SHARP_CTRL), readl(base + RKISPP_SHARP_CORE_CTRL)); return 0; -err: - for (i = 0; i < sizeof(vdev->nr_buf) / +} + +static void fec_free_buf(struct rkispp_device *dev) +{ + struct rkispp_stream_vdev *vdev = &dev->stream_vdev; + struct list_head *list = &vdev->fec.list_rd; + int i; + + if (vdev->fec.cur_rd) + vdev->fec.cur_rd = NULL; + while (!list_empty(list)) + get_list_buf(list, false); + + for (i = 0; i < sizeof(vdev->fec_buf) / sizeof(struct rkispp_dummy_buffer); i++) - rkispp_free_buffer(dev, &vdev->nr_buf.pic_cur + i); - v4l2_err(&dev->v4l2_dev, - "%s Failed to allocate buffer\n", __func__); - return ret; + rkispp_free_buffer(dev, &vdev->fec_buf.mesh_xint + i); } static int config_fec(struct rkispp_device *dev) @@ -679,10 +782,11 @@ static int config_fec(struct rkispp_device *dev) void __iomem *base = dev->base_addr; struct rkispp_dummy_buffer *buf; u32 width, height, fmt, mult = 1; - u32 i, mesh_size; + u32 mesh_size; int ret; vdev = &dev->stream_vdev; + vdev->fec.is_end = true; if (!(vdev->module_ens & ISPP_MODULE_FEC)) return 0; @@ -690,7 +794,7 @@ static int config_fec(struct rkispp_device *dev) stream = &vdev->stream[STREAM_II]; fmt = stream->out_cap_fmt.wr_fmt; } else { - fmt = dev->ispp_sdev.out_fmt.wr_fmt; + fmt = dev->isp_mode & FMT_YUV422; } width = dev->ispp_sdev.out_fmt.width; @@ -714,6 +818,7 @@ static int config_fec(struct rkispp_device *dev) mesh_size = cal_fec_mesh(width, height, 0); buf = &vdev->fec_buf.mesh_xint; + buf->is_need_vaddr = true; buf->size = ALIGN(mesh_size * 2, 8); ret = rkispp_allow_buffer(dev, buf); if (ret < 0) @@ -721,6 +826,7 @@ static int config_fec(struct rkispp_device *dev) writel(buf->dma_addr, base + RKISPP_FEC_MESH_XINT_BASE); buf = &vdev->fec_buf.mesh_yint; + buf->is_need_vaddr = true; buf->size = ALIGN(mesh_size * 2, 8); ret = rkispp_allow_buffer(dev, buf); if (ret < 0) @@ -728,6 +834,7 @@ static int config_fec(struct rkispp_device *dev) writel(buf->dma_addr, base + RKISPP_FEC_MESH_YINT_BASE); buf = &vdev->fec_buf.mesh_xfra; + buf->is_need_vaddr = true; buf->size = ALIGN(mesh_size, 8); ret = rkispp_allow_buffer(dev, buf); if (ret < 0) @@ -735,6 +842,7 @@ static int config_fec(struct rkispp_device *dev) writel(buf->dma_addr, base + RKISPP_FEC_MESH_XFRA_BASE); buf = &vdev->fec_buf.mesh_yfra; + buf->is_need_vaddr = true; buf->size = ALIGN(mesh_size, 8); ret = rkispp_allow_buffer(dev, buf); if (ret < 0) @@ -752,9 +860,7 @@ static int config_fec(struct rkispp_device *dev) readl(base + RKISPP_FEC_CORE_CTRL)); return 0; err: - for (i = 0; i < sizeof(vdev->fec_buf) / - sizeof(struct rkispp_dummy_buffer); i++) - rkispp_free_buffer(dev, &vdev->fec_buf.mesh_xint + i); + fec_free_buf(dev); v4l2_err(&dev->v4l2_dev, "%s Failed to allocate buffer\n", __func__); return ret; @@ -773,14 +879,19 @@ static int config_modules(struct rkispp_device *dev) ret = config_nr_shp(dev); if (ret < 0) - return ret; + goto free_tnr; ret = config_fec(dev); if (ret < 0) - return ret; + goto free_nr; rkispp_params_configure(&dev->params_vdev); + return 0; +free_nr: + nr_free_buf(dev); +free_tnr: + tnr_free_buf(dev); return ret; } @@ -789,25 +900,22 @@ static int start_ii(struct rkispp_stream *stream) struct rkispp_device *dev = stream->isppdev; struct rkispp_stream_vdev *vdev = &dev->stream_vdev; void __iomem *base = dev->base_addr; - struct rkispp_stream *st; - int i; + u32 i, module; - rkispp_clear_bits(base + RKISPP_CTRL_QUICK, GLB_QUICK_EN); writel(ALL_FORCE_UPD, base + RKISPP_CTRL_UPDATE); - if (vdev->is_update_manual) - i = (vdev->module_ens & ISPP_MODULE_FEC) ? - STREAM_S0 : STREAM_MAX; - else - i = STREAM_MB; - - for (; i < STREAM_MAX; i++) { - st = &vdev->stream[i]; - rkispp_frame_end(st); + for (i = STREAM_MB; i < STREAM_MAX; i++) { + if (vdev->stream[i].streaming) + vdev->stream[i].is_upd = true; } stream->streaming = true; - rkispp_frame_end(stream); - + if (vdev->module_ens & ISPP_MODULE_TNR) + module = ISPP_MODULE_TNR; + else if (vdev->module_ens & (ISPP_MODULE_NR | ISPP_MODULE_SHP)) + module = ISPP_MODULE_NR; + else + module = ISPP_MODULE_FEC; + rkispp_module_work_event(dev, NULL, NULL, module, false); return 0; } @@ -816,6 +924,12 @@ static int config_ii(struct rkispp_stream *stream) return config_modules(stream->isppdev); } +static int is_stopped_ii(struct rkispp_stream *stream) +{ + stream->streaming = false; + return true; +} + static int config_mb(struct rkispp_stream *stream) { struct rkispp_device *dev = stream->isppdev; @@ -879,50 +993,35 @@ static int config_mb(struct rkispp_stream *stream) return 0; } -static void stop_mb(struct rkispp_stream *stream) -{ - struct rkispp_device *dev = stream->isppdev; - void __iomem *base = dev->base_addr; - - switch (stream->last_module) { - case ISPP_MODULE_TNR: - rkispp_clear_bits(base + RKISPP_TNR_CORE_CTRL, SW_TNR_EN); - break; - case ISPP_MODULE_NR: - case ISPP_MODULE_SHP: - break; - default: - rkispp_clear_bits(base + RKISPP_FEC_CORE_CTRL, SW_FEC_EN); - } -} - static int is_stopped_mb(struct rkispp_stream *stream) { struct rkispp_device *dev = stream->isppdev; + struct rkispp_stream_vdev *vdev = &dev->stream_vdev; void __iomem *base = dev->base_addr; - u32 val, en; + u32 val; - switch (stream->last_module) { - case ISPP_MODULE_TNR: - en = SW_TNR_EN_SHD; - val = readl(base + RKISPP_TNR_CORE_CTRL); - break; - case ISPP_MODULE_NR: - case ISPP_MODULE_SHP: + if (vdev->module_ens & ISPP_MODULE_FEC) { /* close dma write immediately */ - rkispp_set_bits(base + RKISPP_SHARP_CORE_CTRL, - SW_SHP_DMA_DIS, SW_SHP_DMA_DIS); - val = false; - en = false; - break; - default: - en = SW_FEC_EN_SHD; - val = readl(base + RKISPP_FEC_CORE_CTRL); rkispp_set_bits(base + RKISPP_FEC_CORE_CTRL, 0, SW_FEC2DDR_DIS); + } else if (vdev->module_ens & + (ISPP_MODULE_NR | ISPP_MODULE_SHP)) { + val = readl(base + RKISPP_CTRL_QUICK); + if (val & GLB_QUICK_EN) { + val = dev->stream_vdev.nr.buf.wr[0].dma_addr; + writel(val, base + RKISPP_SHARP_WR_Y_BASE); + writel(val, base + RKISPP_SHARP_WR_UV_BASE); + } else { + rkispp_set_bits(base + RKISPP_SHARP_CORE_CTRL, + 0, SW_SHP_DMA_DIS); + } } - return !(val & en); + /* for wait last frame */ + if (atomic_read(&dev->stream_vdev.refcnt) == 1) + return false; + + return true; } static int limit_check_mb(struct rkispp_stream *stream, @@ -944,9 +1043,6 @@ static int limit_check_mb(struct rkispp_stream *stream, return -EINVAL; } - if (stream->out_cap_fmt.wr_fmt & FMT_FBC) - dev->stream_vdev.is_update_manual = true; - return 0; } @@ -961,20 +1057,22 @@ static int config_scl(struct rkispp_stream *stream) (in_width - 1) + 1; u32 vy_fac = (stream->out_fmt.height - 1) * 8192 / (in_height - 1) + 1; - u32 value = 0; - u8 bypass = 0, mult = 1; + u32 val = SW_SCL_ENABLE, mult = 1; + u32 mask = SW_SCL_WR_YUV_LIMIT | SW_SCL_WR_YUYV_YCSWAP | + SW_SCL_WR_YUYV_FORMAT | SW_SCL_WR_YUV_FORMAT | + SW_SCL_WR_UV_DIS | SW_SCL_BYPASS; if (hy_fac == 8193 && vy_fac == 8193) - bypass = SW_SCL_BYPASS; + val |= SW_SCL_BYPASS; if (fmt->wr_fmt & FMT_YUYV) mult = 2; set_vir_stride(stream, ALIGN(stream->out_fmt.width * mult, 16) >> 2); set_scl_factor(stream, vy_fac << 16 | hy_fac); - value = SW_SCL_ENABLE | bypass | fmt->wr_fmt << 3 | + val |= fmt->wr_fmt << 3 | ((fmt->fourcc != V4L2_PIX_FMT_GREY) ? 0 : SW_SCL_WR_UV_DIS) | ((stream->out_fmt.quantization != V4L2_QUANTIZATION_LIM_RANGE) ? 0 : SW_SCL_WR_YUV_LIMIT); - set_ctrl(stream, value); + rkispp_set_bits(base + stream->config->reg.ctrl, mask, val); v4l2_dbg(1, rkispp_debug, &dev->v4l2_dev, "scl%d ctrl:0x%x stride:0x%x factor:0x%x\n", @@ -987,7 +1085,8 @@ static int config_scl(struct rkispp_stream *stream) static void stop_scl(struct rkispp_stream *stream) { - void __iomem *base = stream->isppdev->base_addr; + struct rkispp_device *dev = stream->isppdev; + void __iomem *base = dev->base_addr; rkispp_clear_bits(base + stream->config->reg.ctrl, SW_SCL_ENABLE); } @@ -1023,7 +1122,6 @@ static int limit_check_scl(struct rkispp_stream *stream, *h * max_ratio < sdev->out_fmt.height || *w * min_ratio > sdev->out_fmt.width || *h * min_ratio > sdev->out_fmt.height) { - ret = -EINVAL; v4l2_err(&dev->v4l2_dev, "scale%d:%dx%d out of range:\n" "\t[width max:%d ratio max:%d min:%d]\n", @@ -1042,11 +1140,11 @@ static int limit_check_scl(struct rkispp_stream *stream, static struct streams_ops input_stream_ops = { .config = config_ii, .start = start_ii, + .is_stopped = is_stopped_ii, }; static struct streams_ops mb_stream_ops = { .config = config_mb, - .stop = stop_mb, .is_stopped = is_stopped_mb, .limit_check = limit_check_mb, }; @@ -1093,8 +1191,9 @@ static int rkispp_queue_setup(struct vb2_queue *queue, } v4l2_dbg(1, rkispp_debug, &dev->v4l2_dev, - "%s count %d, size %d\n", - v4l2_type_names[queue->type], *num_buffers, sizes[0]); + "%s stream:%d count %d, size %d\n", + v4l2_type_names[queue->type], + stream->id, *num_buffers, sizes[0]); return 0; } @@ -1105,9 +1204,9 @@ static void rkispp_buf_queue(struct vb2_buffer *vb) struct rkispp_buffer *isppbuf = to_rkispp_buffer(vbuf); struct vb2_queue *queue = vb->vb2_queue; struct rkispp_stream *stream = queue->drv_priv; - unsigned long lock_flags = 0; struct v4l2_pix_format_mplane *pixm = &stream->out_fmt; struct capture_fmt *cap_fmt = &stream->out_cap_fmt; + unsigned long lock_flags = 0; u32 height, size, offset; int i; @@ -1135,14 +1234,14 @@ static void rkispp_buf_queue(struct vb2_buffer *vb) } v4l2_dbg(2, rkispp_debug, &stream->isppdev->v4l2_dev, - "stream:%d queue buf:0x%x\n", + "%s stream:%d buf:0x%x\n", __func__, stream->id, isppbuf->buff_addr[0]); spin_lock_irqsave(&stream->vbq_lock, lock_flags); if (stream->type == STREAM_INPUT && stream->streaming && - !stream->next_buf) { - stream->next_buf = isppbuf; + !stream->curr_buf) { + stream->curr_buf = isppbuf; update_mi(stream); } else { list_add_tail(&isppbuf->queue, &stream->buf_queue); @@ -1170,52 +1269,36 @@ static void rkispp_destroy_dummy_buf(struct rkispp_stream *stream) struct rkispp_dummy_buffer *buf = &stream->dummy_buf; struct rkispp_device *dev = stream->isppdev; struct rkispp_stream_vdev *vdev; - u32 i; vdev = &dev->stream_vdev; rkispp_free_buffer(dev, buf); if (atomic_read(&vdev->refcnt) == 1) { - vdev->is_update_manual = false; - for (i = 0; i < sizeof(vdev->tnr_buf) / - sizeof(struct rkispp_dummy_buffer); i++) - rkispp_free_buffer(dev, &vdev->tnr_buf.pic_cur + i); - for (i = 0; i < sizeof(vdev->nr_buf) / - sizeof(struct rkispp_dummy_buffer); i++) - rkispp_free_buffer(dev, &vdev->nr_buf.pic_cur + i); - for (i = 0; i < sizeof(vdev->fec_buf) / - sizeof(struct rkispp_dummy_buffer); i++) - rkispp_free_buffer(dev, &vdev->fec_buf.mesh_xint + i); + vdev->irq_ends = 0; + tnr_free_buf(dev); + nr_free_buf(dev); + fec_free_buf(dev); } } static void rkispp_stream_stop(struct rkispp_stream *stream) { struct rkispp_device *dev = stream->isppdev; - bool wait = false; - int ret = 0; + bool is_wait = true; stream->stopping = true; - if (stream->ops->stop) { - stream->ops->stop(stream); - if (dev->inp == INP_DDR && - !dev->stream_vdev.stream[STREAM_II].streaming) - wait = false; - else - wait = true; - } if (dev->inp == INP_ISP && - atomic_read(&dev->stream_vdev.refcnt) == 1) + atomic_read(&dev->stream_vdev.refcnt) == 1) { v4l2_subdev_call(&dev->ispp_sdev.sd, video, s_stream, false); - if (wait) { - ret = wait_event_timeout(stream->done, - !stream->streaming, - msecs_to_jiffies(1000)); - if (!ret) - v4l2_warn(&dev->v4l2_dev, - "waiting on event ret:%d\n", ret); + if (!(dev->isp_mode & ISP_ISPP_QUICK)) + is_wait = false; } + if (is_wait) + wait_event_timeout(stream->done, + !stream->streaming, + msecs_to_jiffies(100)); + stream->is_upd = false; stream->streaming = false; stream->stopping = false; } @@ -1252,7 +1335,7 @@ static void rkispp_stop_streaming(struct vb2_queue *queue) struct rkispp_device *dev = stream->isppdev; v4l2_dbg(1, rkispp_debug, &dev->v4l2_dev, - "%s id:%d\n", __func__, stream->id); + "%s id:%d enter\n", __func__, stream->id); if (!stream->streaming) return; @@ -1261,38 +1344,56 @@ static void rkispp_stop_streaming(struct vb2_queue *queue) destroy_buf_queue(stream, VB2_BUF_STATE_ERROR); rkispp_destroy_dummy_buf(stream); atomic_dec(&dev->stream_vdev.refcnt); + + v4l2_dbg(1, rkispp_debug, &dev->v4l2_dev, + "%s id:%d exit\n", __func__, stream->id); } static int start_isp(struct rkispp_device *dev) { + struct rkispp_subdev *ispp_sdev = &dev->ispp_sdev; struct rkispp_stream_vdev *vdev = &dev->stream_vdev; struct rkispp_stream *stream; + struct rkisp_ispp_mode mode; int i, ret; - if (dev->inp != INP_ISP) + if (dev->inp != INP_ISP || ispp_sdev->state) return 0; /* output stream enable then start isp*/ - for (i = STREAM_MB; i < STREAM_S2 + 1; i++) { + for (i = STREAM_MB; i < STREAM_MAX; i++) { stream = &vdev->stream[i]; if (stream->linked && !stream->streaming) return 0; } - ret = config_modules(dev); + + mode.work_mode = dev->isp_mode; + mode.buf_num = (dev->isp_mode & ISP_ISPP_QUICK) ? + 1 : RKISP_ISPP_BUF_MAX; + if ((vdev->module_ens & ISPP_MODULE_TNR_3TO1) == ISPP_MODULE_TNR_3TO1) + mode.buf_num += 1; + ret = v4l2_subdev_call(ispp_sdev->remote_sd, core, ioctl, + RKISP_ISPP_CMD_SET_MODE, &mode); if (ret) return ret; - writel(ALL_FORCE_UPD, dev->base_addr + RKISPP_CTRL_UPDATE); - if (vdev->is_update_manual) - i = (vdev->module_ens & ISPP_MODULE_FEC) ? - STREAM_S0 : STREAM_MAX; - else - i = STREAM_MB; - for (; i < STREAM_MAX; i++) { - stream = &vdev->stream[i]; - rkispp_frame_end(stream); + + ret = config_modules(dev); + if (ret) { + rkispp_free_pool(vdev); + mode.work_mode = ISP_ISPP_INIT_FAIL; + v4l2_subdev_call(ispp_sdev->remote_sd, core, ioctl, + RKISP_ISPP_CMD_SET_MODE, &mode); + return ret; } - rkispp_set_bits(dev->base_addr + RKISPP_CTRL_QUICK, - 0, GLB_QUICK_EN); + writel(ALL_FORCE_UPD, dev->base_addr + RKISPP_CTRL_UPDATE); + for (i = STREAM_MB; i < STREAM_MAX; i++) { + stream = &vdev->stream[i]; + if (stream->streaming) + stream->is_upd = true; + } + if (dev->isp_mode & ISP_ISPP_QUICK) + rkispp_set_bits(dev->base_addr + RKISPP_CTRL_QUICK, + 0, GLB_QUICK_EN); return v4l2_subdev_call(&dev->ispp_sdev.sd, video, s_stream, true); } @@ -1305,15 +1406,16 @@ static int rkispp_start_streaming(struct vb2_queue *queue, int ret = -1; v4l2_dbg(1, rkispp_debug, &dev->v4l2_dev, - "%s id:%d\n", __func__, stream->id); + "%s id:%d enter\n", __func__, stream->id); if (stream->streaming) return -EBUSY; + stream->is_upd = false; atomic_inc(&dev->stream_vdev.refcnt); if (!dev->inp || !stream->linked) { v4l2_err(&dev->v4l2_dev, - "invalid input source\n"); + "no link or invalid input source\n"); goto free_buf_queue; } @@ -1343,6 +1445,9 @@ static int rkispp_start_streaming(struct vb2_queue *queue, ret = start_isp(dev); if (ret) goto free_dummy_buf; + + v4l2_dbg(1, rkispp_debug, &dev->v4l2_dev, + "%s id:%d exit\n", __func__, stream->id); return 0; free_dummy_buf: rkispp_destroy_dummy_buf(stream); @@ -1350,9 +1455,9 @@ free_buf_queue: destroy_buf_queue(stream, VB2_BUF_STATE_QUEUED); atomic_dec(&dev->stream_vdev.refcnt); stream->streaming = false; - v4l2_err(&dev->v4l2_dev, - "ispp stream:%d on failed ret:%d\n", - stream->id, ret); + stream->is_upd = false; + v4l2_err(&dev->v4l2_dev, "%s id:%d failed ret:%d\n", + __func__, stream->id, ret); return ret; } @@ -1640,6 +1745,425 @@ unreg: return ret; } +static void fec_work_event(struct rkispp_device *dev, + struct rkispp_dummy_buffer *buf_rd, + bool is_isr) +{ + struct rkispp_stream_vdev *vdev = &dev->stream_vdev; + struct rkispp_stream *stream = &vdev->stream[STREAM_II]; + struct list_head *list = &vdev->fec.list_rd; + void __iomem *base = dev->base_addr; + struct rkispp_dummy_buffer *dummy; + unsigned long lock_flags = 0; + bool is_start = false; + u32 val; + + if (!(vdev->module_ens & ISPP_MODULE_FEC)) + return; + + spin_lock_irqsave(&vdev->fec.buf_lock, lock_flags); + + /* event from fec frame end */ + if (!buf_rd && is_isr) { + vdev->fec.is_end = true; + + if (vdev->fec.cur_rd) + rkispp_module_work_event(dev, NULL, + vdev->fec.cur_rd, + ISPP_MODULE_NR, false); + vdev->fec.cur_rd = NULL; + } + + if (buf_rd && vdev->fec.is_end && list_empty(list)) { + /* fec read buf from nr */ + vdev->fec.cur_rd = buf_rd; + } else if (vdev->fec.is_end && !list_empty(list)) { + /* fec read buf from list + * fec processing slow than nr + * new read buf from nr into list + */ + vdev->fec.cur_rd = get_list_buf(list, false); + if (buf_rd) + list_add_tail(&buf_rd->list, list); + } else if (!vdev->fec.is_end && buf_rd) { + /* fec no idle + * new read buf from nr into list + */ + list_add_tail(&buf_rd->list, list); + } + + if (vdev->fec.cur_rd && vdev->fec.is_end) { + dummy = vdev->fec.cur_rd; + val = dummy->dma_addr; + writel(val, base + RKISPP_FEC_RD_Y_BASE); + val = dummy->dma_addr + vdev->nr.uv_offset; + writel(val, base + RKISPP_FEC_RD_UV_BASE); + is_start = true; + } + + if (vdev->fec.is_end && + stream->streaming && + stream->curr_buf && + vdev->module_ens == ISPP_MODULE_FEC) + is_start = true; + + if (is_start) { + u32 seq = 0; + + if (vdev->fec.cur_rd) + seq = vdev->fec.cur_rd->id; + writel(FEC_FORCE_UPD, base + RKISPP_CTRL_UPDATE); + v4l2_dbg(3, rkispp_debug, &dev->v4l2_dev, + "FEC start seq:%d | Y_SHD rd:0x%x\n", + seq, readl(base + RKISPP_FEC_RD_Y_BASE_SHD)); + writel(FEC_ST, base + RKISPP_CTRL_STRT); + vdev->fec.is_end = false; + } + spin_unlock_irqrestore(&vdev->fec.buf_lock, lock_flags); +} + +static void nr_work_event(struct rkispp_device *dev, + struct rkisp_ispp_buf *buf_rd, + struct rkispp_dummy_buffer *buf_wr, + bool is_isr) +{ + struct rkispp_stream_vdev *vdev = &dev->stream_vdev; + struct rkispp_stream *stream = &vdev->stream[STREAM_II]; + void __iomem *base = dev->base_addr; + struct rkispp_dummy_buffer *buf_to_fec = NULL; + struct rkispp_dummy_buffer *dummy; + struct v4l2_subdev *sd = NULL; + struct list_head *list; + struct dma_buf *dbuf; + unsigned long lock_flags = 0; + bool is_start = false, is_quick = false; + bool is_tnr_en = (vdev->module_ens & ISPP_MODULE_TNR); + u32 val; + + if (!(vdev->module_ens & (ISPP_MODULE_NR | ISPP_MODULE_SHP))) + return; + + if (dev->inp == INP_ISP) { + if (dev->isp_mode & ISP_ISPP_QUICK) + is_quick = true; + else if (!is_tnr_en) + sd = dev->ispp_sdev.remote_sd; + } + + spin_lock_irqsave(&vdev->nr.buf_lock, lock_flags); + + /* event from nr frame end */ + if (!buf_rd && !buf_wr && is_isr) { + vdev->nr.is_end = true; + + if (vdev->nr.cur_rd) { + /* nr read buf return to isp or tnr */ + if (sd) + v4l2_subdev_call(sd, video, s_rx_buffer, + vdev->nr.cur_rd, NULL); + else + rkispp_module_work_event(dev, NULL, vdev->nr.cur_rd, + ISPP_MODULE_TNR, is_isr); + vdev->nr.cur_rd = NULL; + } + + if (vdev->nr.cur_wr) { + /* nr write buf to fec */ + buf_to_fec = vdev->nr.cur_wr; + vdev->nr.cur_wr = NULL; + } + } + + list = &vdev->nr.list_rd; + if (buf_rd && vdev->nr.is_end && list_empty(list)) { + /* nr read buf from isp or tnr */ + vdev->nr.cur_rd = buf_rd; + } else if (vdev->nr.is_end && !list_empty(list)) { + /* nr read buf from list + * nr processing slow than isp or tnr + * new read buf from isp or tnr into list + */ + vdev->nr.cur_rd = get_list_buf(list, true); + if (buf_rd) + list_add_tail(&buf_rd->list, list); + } else if (!vdev->nr.is_end && buf_rd) { + /* nr no idle + * new read buf from isp or tnr into list + */ + list_add_tail(&buf_rd->list, list); + } + + list = &vdev->nr.list_wr; + if (vdev->nr.is_end && !vdev->nr.cur_wr) { + /* nr idle, get new write buf */ + vdev->nr.cur_wr = buf_wr ? buf_wr : + get_list_buf(list, false); + } else if (buf_wr) { + /* tnr no idle, write buf from nr into list */ + list_add_tail(&buf_wr->list, list); + } + + if (vdev->nr.cur_rd && vdev->nr.is_end) { + if (is_tnr_en) { + u32 size = sizeof(vdev->tnr.buf) / sizeof(*dummy); + + dbuf = vdev->nr.cur_rd->dbuf[GROUP_BUF_PIC]; + dummy = dbuf_to_dummy(dbuf, &vdev->tnr.buf.iir, size); + val = dummy->dma_addr; + writel(val, base + RKISPP_NR_ADDR_BASE_Y); + val += vdev->nr.uv_offset; + writel(val, base + RKISPP_NR_ADDR_BASE_UV); + + if (readl(base + RKISPP_TNR_CORE_CTRL) & SW_TNR_EN_SHD) { + dbuf = vdev->nr.cur_rd->dbuf[GROUP_BUF_GAIN]; + dummy = dbuf_to_dummy(dbuf, &vdev->tnr.buf.iir, size); + val = dummy->dma_addr; + writel(val, base + RKISPP_NR_ADDR_BASE_GAIN); + } + } else { + struct rkispp_isp_buf_pool *buf; + + buf = get_pool_buf(vdev, vdev->nr.cur_rd); + val = buf->dma[GROUP_BUF_PIC]; + writel(val, base + RKISPP_NR_ADDR_BASE_Y); + val += vdev->nr.uv_offset; + writel(val, base + RKISPP_NR_ADDR_BASE_UV); + + val = buf->dma[GROUP_BUF_GAIN]; + writel(val, base + RKISPP_NR_ADDR_BASE_GAIN); + } + is_start = true; + } + + if (vdev->nr.is_end && + (is_quick || + (stream->streaming && + !is_tnr_en && stream->curr_buf))) + is_start = true; + + if (vdev->nr.cur_wr && is_start) { + dummy = vdev->nr.cur_wr; + val = dummy->dma_addr; + writel(val, base + RKISPP_SHARP_WR_Y_BASE); + val = dummy->dma_addr + vdev->nr.uv_offset; + writel(val, base + RKISPP_SHARP_WR_UV_BASE); + } + + if (is_start) { + u32 seq = 0; + + if (vdev->nr.cur_rd) { + seq = vdev->nr.cur_rd->frame_id; + if (sd) + atomic_set(&dev->ispp_sdev.frm_sync_seq, + vdev->nr.cur_rd->frame_id); + if (vdev->nr.cur_wr) + vdev->nr.cur_wr->id = seq; + } + + writel(OTHER_FORCE_UPD, base + RKISPP_CTRL_UPDATE); + + v4l2_dbg(3, rkispp_debug, &dev->v4l2_dev, + "NR start seq:%d | Y_SHD rd:0x%x wr:0x%x\n", + seq, readl(base + RKISPP_NR_ADDR_BASE_Y_SHD), + readl(base + RKISPP_SHARP_WR_Y_BASE_SHD)); + + for (val = STREAM_S0; val < STREAM_MAX; val++) { + stream = &vdev->stream[val]; + if (stream->stopping && stream->ops->stop) + stream->ops->stop(stream); + } + + if (!is_quick) + writel(NR_SHP_ST, base + RKISPP_CTRL_STRT); + vdev->nr.is_end = false; + } + + /* nr_shp->fec->scl + * fec start working should after nr + * for scl will update by OTHER_FORCE_UPD + */ + if (buf_to_fec) + rkispp_module_work_event(dev, buf_to_fec, NULL, + ISPP_MODULE_FEC, is_isr); + spin_unlock_irqrestore(&vdev->nr.buf_lock, lock_flags); +} + +static void tnr_work_event(struct rkispp_device *dev, + struct rkisp_ispp_buf *buf_rd, + struct rkisp_ispp_buf *buf_wr, + bool is_isr) +{ + struct rkispp_stream_vdev *vdev = &dev->stream_vdev; + struct rkispp_stream *stream = &vdev->stream[STREAM_II]; + void __iomem *base = dev->base_addr; + struct rkispp_dummy_buffer *dummy; + struct v4l2_subdev *sd = NULL; + struct list_head *list; + struct dma_buf *dbuf; + unsigned long lock_flags = 0; + u32 val, size = sizeof(vdev->tnr.buf) / sizeof(*dummy); + bool is_3to1 = vdev->tnr.is_3to1, is_start = false; + + if (!(vdev->module_ens & ISPP_MODULE_TNR) || + (dev->inp == INP_ISP && dev->isp_mode & ISP_ISPP_QUICK)) + return; + + if (dev->inp == INP_ISP) + sd = dev->ispp_sdev.remote_sd; + + spin_lock_irqsave(&vdev->tnr.buf_lock, lock_flags); + + /* event from tnr frame end */ + if (!buf_rd && !buf_wr && is_isr) { + vdev->tnr.is_end = true; + + if (vdev->tnr.cur_rd) { + /* tnr read buf return to isp */ + v4l2_subdev_call(sd, video, s_rx_buffer, + vdev->tnr.cur_rd, NULL); + vdev->tnr.cur_rd = NULL; + } + + if (vdev->tnr.cur_wr) { + /* tnr write buf to nr */ + rkispp_module_work_event(dev, vdev->tnr.cur_wr, NULL, + ISPP_MODULE_NR, is_isr); + vdev->tnr.cur_wr = NULL; + } + } + + list = &vdev->tnr.list_rd; + if (buf_rd && vdev->tnr.is_end && list_empty(list)) { + /* tnr read buf from isp */ + vdev->tnr.cur_rd = vdev->tnr.nxt_rd; + vdev->tnr.nxt_rd = buf_rd; + if (!is_3to1) + vdev->tnr.cur_rd = vdev->tnr.nxt_rd; + } else if (vdev->tnr.is_end && !list_empty(list)) { + /* tnr read buf from list + * tnr processing slow than isp + * new read buf from isp into list + */ + vdev->tnr.cur_rd = vdev->tnr.nxt_rd; + vdev->tnr.nxt_rd = get_list_buf(list, true); + if (!is_3to1) + vdev->tnr.cur_rd = vdev->tnr.nxt_rd; + + if (buf_rd) + list_add_tail(&buf_rd->list, list); + } else if (!vdev->tnr.is_end && buf_rd) { + /* tnr no idle + * new read buf from isp into list + */ + list_add_tail(&buf_rd->list, list); + } + + list = &vdev->tnr.list_wr; + if (vdev->tnr.is_end && !vdev->tnr.cur_wr) { + /* tnr idle, get new write buf */ + vdev->tnr.cur_wr = + buf_wr ? buf_wr : get_list_buf(list, true); + } else if (buf_wr) { + /* tnr no idle, write buf from nr into list */ + list_add_tail(&buf_wr->list, list); + } + + if (vdev->tnr.cur_rd && vdev->tnr.nxt_rd && vdev->tnr.is_end) { + struct rkispp_isp_buf_pool *buf; + + buf = get_pool_buf(vdev, vdev->tnr.cur_rd); + val = buf->dma[GROUP_BUF_PIC]; + writel(val, base + RKISPP_TNR_CUR_Y_BASE); + val += vdev->tnr.uv_offset; + writel(val, base + RKISPP_TNR_CUR_UV_BASE); + + val = buf->dma[GROUP_BUF_GAIN]; + writel(val, base + RKISPP_TNR_GAIN_CUR_Y_BASE); + if (readl(base + RKISPP_TNR_CORE_CTRL) & SW_TNR_EN) { + rkispp_set_bits(base + RKISPP_CTRL_QUICK, 0, + GLB_NR_SD32_TNR); + } else { + rkispp_clear_bits(base + RKISPP_CTRL_QUICK, + GLB_NR_SD32_TNR); + writel(val, base + RKISPP_NR_ADDR_BASE_GAIN); + } + if (is_3to1) { + buf = get_pool_buf(vdev, vdev->tnr.nxt_rd); + val = buf->dma[GROUP_BUF_PIC]; + writel(val, base + RKISPP_TNR_NXT_Y_BASE); + val += vdev->tnr.uv_offset; + writel(val, base + RKISPP_TNR_NXT_UV_BASE); + + val = buf->dma[GROUP_BUF_GAIN]; + writel(val, base + RKISPP_TNR_GAIN_NXT_Y_BASE); + } else { + vdev->tnr.nxt_rd = NULL; + } + is_start = true; + } + + if (stream->streaming && + vdev->tnr.is_end && + stream->curr_buf) + is_start = true; + + if (vdev->tnr.cur_wr && is_start) { + dbuf = vdev->tnr.cur_wr->dbuf[GROUP_BUF_PIC]; + dummy = dbuf_to_dummy(dbuf, &vdev->tnr.buf.iir, size); + val = dummy->dma_addr; + writel(val, base + RKISPP_TNR_WR_Y_BASE); + val += vdev->tnr.uv_offset; + writel(val, base + RKISPP_TNR_WR_UV_BASE); + + dbuf = vdev->tnr.cur_wr->dbuf[GROUP_BUF_GAIN]; + dummy = dbuf_to_dummy(dbuf, &vdev->tnr.buf.iir, size); + val = dummy->dma_addr; + writel(val, base + RKISPP_TNR_GAIN_WR_Y_BASE); + } + + if (is_start) { + u32 seq = 0; + + if (vdev->tnr.cur_rd) { + seq = vdev->tnr.cur_rd->frame_id - is_3to1; + atomic_set(&dev->ispp_sdev.frm_sync_seq, seq); + if (vdev->tnr.cur_wr) + vdev->tnr.cur_wr->frame_id = seq; + } + + writel(TNR_FORCE_UPD, base + RKISPP_CTRL_UPDATE); + + v4l2_dbg(3, rkispp_debug, &dev->v4l2_dev, + "TNR start seq:%d | Y_SHD nxt:0x%x cur:0x%x iir:0x%x wr:0x%x\n", + seq, readl(base + RKISPP_TNR_NXT_Y_BASE_SHD), + readl(base + RKISPP_TNR_CUR_Y_BASE_SHD), + readl(base + RKISPP_TNR_IIR_Y_BASE_SHD), + readl(base + RKISPP_TNR_WR_Y_BASE_SHD)); + + /* iir using previous tnr write frame */ + writel(readl(base + RKISPP_TNR_WR_Y_BASE), + base + RKISPP_TNR_IIR_Y_BASE); + writel(readl(base + RKISPP_TNR_WR_UV_BASE), + base + RKISPP_TNR_IIR_UV_BASE); + writel(TNR_ST, base + RKISPP_CTRL_STRT); + vdev->tnr.is_end = false; + } + spin_unlock_irqrestore(&vdev->tnr.buf_lock, lock_flags); +} + +void rkispp_module_work_event(struct rkispp_device *dev, + void *buf_rd, void *buf_wr, + u32 module, bool is_isr) +{ + if (module & ISPP_MODULE_TNR) + tnr_work_event(dev, buf_rd, buf_wr, is_isr); + else if (module & ISPP_MODULE_NR) + nr_work_event(dev, buf_rd, buf_wr, is_isr); + else + fec_work_event(dev, buf_rd, is_isr); +} + void rkispp_isr(u32 mis_val, struct rkispp_device *dev) { struct rkispp_stream_vdev *vdev; @@ -1658,24 +2182,17 @@ void rkispp_isr(u32 mis_val, struct rkispp_device *dev) v4l2_err(&dev->v4l2_dev, "ispp err:0x%x\n", mis_val); - if (mis_val & (CMD_TNR_ST_DONE | CMD_NR_SHP_ST_DONE)) + if (mis_val & (CMD_TNR_ST_DONE | CMD_NR_SHP_ST_DONE) && + (dev->isp_mode & ISP_ISPP_QUICK || dev->inp == INP_DDR)) atomic_inc(&dev->ispp_sdev.frm_sync_seq); rkispp_params_isr(&dev->params_vdev, mis_val); rkispp_stats_isr(&dev->stats_vdev, mis_val); - if (mis_val & TNR_INT) { + if (mis_val & TNR_INT) if (readl(base + RKISPP_TNR_CTRL) & SW_TNR_1ST_FRM) rkispp_clear_bits(base + RKISPP_TNR_CTRL, SW_TNR_1ST_FRM); - if (dev->inp == INP_DDR && - vdev->module_ens & (ISPP_MODULE_NR | ISPP_MODULE_SHP)) - writel(NR_SHP_ST, base + RKISPP_CTRL_STRT); - } - - if (mis_val & SHP_INT && - vdev->module_ens & ISPP_MODULE_FEC) - writel(FEC_ST, base + RKISPP_CTRL_STRT); for (i = 0; i < STREAM_MAX; i++) { stream = &vdev->stream[i]; @@ -1683,20 +2200,19 @@ void rkispp_isr(u32 mis_val, struct rkispp_device *dev) if (!stream->streaming || !(mis_val & INT_FRAME(stream))) continue; - if (stream->stopping) { - if (stream->ops->is_stopped && - stream->ops->is_stopped(stream)) { - stream->stopping = false; - stream->streaming = false; - wake_up(&stream->done); - } + if (stream->stopping && + stream->ops->is_stopped && + stream->ops->is_stopped(stream)) { + stream->stopping = false; + stream->streaming = false; + stream->is_upd = false; + wake_up(&stream->done); } else { rkispp_frame_end(stream); } } - if (vdev->is_update_manual) - check_to_force_update(dev, mis_val); + check_to_force_update(dev, mis_val); } int rkispp_register_stream_vdevs(struct rkispp_device *dev) @@ -1710,6 +2226,14 @@ int rkispp_register_stream_vdevs(struct rkispp_device *dev) stream_vdev = &dev->stream_vdev; memset(stream_vdev, 0, sizeof(*stream_vdev)); atomic_set(&stream_vdev->refcnt, 0); + INIT_LIST_HEAD(&stream_vdev->tnr.list_rd); + INIT_LIST_HEAD(&stream_vdev->tnr.list_wr); + INIT_LIST_HEAD(&stream_vdev->nr.list_rd); + INIT_LIST_HEAD(&stream_vdev->nr.list_wr); + INIT_LIST_HEAD(&stream_vdev->fec.list_rd); + spin_lock_init(&stream_vdev->tnr.buf_lock); + spin_lock_init(&stream_vdev->nr.buf_lock); + spin_lock_init(&stream_vdev->fec.buf_lock); for (i = 0; i < STREAM_MAX; i++) { stream = &stream_vdev->stream[i]; diff --git a/drivers/media/platform/rockchip/ispp/stream.h b/drivers/media/platform/rockchip/ispp/stream.h index 7de3b8f43182..5bcc69111289 100644 --- a/drivers/media/platform/rockchip/ispp/stream.h +++ b/drivers/media/platform/rockchip/ispp/stream.h @@ -6,6 +6,7 @@ #include "common.h" +#define RKISPP_BUF_POOL_MAX (RKISP_ISPP_BUF_MAX + 1) struct rkispp_stream; /* @@ -73,24 +74,55 @@ enum stream_type { STREAM_OUTPUT, }; -/* tnr internal using buf */ -struct in_tnr_buf { - struct rkispp_dummy_buffer pic_cur; - struct rkispp_dummy_buffer pic_next; - struct rkispp_dummy_buffer gain_cur; - struct rkispp_dummy_buffer gain_next; - struct rkispp_dummy_buffer gain_kg; - struct rkispp_dummy_buffer iir; - struct rkispp_dummy_buffer pic_wr; - struct rkispp_dummy_buffer gain_wr; +/* internal using buf */ + +struct rkispp_isp_buf_pool { + struct rkisp_ispp_buf *dbufs; + void *mem_priv[GROUP_BUF_MAX]; + dma_addr_t dma[GROUP_BUF_MAX]; +}; + +struct in_tnr_buf { + struct rkispp_dummy_buffer iir; + struct rkispp_dummy_buffer gain_kg; + struct rkispp_dummy_buffer wr[RKISP_ISPP_BUF_MAX][GROUP_BUF_MAX]; }; -/* nr internal using buf */ struct in_nr_buf { - struct rkispp_dummy_buffer pic_cur; - struct rkispp_dummy_buffer gain_cur; - struct rkispp_dummy_buffer pic_wr; struct rkispp_dummy_buffer tmp_yuv; + struct rkispp_dummy_buffer wr[RKISP_ISPP_BUF_MAX]; +}; + +struct tnr_module { + struct in_tnr_buf buf; + struct list_head list_rd; + struct list_head list_wr; + spinlock_t buf_lock; + struct rkisp_ispp_buf *cur_rd; + struct rkisp_ispp_buf *nxt_rd; + struct rkisp_ispp_buf *cur_wr; + u32 uv_offset; + bool is_end; + bool is_3to1; +}; + +struct nr_module { + struct in_nr_buf buf; + struct list_head list_rd; + struct list_head list_wr; + spinlock_t buf_lock; + struct rkisp_ispp_buf *cur_rd; + struct rkispp_dummy_buffer *cur_wr; + u32 uv_offset; + bool is_end; +}; + +struct fec_module { + struct list_head list_rd; + struct rkispp_dummy_buffer *cur_rd; + spinlock_t buf_lock; + u32 uv_offset; + bool is_end; }; /* fec internal using buf */ @@ -134,22 +166,29 @@ struct rkispp_stream { struct capture_fmt out_cap_fmt; struct v4l2_pix_format_mplane out_fmt; u8 last_module; - u8 streaming; - u8 stopping; - u8 linked; + bool streaming; + bool stopping; + bool linked; + bool is_upd; }; /* rkispp stream device */ struct rkispp_stream_vdev { struct rkispp_stream stream[STREAM_MAX]; - struct in_tnr_buf tnr_buf; - struct in_nr_buf nr_buf; + struct rkispp_isp_buf_pool pool[RKISPP_BUF_POOL_MAX]; + struct tnr_module tnr; + struct nr_module nr; + struct fec_module fec; struct in_fec_buf fec_buf; atomic_t refcnt; u32 module_ens; - u8 is_update_manual; + u32 irq_ends; }; +void rkispp_free_pool(struct rkispp_stream_vdev *vdev); +void rkispp_module_work_event(struct rkispp_device *dev, + void *buf_rd, void *buf_wr, + u32 module, bool is_isr); void rkispp_isr(u32 mis_val, struct rkispp_device *dev); void rkispp_unregister_stream_vdevs(struct rkispp_device *dev); int rkispp_register_stream_vdevs(struct rkispp_device *dev);