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