summaryrefslogtreecommitdiff
path: root/drivers/frame_provider/decoder/utils/vdec_input.c (plain)
blob: 8550575d259d9b21bb8db9c822d259ddc7fb13a9
1/*
2 * drivers/amlogic/media/frame_provider/decoder/utils/vdec_input.c
3 *
4 * Copyright (C) 2016 Amlogic, Inc. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 */
17
18#include <linux/uaccess.h>
19#include <linux/list.h>
20#include <linux/slab.h>
21#include <linux/dma-mapping.h>
22#include <linux/amlogic/media/codec_mm/codec_mm.h>
23
24#include "../../../stream_input/amports/amports_priv.h"
25#include "vdec.h"
26#include "vdec_input.h"
27
28#include <asm/cacheflush.h>
29#include <linux/crc32.h>
30
31
32#define VFRAME_BLOCK_SIZE (512 * SZ_1K)/*512 for 1080p default init.*/
33#define VFRAME_BLOCK_SIZE_4K (2 * SZ_1M) /*2M for 4K default.*/
34#define VFRAME_BLOCK_SIZE_MAX (4 * SZ_1M)
35
36#define VFRAME_BLOCK_PAGEALIGN 4
37#define VFRAME_BLOCK_MIN_LEVEL (2 * SZ_1M)
38#define VFRAME_BLOCK_MAX_LEVEL (8 * SZ_1M)
39#define VFRAME_BLOCK_MAX_TOTAL_SIZE (16 * SZ_1M)
40
41/*
422s for OMX
43*/
44#define MAX_FRAME_DURATION_S 2
45
46
47#define VFRAME_BLOCK_HOLE (SZ_64K)
48
49#define MIN_FRAME_PADDING_SIZE ((u32)(L1_CACHE_BYTES))
50
51#define EXTRA_PADDING_SIZE (16 * SZ_1K) /*HEVC_PADDING_SIZE*/
52
53#define MEM_NAME "VFRAME_INPUT"
54
55//static int vdec_input_get_duration_u64(struct vdec_input_s *input);
56static struct vframe_block_list_s *
57 vdec_input_alloc_new_block(struct vdec_input_s *input,
58 ulong phy_addr,
59 int size);
60
61static int copy_from_user_to_phyaddr(void *virts, const char __user *buf,
62 u32 size, ulong phys, u32 pading, bool is_mapped)
63{
64 u32 i, span = SZ_1M;
65 u32 count = size / PAGE_ALIGN(span);
66 u32 remain = size % PAGE_ALIGN(span);
67 ulong addr = phys;
68 u8 *p = virts;
69
70 if (is_mapped) {
71 if (copy_from_user(p, buf, size))
72 return -EFAULT;
73
74 if (pading)
75 memset(p + size, 0, pading);
76
77 codec_mm_dma_flush(p, size + pading, DMA_TO_DEVICE);
78
79 return 0;
80 }
81
82 for (i = 0; i < count; i++) {
83 addr = phys + i * span;
84 p = codec_mm_vmap(addr, span);
85 if (!p)
86 return -1;
87
88 if (copy_from_user(p, buf + i * span, span)) {
89 codec_mm_unmap_phyaddr(p);
90 return -EFAULT;
91 }
92
93 codec_mm_dma_flush(p, span, DMA_TO_DEVICE);
94 codec_mm_unmap_phyaddr(p);
95 }
96
97 if (!remain)
98 return 0;
99
100 span = size - remain;
101 addr = phys + span;
102 p = codec_mm_vmap(addr, remain + pading);
103 if (!p)
104 return -1;
105
106 if (copy_from_user(p, buf + span, remain)) {
107 codec_mm_unmap_phyaddr(p);
108 return -EFAULT;
109 }
110
111 if (pading)
112 memset(p + remain, 0, pading);
113
114 codec_mm_dma_flush(p, remain + pading, DMA_TO_DEVICE);
115 codec_mm_unmap_phyaddr(p);
116
117 return 0;
118}
119
120static int vframe_chunk_fill(struct vdec_input_s *input,
121 struct vframe_chunk_s *chunk, const char *buf,
122 size_t count, struct vframe_block_list_s *block)
123{
124 u8 *p = (u8 *)block->start_virt + block->wp;
125 if (block->type == VDEC_TYPE_FRAME_BLOCK) {
126 copy_from_user_to_phyaddr(p, buf, count,
127 block->start + block->wp,
128 chunk->pading_size,
129 block->is_mapped);
130 } else if (block->type == VDEC_TYPE_FRAME_CIRCULAR) {
131 size_t len = min((size_t)(block->size - block->wp), count);
132 u32 wp;
133
134 copy_from_user_to_phyaddr(p, buf, len,
135 block->start + block->wp, 0,
136 block->is_mapped);
137 p += len;
138
139 if (count > len) {
140 copy_from_user_to_phyaddr(p, buf + len,
141 count - len,
142 block->start, 0,
143 block->is_mapped);
144
145 p += count - len;
146 }
147
148 wp = block->wp + count;
149 if (wp >= block->size)
150 wp -= block->size;
151
152 len = min(block->size - wp, chunk->pading_size);
153
154 if (!block->is_mapped) {
155 p = codec_mm_vmap(block->start + wp, len);
156 memset(p, 0, len);
157 codec_mm_dma_flush(p, len, DMA_TO_DEVICE);
158 codec_mm_unmap_phyaddr(p);
159 } else {
160 memset(p, 0, len);
161 codec_mm_dma_flush(p, len, DMA_TO_DEVICE);
162 }
163
164 if (chunk->pading_size > len) {
165 p = (u8 *)block->start_virt;
166
167 if (!block->is_mapped) {
168 p = codec_mm_vmap(block->start,
169 chunk->pading_size - len);
170 memset(p, 0, chunk->pading_size - len);
171 codec_mm_dma_flush(p,
172 chunk->pading_size - len,
173 DMA_TO_DEVICE);
174 codec_mm_unmap_phyaddr(p);
175 } else {
176 memset(p, 0, chunk->pading_size - len);
177 codec_mm_dma_flush(p,
178 chunk->pading_size - len,
179 DMA_TO_DEVICE);
180 }
181 }
182 }
183
184 return 0;
185}
186
187static inline u32 vframe_block_space(struct vframe_block_list_s *block)
188{
189 if (block->type == VDEC_TYPE_FRAME_BLOCK) {
190 return block->size - block->wp;
191 } else {
192 return (block->rp >= block->wp) ?
193 (block->rp - block->wp) :
194 (block->rp - block->wp + block->size);
195 }
196}
197
198static void vframe_block_add_chunk(struct vframe_block_list_s *block,
199 struct vframe_chunk_s *chunk)
200{
201 block->wp += chunk->size + chunk->pading_size;
202 if (block->wp >= block->size)
203 block->wp -= block->size;
204 block->data_size += chunk->size;
205 block->chunk_count++;
206 chunk->block = block;
207 block->input->wr_block = block;
208 chunk->sequence = block->input->sequence;
209 block->input->sequence++;
210}
211
212static void vframe_block_free_block(struct vframe_block_list_s *block)
213{
214 if (block->addr) {
215 codec_mm_free_for_dma(MEM_NAME, block->addr);
216 }
217 /*
218 *pr_err("free block %d, size=%d\n", block->id, block->size);
219 */
220 kfree(block);
221}
222
223static int vframe_block_init_alloc_storage(struct vdec_input_s *input,
224 struct vframe_block_list_s *block,
225 ulong phy_addr,
226 int size)
227{
228 int alloc_size = input->default_block_size;
229 block->magic = 0x4b434c42;
230 block->input = input;
231 block->type = input->type;
232
233 /*
234 * todo: for different type use different size
235 */
236 if (phy_addr) {
237 block->is_out_buf = 1;
238 block->start_virt = NULL;
239 block->start = phy_addr;
240 block->size = size;
241 } else {
242 alloc_size = PAGE_ALIGN(alloc_size);
243 block->addr = codec_mm_alloc_for_dma_ex(
244 MEM_NAME,
245 alloc_size/PAGE_SIZE,
246 VFRAME_BLOCK_PAGEALIGN,
247 CODEC_MM_FLAGS_DMA_CPU | CODEC_MM_FLAGS_FOR_VDECODER,
248 input->id,
249 block->id);
250
251 if (!block->addr) {
252 pr_err("Input block allocation failed\n");
253 return -ENOMEM;
254 }
255
256 block->start_virt = (void *)codec_mm_phys_to_virt(block->addr);
257 if (block->start_virt)
258 block->is_mapped = true;
259 block->start = block->addr;
260 block->size = alloc_size;
261 block->is_out_buf = 0;
262 }
263
264 return 0;
265}
266
267void vdec_input_init(struct vdec_input_s *input, struct vdec_s *vdec)
268{
269 INIT_LIST_HEAD(&input->vframe_block_list);
270 INIT_LIST_HEAD(&input->vframe_block_free_list);
271 INIT_LIST_HEAD(&input->vframe_chunk_list);
272 spin_lock_init(&input->lock);
273 input->id = vdec->id;
274 input->block_nums = 0;
275 input->vdec = vdec;
276 input->block_id_seq = 0;
277 input->size = 0;
278 input->default_block_size = VFRAME_BLOCK_SIZE;
279}
280int vdec_input_prepare_bufs(struct vdec_input_s *input,
281 int frame_width, int frame_height)
282{
283 struct vframe_block_list_s *block;
284 int i;
285 unsigned long flags;
286
287 if (vdec_secure(input->vdec))
288 return 0;
289 if (input->size > 0)
290 return 0;
291 if (frame_width * frame_height >= 1920 * 1088) {
292 /*have add data before. ignore prepare buffers.*/
293 input->default_block_size = VFRAME_BLOCK_SIZE_4K;
294 }
295 /*prepared 3 buffers for smooth start.*/
296 for (i = 0; i < 3; i++) {
297 block = vdec_input_alloc_new_block(input, 0, 0);
298 if (!block)
299 break;
300 flags = vdec_input_lock(input);
301 list_move_tail(&block->list,
302 &input->vframe_block_free_list);
303 input->wr_block = NULL;
304 vdec_input_unlock(input, flags);
305 }
306 return 0;
307}
308
309static int vdec_input_dump_block_locked(
310 struct vframe_block_list_s *block,
311 char *buf, int size)
312{
313 char *pbuf = buf;
314 char sbuf[512];
315 int tsize = 0;
316 int s;
317 if (!pbuf) {
318 pbuf = sbuf;
319 size = 512;
320 }
321 #define BUFPRINT(args...) \
322 do {\
323 s = snprintf(pbuf, size - tsize, args);\
324 tsize += s;\
325 pbuf += s; \
326 } while (0)
327
328 BUFPRINT("\tblock:[%d:%p]-addr=%p,vstart=%p,type=%d\n",
329 block->id,
330 block,
331 (void *)block->addr,
332 (void *)block->start_virt,
333 block->type);
334 BUFPRINT("\t-blocksize=%d,data=%d,wp=%d,rp=%d,chunk_count=%d\n",
335 block->size,
336 block->data_size,
337 block->wp,
338 block->rp,
339 block->chunk_count);
340 /*
341 BUFPRINT("\tlist=%p,next=%p,prev=%p\n",
342 &block->list,
343 block->list.next,
344 block->list.prev);
345 */
346 #undef BUFPRINT
347 if (!buf)
348 pr_info("%s", sbuf);
349 return tsize;
350}
351
352int vdec_input_dump_blocks(struct vdec_input_s *input,
353 char *bufs, int size)
354{
355 struct list_head *p, *tmp;
356 unsigned long flags;
357 char *lbuf = bufs;
358 char sbuf[256];
359 int s = 0;
360
361 if (size <= 0)
362 return 0;
363 if (!bufs)
364 lbuf = sbuf;
365 s += snprintf(lbuf + s, size - s,
366 "blocks:vdec-%d id:%d,bufsize=%d,dsize=%d,frames:%d,dur:%dms\n",
367 input->id,
368 input->block_nums,
369 input->size,
370 input->data_size,
371 input->have_frame_num,
372 vdec_input_get_duration_u64(input)/1000);
373 if (bufs)
374 lbuf += s;
375 else {
376 pr_info("%s", sbuf);
377 lbuf = NULL;
378 }
379
380 flags = vdec_input_lock(input);
381 /* dump input blocks */
382 list_for_each_safe(p, tmp, &input->vframe_block_list) {
383 struct vframe_block_list_s *block = list_entry(
384 p, struct vframe_block_list_s, list);
385 if (bufs != NULL) {
386 lbuf = bufs + s;
387 if (size - s < 128)
388 break;
389 }
390 s += vdec_input_dump_block_locked(block, lbuf, size - s);
391 }
392 list_for_each_safe(p, tmp, &input->vframe_block_free_list) {
393 struct vframe_block_list_s *block = list_entry(
394 p, struct vframe_block_list_s, list);
395 if (bufs != NULL) {
396 lbuf = bufs + s;
397 if (size - s < 128)
398 break;
399 }
400 s += vdec_input_dump_block_locked(block, lbuf, size - s);
401 }
402 vdec_input_unlock(input, flags);
403 return s;
404}
405
406static int vdec_input_dump_chunk_locked(
407 int id,
408 struct vframe_chunk_s *chunk,
409 char *buf, int size)
410{
411 char *pbuf = buf;
412 char sbuf[512];
413 int tsize = 0;
414 int s;
415 if (!pbuf) {
416 pbuf = sbuf;
417 size = 512;
418 }
419 #define BUFPRINT(args...) \
420 do {\
421 s = snprintf(pbuf, size - tsize, args);\
422 tsize += s;\
423 pbuf += s; \
424 } while (0)
425
426 BUFPRINT(
427 "\t[%d][%lld:%p]-off=%d,size:%d,p:%d,\tpts64=%lld,addr=%p\n",
428 id,
429 chunk->sequence,
430 chunk->block,
431 chunk->offset,
432 chunk->size,
433 chunk->pading_size,
434 chunk->pts64,
435 (void *)(chunk->block->addr + chunk->offset));
436 /*
437 BUFPRINT("\tlist=%p,next=%p,prev=%p\n",
438 &chunk->list,
439 chunk->list.next,
440 chunk->list.prev);
441 */
442 #undef BUFPRINT
443 if (!buf)
444 pr_info("%s", sbuf);
445 return tsize;
446}
447
448int vdec_input_dump_chunks(int id, struct vdec_input_s *input,
449 char *bufs, int size)
450{
451
452 struct list_head *p, *tmp;
453 unsigned long flags;
454 char *lbuf = bufs;
455 char sbuf[256];
456 int s = 0;
457 int i = 0;
458
459 if (size <= 0)
460 return 0;
461 if (!bufs)
462 lbuf = sbuf;
463 s = snprintf(lbuf + s, size - s,
464 "[%d]blocks:vdec-%d id:%d,bufsize=%d,dsize=%d,frames:%d,maxframe:%d\n",
465 id,
466 input->id,
467 input->block_nums,
468 input->size,
469 input->data_size,
470 input->have_frame_num,
471 input->frame_max_size);
472 if (bufs)
473 lbuf += s;
474 if (!bufs) {
475 pr_info("%s", sbuf);
476 lbuf = NULL;
477 }
478 flags = vdec_input_lock(input);
479 /*dump chunks list infos.*/
480 list_for_each_safe(p, tmp, &input->vframe_chunk_list) {
481 struct vframe_chunk_s *chunk = list_entry(
482 p, struct vframe_chunk_s, list);
483 if (bufs != NULL)
484 lbuf = bufs + s;
485 s += vdec_input_dump_chunk_locked(id, chunk, lbuf, size - s);
486 i++;
487 if (i >= 10)
488 break;
489 }
490 vdec_input_unlock(input, flags);
491 return s;
492}
493
494
495
496int vdec_input_set_buffer(struct vdec_input_s *input, u32 start, u32 size)
497{
498 if (input_frame_based(input))
499 return -EINVAL;
500
501 input->start = start;
502 input->size = size;
503 input->swap_rp = start;
504
505 if (vdec_secure(input->vdec))
506 input->swap_page_phys = codec_mm_alloc_for_dma("SWAP",
507 1, 0, CODEC_MM_FLAGS_TVP);
508 else {
509 input->swap_page = alloc_page(GFP_KERNEL);
510 if (input->swap_page) {
511 input->swap_page_phys =
512 page_to_phys(input->swap_page);
513 }
514 }
515
516 if (input->swap_page_phys == 0)
517 return -ENOMEM;
518
519 return 0;
520}
521EXPORT_SYMBOL(vdec_input_set_buffer);
522
523void vdec_input_set_type(struct vdec_input_s *input, int type, int target)
524{
525 input->type = type;
526 input->target = target;
527 if (type == VDEC_TYPE_FRAME_CIRCULAR) {
528 /*alway used max block.*/
529 input->default_block_size = VFRAME_BLOCK_SIZE_MAX;
530 }
531}
532EXPORT_SYMBOL(vdec_input_set_type);
533
534int vdec_input_get_status(struct vdec_input_s *input,
535 struct vdec_input_status_s *status)
536{
537 unsigned long flags;
538
539 if (input->vdec == NULL)
540 return -EINVAL;
541
542 flags = vdec_input_lock(input);
543
544 if (list_empty(&input->vframe_block_list)) {
545 status->size = VFRAME_BLOCK_SIZE;
546 status->data_len = 0;
547 status->free_len = VFRAME_BLOCK_SIZE;
548 status->read_pointer = 0;
549 } else {
550 int r = VFRAME_BLOCK_MAX_LEVEL - vdec_input_level(input)
551 - VFRAME_BLOCK_HOLE;
552 status->size = input->size;
553 status->data_len = vdec_input_level(input);
554 status->free_len = (r > 0) ? r : 0;
555 status->read_pointer = input->total_rd_count;
556 }
557
558 vdec_input_unlock(input, flags);
559
560 return 0;
561}
562EXPORT_SYMBOL(vdec_input_get_status);
563
564static void vdec_input_add_block(struct vdec_input_s *input,
565 struct vframe_block_list_s *block)
566{
567 unsigned long flags;
568
569 flags = vdec_input_lock(input);
570 block->wp = 0;
571 block->id = input->block_id_seq++;
572 list_add_tail(&block->list, &input->vframe_block_list);
573 input->size += block->size;
574 input->block_nums++;
575 input->wr_block = block;
576 vdec_input_unlock(input, flags);
577}
578
579static inline void vdec_input_del_block_locked(struct vdec_input_s *input,
580 struct vframe_block_list_s *block)
581{
582 list_del(&block->list);
583 input->size -= block->size;
584 input->block_nums--;
585}
586
587int vdec_input_level(struct vdec_input_s *input)
588{
589 return input->total_wr_count - input->total_rd_count;
590}
591EXPORT_SYMBOL(vdec_input_level);
592
593static struct vframe_block_list_s *
594 vdec_input_alloc_new_block(struct vdec_input_s *input,
595 ulong phy_addr,
596 int size)
597{
598 struct vframe_block_list_s *block;
599 block = kzalloc(sizeof(struct vframe_block_list_s),
600 GFP_KERNEL);
601 if (block == NULL) {
602 input->no_mem_err_cnt++;
603 pr_err("vframe_block structure allocation failed\n");
604 return NULL;
605 }
606
607 if (vframe_block_init_alloc_storage(input,
608 block, phy_addr, size) != 0) {
609 kfree(block);
610 pr_err("vframe_block storage allocation failed\n");
611 return NULL;
612 }
613
614 INIT_LIST_HEAD(&block->list);
615
616 vdec_input_add_block(input, block);
617
618 /*
619 *pr_info("vdec-%d:new block id=%d, total_blocks:%d, size=%d\n",
620 * input->id,
621 * block->id,
622 * input->block_nums,
623 * block->size);
624 */
625 if (0 && input->size > VFRAME_BLOCK_MAX_LEVEL * 2) {
626 /*
627 used
628 */
629 pr_info(
630 "input[%d] reach max: size:%d, blocks:%d",
631 input->id,
632 input->size,
633 input->block_nums);
634 pr_info("level:%d, wr:%lld,rd:%lld\n",
635 vdec_input_level(input),
636 input->total_wr_count,
637 input->total_rd_count);
638 vdec_input_dump_blocks(input, NULL, 0);
639 }
640 return block;
641}
642int vdec_input_get_duration_u64(struct vdec_input_s *input)
643{
644 int duration = (input->last_inpts_u64 - input->last_comsumed_pts_u64);
645 if (input->last_in_nopts_cnt > 0 &&
646 input->last_comsumed_pts_u64 > 0 &&
647 input->last_duration > 0) {
648 duration += (input->last_in_nopts_cnt -
649 input->last_comsumed_no_pts_cnt) *
650 input->last_duration;
651 }
652 if (duration > 1000 * 1000000)/*> 1000S,I think jumped.*/
653 duration = 0;
654 if (duration <= 0 && input->last_duration > 0) {
655 /*..*/
656 duration = input->last_duration * input->have_frame_num;
657 }
658 if (duration < 0)
659 duration = 0;
660 return duration;
661}
662EXPORT_SYMBOL(vdec_input_get_duration_u64);
663
664/*
665 ret >= 13: have enough buffer, blocked add more buffers
666*/
667static int vdec_input_have_blocks_enough(struct vdec_input_s *input)
668{
669 int ret = 0;
670 if (vdec_input_level(input) > VFRAME_BLOCK_MIN_LEVEL)
671 ret += 1;
672 if (vdec_input_level(input) >= VFRAME_BLOCK_MAX_LEVEL)
673 ret += 2;
674 if (vdec_input_get_duration_u64(input) > MAX_FRAME_DURATION_S)
675 ret += 4;
676 if (input->have_frame_num > 30)
677 ret += 8;
678 else
679 ret -= 8;/*not enough frames.*/
680 if (input->size >= VFRAME_BLOCK_MAX_TOTAL_SIZE)
681 ret += 100;/*always bloced add more buffers.*/
682
683 return ret;
684}
685static int vdec_input_get_free_block(
686 struct vdec_input_s *input,
687 int size,/*frame size + pading*/
688 struct vframe_block_list_s **block_ret)
689{
690 struct vframe_block_list_s *to_freeblock = NULL;
691 struct vframe_block_list_s *block = NULL;
692 unsigned long flags;
693 flags = vdec_input_lock(input);
694 /*get from free list.*/
695 if (!list_empty(&input->vframe_block_free_list)) {
696 block = list_entry(input->vframe_block_free_list.next,
697 struct vframe_block_list_s, list);
698 if (block->size < (size)) {
699 vdec_input_del_block_locked(input, block);
700 to_freeblock = block;
701 block = NULL;
702 } else {
703 list_move_tail(&block->list,
704 &input->vframe_block_list);
705 input->wr_block = block;/*swith to new block*/
706 }
707 }
708 vdec_input_unlock(input, flags);
709 if (to_freeblock) {
710 /*free the small block.*/
711 vframe_block_free_block(to_freeblock);
712 }
713 if (block) {
714 *block_ret = block;
715 return 0;
716 }
717
718 if (vdec_input_have_blocks_enough(input) > 13) {
719 /*buf fulled */
720 return -EAGAIN;
721 }
722 if (input->no_mem_err_cnt > 3) {
723 /*alloced failed more times.
724 */
725 return -EAGAIN;
726 }
727 if (input->default_block_size <=
728 size * 2) {
729 int def_size = input->default_block_size;
730 do {
731 def_size *= 2;
732 } while ((def_size <= 2 * size) &&
733 (def_size <= VFRAME_BLOCK_SIZE_MAX));
734 if (def_size < size)
735 def_size = ALIGN(size + 64, (1 << 17));
736 /*128k aligned,same as codec_mm*/
737 input->default_block_size = def_size;
738 }
739 block = vdec_input_alloc_new_block(input, 0, 0);
740 if (!block) {
741 input->no_mem_err_cnt++;
742 return -EAGAIN;
743 }
744 input->no_mem_err_cnt = 0;
745 *block_ret = block;
746 return 0;
747}
748
749int vdec_input_add_chunk(struct vdec_input_s *input, const char *buf,
750 size_t count, u32 handle)
751{
752 unsigned long flags;
753 struct vframe_chunk_s *chunk;
754 struct vdec_s *vdec = input->vdec;
755 struct vframe_block_list_s *block;
756
757 int need_pading_size = MIN_FRAME_PADDING_SIZE;
758
759 if (vdec_secure(vdec)) {
760 block = vdec_input_alloc_new_block(input, (ulong)buf,
761 PAGE_ALIGN(count + HEVC_PADDING_SIZE + 1)); /*Add padding large than HEVC_PADDING_SIZE */
762 if (!block)
763 return -ENOMEM;
764 block->handle = handle;
765 } else {
766#if 0
767 if (add_count == 0) {
768 add_count++;
769 memcpy(sps, buf, 30);
770 return 30;
771 } else if (add_count == 1) {
772 add_count++;
773 memcpy(pps, buf, 8);
774 return 8;
775 }
776 add_count++;
777#endif
778
779#if 0
780 pr_info("vdec_input_add_frame add %p, count=%d\n", buf, (int)count);
781
782 if (count >= 8) {
783 pr_info("%02x %02x %02x %02x %02x %02x %02x %02x\n",
784 buf[0], buf[1], buf[2], buf[3],
785 buf[4], buf[5], buf[6], buf[7]);
786 }
787 if (count >= 16) {
788 pr_info("%02x %02x %02x %02x %02x %02x %02x %02x\n",
789 buf[8], buf[9], buf[10], buf[11],
790 buf[12], buf[13], buf[14], buf[15]);
791 }
792 if (count >= 24) {
793 pr_info("%02x %02x %02x %02x %02x %02x %02x %02x\n",
794 buf[16], buf[17], buf[18], buf[19],
795 buf[20], buf[21], buf[22], buf[23]);
796 }
797 if (count >= 32) {
798 pr_info("%02x %02x %02x %02x %02x %02x %02x %02x\n",
799 buf[24], buf[25], buf[26], buf[27],
800 buf[28], buf[29], buf[30], buf[31]);
801 }
802#endif
803 if (input_stream_based(input))
804 return -EINVAL;
805
806 if (count < PAGE_SIZE) {
807 need_pading_size = PAGE_ALIGN(count + need_pading_size) -
808 count;
809 } else {
810 /*to 64 bytes aligned;*/
811 if (count & 0x3f)
812 need_pading_size += 64 - (count & 0x3f);
813 }
814 block = input->wr_block;
815 if (block &&
816 (vframe_block_space(block) > (count + need_pading_size))) {
817 /*this block have enough buffers.
818 do nothings.
819 */
820 } else if (block && (block->type == VDEC_TYPE_FRAME_CIRCULAR)) {
821 /*in circular module.
822 only one block,.*/
823 return -EAGAIN;
824 } else if (block != NULL) {
825 /*have block but not enough space.
826 recycle the no enough blocks.*/
827 flags = vdec_input_lock(input);
828 if (input->wr_block == block &&
829 block->chunk_count == 0) {
830 block->rp = 0;
831 block->wp = 0;
832 /*block no data move to freelist*/
833 list_move_tail(&block->list,
834 &input->vframe_block_free_list);
835 input->wr_block = NULL;
836 }
837 vdec_input_unlock(input, flags);
838 block = NULL;
839 }
840 if (!block) {/*try new block.*/
841 int ret = vdec_input_get_free_block(input,
842 count + need_pading_size + EXTRA_PADDING_SIZE,
843 &block);
844 if (ret < 0)/*no enough block now.*/
845 return ret;
846 }
847 }
848
849 chunk = kzalloc(sizeof(struct vframe_chunk_s), GFP_KERNEL);
850
851 if (!chunk) {
852 pr_err("vframe_chunk structure allocation failed\n");
853 return -ENOMEM;
854 }
855
856 chunk->magic = 0x4b554843;
857 if (vdec->pts_valid) {
858 chunk->pts = vdec->pts;
859 chunk->pts64 = vdec->pts64;
860 }
861
862 if (vdec->timestamp_valid)
863 chunk->timestamp = vdec->timestamp;
864
865 if (vdec->pts_valid &&
866 input->last_inpts_u64 > 0 &&
867 input->last_in_nopts_cnt == 0) {
868 int d = (int)(chunk->pts64 - input->last_inpts_u64);
869 if (d > 0 && (d < input->last_duration))
870 input->last_duration = d;
871 /* alwasy: used the smallest duration;
872 if 60fps->30 fps.
873 maybe have warning value.
874 */
875 }
876 chunk->pts_valid = vdec->pts_valid;
877 vdec->pts_valid = false;
878 INIT_LIST_HEAD(&chunk->list);
879
880 if (vdec_secure(vdec)) {
881 chunk->offset = 0;
882 chunk->size = count;
883 chunk->pading_size = PAGE_ALIGN(chunk->size + need_pading_size) -
884 chunk->size;
885 } else {
886 chunk->offset = block->wp;
887 chunk->size = count;
888 chunk->pading_size = need_pading_size;
889 if (vframe_chunk_fill(input, chunk, buf, count, block)) {
890 pr_err("vframe_chunk_fill failed\n");
891 kfree(chunk);
892 return -EFAULT;
893 }
894
895 }
896
897
898 flags = vdec_input_lock(input);
899
900 vframe_block_add_chunk(block, chunk);
901
902 list_add_tail(&chunk->list, &input->vframe_chunk_list);
903 input->data_size += chunk->size;
904 input->have_frame_num++;
905
906 if (input->have_frame_num == 1)
907 input->vdec_up(vdec);
908 ATRACE_COUNTER(MEM_NAME, input->have_frame_num);
909 if (chunk->pts_valid) {
910 input->last_inpts_u64 = chunk->pts64;
911 input->last_in_nopts_cnt = 0;
912 } else {
913 /*nopts*/
914 input->last_in_nopts_cnt++;
915 }
916 if (chunk->size > input->frame_max_size)
917 input->frame_max_size = chunk->size;
918 input->total_wr_count += count;
919 vdec_input_unlock(input, flags);
920#if 0
921 if (add_count == 2)
922 input->total_wr_count += 38;
923#endif
924
925 return count;
926}
927
928int vdec_input_add_frame(struct vdec_input_s *input, const char *buf,
929 size_t count)
930{
931 int ret = 0;
932 struct drm_info drm;
933 struct vdec_s *vdec = input->vdec;
934 unsigned long phy_buf;
935
936 if (vdec_secure(vdec)) {
937 while (count > 0) {
938 if (count < sizeof(struct drm_info))
939 return -EIO;
940 if (copy_from_user(&drm, buf + ret, sizeof(struct drm_info)))
941 return -EAGAIN;
942 if (!(drm.drm_flag & TYPE_DRMINFO_V2))
943 return -EIO; /*must drm info v2 version*/
944 phy_buf = (unsigned long) drm.drm_phy;
945 vdec_input_add_chunk(input, (char *)phy_buf,
946 (size_t)drm.drm_pktsize, drm.handle);
947 count -= sizeof(struct drm_info);
948 ret += sizeof(struct drm_info);
949
950 /* the drm frame data might include head infos and raw */
951 /* data thus the next drm unit still need a valid pts.*/
952 if (count >= sizeof(struct drm_info))
953 vdec->pts_valid = true;
954 }
955 } else {
956 ret = vdec_input_add_chunk(input, buf, count, 0);
957 }
958
959 return ret;
960}
961EXPORT_SYMBOL(vdec_input_add_frame);
962
963struct vframe_chunk_s *vdec_input_next_chunk(struct vdec_input_s *input)
964{
965 struct vframe_chunk_s *chunk = NULL;
966 unsigned long flags;
967 flags = vdec_input_lock(input);
968 if (!list_empty(&input->vframe_chunk_list)) {
969 chunk = list_first_entry(&input->vframe_chunk_list,
970 struct vframe_chunk_s, list);
971 }
972 vdec_input_unlock(input, flags);
973 return chunk;
974}
975EXPORT_SYMBOL(vdec_input_next_chunk);
976
977struct vframe_chunk_s *vdec_input_next_input_chunk(
978 struct vdec_input_s *input)
979{
980 struct vframe_chunk_s *chunk = NULL;
981 struct list_head *p;
982 unsigned long flags;
983 flags = vdec_input_lock(input);
984
985 list_for_each(p, &input->vframe_chunk_list) {
986 struct vframe_chunk_s *c = list_entry(
987 p, struct vframe_chunk_s, list);
988 if ((c->flag & VFRAME_CHUNK_FLAG_CONSUMED) == 0) {
989 chunk = c;
990 break;
991 }
992 }
993 vdec_input_unlock(input, flags);
994 return chunk;
995}
996EXPORT_SYMBOL(vdec_input_next_input_chunk);
997
998void vdec_input_release_chunk(struct vdec_input_s *input,
999 struct vframe_chunk_s *chunk)
1000{
1001 struct vframe_chunk_s *p;
1002 u32 chunk_valid = 0;
1003 unsigned long flags;
1004 struct vframe_block_list_s *block = chunk->block;
1005 struct vframe_block_list_s *tofreeblock = NULL;
1006 flags = vdec_input_lock(input);
1007
1008 list_for_each_entry(p, &input->vframe_chunk_list, list) {
1009 if (p == chunk) {
1010 chunk_valid = 1;
1011 break;
1012 }
1013 }
1014 /* 2 threads go here, the other done the deletion,so return*/
1015 if (chunk_valid == 0) {
1016 vdec_input_unlock(input, flags);
1017 pr_err("%s chunk is deleted,so return.\n", __func__);
1018 return;
1019 }
1020
1021 list_del(&chunk->list);
1022 input->have_frame_num--;
1023 ATRACE_COUNTER(MEM_NAME, input->have_frame_num);
1024 if (chunk->pts_valid) {
1025 input->last_comsumed_no_pts_cnt = 0;
1026 input->last_comsumed_pts_u64 = chunk->pts64;
1027 } else
1028 input->last_comsumed_no_pts_cnt++;
1029 block->rp += chunk->size;
1030 if (block->rp >= block->size)
1031 block->rp -= block->size;
1032 block->data_size -= chunk->size;
1033 block->chunk_count--;
1034 input->data_size -= chunk->size;
1035 input->total_rd_count += chunk->size;
1036 if (block->is_out_buf) {
1037 list_move_tail(&block->list,
1038 &input->vframe_block_free_list);
1039 } else if (block->chunk_count == 0 &&
1040 input->wr_block != block ) {/*don't free used block*/
1041 if (block->size < input->default_block_size) {
1042 vdec_input_del_block_locked(input, block);
1043 tofreeblock = block;
1044 } else {
1045 block->rp = 0;
1046 block->wp = 0;
1047 list_move_tail(&block->list,
1048 &input->vframe_block_free_list);
1049 }
1050 }
1051
1052 vdec_input_unlock(input, flags);
1053 if (tofreeblock)
1054 vframe_block_free_block(tofreeblock);
1055 kfree(chunk);
1056}
1057EXPORT_SYMBOL(vdec_input_release_chunk);
1058
1059unsigned long vdec_input_lock(struct vdec_input_s *input)
1060{
1061 unsigned long flags;
1062
1063 spin_lock_irqsave(&input->lock, flags);
1064
1065 return flags;
1066}
1067EXPORT_SYMBOL(vdec_input_lock);
1068
1069void vdec_input_unlock(struct vdec_input_s *input, unsigned long flags)
1070{
1071 spin_unlock_irqrestore(&input->lock, flags);
1072}
1073EXPORT_SYMBOL(vdec_input_unlock);
1074
1075void vdec_input_release(struct vdec_input_s *input)
1076{
1077 struct list_head *p, *tmp;
1078
1079 /* release chunk data */
1080 list_for_each_safe(p, tmp, &input->vframe_chunk_list) {
1081 struct vframe_chunk_s *chunk = list_entry(
1082 p, struct vframe_chunk_s, list);
1083 vdec_input_release_chunk(input, chunk);
1084 }
1085 list_for_each_safe(p, tmp, &input->vframe_block_list) {
1086 /*should never here.*/
1087 list_move_tail(p, &input->vframe_block_free_list);
1088 }
1089 /* release input blocks */
1090 list_for_each_safe(p, tmp, &input->vframe_block_free_list) {
1091 struct vframe_block_list_s *block = list_entry(
1092 p, struct vframe_block_list_s, list);
1093 vdec_input_del_block_locked(input, block);
1094 vframe_block_free_block(block);
1095 }
1096
1097 /* release swap pages */
1098 if (input->swap_page_phys) {
1099 if (vdec_secure(input->vdec))
1100 codec_mm_free_for_dma("SWAP", input->swap_page_phys);
1101 else
1102 __free_page(input->swap_page);
1103 input->swap_page = NULL;
1104 input->swap_page_phys = 0;
1105 }
1106 input->swap_valid = false;
1107}
1108EXPORT_SYMBOL(vdec_input_release);
1109
1110u32 vdec_input_get_freed_handle(struct vdec_s *vdec)
1111{
1112 struct vframe_block_list_s *block;
1113 struct vdec_input_s *input = &vdec->input;
1114 unsigned long flags;
1115 u32 handle = 0;
1116
1117 if (!vdec_secure(vdec))
1118 return 0;
1119
1120 flags = vdec_input_lock(input);
1121 block = list_first_entry_or_null(&input->vframe_block_free_list,
1122 struct vframe_block_list_s, list);
1123
1124 if (block) {
1125 handle = block->handle;
1126 vdec_input_del_block_locked(input, block);
1127 kfree(block);
1128 }
1129 vdec_input_unlock(input, flags);
1130 return handle;
1131}
1132EXPORT_SYMBOL(vdec_input_get_freed_handle);
1133
1134
1135