xref: /OK3568_Linux_fs/kernel/drivers/media/platform/rockchip/ispp/stats.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun #include <linux/kfifo.h>
5*4882a593Smuzhiyun #include <media/v4l2-common.h>
6*4882a593Smuzhiyun #include <media/v4l2-ioctl.h>
7*4882a593Smuzhiyun #include <media/videobuf2-core.h>
8*4882a593Smuzhiyun #include <media/videobuf2-vmalloc.h>	/* for ISP statistics */
9*4882a593Smuzhiyun #include <media/videobuf2-dma-contig.h>
10*4882a593Smuzhiyun #include <media/videobuf2-dma-sg.h>
11*4882a593Smuzhiyun #include <media/v4l2-mc.h>
12*4882a593Smuzhiyun #include <uapi/linux/rk-video-format.h>
13*4882a593Smuzhiyun #include "dev.h"
14*4882a593Smuzhiyun #include "regs.h"
15*4882a593Smuzhiyun #include "stats.h"
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #define RKISPP_STATS_REQ_BUFS_MIN 2
18*4882a593Smuzhiyun #define RKISPP_STATS_REQ_BUFS_MAX 8
19*4882a593Smuzhiyun 
update_addr(struct rkispp_stats_vdev * stats_vdev)20*4882a593Smuzhiyun static void update_addr(struct rkispp_stats_vdev *stats_vdev)
21*4882a593Smuzhiyun {
22*4882a593Smuzhiyun 	struct rkispp_dummy_buffer *dummy_buf;
23*4882a593Smuzhiyun 	u32 addr;
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun 	if (stats_vdev->curr_buf) {
26*4882a593Smuzhiyun 		addr = stats_vdev->curr_buf->buff_addr[0];
27*4882a593Smuzhiyun 		rkispp_write(stats_vdev->dev, RKISPP_ORB_WR_BASE, addr);
28*4882a593Smuzhiyun 	}
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun 	if (!stats_vdev->curr_buf) {
31*4882a593Smuzhiyun 		dummy_buf = &stats_vdev->dev->hw_dev->dummy_buf;
32*4882a593Smuzhiyun 		if (!dummy_buf->mem_priv)
33*4882a593Smuzhiyun 			return;
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun 		rkispp_write(stats_vdev->dev, RKISPP_ORB_WR_BASE, dummy_buf->dma_addr);
36*4882a593Smuzhiyun 	}
37*4882a593Smuzhiyun }
38*4882a593Smuzhiyun 
rkispp_stats_frame_end(struct rkispp_stats_vdev * stats_vdev)39*4882a593Smuzhiyun static int rkispp_stats_frame_end(struct rkispp_stats_vdev *stats_vdev)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun 	void __iomem *base = stats_vdev->dev->hw_dev->base_addr;
42*4882a593Smuzhiyun 	struct rkispp_device *dev = stats_vdev->dev;
43*4882a593Smuzhiyun 	struct rkispp_stream_vdev *vdev = &dev->stream_vdev;
44*4882a593Smuzhiyun 	unsigned long lock_flags = 0;
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	if (stats_vdev->curr_buf) {
47*4882a593Smuzhiyun 		u32 payload_size = 0;
48*4882a593Smuzhiyun 		u64 ns = ktime_get_ns();
49*4882a593Smuzhiyun 		u32 cur_frame_id = stats_vdev->frame_id;
50*4882a593Smuzhiyun 		struct rkispp_buffer *curr_buf = stats_vdev->curr_buf;
51*4882a593Smuzhiyun 		void *vaddr = vb2_plane_vaddr(&curr_buf->vb.vb2_buf, 0);
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 		if (stats_vdev->vdev_id == STATS_VDEV_TNR) {
54*4882a593Smuzhiyun 			struct rkispp_stats_tnrbuf *tnrbuf = vaddr;
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 			payload_size = sizeof(struct rkispp_stats_tnrbuf);
57*4882a593Smuzhiyun 			tnrbuf->frame_id = cur_frame_id;
58*4882a593Smuzhiyun 			tnrbuf->gain.index = -1;
59*4882a593Smuzhiyun 			tnrbuf->gainkg.index = -1;
60*4882a593Smuzhiyun 			if (vdev->tnr.cur_wr) {
61*4882a593Smuzhiyun 				tnrbuf->gain.index = vdev->tnr.cur_wr->didx[GROUP_BUF_GAIN];
62*4882a593Smuzhiyun 				tnrbuf->gain.size = vdev->tnr.cur_wr->dbuf[GROUP_BUF_GAIN]->size;
63*4882a593Smuzhiyun 				tnrbuf->gainkg.index = vdev->tnr.buf.gain_kg.index;
64*4882a593Smuzhiyun 				tnrbuf->gainkg.size = vdev->tnr.buf.gain_kg.size;
65*4882a593Smuzhiyun 			}
66*4882a593Smuzhiyun 		} else if (stats_vdev->vdev_id == STATS_VDEV_NR) {
67*4882a593Smuzhiyun 			struct rkispp_stats_nrbuf *nrbuf = vaddr;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 			payload_size = sizeof(struct rkispp_stats_nrbuf);
70*4882a593Smuzhiyun 			nrbuf->total_num = readl(base + RKISPP_ORB_TOTAL_NUM);
71*4882a593Smuzhiyun 			nrbuf->frame_id = cur_frame_id;
72*4882a593Smuzhiyun 			nrbuf->image.index = -1;
73*4882a593Smuzhiyun 			if (vdev->nr.cur_wr &&
74*4882a593Smuzhiyun 			    (dev->stream_vdev.module_ens & ISPP_MODULE_FEC_ST) == ISPP_MODULE_FEC_ST) {
75*4882a593Smuzhiyun 				nrbuf->image.index = vdev->nr.cur_wr->index;
76*4882a593Smuzhiyun 				nrbuf->image.size = vdev->nr.cur_wr->size;
77*4882a593Smuzhiyun 				v4l2_dbg(3, rkispp_debug, &dev->v4l2_dev,
78*4882a593Smuzhiyun 					 "%s frame:%d nr output buf index:%d fd:%d dma:%pad\n",
79*4882a593Smuzhiyun 					 __func__, cur_frame_id,
80*4882a593Smuzhiyun 					 vdev->nr.cur_wr->index,
81*4882a593Smuzhiyun 					 vdev->nr.cur_wr->dma_fd,
82*4882a593Smuzhiyun 					 &vdev->nr.cur_wr->dma_addr);
83*4882a593Smuzhiyun 			}
84*4882a593Smuzhiyun 		}
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 		curr_buf->vb.vb2_buf.timestamp = ns;
87*4882a593Smuzhiyun 		curr_buf->vb.sequence = cur_frame_id;
88*4882a593Smuzhiyun 		vb2_set_plane_payload(&curr_buf->vb.vb2_buf, 0, payload_size);
89*4882a593Smuzhiyun 		vb2_buffer_done(&curr_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
90*4882a593Smuzhiyun 		stats_vdev->curr_buf = NULL;
91*4882a593Smuzhiyun 	}
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	spin_lock_irqsave(&stats_vdev->irq_lock, lock_flags);
94*4882a593Smuzhiyun 	if (!list_empty(&stats_vdev->stat)) {
95*4882a593Smuzhiyun 		stats_vdev->curr_buf = list_first_entry(&stats_vdev->stat,
96*4882a593Smuzhiyun 					struct rkispp_buffer, queue);
97*4882a593Smuzhiyun 		list_del(&stats_vdev->curr_buf->queue);
98*4882a593Smuzhiyun 	}
99*4882a593Smuzhiyun 	spin_unlock_irqrestore(&stats_vdev->irq_lock, lock_flags);
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	if (stats_vdev->vdev_id == STATS_VDEV_NR)
102*4882a593Smuzhiyun 		update_addr(stats_vdev);
103*4882a593Smuzhiyun 	return 0;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
rkispp_stats_enum_fmt_meta_cap(struct file * file,void * priv,struct v4l2_fmtdesc * f)106*4882a593Smuzhiyun static int rkispp_stats_enum_fmt_meta_cap(struct file *file, void *priv,
107*4882a593Smuzhiyun 					  struct v4l2_fmtdesc *f)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun 	struct video_device *video = video_devdata(file);
110*4882a593Smuzhiyun 	struct rkispp_stats_vdev *stats_vdev = video_get_drvdata(video);
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	if (f->index > 0 || f->type != video->queue->type)
113*4882a593Smuzhiyun 		return -EINVAL;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	f->pixelformat = stats_vdev->vdev_fmt.fmt.meta.dataformat;
116*4882a593Smuzhiyun 	return 0;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun 
rkispp_stats_g_fmt_meta_cap(struct file * file,void * priv,struct v4l2_format * f)119*4882a593Smuzhiyun static int rkispp_stats_g_fmt_meta_cap(struct file *file, void *priv,
120*4882a593Smuzhiyun 				       struct v4l2_format *f)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun 	struct video_device *video = video_devdata(file);
123*4882a593Smuzhiyun 	struct rkispp_stats_vdev *stats_vdev = video_get_drvdata(video);
124*4882a593Smuzhiyun 	struct v4l2_meta_format *meta = &f->fmt.meta;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	if (f->type != video->queue->type)
127*4882a593Smuzhiyun 		return -EINVAL;
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	memset(meta, 0, sizeof(*meta));
130*4882a593Smuzhiyun 	meta->dataformat = stats_vdev->vdev_fmt.fmt.meta.dataformat;
131*4882a593Smuzhiyun 	meta->buffersize = stats_vdev->vdev_fmt.fmt.meta.buffersize;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	return 0;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun 
rkispp_stats_querycap(struct file * file,void * priv,struct v4l2_capability * cap)136*4882a593Smuzhiyun static int rkispp_stats_querycap(struct file *file,
137*4882a593Smuzhiyun 				 void *priv, struct v4l2_capability *cap)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun 	struct video_device *vdev = video_devdata(file);
140*4882a593Smuzhiyun 	struct rkispp_stats_vdev *stats_vdev = video_get_drvdata(vdev);
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	strcpy(cap->driver, DRIVER_NAME);
143*4882a593Smuzhiyun 	snprintf(cap->driver, sizeof(cap->driver),
144*4882a593Smuzhiyun 		 "%s_v%d", DRIVER_NAME,
145*4882a593Smuzhiyun 		 stats_vdev->dev->ispp_ver >> 4);
146*4882a593Smuzhiyun 	strlcpy(cap->card, vdev->name, sizeof(cap->card));
147*4882a593Smuzhiyun 	strlcpy(cap->bus_info, "platform: " DRIVER_NAME, sizeof(cap->bus_info));
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	return 0;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun 
rkispp_stats_fh_open(struct file * filp)152*4882a593Smuzhiyun static int rkispp_stats_fh_open(struct file *filp)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun 	struct rkispp_stats_vdev *stats = video_drvdata(filp);
155*4882a593Smuzhiyun 	struct rkispp_device *isppdev = stats->dev;
156*4882a593Smuzhiyun 	int ret;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	ret = v4l2_fh_open(filp);
159*4882a593Smuzhiyun 	if (!ret) {
160*4882a593Smuzhiyun 		ret = v4l2_pipeline_pm_get(&stats->vnode.vdev.entity);
161*4882a593Smuzhiyun 		if (ret < 0) {
162*4882a593Smuzhiyun 			v4l2_err(&isppdev->v4l2_dev,
163*4882a593Smuzhiyun 				 "pipeline power on failed %d\n", ret);
164*4882a593Smuzhiyun 			vb2_fop_release(filp);
165*4882a593Smuzhiyun 		}
166*4882a593Smuzhiyun 	}
167*4882a593Smuzhiyun 	return ret;
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun 
rkispp_stats_fh_release(struct file * filp)170*4882a593Smuzhiyun static int rkispp_stats_fh_release(struct file *filp)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	struct rkispp_stats_vdev *stats = video_drvdata(filp);
173*4882a593Smuzhiyun 	int ret;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	ret = vb2_fop_release(filp);
176*4882a593Smuzhiyun 	if (!ret)
177*4882a593Smuzhiyun 		v4l2_pipeline_pm_put(&stats->vnode.vdev.entity);
178*4882a593Smuzhiyun 	return ret;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun /* ISP video device IOCTLs */
182*4882a593Smuzhiyun static const struct v4l2_ioctl_ops rkispp_stats_ioctl = {
183*4882a593Smuzhiyun 	.vidioc_reqbufs = vb2_ioctl_reqbufs,
184*4882a593Smuzhiyun 	.vidioc_querybuf = vb2_ioctl_querybuf,
185*4882a593Smuzhiyun 	.vidioc_create_bufs = vb2_ioctl_create_bufs,
186*4882a593Smuzhiyun 	.vidioc_qbuf = vb2_ioctl_qbuf,
187*4882a593Smuzhiyun 	.vidioc_dqbuf = vb2_ioctl_dqbuf,
188*4882a593Smuzhiyun 	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
189*4882a593Smuzhiyun 	.vidioc_expbuf = vb2_ioctl_expbuf,
190*4882a593Smuzhiyun 	.vidioc_streamon = vb2_ioctl_streamon,
191*4882a593Smuzhiyun 	.vidioc_streamoff = vb2_ioctl_streamoff,
192*4882a593Smuzhiyun 	.vidioc_enum_fmt_meta_cap = rkispp_stats_enum_fmt_meta_cap,
193*4882a593Smuzhiyun 	.vidioc_g_fmt_meta_cap = rkispp_stats_g_fmt_meta_cap,
194*4882a593Smuzhiyun 	.vidioc_s_fmt_meta_cap = rkispp_stats_g_fmt_meta_cap,
195*4882a593Smuzhiyun 	.vidioc_try_fmt_meta_cap = rkispp_stats_g_fmt_meta_cap,
196*4882a593Smuzhiyun 	.vidioc_querycap = rkispp_stats_querycap
197*4882a593Smuzhiyun };
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun struct v4l2_file_operations rkispp_stats_fops = {
200*4882a593Smuzhiyun 	.mmap = vb2_fop_mmap,
201*4882a593Smuzhiyun 	.unlocked_ioctl = video_ioctl2,
202*4882a593Smuzhiyun 	.poll = vb2_fop_poll,
203*4882a593Smuzhiyun 	.open = rkispp_stats_fh_open,
204*4882a593Smuzhiyun 	.release = rkispp_stats_fh_release,
205*4882a593Smuzhiyun };
206*4882a593Smuzhiyun 
rkispp_stats_vb2_queue_setup(struct vb2_queue * vq,unsigned int * num_buffers,unsigned int * num_planes,unsigned int sizes[],struct device * alloc_ctxs[])207*4882a593Smuzhiyun static int rkispp_stats_vb2_queue_setup(struct vb2_queue *vq,
208*4882a593Smuzhiyun 					unsigned int *num_buffers,
209*4882a593Smuzhiyun 					unsigned int *num_planes,
210*4882a593Smuzhiyun 					unsigned int sizes[],
211*4882a593Smuzhiyun 					struct device *alloc_ctxs[])
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun 	struct rkispp_stats_vdev *stats_vdev = vq->drv_priv;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	*num_planes = 1;
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	*num_buffers = clamp_t(u32, *num_buffers, RKISPP_STATS_REQ_BUFS_MIN,
218*4882a593Smuzhiyun 			       RKISPP_STATS_REQ_BUFS_MAX);
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	switch (stats_vdev->vdev_id) {
221*4882a593Smuzhiyun 	case STATS_VDEV_TNR:
222*4882a593Smuzhiyun 		sizes[0] = sizeof(struct rkispp_stats_tnrbuf);
223*4882a593Smuzhiyun 		break;
224*4882a593Smuzhiyun 	case STATS_VDEV_NR:
225*4882a593Smuzhiyun 	default:
226*4882a593Smuzhiyun 		sizes[0] = sizeof(struct rkispp_stats_nrbuf);
227*4882a593Smuzhiyun 		break;
228*4882a593Smuzhiyun 	}
229*4882a593Smuzhiyun 	INIT_LIST_HEAD(&stats_vdev->stat);
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	return 0;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun 
rkispp_stats_vb2_buf_queue(struct vb2_buffer * vb)234*4882a593Smuzhiyun static void rkispp_stats_vb2_buf_queue(struct vb2_buffer *vb)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
237*4882a593Smuzhiyun 	struct rkispp_buffer *buf = to_rkispp_buffer(vbuf);
238*4882a593Smuzhiyun 	struct vb2_queue *vq = vb->vb2_queue;
239*4882a593Smuzhiyun 	struct rkispp_stats_vdev *stats_dev = vq->drv_priv;
240*4882a593Smuzhiyun 	unsigned long lock_flags = 0;
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	vb2_plane_vaddr(vb, 0);
243*4882a593Smuzhiyun 	if (stats_dev->dev->hw_dev->is_dma_sg_ops) {
244*4882a593Smuzhiyun 		struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 		buf->buff_addr[0] = sg_dma_address(sgt->sgl);
247*4882a593Smuzhiyun 	} else {
248*4882a593Smuzhiyun 		buf->buff_addr[0] = vb2_dma_contig_plane_dma_addr(vb, 0);
249*4882a593Smuzhiyun 	}
250*4882a593Smuzhiyun 	spin_lock_irqsave(&stats_dev->irq_lock, lock_flags);
251*4882a593Smuzhiyun 	list_add_tail(&buf->queue, &stats_dev->stat);
252*4882a593Smuzhiyun 	spin_unlock_irqrestore(&stats_dev->irq_lock, lock_flags);
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun 
destroy_buf_queue(struct rkispp_stats_vdev * stats_vdev,enum vb2_buffer_state state)255*4882a593Smuzhiyun static void destroy_buf_queue(struct rkispp_stats_vdev *stats_vdev,
256*4882a593Smuzhiyun 			      enum vb2_buffer_state state)
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun 	struct rkispp_buffer *buf;
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	if (stats_vdev->curr_buf) {
261*4882a593Smuzhiyun 		list_add_tail(&stats_vdev->curr_buf->queue, &stats_vdev->stat);
262*4882a593Smuzhiyun 		stats_vdev->curr_buf = NULL;
263*4882a593Smuzhiyun 	}
264*4882a593Smuzhiyun 	while (!list_empty(&stats_vdev->stat)) {
265*4882a593Smuzhiyun 		buf = list_first_entry(&stats_vdev->stat,
266*4882a593Smuzhiyun 			struct rkispp_buffer, queue);
267*4882a593Smuzhiyun 		list_del(&buf->queue);
268*4882a593Smuzhiyun 		vb2_buffer_done(&buf->vb.vb2_buf, state);
269*4882a593Smuzhiyun 	}
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun 
rkispp_stats_vb2_stop_streaming(struct vb2_queue * vq)272*4882a593Smuzhiyun static void rkispp_stats_vb2_stop_streaming(struct vb2_queue *vq)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun 	struct rkispp_stats_vdev *stats_vdev = vq->drv_priv;
275*4882a593Smuzhiyun 	unsigned long flags;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	spin_lock_irqsave(&stats_vdev->irq_lock, flags);
278*4882a593Smuzhiyun 	stats_vdev->streamon = false;
279*4882a593Smuzhiyun 	destroy_buf_queue(stats_vdev, VB2_BUF_STATE_ERROR);
280*4882a593Smuzhiyun 	spin_unlock_irqrestore(&stats_vdev->irq_lock, flags);
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun static int
rkispp_stats_vb2_start_streaming(struct vb2_queue * queue,unsigned int count)284*4882a593Smuzhiyun rkispp_stats_vb2_start_streaming(struct vb2_queue *queue,
285*4882a593Smuzhiyun 				 unsigned int count)
286*4882a593Smuzhiyun {
287*4882a593Smuzhiyun 	struct rkispp_stats_vdev *stats_vdev = queue->drv_priv;
288*4882a593Smuzhiyun 	unsigned long flags;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	if (stats_vdev->streamon)
291*4882a593Smuzhiyun 		return -EBUSY;
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	/* config first buf */
294*4882a593Smuzhiyun 	rkispp_stats_frame_end(stats_vdev);
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	spin_lock_irqsave(&stats_vdev->irq_lock, flags);
297*4882a593Smuzhiyun 	stats_vdev->streamon = true;
298*4882a593Smuzhiyun 	spin_unlock_irqrestore(&stats_vdev->irq_lock, flags);
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	return 0;
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun static struct vb2_ops rkispp_stats_vb2_ops = {
304*4882a593Smuzhiyun 	.queue_setup = rkispp_stats_vb2_queue_setup,
305*4882a593Smuzhiyun 	.buf_queue = rkispp_stats_vb2_buf_queue,
306*4882a593Smuzhiyun 	.wait_prepare = vb2_ops_wait_prepare,
307*4882a593Smuzhiyun 	.wait_finish = vb2_ops_wait_finish,
308*4882a593Smuzhiyun 	.stop_streaming = rkispp_stats_vb2_stop_streaming,
309*4882a593Smuzhiyun 	.start_streaming = rkispp_stats_vb2_start_streaming,
310*4882a593Smuzhiyun };
311*4882a593Smuzhiyun 
rkispp_stats_init_vb2_queue(struct vb2_queue * q,struct rkispp_stats_vdev * stats_vdev)312*4882a593Smuzhiyun static int rkispp_stats_init_vb2_queue(struct vb2_queue *q,
313*4882a593Smuzhiyun 				       struct rkispp_stats_vdev *stats_vdev)
314*4882a593Smuzhiyun {
315*4882a593Smuzhiyun 	q->type = V4L2_BUF_TYPE_META_CAPTURE;
316*4882a593Smuzhiyun 	q->io_modes = VB2_MMAP | VB2_USERPTR;
317*4882a593Smuzhiyun 	q->drv_priv = stats_vdev;
318*4882a593Smuzhiyun 	q->ops = &rkispp_stats_vb2_ops;
319*4882a593Smuzhiyun 	q->mem_ops = stats_vdev->dev->hw_dev->mem_ops;
320*4882a593Smuzhiyun 	q->buf_struct_size = sizeof(struct rkispp_buffer);
321*4882a593Smuzhiyun 	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
322*4882a593Smuzhiyun 	q->lock = &stats_vdev->dev->iqlock;
323*4882a593Smuzhiyun 	q->dev = stats_vdev->dev->hw_dev->dev;
324*4882a593Smuzhiyun 	if (stats_vdev->dev->hw_dev->is_dma_contig)
325*4882a593Smuzhiyun 		q->dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS;
326*4882a593Smuzhiyun 	q->gfp_flags = GFP_DMA32;
327*4882a593Smuzhiyun 	return vb2_queue_init(q);
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun 
rkispp_stats_isr(struct rkispp_stats_vdev * stats_vdev)330*4882a593Smuzhiyun void rkispp_stats_isr(struct rkispp_stats_vdev *stats_vdev)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun 	spin_lock(&stats_vdev->irq_lock);
333*4882a593Smuzhiyun 	if (!stats_vdev->streamon) {
334*4882a593Smuzhiyun 		spin_unlock(&stats_vdev->irq_lock);
335*4882a593Smuzhiyun 		return;
336*4882a593Smuzhiyun 	}
337*4882a593Smuzhiyun 	spin_unlock(&stats_vdev->irq_lock);
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	rkispp_stats_frame_end(stats_vdev);
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun 
rkispp_init_stats_vdev(struct rkispp_stats_vdev * stats_vdev)342*4882a593Smuzhiyun static void rkispp_init_stats_vdev(struct rkispp_stats_vdev *stats_vdev)
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun 	stats_vdev->vdev_fmt.fmt.meta.dataformat = V4L2_META_FMT_RK_ISPP_STAT;
345*4882a593Smuzhiyun 	switch (stats_vdev->vdev_id) {
346*4882a593Smuzhiyun 	case STATS_VDEV_TNR:
347*4882a593Smuzhiyun 		stats_vdev->vdev_fmt.fmt.meta.buffersize =
348*4882a593Smuzhiyun 			sizeof(struct rkispp_stats_tnrbuf);
349*4882a593Smuzhiyun 		break;
350*4882a593Smuzhiyun 	case STATS_VDEV_NR:
351*4882a593Smuzhiyun 	default:
352*4882a593Smuzhiyun 		stats_vdev->vdev_fmt.fmt.meta.buffersize =
353*4882a593Smuzhiyun 			sizeof(struct rkispp_stats_nrbuf);
354*4882a593Smuzhiyun 		break;
355*4882a593Smuzhiyun 	}
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun 
rkispp_register_stats_vdev(struct rkispp_device * dev,enum rkispp_statsvdev_id vdev_id)358*4882a593Smuzhiyun static int rkispp_register_stats_vdev(struct rkispp_device *dev,
359*4882a593Smuzhiyun 				      enum rkispp_statsvdev_id vdev_id)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun 	struct rkispp_stats_vdev *stats_vdev = &dev->stats_vdev[vdev_id];
362*4882a593Smuzhiyun 	struct rkispp_vdev_node *node = &stats_vdev->vnode;
363*4882a593Smuzhiyun 	struct video_device *vdev = &node->vdev;
364*4882a593Smuzhiyun 	int ret;
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	stats_vdev->dev = dev;
367*4882a593Smuzhiyun 	stats_vdev->vdev_id = vdev_id;
368*4882a593Smuzhiyun 	INIT_LIST_HEAD(&stats_vdev->stat);
369*4882a593Smuzhiyun 	spin_lock_init(&stats_vdev->irq_lock);
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	switch (vdev_id) {
372*4882a593Smuzhiyun 	case STATS_VDEV_TNR:
373*4882a593Smuzhiyun 		strncpy(vdev->name, "rkispp_tnr_stats", sizeof(vdev->name) - 1);
374*4882a593Smuzhiyun 		break;
375*4882a593Smuzhiyun 	case STATS_VDEV_NR:
376*4882a593Smuzhiyun 	default:
377*4882a593Smuzhiyun 		strncpy(vdev->name, "rkispp_nr_stats", sizeof(vdev->name) - 1);
378*4882a593Smuzhiyun 		break;
379*4882a593Smuzhiyun 	}
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	vdev->ioctl_ops = &rkispp_stats_ioctl;
382*4882a593Smuzhiyun 	vdev->fops = &rkispp_stats_fops;
383*4882a593Smuzhiyun 	vdev->release = video_device_release_empty;
384*4882a593Smuzhiyun 	vdev->lock = &dev->iqlock;
385*4882a593Smuzhiyun 	vdev->v4l2_dev = &dev->v4l2_dev;
386*4882a593Smuzhiyun 	vdev->queue = &node->buf_queue;
387*4882a593Smuzhiyun 	vdev->device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING;
388*4882a593Smuzhiyun 	vdev->vfl_dir =  VFL_DIR_RX;
389*4882a593Smuzhiyun 	rkispp_stats_init_vb2_queue(vdev->queue, stats_vdev);
390*4882a593Smuzhiyun 	rkispp_init_stats_vdev(stats_vdev);
391*4882a593Smuzhiyun 	video_set_drvdata(vdev, stats_vdev);
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	node->pad.flags = MEDIA_PAD_FL_SINK;
394*4882a593Smuzhiyun 	ret = media_entity_pads_init(&vdev->entity, 1, &node->pad);
395*4882a593Smuzhiyun 	if (ret < 0)
396*4882a593Smuzhiyun 		goto err_release_queue;
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
399*4882a593Smuzhiyun 	if (ret < 0) {
400*4882a593Smuzhiyun 		dev_err(&vdev->dev,
401*4882a593Smuzhiyun 			"could not register Video for Linux device\n");
402*4882a593Smuzhiyun 		goto err_cleanup_media_entity;
403*4882a593Smuzhiyun 	}
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	return 0;
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun err_cleanup_media_entity:
408*4882a593Smuzhiyun 	media_entity_cleanup(&vdev->entity);
409*4882a593Smuzhiyun err_release_queue:
410*4882a593Smuzhiyun 	vb2_queue_release(vdev->queue);
411*4882a593Smuzhiyun 	return ret;
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun 
rkispp_unregister_stats_vdev(struct rkispp_device * dev,enum rkispp_statsvdev_id vdev_id)414*4882a593Smuzhiyun static void rkispp_unregister_stats_vdev(struct rkispp_device *dev,
415*4882a593Smuzhiyun 					 enum rkispp_statsvdev_id vdev_id)
416*4882a593Smuzhiyun {
417*4882a593Smuzhiyun 	struct rkispp_stats_vdev *stats_vdev = &dev->stats_vdev[vdev_id];
418*4882a593Smuzhiyun 	struct rkispp_vdev_node *node = &stats_vdev->vnode;
419*4882a593Smuzhiyun 	struct video_device *vdev = &node->vdev;
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	video_unregister_device(vdev);
422*4882a593Smuzhiyun 	media_entity_cleanup(&vdev->entity);
423*4882a593Smuzhiyun 	vb2_queue_release(vdev->queue);
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun 
rkispp_register_stats_vdevs(struct rkispp_device * dev)426*4882a593Smuzhiyun int rkispp_register_stats_vdevs(struct rkispp_device *dev)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun 	int ret = 0;
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	if (dev->ispp_ver != ISPP_V10)
431*4882a593Smuzhiyun 		return 0;
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	ret = rkispp_register_stats_vdev(dev, STATS_VDEV_TNR);
434*4882a593Smuzhiyun 	if (ret)
435*4882a593Smuzhiyun 		return ret;
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	ret = rkispp_register_stats_vdev(dev, STATS_VDEV_NR);
438*4882a593Smuzhiyun 	if (ret) {
439*4882a593Smuzhiyun 		rkispp_unregister_stats_vdev(dev, STATS_VDEV_TNR);
440*4882a593Smuzhiyun 		return ret;
441*4882a593Smuzhiyun 	}
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	return ret;
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun 
rkispp_unregister_stats_vdevs(struct rkispp_device * dev)446*4882a593Smuzhiyun void rkispp_unregister_stats_vdevs(struct rkispp_device *dev)
447*4882a593Smuzhiyun {
448*4882a593Smuzhiyun 	if (dev->ispp_ver != ISPP_V10)
449*4882a593Smuzhiyun 		return;
450*4882a593Smuzhiyun 	rkispp_unregister_stats_vdev(dev, STATS_VDEV_TNR);
451*4882a593Smuzhiyun 	rkispp_unregister_stats_vdev(dev, STATS_VDEV_NR);
452*4882a593Smuzhiyun }
453