1 /*
2 * linux-5.4/drivers/media/platform/sunxi-vin/vin-stat/vin_h3a.c
3 *
4 * Copyright (c) 2007-2017 Allwinnertech Co., Ltd.
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17 #include <linux/slab.h>
18 #include <linux/uaccess.h>
19
20 #include "vin_h3a.h"
21
22 #include "../vin-isp/sunxi_isp.h"
23 #include "../vin-video/vin_video.h"
24
__isp_stat_buf_find(struct isp_stat * stat,int look_empty)25 static struct ispstat_buffer *__isp_stat_buf_find(struct isp_stat *stat, int look_empty)
26 {
27 struct ispstat_buffer *found = NULL;
28 int i;
29
30 for (i = 0; i < stat->buf_cnt; i++) {
31 struct ispstat_buffer *curr = &stat->buf[i];
32
33 /*
34 * Don't select the buffer which is being copied to
35 * userspace or used by the module.
36 */
37 if (curr == stat->locked_buf || curr == stat->active_buf)
38 continue;
39
40 /* Don't select uninitialised buffers if it's not required */
41 if (!look_empty && curr->empty)
42 continue;
43
44 if (curr->empty) {
45 found = curr;
46 break;
47 }
48
49 if (!found ||
50 (s32)curr->frame_number - (s32)found->frame_number < 0)
51 found = curr;
52 }
53
54 return found;
55 }
56
isp_stat_buf_find_oldest(struct isp_stat * stat)57 static inline struct ispstat_buffer *isp_stat_buf_find_oldest(struct isp_stat *stat)
58 {
59 return __isp_stat_buf_find(stat, 0);
60 }
61
isp_stat_buf_find_oldest_or_empty(struct isp_stat * stat)62 static inline struct ispstat_buffer *isp_stat_buf_find_oldest_or_empty(struct isp_stat *stat)
63 {
64 return __isp_stat_buf_find(stat, 1);
65 }
66
isp_stat_buf_queue(struct isp_stat * stat)67 static int isp_stat_buf_queue(struct isp_stat *stat)
68 {
69 if (!stat->active_buf)
70 return STAT_NO_BUF;
71
72 stat->active_buf->buf_size = stat->buf_size;
73
74 stat->active_buf->frame_number = stat->frame_number;
75 stat->active_buf->empty = 0;
76 stat->active_buf = NULL;
77
78 return STAT_BUF_DONE;
79 }
80
81 /* Get next free buffer to write the statistics to and mark it active. */
isp_stat_buf_next(struct isp_stat * stat)82 static void isp_stat_buf_next(struct isp_stat *stat)
83 {
84 if (unlikely(stat->active_buf)) {
85 /* Overwriting unused active buffer */
86 vin_log(VIN_LOG_STAT, "%s: new buffer requested without queuing active one.\n", stat->sd.name);
87 } else {
88 stat->active_buf = isp_stat_buf_find_oldest_or_empty(stat);
89 }
90 }
91
isp_stat_buf_release(struct isp_stat * stat)92 static void isp_stat_buf_release(struct isp_stat *stat)
93 {
94 unsigned long flags;
95
96 spin_lock_irqsave(&stat->isp->slock, flags);
97 stat->locked_buf = NULL;
98 spin_unlock_irqrestore(&stat->isp->slock, flags);
99 }
100
101 /* Get buffer to userspace. */
isp_stat_buf_get(struct isp_stat * stat,struct vin_isp_stat_data * data)102 static struct ispstat_buffer *isp_stat_buf_get(struct isp_stat *stat, struct vin_isp_stat_data *data)
103 {
104 int rval = 0;
105 unsigned long flags;
106 struct ispstat_buffer *buf;
107
108 spin_lock_irqsave(&stat->isp->slock, flags);
109
110 while (1) {
111 buf = isp_stat_buf_find_oldest(stat);
112 if (!buf) {
113 spin_unlock_irqrestore(&stat->isp->slock, flags);
114 vin_log(VIN_LOG_STAT, "%s: cannot find a buffer.\n", stat->sd.name);
115 return ERR_PTR(-EBUSY);
116 }
117 break;
118 }
119
120 stat->locked_buf = buf;
121
122 spin_unlock_irqrestore(&stat->isp->slock, flags);
123 if (NULL != data) {
124 if (buf->buf_size > data->buf_size) {
125 vin_warn("%s: userspace's buffer size is not enough.\n", stat->sd.name);
126 isp_stat_buf_release(stat);
127 return ERR_PTR(-EINVAL);
128 }
129 rval = copy_to_user(data->buf, buf->virt_addr, buf->buf_size);
130 if (rval) {
131 vin_warn("%s: failed copying %d bytes of stat data\n", stat->sd.name, rval);
132 buf = ERR_PTR(-EFAULT);
133 isp_stat_buf_release(stat);
134 }
135 }
136 return buf;
137 }
138
isp_stat_bufs_free(struct isp_stat * stat)139 static void isp_stat_bufs_free(struct isp_stat *stat)
140 {
141 int i;
142
143 for (i = 1; i < stat->buf_cnt; i++) {
144 struct ispstat_buffer *buf = &stat->buf[i];
145 struct vin_mm *mm = &stat->ion_man[i];
146 mm->size = stat->buf_size;
147
148 if (!buf->virt_addr)
149 continue;
150
151 mm->vir_addr = buf->virt_addr;
152 mm->dma_addr = buf->dma_addr;
153 os_mem_free(&stat->isp->pdev->dev, mm);
154
155 buf->dma_addr = NULL;
156 buf->virt_addr = NULL;
157 buf->empty = 1;
158 }
159
160 vin_log(VIN_LOG_STAT, "%s: all buffers were freed.\n", stat->sd.name);
161
162 stat->buf_size = 0;
163 stat->active_buf = NULL;
164 }
165
isp_stat_bufs_alloc(struct isp_stat * stat,u32 size,u32 count)166 static int isp_stat_bufs_alloc(struct isp_stat *stat, u32 size, u32 count)
167 {
168 unsigned long flags;
169 int i;
170
171 spin_lock_irqsave(&stat->isp->slock, flags);
172
173 BUG_ON(stat->locked_buf != NULL);
174
175 for (i = 1; i < stat->buf_cnt; i++)
176 stat->buf[i].empty = 1;
177
178 /* Are the old buffers big enough? */
179 if ((stat->buf_size >= size) && (stat->buf_cnt == count)) {
180 spin_unlock_irqrestore(&stat->isp->slock, flags);
181 vin_log(VIN_LOG_STAT, "%s: old stat buffers are enough.\n", stat->sd.name);
182 return 0;
183 }
184
185 spin_unlock_irqrestore(&stat->isp->slock, flags);
186
187 isp_stat_bufs_free(stat);
188
189 stat->buf_size = size;
190 stat->buf_cnt = count;
191
192 for (i = 1; i < stat->buf_cnt; i++) {
193 struct ispstat_buffer *buf = &stat->buf[i];
194 struct vin_mm *mm = &stat->ion_man[i];
195 mm->size = size;
196 if (!os_mem_alloc(&stat->isp->pdev->dev, mm)) {
197 buf->virt_addr = mm->vir_addr;
198 buf->dma_addr = mm->dma_addr;
199 }
200 if (!buf->virt_addr || !buf->dma_addr) {
201 vin_err("%s: Can't acquire memory for DMA buffer %d\n", stat->sd.name, i);
202 isp_stat_bufs_free(stat);
203 return -ENOMEM;
204 }
205 buf->empty = 1;
206 }
207 return 0;
208 }
209
isp_stat_queue_event(struct isp_stat * stat,int err)210 static void isp_stat_queue_event(struct isp_stat *stat, int err)
211 {
212 struct video_device *vdev = stat->sd.devnode;
213 struct v4l2_event event;
214 struct vin_isp_stat_event_status *status = (void *)event.u.data;
215
216 memset(&event, 0, sizeof(event));
217 if (!err)
218 status->frame_number = stat->frame_number;
219 else
220 status->buf_err = 1;
221
222 event.type = stat->event_type;
223 v4l2_event_queue(vdev, &event);
224 }
225
isp_stat_request_statistics(struct isp_stat * stat,struct vin_isp_stat_data * data)226 int isp_stat_request_statistics(struct isp_stat *stat,
227 struct vin_isp_stat_data *data)
228 {
229 struct ispstat_buffer *buf;
230
231 if (stat->state != ISPSTAT_ENABLED) {
232 vin_log(VIN_LOG_STAT, "%s: engine not enabled.\n", stat->sd.name);
233 return -EINVAL;
234 }
235 vin_log(VIN_LOG_STAT, "user wants to request statistics.\n");
236
237 mutex_lock(&stat->ioctl_lock);
238 buf = isp_stat_buf_get(stat, data);
239 if (IS_ERR(buf)) {
240 mutex_unlock(&stat->ioctl_lock);
241 return PTR_ERR(buf);
242 }
243
244 data->frame_number = buf->frame_number;
245 data->buf_size = buf->buf_size;
246
247 buf->empty = 1;
248 isp_stat_buf_release(stat);
249 mutex_unlock(&stat->ioctl_lock);
250
251 return 0;
252 }
253
isp_stat_config(struct isp_stat * stat,void * new_conf)254 int isp_stat_config(struct isp_stat *stat, void *new_conf)
255 {
256 int ret;
257 u32 count;
258 struct vin_isp_h3a_config *user_cfg = new_conf;
259
260 if (!new_conf) {
261 vin_log(VIN_LOG_STAT, "%s: configuration is NULL\n", stat->sd.name);
262 return -EINVAL;
263 }
264
265 mutex_lock(&stat->ioctl_lock);
266
267 user_cfg->buf_size = ISP_STAT_TOTAL_SIZE;
268
269 if (stat->sensor_fps <= 30)
270 count = 2;
271 else if (stat->sensor_fps <= 60)
272 count = 3;
273 else if (stat->sensor_fps <= 120)
274 count = 4;
275 else
276 count = 5;
277
278 ret = isp_stat_bufs_alloc(stat, user_cfg->buf_size, count);
279 if (ret) {
280 mutex_unlock(&stat->ioctl_lock);
281 return ret;
282 }
283
284 /* Module has a valid configuration. */
285 stat->configured = 1;
286
287 mutex_unlock(&stat->ioctl_lock);
288
289 return 0;
290 }
291
isp_stat_buf_process(struct isp_stat * stat,int buf_state)292 static int isp_stat_buf_process(struct isp_stat *stat, int buf_state)
293 {
294 int ret = STAT_NO_BUF;
295 dma_addr_t dma_addr;
296
297 if (buf_state == STAT_BUF_DONE && stat->state == ISPSTAT_ENABLED) {
298 ret = isp_stat_buf_queue(stat);
299 isp_stat_buf_next(stat);
300
301 if (!stat->active_buf)
302 return STAT_NO_BUF;
303
304 dma_addr = (dma_addr_t)(stat->active_buf->dma_addr);
305 bsp_isp_set_statistics_addr(stat->isp->id, dma_addr);
306 }
307
308 return ret;
309 }
310
isp_stat_enable(struct isp_stat * stat,u8 enable)311 int isp_stat_enable(struct isp_stat *stat, u8 enable)
312 {
313 unsigned long irqflags;
314
315 vin_log(VIN_LOG_STAT, "%s: user wants to %s module.\n", stat->sd.name, enable ? "enable" : "disable");
316
317 /* Prevent enabling while configuring */
318 mutex_lock(&stat->ioctl_lock);
319
320 spin_lock_irqsave(&stat->isp->slock, irqflags);
321
322 if (!stat->configured && enable) {
323 spin_unlock_irqrestore(&stat->isp->slock, irqflags);
324 mutex_unlock(&stat->ioctl_lock);
325 vin_log(VIN_LOG_STAT, "%s: cannot enable module as it's never been successfully configured so far.\n", stat->sd.name);
326 return -EINVAL;
327 }
328 stat->stat_en_flag = enable;
329 stat->isp->f1_after_librun = 0;
330
331 if (enable)
332 stat->state = ISPSTAT_ENABLED;
333 else
334 stat->state = ISPSTAT_DISABLED;
335
336 isp_stat_buf_next(stat);
337
338 spin_unlock_irqrestore(&stat->isp->slock, irqflags);
339 mutex_unlock(&stat->ioctl_lock);
340
341 return 0;
342 }
343
isp_stat_isr(struct isp_stat * stat)344 void isp_stat_isr(struct isp_stat *stat)
345 {
346 int ret = STAT_BUF_DONE;
347 unsigned long irqflags;
348
349 vin_log(VIN_LOG_STAT, "buf state is %d, frame number is %d 0x%x %d\n",
350 stat->state, stat->frame_number, stat->buf_size, stat->configured);
351
352 spin_lock_irqsave(&stat->isp->slock, irqflags);
353 if (stat->state == ISPSTAT_DISABLED) {
354 spin_unlock_irqrestore(&stat->isp->slock, irqflags);
355 return;
356 }
357 stat->isp->h3a_stat.frame_number++;
358
359 ret = isp_stat_buf_process(stat, ret);
360
361 spin_unlock_irqrestore(&stat->isp->slock, irqflags);
362
363 isp_stat_queue_event(stat, ret != STAT_BUF_DONE);
364 }
365
h3a_ioctl(struct v4l2_subdev * sd,unsigned int cmd,void * arg)366 static long h3a_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
367 {
368 struct isp_stat *stat = v4l2_get_subdevdata(sd);
369 vin_log(VIN_LOG_STAT, "%s cmd is 0x%x\n", __func__, cmd);
370 switch (cmd) {
371 case VIDIOC_VIN_ISP_H3A_CFG:
372 return isp_stat_config(stat, arg);
373 case VIDIOC_VIN_ISP_STAT_REQ:
374 return isp_stat_request_statistics(stat, arg);
375 case VIDIOC_VIN_ISP_STAT_EN:
376 return isp_stat_enable(stat, *(u8 *)arg);
377 }
378
379 return -ENOIOCTLCMD;
380 }
381
382 #ifdef CONFIG_COMPAT
383 struct vin_isp_stat_data32 {
384 compat_caddr_t buf;
385 __u32 buf_size;
386 __u32 frame_number;
387 __u32 config_counter;
388 };
389 struct vin_isp_h3a_config32 {
390 __u32 buf_size;
391 __u32 config_counter;
392 };
393
get_isp_statistics_buf32(struct vin_isp_stat_data * kp,struct vin_isp_stat_data32 __user * up)394 static int get_isp_statistics_buf32(struct vin_isp_stat_data *kp,
395 struct vin_isp_stat_data32 __user *up)
396 {
397 u32 tmp;
398
399 if (!access_ok(up, sizeof(struct vin_isp_stat_data32)) ||
400 get_user(kp->buf_size, &up->buf_size) ||
401 get_user(kp->frame_number, &up->frame_number) ||
402 get_user(kp->config_counter, &up->config_counter) ||
403 get_user(tmp, &up->buf))
404 return -EFAULT;
405 kp->buf = compat_ptr(tmp);
406 return 0;
407 }
408
put_isp_statistics_buf32(struct vin_isp_stat_data * kp,struct vin_isp_stat_data32 __user * up)409 static int put_isp_statistics_buf32(struct vin_isp_stat_data *kp,
410 struct vin_isp_stat_data32 __user *up)
411 {
412 u32 tmp = (u32) ((unsigned long)kp->buf);
413
414 if (!access_ok(up, sizeof(struct vin_isp_stat_data32)) ||
415 put_user(kp->buf_size, &up->buf_size) ||
416 put_user(kp->frame_number, &up->frame_number) ||
417 put_user(kp->config_counter, &up->config_counter) ||
418 put_user(tmp, &up->buf))
419 return -EFAULT;
420 return 0;
421 }
422
get_isp_statistics_config32(struct vin_isp_h3a_config * kp,struct vin_isp_h3a_config32 __user * up)423 static int get_isp_statistics_config32(struct vin_isp_h3a_config *kp,
424 struct vin_isp_h3a_config32 __user *up)
425 {
426 if (!access_ok(up, sizeof(struct vin_isp_h3a_config32)) ||
427 get_user(kp->buf_size, &up->buf_size) ||
428 get_user(kp->config_counter, &up->config_counter))
429 return -EFAULT;
430 return 0;
431 }
432
put_isp_statistics_config32(struct vin_isp_h3a_config * kp,struct vin_isp_h3a_config32 __user * up)433 static int put_isp_statistics_config32(struct vin_isp_h3a_config *kp,
434 struct vin_isp_h3a_config32 __user *up)
435 {
436 if (!access_ok(up, sizeof(struct vin_isp_h3a_config32)) ||
437 put_user(kp->buf_size, &up->buf_size) ||
438 put_user(kp->config_counter, &up->config_counter))
439 return -EFAULT;
440 return 0;
441 }
442
get_isp_statistics_enable32(unsigned int * kp,unsigned int __user * up)443 static int get_isp_statistics_enable32(unsigned int *kp,
444 unsigned int __user *up)
445 {
446 if (!access_ok(up, sizeof(struct vin_isp_h3a_config32)) ||
447 get_user(*kp, up))
448 return -EFAULT;
449 return 0;
450 }
451
put_isp_statistics_enable32(unsigned int * kp,unsigned int __user * up)452 static int put_isp_statistics_enable32(unsigned int *kp,
453 unsigned int __user *up)
454 {
455 if (!access_ok(up, sizeof(struct vin_isp_h3a_config32)) ||
456 put_user(*kp, up))
457 return -EFAULT;
458 return 0;
459 }
460
461 #define VIDIOC_VIN_ISP_H3A_CFG32 _IOWR('V', BASE_VIDIOC_PRIVATE + 31, struct vin_isp_h3a_config32)
462 #define VIDIOC_VIN_ISP_STAT_REQ32 _IOWR('V', BASE_VIDIOC_PRIVATE + 32, struct vin_isp_stat_data32)
463 #define VIDIOC_VIN_ISP_STAT_EN32 _IOWR('V', BASE_VIDIOC_PRIVATE + 33, unsigned int)
464
h3a_compat_ioctl32(struct v4l2_subdev * sd,unsigned int cmd,unsigned long arg)465 static long h3a_compat_ioctl32(struct v4l2_subdev *sd,
466 unsigned int cmd, unsigned long arg)
467 {
468 union {
469 struct vin_isp_h3a_config isb;
470 struct vin_isp_stat_data isd;
471 unsigned int isu;
472 } karg;
473 void __user *up = compat_ptr(arg);
474 int compatible_arg = 1;
475 long err = 0;
476
477 vin_log(VIN_LOG_STAT, "%s cmd is 0x%x\n", __func__, cmd);
478
479 switch (cmd) {
480 case VIDIOC_VIN_ISP_STAT_REQ32:
481 cmd = VIDIOC_VIN_ISP_STAT_REQ;
482 break;
483 case VIDIOC_VIN_ISP_H3A_CFG32:
484 cmd = VIDIOC_VIN_ISP_H3A_CFG;
485 break;
486 case VIDIOC_VIN_ISP_STAT_EN32:
487 cmd = VIDIOC_VIN_ISP_STAT_EN;
488 break;
489 }
490
491 switch (cmd) {
492 case VIDIOC_VIN_ISP_STAT_REQ:
493 err = get_isp_statistics_buf32(&karg.isd, up);
494 compatible_arg = 0;
495 break;
496 case VIDIOC_VIN_ISP_H3A_CFG:
497 err = get_isp_statistics_config32(&karg.isb, up);
498 compatible_arg = 0;
499 break;
500 case VIDIOC_VIN_ISP_STAT_EN:
501 err = get_isp_statistics_enable32(&karg.isu, up);
502 compatible_arg = 0;
503 break;
504 }
505
506 if (err)
507 return err;
508
509 if (compatible_arg)
510 err = h3a_ioctl(sd, cmd, up);
511 else {
512 err = h3a_ioctl(sd, cmd, &karg);
513 }
514
515 switch (cmd) {
516 case VIDIOC_VIN_ISP_STAT_REQ:
517 err = put_isp_statistics_buf32(&karg.isd, up);
518 break;
519 case VIDIOC_VIN_ISP_H3A_CFG:
520 err = put_isp_statistics_config32(&karg.isb, up);
521 break;
522 case VIDIOC_VIN_ISP_STAT_EN:
523 err = put_isp_statistics_enable32(&karg.isu, up);
524 compatible_arg = 0;
525 break;
526 }
527
528 return err;
529 }
530 #endif
531
isp_stat_subscribe_event(struct v4l2_subdev * subdev,struct v4l2_fh * fh,struct v4l2_event_subscription * sub)532 int isp_stat_subscribe_event(struct v4l2_subdev *subdev,
533 struct v4l2_fh *fh,
534 struct v4l2_event_subscription *sub)
535 {
536 struct isp_stat *stat = v4l2_get_subdevdata(subdev);
537
538 if (sub->type != stat->event_type)
539 return -EINVAL;
540
541 return v4l2_event_subscribe(fh, sub, STAT_NEVENTS, NULL);
542 }
543
544 static const struct v4l2_subdev_core_ops h3a_subdev_core_ops = {
545 .ioctl = h3a_ioctl,
546 #ifdef CONFIG_COMPAT
547 .compat_ioctl32 = h3a_compat_ioctl32,
548 #endif
549 .subscribe_event = isp_stat_subscribe_event,
550 .unsubscribe_event = v4l2_event_subdev_unsubscribe,
551 };
552
553 static const struct v4l2_subdev_ops h3a_subdev_ops = {
554 .core = &h3a_subdev_core_ops,
555 };
556
vin_isp_h3a_init(struct isp_dev * isp)557 int vin_isp_h3a_init(struct isp_dev *isp)
558 {
559 struct isp_stat *stat = &isp->h3a_stat;
560
561 vin_log(VIN_LOG_STAT, "%s\n", __func__);
562
563 stat->isp = isp;
564 stat->event_type = V4L2_EVENT_VIN_H3A;
565
566 mutex_init(&stat->ioctl_lock);
567
568 v4l2_subdev_init(&stat->sd, &h3a_subdev_ops);
569 snprintf(stat->sd.name, V4L2_SUBDEV_NAME_SIZE, "sunxi_h3a.%u", isp->id);
570 stat->sd.grp_id = VIN_GRP_ID_STAT;
571 stat->sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
572 v4l2_set_subdevdata(&stat->sd, stat);
573
574 stat->pad.flags = MEDIA_PAD_FL_SINK;
575 stat->sd.entity.function = MEDIA_ENT_F_PROC_VIDEO_STATISTICS;
576
577 return media_entity_pads_init(&stat->sd.entity, 1, &stat->pad);
578 }
579
vin_isp_h3a_cleanup(struct isp_dev * isp)580 void vin_isp_h3a_cleanup(struct isp_dev *isp)
581 {
582 struct isp_stat *stat = &isp->h3a_stat;
583
584 vin_log(VIN_LOG_STAT, "%s\n", __func__);
585
586 media_entity_cleanup(&stat->sd.entity);
587 mutex_destroy(&stat->ioctl_lock);
588 isp_stat_bufs_free(stat);
589 }
590