| /* |
| * drivers/amlogic/media/video_sink/video_keeper.c |
| * |
| * Copyright (C) 2017 Amlogic, Inc. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| * more details. |
| * |
| */ |
| |
| #include <linux/version.h> |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/spinlock.h> |
| #include <linux/interrupt.h> |
| #include <linux/fs.h> |
| #include <linux/string.h> |
| #include <linux/io.h> |
| #include <linux/mm.h> |
| #include <linux/err.h> |
| #include <linux/mutex.h> |
| #include <linux/platform_device.h> |
| #include <linux/ctype.h> |
| #include <linux/amlogic/media/frame_sync/ptsserv.h> |
| #include <linux/amlogic/media/frame_sync/timestamp.h> |
| #include <linux/amlogic/media/frame_sync/tsync.h> |
| |
| #include <linux/amlogic/media/vfm/vframe.h> |
| #include <linux/amlogic/media/vfm/vframe_provider.h> |
| #include <linux/amlogic/media/vfm/vframe_receiver.h> |
| #include <linux/amlogic/media/vout/vout_notify.h> |
| #include <linux/sched.h> |
| #include <linux/slab.h> |
| #include <linux/poll.h> |
| #include <linux/clk.h> |
| /*#include <linux/amlogic/gpio-amlogic.h>*/ |
| #include <linux/amlogic/media/canvas/canvas.h> |
| #include <linux/amlogic/media/canvas/canvas_mgr.h> |
| #include <linux/dma-mapping.h> |
| #include <linux/dma-contiguous.h> |
| #ifdef CONFIG_AMLOGIC_MEDIA_GE2D |
| #include <linux/amlogic/media/ge2d/ge2d.h> |
| #include <linux/amlogic/media/canvas/canvas_mgr.h> |
| #endif |
| #include <linux/amlogic/media/codec_mm/codec_mm.h> |
| #include <linux/amlogic/media/codec_mm/codec_mm_keeper.h> |
| |
| #include "video_priv.h" |
| #include <linux/amlogic/media/video_sink/video_keeper.h> |
| #include <linux/amlogic/media/registers/register.h> |
| #include <linux/amlogic/media/video_sink/vpp.h> |
| #include <linux/amlogic/media/video_sink/video.h> |
| #include <linux/amlogic/media/utils/vdec_reg.h> |
| |
| #define MEM_NAME "video-keeper" |
| static DEFINE_MUTEX(video_keeper_mutex); |
| |
| static unsigned long keep_y_addr, keep_u_addr, keep_v_addr; |
| static int keep_video_on; |
| static int keep_video_pip_on; |
| static int keep_id; |
| static int keep_head_id; |
| static int keep_dw_id; |
| static int keep_pip_id; |
| static int keep_pip_head_id; |
| static int keep_pip_dw_id; |
| static int keep_el_id; |
| static int keep_el_head_id; |
| static int keep_el_dw_id; |
| static int keep_pip_el_id; |
| static int keep_pip_el_head_id; |
| static int keep_pip_el_dw_id; |
| |
| #define Y_BUFFER_SIZE 0x600000 /* for 1920*1088 */ |
| #define U_BUFFER_SIZE 0x100000 /* compatible with NV21 */ |
| #define V_BUFFER_SIZE 0x80000 |
| |
| #define RESERVE_CLR_FRAME |
| |
| static inline ulong keep_phy_addr(unsigned long addr) |
| { |
| return addr; |
| } |
| |
| #ifdef CONFIG_AMLOGIC_MEDIA_GE2D |
| static int display_canvas_y_dup; |
| static int display_canvas_u_dup; |
| static int display_canvas_v_dup; |
| static struct ge2d_context_s *ge2d_video_context; |
| |
| static int ge2d_videotask_init(void) |
| { |
| const char *keep_owner = "keepframe"; |
| |
| if (ge2d_video_context == NULL) |
| ge2d_video_context = create_ge2d_work_queue(); |
| |
| if (ge2d_video_context == NULL) { |
| pr_info("create_ge2d_work_queue video task failed\n"); |
| return -1; |
| } |
| if (!display_canvas_y_dup) |
| display_canvas_y_dup = canvas_pool_map_alloc_canvas(keep_owner); |
| if (!display_canvas_u_dup) |
| display_canvas_u_dup = canvas_pool_map_alloc_canvas(keep_owner); |
| if (!display_canvas_v_dup) |
| display_canvas_v_dup = canvas_pool_map_alloc_canvas(keep_owner); |
| pr_info("create_ge2d_work_queue video task ok\n"); |
| |
| return 0; |
| } |
| |
| |
| |
| static int ge2d_videotask_release(void) |
| { |
| if (ge2d_video_context) { |
| destroy_ge2d_work_queue(ge2d_video_context); |
| ge2d_video_context = NULL; |
| } |
| if (display_canvas_y_dup) |
| canvas_pool_map_free_canvas(display_canvas_y_dup); |
| if (display_canvas_u_dup) |
| canvas_pool_map_free_canvas(display_canvas_u_dup); |
| if (display_canvas_v_dup) |
| canvas_pool_map_free_canvas(display_canvas_v_dup); |
| |
| return 0; |
| } |
| |
| static int ge2d_store_frame_S_YUV444(u32 cur_index) |
| { |
| u32 y_index, des_index, src_index; |
| struct canvas_s cs, cd; |
| ulong yaddr; |
| u32 ydupindex; |
| |
| struct config_para_ex_s ge2d_config; |
| |
| memset(&ge2d_config, 0, sizeof(struct config_para_ex_s)); |
| |
| ydupindex = display_canvas_y_dup; |
| |
| pr_info("ge2d_store_frame_S_YUV444 cur_index:s:0x%x\n", cur_index); |
| /* pr_info("ge2d_store_frame cur_index:d:0x%x\n", canvas_tab[0]); */ |
| y_index = cur_index & 0xff; |
| canvas_read(y_index, &cs); |
| |
| yaddr = keep_phy_addr(keep_y_addr); |
| canvas_config(ydupindex, |
| (ulong) yaddr, |
| cs.width, cs.height, CANVAS_ADDR_NOWRAP, cs.blkmode); |
| |
| canvas_read(ydupindex, &cd); |
| src_index = y_index; |
| des_index = ydupindex; |
| |
| pr_info("ge2d_canvas_dup ADDR srcy[0x%lx] des[0x%lx] des_index[0x%x]\n", |
| cs.addr, cd.addr, des_index); |
| |
| ge2d_config.alu_const_color = 0; |
| ge2d_config.bitmask_en = 0; |
| ge2d_config.src1_gb_alpha = 0; |
| |
| ge2d_config.src_planes[0].addr = cs.addr; |
| ge2d_config.src_planes[0].w = cs.width; |
| ge2d_config.src_planes[0].h = cs.height; |
| |
| ge2d_config.dst_planes[0].addr = cd.addr; |
| ge2d_config.dst_planes[0].w = cd.width; |
| ge2d_config.dst_planes[0].h = cd.height; |
| |
| ge2d_config.src_para.canvas_index = src_index; |
| ge2d_config.src_para.mem_type = CANVAS_TYPE_INVALID; |
| ge2d_config.src_para.format = GE2D_FORMAT_S24_YUV444; |
| ge2d_config.src_para.fill_color_en = 0; |
| ge2d_config.src_para.fill_mode = 0; |
| ge2d_config.src_para.color = 0; |
| ge2d_config.src_para.top = 0; |
| ge2d_config.src_para.left = 0; |
| ge2d_config.src_para.width = cs.width; |
| ge2d_config.src_para.height = cs.height; |
| ge2d_config.src2_para.mem_type = CANVAS_TYPE_INVALID; |
| ge2d_config.dst_para.canvas_index = des_index; |
| ge2d_config.dst_para.mem_type = CANVAS_TYPE_INVALID; |
| ge2d_config.dst_para.format = GE2D_FORMAT_S24_YUV444; |
| ge2d_config.dst_para.fill_color_en = 0; |
| ge2d_config.dst_para.fill_mode = 0; |
| ge2d_config.dst_para.color = 0; |
| ge2d_config.dst_para.top = 0; |
| ge2d_config.dst_para.left = 0; |
| ge2d_config.dst_para.width = cs.width; |
| ge2d_config.dst_para.height = cs.height; |
| |
| if (ge2d_context_config_ex(ge2d_video_context, &ge2d_config) < 0) { |
| pr_info("ge2d_context_config_ex failed\n"); |
| return -1; |
| } |
| |
| stretchblt_noalpha(ge2d_video_context, 0, 0, cs.width, cs.height, |
| 0, 0, cs.width, cs.height); |
| return 0; |
| } |
| |
| static int ge2d_store_frame_YUV444(u32 cur_index) |
| { |
| u32 y_index, des_index, src_index; |
| struct canvas_s cs, cd; |
| ulong yaddr; |
| u32 ydupindex; |
| struct config_para_ex_s ge2d_config; |
| |
| memset(&ge2d_config, 0, sizeof(struct config_para_ex_s)); |
| |
| ydupindex = display_canvas_y_dup; |
| |
| pr_info("ge2d_store_frame_YUV444 cur_index:s:0x%x\n", cur_index); |
| /* pr_info("ge2d_store_frame cur_index:d:0x%x\n", canvas_tab[0]); */ |
| y_index = cur_index & 0xff; |
| canvas_read(y_index, &cs); |
| |
| yaddr = keep_phy_addr(keep_y_addr); |
| canvas_config(ydupindex, |
| (ulong) yaddr, |
| cs.width, cs.height, |
| CANVAS_ADDR_NOWRAP, cs.blkmode); |
| |
| canvas_read(ydupindex, &cd); |
| src_index = y_index; |
| des_index = ydupindex; |
| |
| pr_info("ge2d_canvas_dup ADDR srcy[0x%lx] des[0x%lx]\n", cs.addr, |
| cd.addr); |
| |
| ge2d_config.alu_const_color = 0; |
| ge2d_config.bitmask_en = 0; |
| ge2d_config.src1_gb_alpha = 0; |
| |
| ge2d_config.src_planes[0].addr = cs.addr; |
| ge2d_config.src_planes[0].w = cs.width; |
| ge2d_config.src_planes[0].h = cs.height; |
| |
| ge2d_config.dst_planes[0].addr = cd.addr; |
| ge2d_config.dst_planes[0].w = cd.width; |
| ge2d_config.dst_planes[0].h = cd.height; |
| |
| ge2d_config.src_para.canvas_index = src_index; |
| ge2d_config.src_para.mem_type = CANVAS_TYPE_INVALID; |
| ge2d_config.src_para.format = GE2D_FORMAT_M24_YUV444; |
| ge2d_config.src_para.fill_color_en = 0; |
| ge2d_config.src_para.fill_mode = 0; |
| ge2d_config.src_para.color = 0; |
| ge2d_config.src_para.top = 0; |
| ge2d_config.src_para.left = 0; |
| ge2d_config.src_para.width = cs.width; |
| ge2d_config.src_para.height = cs.height; |
| ge2d_config.src2_para.mem_type = CANVAS_TYPE_INVALID; |
| ge2d_config.dst_para.canvas_index = des_index; |
| ge2d_config.dst_para.mem_type = CANVAS_TYPE_INVALID; |
| ge2d_config.dst_para.format = GE2D_FORMAT_M24_YUV444; |
| ge2d_config.dst_para.fill_color_en = 0; |
| ge2d_config.dst_para.fill_mode = 0; |
| ge2d_config.dst_para.color = 0; |
| ge2d_config.dst_para.top = 0; |
| ge2d_config.dst_para.left = 0; |
| ge2d_config.dst_para.width = cs.width; |
| ge2d_config.dst_para.height = cs.height; |
| |
| if (ge2d_context_config_ex(ge2d_video_context, &ge2d_config) < 0) { |
| pr_info("ge2d_context_config_ex failed\n"); |
| return -1; |
| } |
| |
| stretchblt_noalpha(ge2d_video_context, |
| 0, 0, cs.width, cs.height, |
| 0, 0, cs.width, cs.height); |
| |
| return 0; |
| } |
| |
| /* static u32 canvas_tab[1]; */ |
| static int ge2d_store_frame_NV21(u32 cur_index) |
| { |
| u32 y_index, u_index, des_index, src_index; |
| struct canvas_s cs0, cs1, cd; |
| ulong yaddr, uaddr; |
| u32 ydupindex, udupindex; |
| struct config_para_ex_s ge2d_config; |
| |
| memset(&ge2d_config, 0, sizeof(struct config_para_ex_s)); |
| |
| ydupindex = display_canvas_y_dup; |
| udupindex = display_canvas_u_dup; |
| |
| pr_info("ge2d_store_frame_NV21 cur_index:s:0x%x\n", cur_index); |
| |
| /* pr_info("ge2d_store_frame cur_index:d:0x%x\n", canvas_tab[0]); */ |
| yaddr = keep_phy_addr(keep_y_addr); |
| uaddr = keep_phy_addr(keep_u_addr); |
| |
| y_index = cur_index & 0xff; |
| u_index = (cur_index >> 8) & 0xff; |
| |
| canvas_read(y_index, &cs0); |
| canvas_read(u_index, &cs1); |
| canvas_config(ydupindex, |
| (ulong) yaddr, |
| cs0.width, cs0.height, |
| CANVAS_ADDR_NOWRAP, cs0.blkmode); |
| canvas_config(udupindex, |
| (ulong) uaddr, |
| cs1.width, cs1.height, |
| CANVAS_ADDR_NOWRAP, cs1.blkmode); |
| |
| canvas_read(ydupindex, &cd); |
| src_index = ((y_index & 0xff) | ((u_index << 8) & 0x0000ff00)); |
| des_index = ((ydupindex & 0xff) | ((udupindex << 8) & 0x0000ff00)); |
| |
| pr_info("ge2d_store_frame d:0x%x\n", des_index); |
| |
| ge2d_config.alu_const_color = 0; |
| ge2d_config.bitmask_en = 0; |
| ge2d_config.src1_gb_alpha = 0; |
| |
| ge2d_config.src_planes[0].addr = cs0.addr; |
| ge2d_config.src_planes[0].w = cs0.width; |
| ge2d_config.src_planes[0].h = cs0.height; |
| ge2d_config.src_planes[1].addr = cs1.addr; |
| ge2d_config.src_planes[1].w = cs1.width; |
| ge2d_config.src_planes[1].h = cs1.height; |
| |
| ge2d_config.dst_planes[0].addr = cd.addr; |
| ge2d_config.dst_planes[0].w = cd.width; |
| ge2d_config.dst_planes[0].h = cd.height; |
| |
| ge2d_config.src_para.canvas_index = src_index; |
| ge2d_config.src_para.mem_type = CANVAS_TYPE_INVALID; |
| ge2d_config.src_para.format = GE2D_FORMAT_M24_NV21; |
| ge2d_config.src_para.fill_color_en = 0; |
| ge2d_config.src_para.fill_mode = 0; |
| ge2d_config.src_para.color = 0; |
| ge2d_config.src_para.top = 0; |
| ge2d_config.src_para.left = 0; |
| ge2d_config.src_para.width = cs0.width; |
| ge2d_config.src_para.height = cs0.height; |
| ge2d_config.src2_para.mem_type = CANVAS_TYPE_INVALID; |
| ge2d_config.dst_para.canvas_index = des_index; |
| ge2d_config.dst_para.mem_type = CANVAS_TYPE_INVALID; |
| ge2d_config.dst_para.format = GE2D_FORMAT_M24_NV21; |
| ge2d_config.dst_para.fill_color_en = 0; |
| ge2d_config.dst_para.fill_mode = 0; |
| ge2d_config.dst_para.color = 0; |
| ge2d_config.dst_para.top = 0; |
| ge2d_config.dst_para.left = 0; |
| ge2d_config.dst_para.width = cs0.width; |
| ge2d_config.dst_para.height = cs0.height; |
| |
| if (ge2d_context_config_ex(ge2d_video_context, &ge2d_config) < 0) { |
| pr_info("ge2d_context_config_ex failed\n"); |
| return -1; |
| } |
| |
| stretchblt_noalpha(ge2d_video_context, |
| 0, 0, cs0.width, cs0.height, |
| 0, 0, cs0.width, cs0.height); |
| |
| return 0; |
| } |
| |
| /* static u32 canvas_tab[1]; */ |
| static int ge2d_store_frame_YUV420(u32 cur_index) |
| { |
| u32 y_index, u_index, v_index; |
| struct canvas_s cs, cd; |
| ulong yaddr, uaddr, vaddr; |
| u32 ydupindex, udupindex, vdupindex; |
| struct config_para_ex_s ge2d_config; |
| |
| memset(&ge2d_config, 0, sizeof(struct config_para_ex_s)); |
| |
| ydupindex = display_canvas_y_dup; |
| udupindex = display_canvas_u_dup; |
| vdupindex = display_canvas_v_dup; |
| |
| pr_info("ge2d_store_frame_YUV420 cur_index:s:0x%x\n", cur_index); |
| /* operation top line */ |
| /* Y data */ |
| ge2d_config.alu_const_color = 0; |
| ge2d_config.bitmask_en = 0; |
| ge2d_config.src1_gb_alpha = 0; |
| |
| y_index = cur_index & 0xff; |
| canvas_read(y_index, &cs); |
| ge2d_config.src_planes[0].addr = cs.addr; |
| ge2d_config.src_planes[0].w = cs.width; |
| ge2d_config.src_planes[0].h = cs.height; |
| ge2d_config.src_planes[1].addr = 0; |
| ge2d_config.src_planes[1].w = 0; |
| ge2d_config.src_planes[1].h = 0; |
| ge2d_config.src_planes[2].addr = 0; |
| ge2d_config.src_planes[2].w = 0; |
| ge2d_config.src_planes[2].h = 0; |
| |
| yaddr = keep_phy_addr(keep_y_addr); |
| canvas_config(ydupindex, |
| (ulong) yaddr, |
| cs.width, cs.height, |
| CANVAS_ADDR_NOWRAP, cs.blkmode); |
| |
| canvas_read(ydupindex, &cd); |
| ge2d_config.dst_planes[0].addr = cd.addr; |
| ge2d_config.dst_planes[0].w = cd.width; |
| ge2d_config.dst_planes[0].h = cd.height; |
| ge2d_config.dst_planes[1].addr = 0; |
| ge2d_config.dst_planes[1].w = 0; |
| ge2d_config.dst_planes[1].h = 0; |
| ge2d_config.dst_planes[2].addr = 0; |
| ge2d_config.dst_planes[2].w = 0; |
| ge2d_config.dst_planes[2].h = 0; |
| |
| ge2d_config.src_key.key_enable = 0; |
| ge2d_config.src_key.key_mask = 0; |
| ge2d_config.src_key.key_mode = 0; |
| ge2d_config.src_key.key_color = 0; |
| |
| ge2d_config.src_para.canvas_index = y_index; |
| ge2d_config.src_para.mem_type = CANVAS_TYPE_INVALID; |
| ge2d_config.src_para.format = GE2D_FMT_S8_Y; |
| ge2d_config.src_para.fill_color_en = 0; |
| ge2d_config.src_para.fill_mode = 0; |
| ge2d_config.src_para.x_rev = 0; |
| ge2d_config.src_para.y_rev = 0; |
| ge2d_config.src_para.color = 0; |
| ge2d_config.src_para.top = 0; |
| ge2d_config.src_para.left = 0; |
| ge2d_config.src_para.width = cs.width; |
| ge2d_config.src_para.height = cs.height; |
| ge2d_config.src2_para.mem_type = CANVAS_TYPE_INVALID; |
| ge2d_config.dst_para.canvas_index = ydupindex; |
| ge2d_config.dst_para.mem_type = CANVAS_TYPE_INVALID; |
| ge2d_config.dst_para.format = GE2D_FMT_S8_Y; |
| ge2d_config.dst_para.fill_color_en = 0; |
| ge2d_config.dst_para.fill_mode = 0; |
| ge2d_config.dst_para.x_rev = 0; |
| ge2d_config.dst_para.y_rev = 0; |
| ge2d_config.dst_xy_swap = 0; |
| ge2d_config.dst_para.color = 0; |
| ge2d_config.dst_para.top = 0; |
| ge2d_config.dst_para.left = 0; |
| ge2d_config.dst_para.width = cs.width; |
| ge2d_config.dst_para.height = cs.height; |
| |
| if (ge2d_context_config_ex(ge2d_video_context, &ge2d_config) < 0) { |
| pr_info("++ge2d configing error.\n"); |
| return -1; |
| } |
| stretchblt_noalpha(ge2d_video_context, |
| 0, 0, cs.width, cs.height, |
| 0, 0, cs.width, cs.height); |
| |
| /* U data */ |
| ge2d_config.alu_const_color = 0; |
| ge2d_config.bitmask_en = 0; |
| ge2d_config.src1_gb_alpha = 0; |
| |
| u_index = (cur_index >> 8) & 0xff; |
| canvas_read(u_index, &cs); |
| ge2d_config.src_planes[0].addr = cs.addr; |
| ge2d_config.src_planes[0].w = cs.width; |
| ge2d_config.src_planes[0].h = cs.height; |
| ge2d_config.src_planes[1].addr = 0; |
| ge2d_config.src_planes[1].w = 0; |
| ge2d_config.src_planes[1].h = 0; |
| ge2d_config.src_planes[2].addr = 0; |
| ge2d_config.src_planes[2].w = 0; |
| ge2d_config.src_planes[2].h = 0; |
| |
| uaddr = keep_phy_addr(keep_u_addr); |
| canvas_config(udupindex, |
| (ulong) uaddr, |
| cs.width, cs.height, |
| CANVAS_ADDR_NOWRAP, cs.blkmode); |
| |
| canvas_read(udupindex, &cd); |
| ge2d_config.dst_planes[0].addr = cd.addr; |
| ge2d_config.dst_planes[0].w = cd.width; |
| ge2d_config.dst_planes[0].h = cd.height; |
| ge2d_config.dst_planes[1].addr = 0; |
| ge2d_config.dst_planes[1].w = 0; |
| ge2d_config.dst_planes[1].h = 0; |
| ge2d_config.dst_planes[2].addr = 0; |
| ge2d_config.dst_planes[2].w = 0; |
| ge2d_config.dst_planes[2].h = 0; |
| |
| ge2d_config.src_key.key_enable = 0; |
| ge2d_config.src_key.key_mask = 0; |
| ge2d_config.src_key.key_mode = 0; |
| ge2d_config.src_key.key_color = 0; |
| |
| ge2d_config.src_para.canvas_index = u_index; |
| ge2d_config.src_para.mem_type = CANVAS_TYPE_INVALID; |
| ge2d_config.src_para.format = GE2D_FMT_S8_CB; |
| ge2d_config.src_para.fill_color_en = 0; |
| ge2d_config.src_para.fill_mode = 0; |
| ge2d_config.src_para.x_rev = 0; |
| ge2d_config.src_para.y_rev = 0; |
| ge2d_config.src_para.color = 0; |
| ge2d_config.src_para.top = 0; |
| ge2d_config.src_para.left = 0; |
| ge2d_config.src_para.width = cs.width; |
| ge2d_config.src_para.height = cs.height; |
| |
| ge2d_config.dst_para.canvas_index = udupindex; |
| ge2d_config.dst_para.mem_type = CANVAS_TYPE_INVALID; |
| ge2d_config.dst_para.format = GE2D_FMT_S8_CB; |
| ge2d_config.dst_para.fill_color_en = 0; |
| ge2d_config.dst_para.fill_mode = 0; |
| ge2d_config.dst_para.x_rev = 0; |
| ge2d_config.dst_para.y_rev = 0; |
| ge2d_config.dst_xy_swap = 0; |
| ge2d_config.dst_para.color = 0; |
| ge2d_config.dst_para.top = 0; |
| ge2d_config.dst_para.left = 0; |
| ge2d_config.dst_para.width = cs.width; |
| ge2d_config.dst_para.height = cs.height; |
| |
| if (ge2d_context_config_ex(ge2d_video_context, &ge2d_config) < 0) { |
| pr_info("++ge2d configing error.\n"); |
| return -1; |
| } |
| stretchblt_noalpha(ge2d_video_context, |
| 0, 0, cs.width, cs.height, |
| 0, 0, cs.width, cs.height); |
| |
| /* operation top line */ |
| /* V data */ |
| ge2d_config.alu_const_color = 0; |
| ge2d_config.bitmask_en = 0; |
| ge2d_config.src1_gb_alpha = 0; |
| |
| v_index = (cur_index >> 16) & 0xff; |
| canvas_read(v_index, &cs); |
| ge2d_config.src_planes[0].addr = cs.addr; |
| ge2d_config.src_planes[0].w = cs.width; |
| ge2d_config.src_planes[0].h = cs.height; |
| ge2d_config.src_planes[1].addr = 0; |
| ge2d_config.src_planes[1].w = 0; |
| ge2d_config.src_planes[1].h = 0; |
| ge2d_config.src_planes[2].addr = 0; |
| ge2d_config.src_planes[2].w = 0; |
| ge2d_config.src_planes[2].h = 0; |
| |
| vaddr = keep_phy_addr(keep_v_addr); |
| canvas_config(vdupindex, |
| (ulong) vaddr, |
| cs.width, cs.height, |
| CANVAS_ADDR_NOWRAP, cs.blkmode); |
| |
| ge2d_config.dst_planes[0].addr = cd.addr; |
| ge2d_config.dst_planes[0].w = cd.width; |
| ge2d_config.dst_planes[0].h = cd.height; |
| ge2d_config.dst_planes[1].addr = 0; |
| ge2d_config.dst_planes[1].w = 0; |
| ge2d_config.dst_planes[1].h = 0; |
| ge2d_config.dst_planes[2].addr = 0; |
| ge2d_config.dst_planes[2].w = 0; |
| ge2d_config.dst_planes[2].h = 0; |
| |
| ge2d_config.src_key.key_enable = 0; |
| ge2d_config.src_key.key_mask = 0; |
| ge2d_config.src_key.key_mode = 0; |
| ge2d_config.src_key.key_color = 0; |
| |
| ge2d_config.src_para.canvas_index = v_index; |
| ge2d_config.src_para.mem_type = CANVAS_TYPE_INVALID; |
| ge2d_config.src_para.format = GE2D_FMT_S8_CR; |
| ge2d_config.src_para.fill_color_en = 0; |
| ge2d_config.src_para.fill_mode = 0; |
| ge2d_config.src_para.x_rev = 0; |
| ge2d_config.src_para.y_rev = 0; |
| ge2d_config.src_para.color = 0; |
| ge2d_config.src_para.top = 0; |
| ge2d_config.src_para.left = 0; |
| ge2d_config.src_para.width = cs.width; |
| ge2d_config.src_para.height = cs.height; |
| |
| ge2d_config.dst_para.canvas_index = vdupindex; |
| ge2d_config.dst_para.mem_type = CANVAS_TYPE_INVALID; |
| ge2d_config.dst_para.format = GE2D_FMT_S8_CR; |
| ge2d_config.dst_para.fill_color_en = 0; |
| ge2d_config.dst_para.fill_mode = 0; |
| ge2d_config.dst_para.x_rev = 0; |
| ge2d_config.dst_para.y_rev = 0; |
| ge2d_config.dst_xy_swap = 0; |
| ge2d_config.dst_para.color = 0; |
| ge2d_config.dst_para.top = 0; |
| ge2d_config.dst_para.left = 0; |
| ge2d_config.dst_para.width = cs.width; |
| ge2d_config.dst_para.height = cs.height; |
| |
| if (ge2d_context_config_ex(ge2d_video_context, &ge2d_config) < 0) { |
| pr_info("++ge2d configing error.\n"); |
| return -1; |
| } |
| stretchblt_noalpha(ge2d_video_context, |
| 0, 0, cs.width, cs.height, |
| 0, 0, cs.width, cs.height); |
| return 0; |
| } |
| |
| static void ge2d_keeplastframe_block(int cur_index, int format) |
| { |
| u32 y_index, u_index, v_index; |
| #ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA |
| u32 y_index2, u_index2, v_index2; |
| #endif |
| |
| video_module_lock(); |
| |
| #ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA |
| y_index = vd_layer[0].canvas_tbl[0][0]; |
| y_index2 = vd_layer[0].canvas_tbl[1][0]; |
| u_index = vd_layer[0].canvas_tbl[0][1]; |
| u_index2 = vd_layer[0].canvas_tbl[1][1]; |
| v_index = vd_layer[0].canvas_tbl[0][2]; |
| v_index2 = vd_layer[0].canvas_tbl[1][2]; |
| #else |
| /* |
| *cur_index = READ_VCBUS_REG(VD1_IF0_CANVAS0 + |
| * get_video_cur_dev->viu_off); |
| */ |
| y_index = cur_index & 0xff; |
| u_index = (cur_index >> 8) & 0xff; |
| v_index = (cur_index >> 16) & 0xff; |
| #endif |
| |
| switch (format) { |
| case GE2D_FORMAT_S24_YUV444: |
| pr_info("GE2D_FORMAT_S24_YUV444\n"); |
| ge2d_store_frame_S_YUV444(cur_index); |
| canvas_update_addr(y_index, keep_phy_addr(keep_y_addr)); |
| #ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA |
| canvas_update_addr(y_index2, keep_phy_addr(keep_y_addr)); |
| pr_info("y_index: [0x%x],y_index2: [0x%x]\n", |
| y_index, y_index2); |
| #endif |
| pr_info("cur_index: [0x%x],keep_y_addr: [0x%lx]\n", |
| cur_index, keep_y_addr); |
| |
| break; |
| case GE2D_FORMAT_M24_YUV444: |
| pr_info("GE2D_FORMAT_M24_YUV444\n"); |
| ge2d_store_frame_YUV444(cur_index); |
| canvas_update_addr(y_index, keep_phy_addr(keep_y_addr)); |
| #ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA |
| canvas_update_addr(y_index2, keep_phy_addr(keep_y_addr)); |
| #endif |
| break; |
| case GE2D_FORMAT_M24_NV21: |
| pr_info("GE2D_FORMAT_M24_NV21\n"); |
| ge2d_store_frame_NV21(cur_index); |
| canvas_update_addr(y_index, keep_phy_addr(keep_y_addr)); |
| canvas_update_addr(u_index, keep_phy_addr(keep_u_addr)); |
| #ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA |
| canvas_update_addr(y_index2, keep_phy_addr(keep_y_addr)); |
| canvas_update_addr(u_index2, keep_phy_addr(keep_u_addr)); |
| #endif |
| break; |
| case GE2D_FORMAT_M24_YUV420: |
| pr_info("GE2D_FORMAT_M24_YUV420\n"); |
| ge2d_store_frame_YUV420(cur_index); |
| canvas_update_addr(y_index, keep_phy_addr(keep_y_addr)); |
| canvas_update_addr(u_index, keep_phy_addr(keep_u_addr)); |
| canvas_update_addr(v_index, keep_phy_addr(keep_v_addr)); |
| #ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA |
| canvas_update_addr(y_index2, keep_phy_addr(keep_y_addr)); |
| canvas_update_addr(u_index2, keep_phy_addr(keep_u_addr)); |
| canvas_update_addr(v_index2, keep_phy_addr(keep_v_addr)); |
| #endif |
| break; |
| default: |
| pr_info("default\n"); |
| break; |
| } |
| video_module_unlock(); |
| |
| } |
| #endif |
| #ifndef CONFIG_AMLOGIC_MEDIA_GE2D |
| #define FETCHBUF_SIZE (64*1024) /*DEBUG_TMP*/ |
| static int canvas_dup(ulong dst, ulong src_paddr, ulong size) |
| { |
| void *src_addr = codec_mm_phys_to_virt(src_paddr); |
| void *dst_addr = codec_mm_phys_to_virt(dst); |
| |
| if (src_paddr && dst && src_addr && dst_addr) { |
| dma_addr_t dma_addr = 0; |
| memcpy(dst_addr, src_addr, size); |
| dma_addr = dma_map_single(get_video_device(), dst_addr, |
| size, DMA_TO_DEVICE); |
| dma_unmap_single(get_video_device(), dma_addr, |
| FETCHBUF_SIZE, DMA_TO_DEVICE); |
| return 1; |
| } |
| |
| return 0; |
| } |
| #endif |
| #ifdef RESERVE_CLR_FRAME |
| static int free_alloced_keep_buffer(void) |
| { |
| /*pr_info("free_alloced_keep_buffer %p.%p.%p\n", |
| (void *)keep_y_addr, (void *)keep_u_addr, (void *)keep_v_addr); |
| */ |
| if (keep_y_addr) { |
| codec_mm_free_for_dma(MEM_NAME, keep_y_addr); |
| keep_y_addr = 0; |
| } |
| |
| if (keep_u_addr) { |
| codec_mm_free_for_dma(MEM_NAME, keep_u_addr); |
| keep_u_addr = 0; |
| } |
| |
| if (keep_v_addr) { |
| codec_mm_free_for_dma(MEM_NAME, keep_v_addr); |
| keep_v_addr = 0; |
| } |
| return 0; |
| } |
| |
| static int alloc_keep_buffer(void) |
| { |
| int flags = CODEC_MM_FLAGS_DMA | |
| CODEC_MM_FLAGS_FOR_VDECODER; |
| #ifndef CONFIG_AMLOGIC_MEDIA_GE2D |
| /* |
| * if not used ge2d. |
| * need CPU access. |
| */ |
| flags = CODEC_MM_FLAGS_DMA | CODEC_MM_FLAGS_FOR_VDECODER; |
| #endif |
| if ((flags & CODEC_MM_FLAGS_FOR_VDECODER) && |
| codec_mm_video_tvp_enabled()) |
| /*TVP TODO for MULTI*/ |
| flags |= CODEC_MM_FLAGS_TVP; |
| |
| if (!keep_y_addr) { |
| keep_y_addr = codec_mm_alloc_for_dma( |
| MEM_NAME, |
| PAGE_ALIGN(Y_BUFFER_SIZE)/PAGE_SIZE, 0, flags); |
| if (!keep_y_addr) { |
| pr_err("%s: failed to alloc y addr\n", __func__); |
| goto err1; |
| } |
| } |
| |
| if (!keep_u_addr) { |
| keep_u_addr = codec_mm_alloc_for_dma( |
| MEM_NAME, |
| PAGE_ALIGN(U_BUFFER_SIZE)/PAGE_SIZE, 0, flags); |
| if (!keep_u_addr) { |
| pr_err("%s: failed to alloc u addr\n", __func__); |
| goto err1; |
| } |
| } |
| |
| if (!keep_v_addr) { |
| keep_v_addr = codec_mm_alloc_for_dma( |
| MEM_NAME, |
| PAGE_ALIGN(V_BUFFER_SIZE)/PAGE_SIZE, 0, flags); |
| if (!keep_v_addr) { |
| pr_err("%s: failed to alloc v addr\n", __func__); |
| goto err1; |
| } |
| } |
| pr_info("alloced keep buffer yaddr=%p,u_addr=%p,v_addr=%p,tvp=%d\n", |
| (void *)keep_y_addr, |
| (void *)keep_u_addr, |
| (void *)keep_v_addr, |
| codec_mm_video_tvp_enabled()); |
| return 0; |
| |
| err1: |
| free_alloced_keep_buffer(); |
| return -ENOMEM; |
| } |
| |
| /* |
| *flags,used per bit: |
| *deflaut free alloced keeper buffer. |
| *0x1: free scatters keeper.. |
| *0x2: |
| */ |
| void try_free_keep_video(int flags) |
| { |
| int free_scatter_keeper = flags & 0x1; |
| bool layer1_used = false; |
| bool layer2_used = false; |
| |
| if (vd_layer[0].dispbuf_mapping |
| == &cur_dispbuf) |
| layer1_used = true; |
| if (vd_layer[1].dispbuf_mapping |
| == &cur_dispbuf) |
| layer2_used = true; |
| |
| if (keep_video_on || free_scatter_keeper) { |
| /*pr_info("disbled keep video before free keep buffer.\n");*/ |
| keep_video_on = 0; |
| if (layer1_used) { |
| if (!get_video_enabled()) { |
| pr_info("disabled amvideo on vd1 for next before free keep buffer!\n"); |
| _video_set_disable(flags ? |
| VIDEO_DISABLE_NORMAL : |
| VIDEO_DISABLE_FORNEXT); |
| } else { |
| safe_switch_videolayer(0, false, false); |
| } |
| } |
| if (layer2_used) { |
| if (!get_videopip_enabled()) { |
| pr_info("disabled amvideo on vd2 for next before free keep buffer!\n"); |
| _videopip_set_disable(flags ? |
| VIDEO_DISABLE_NORMAL : |
| VIDEO_DISABLE_FORNEXT); |
| } else { |
| safe_switch_videolayer(1, false, false); |
| } |
| } |
| } |
| mutex_lock(&video_keeper_mutex); |
| video_keeper_new_frame_notify(); |
| free_alloced_keep_buffer(); |
| mutex_unlock(&video_keeper_mutex); |
| } |
| EXPORT_SYMBOL(try_free_keep_video); |
| #endif |
| |
| void try_free_keep_videopip(int flags) |
| { |
| int free_scatter_keeper = flags & 0x1; |
| bool layer1_used = false; |
| bool layer2_used = false; |
| |
| if (vd_layer[0].dispbuf_mapping |
| == &cur_pipbuf) |
| layer1_used = true; |
| if (vd_layer[1].dispbuf_mapping |
| == &cur_pipbuf) |
| layer2_used = true; |
| |
| if (keep_video_pip_on || free_scatter_keeper) { |
| /*pr_info("disbled keep video before free keep buffer.\n");*/ |
| keep_video_pip_on = 0; |
| if (layer1_used) { |
| if (!get_video_enabled()) { |
| pr_info("disabled pip on vd1 for next before free keep buffer!\n"); |
| _video_set_disable(flags ? |
| VIDEO_DISABLE_NORMAL : |
| VIDEO_DISABLE_FORNEXT); |
| } else { |
| safe_switch_videolayer(0, false, false); |
| } |
| } |
| if (layer2_used) { |
| if (!get_videopip_enabled()) { |
| pr_info("disabled pip on vd2 for next before free keep buffer!\n"); |
| _videopip_set_disable(flags ? |
| VIDEO_DISABLE_NORMAL : |
| VIDEO_DISABLE_FORNEXT); |
| } else { |
| safe_switch_videolayer(1, false, false); |
| } |
| } |
| } |
| mutex_lock(&video_keeper_mutex); |
| video_pip_keeper_new_frame_notify(); |
| mutex_unlock(&video_keeper_mutex); |
| } |
| EXPORT_SYMBOL(try_free_keep_videopip); |
| |
| static void video_keeper_update_keeper_mem( |
| void *mem_handle, int type, |
| int *id) |
| { |
| int ret; |
| int old_id = *id; |
| |
| if (!mem_handle) |
| return; |
| ret = codec_mm_keeper_mask_keep_mem(mem_handle, |
| type); |
| if (ret > 0) { |
| if (old_id > 0 && ret != old_id) { |
| /*wait 80 ms for vsync post.*/ |
| codec_mm_keeper_unmask_keeper(old_id, 120); |
| } |
| *id = ret; |
| } |
| } |
| |
| static int video_keeper_frame_keep_locked( |
| struct vframe_s *cur_buf, |
| struct vframe_s *cur_buf_el) |
| { |
| int type = MEM_TYPE_CODEC_MM; |
| |
| if (cur_buf->type & VIDTYPE_SCATTER) |
| type = MEM_TYPE_CODEC_MM_SCATTER; |
| video_keeper_update_keeper_mem( |
| cur_buf->mem_handle, |
| type, |
| &keep_id); |
| video_keeper_update_keeper_mem( |
| cur_buf->mem_head_handle, |
| MEM_TYPE_CODEC_MM, |
| &keep_head_id); |
| video_keeper_update_keeper_mem( |
| cur_buf->mem_dw_handle, |
| MEM_TYPE_CODEC_MM, |
| &keep_dw_id); |
| if (cur_buf_el) { |
| if (cur_buf->type & VIDTYPE_SCATTER) |
| type = MEM_TYPE_CODEC_MM_SCATTER; |
| else |
| type = MEM_TYPE_CODEC_MM; |
| video_keeper_update_keeper_mem( |
| cur_buf_el->mem_handle, |
| type, |
| &keep_el_id); |
| video_keeper_update_keeper_mem( |
| cur_buf_el->mem_head_handle, |
| MEM_TYPE_CODEC_MM, |
| &keep_el_head_id); |
| video_keeper_update_keeper_mem( |
| cur_buf_el->mem_dw_handle, |
| MEM_TYPE_CODEC_MM, |
| &keep_el_dw_id); |
| } |
| return (keep_id + keep_head_id + keep_dw_id) > 0; |
| } |
| |
| static int video_pip_keeper_frame_keep_locked( |
| struct vframe_s *cur_buf, |
| struct vframe_s *cur_buf_el) |
| { |
| int type = MEM_TYPE_CODEC_MM; |
| |
| if (cur_buf) { |
| if (cur_buf->type & VIDTYPE_SCATTER) |
| type = MEM_TYPE_CODEC_MM_SCATTER; |
| video_keeper_update_keeper_mem( |
| cur_buf->mem_handle, |
| type, |
| &keep_pip_id); |
| video_keeper_update_keeper_mem( |
| cur_buf->mem_head_handle, |
| MEM_TYPE_CODEC_MM, |
| &keep_pip_head_id); |
| video_keeper_update_keeper_mem( |
| cur_buf->mem_dw_handle, |
| MEM_TYPE_CODEC_MM, |
| &keep_pip_dw_id); |
| } |
| if (cur_buf_el) { |
| if (cur_buf_el->type & VIDTYPE_SCATTER) |
| type = MEM_TYPE_CODEC_MM_SCATTER; |
| else |
| type = MEM_TYPE_CODEC_MM; |
| video_keeper_update_keeper_mem( |
| cur_buf_el->mem_handle, |
| type, |
| &keep_pip_el_id); |
| video_keeper_update_keeper_mem( |
| cur_buf_el->mem_head_handle, |
| MEM_TYPE_CODEC_MM, |
| &keep_pip_el_head_id); |
| video_keeper_update_keeper_mem( |
| cur_buf_el->mem_dw_handle, |
| MEM_TYPE_CODEC_MM, |
| &keep_pip_el_dw_id); |
| } |
| return (keep_pip_id + keep_pip_head_id + keep_pip_el_dw_id) > 0; |
| } |
| |
| /* |
| * call in irq. |
| *don't used mutex |
| */ |
| void video_keeper_new_frame_notify(void) |
| { |
| if (keep_video_on) { |
| pr_info("new frame show, free keeper\n"); |
| keep_video_on = 0; |
| } |
| if (keep_id > 0) { |
| /*wait 80 ms for vsync post.*/ |
| codec_mm_keeper_unmask_keeper(keep_id, 120); |
| keep_id = 0; |
| } |
| if (keep_head_id > 0) { |
| /*wait 80 ms for vsync post.*/ |
| codec_mm_keeper_unmask_keeper(keep_head_id, 120); |
| keep_head_id = 0; |
| } |
| if (keep_dw_id > 0) { |
| /*wait 80 ms for vsync post.*/ |
| codec_mm_keeper_unmask_keeper(keep_dw_id, 120); |
| keep_dw_id = 0; |
| } |
| |
| if (keep_el_id > 0) { |
| /*wait 80 ms for vsync post.*/ |
| codec_mm_keeper_unmask_keeper(keep_el_id, 120); |
| keep_el_id = 0; |
| } |
| if (keep_el_head_id > 0) { |
| /*wait 80 ms for vsync post.*/ |
| codec_mm_keeper_unmask_keeper(keep_el_head_id, 120); |
| keep_el_head_id = 0; |
| } |
| if (keep_el_dw_id > 0) { |
| /*wait 80 ms for vsync post.*/ |
| codec_mm_keeper_unmask_keeper(keep_el_dw_id, 120); |
| keep_el_dw_id = 0; |
| } |
| return; |
| } |
| |
| void video_pip_keeper_new_frame_notify(void) |
| { |
| if (keep_video_pip_on) { |
| pr_info("new frame show, pip free keeper\n"); |
| keep_video_pip_on = 0; |
| } |
| if (keep_pip_id > 0) { |
| /*wait 80 ms for vsync post.*/ |
| codec_mm_keeper_unmask_keeper(keep_pip_id, 120); |
| keep_pip_id = 0; |
| } |
| if (keep_pip_head_id > 0) { |
| /*wait 80 ms for vsync post.*/ |
| codec_mm_keeper_unmask_keeper(keep_pip_head_id, 120); |
| keep_pip_head_id = 0; |
| } |
| if (keep_pip_dw_id > 0) { |
| /*wait 80 ms for vsync post.*/ |
| codec_mm_keeper_unmask_keeper(keep_pip_dw_id, 120); |
| keep_pip_dw_id = 0; |
| } |
| |
| if (keep_pip_el_id > 0) { |
| /*wait 80 ms for vsync post.*/ |
| codec_mm_keeper_unmask_keeper(keep_pip_el_id, 120); |
| keep_pip_el_id = 0; |
| } |
| if (keep_pip_el_head_id > 0) { |
| /*wait 80 ms for vsync post.*/ |
| codec_mm_keeper_unmask_keeper(keep_pip_el_head_id, 120); |
| keep_pip_el_head_id = 0; |
| } |
| if (keep_pip_el_dw_id > 0) { |
| /*wait 80 ms for vsync post.*/ |
| codec_mm_keeper_unmask_keeper(keep_pip_el_dw_id, 120); |
| keep_pip_el_dw_id = 0; |
| } |
| |
| } |
| |
| #ifdef CONFIG_AMLOGIC_MEDIA_GE2D |
| static unsigned int vf_ge2d_keep_frame_locked(struct vframe_s *ge2d_buf) |
| { |
| u32 cur_index = 0; |
| u32 y_index, u_index, v_index; |
| struct canvas_s cs0, cs1, cs2, cd; |
| bool layer1_used = false; |
| bool layer2_used = false; |
| |
| if (vd_layer[0].dispbuf_mapping |
| == &cur_dispbuf) |
| layer1_used = true; |
| if (vd_layer[1].dispbuf_mapping |
| == &cur_dispbuf) |
| layer2_used = true; |
| |
| #ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC |
| if (codec_mm_video_tvp_enabled()) { |
| pr_info("keep exit is TVP\n"); |
| return 0; |
| } |
| #endif |
| |
| if (ge2d_buf->type & VIDTYPE_COMPRESS) { |
| /* todo: duplicate compressed video frame */ |
| pr_info("keep exit is skip VIDTYPE_COMPRESS\n"); |
| return 0; |
| } |
| |
| if (!layer1_used && !layer2_used) { |
| /* No layer to display this path */ |
| pr_info("keep exit because no layer to keep this buffer\n"); |
| return -1; |
| } |
| |
| if (layer1_used) |
| cur_index = get_layer_display_canvas(0); |
| else if (layer2_used) |
| cur_index = get_layer_display_canvas(1); |
| |
| y_index = cur_index & 0xff; |
| u_index = (cur_index >> 8) & 0xff; |
| v_index = (cur_index >> 16) & 0xff; |
| canvas_read(y_index, &cd); |
| |
| if ((cd.width * cd.height) <= 1920 * 1088 * 3 |
| && !keep_y_addr) { |
| alloc_keep_buffer(); |
| } |
| if (!keep_y_addr) { |
| pr_info("%s:alloc keep buffer failed, keep_y_addr is NULL!\n", |
| __func__); |
| return 0; |
| } |
| |
| if (get_video_debug_flags() & DEBUG_FLAG_BLACKOUT) { |
| pr_info("%s keep_y_addr=%p %x\n", |
| __func__, (void *)keep_y_addr, |
| canvas_get_addr(y_index)); |
| } |
| |
| if ((ge2d_buf->type & VIDTYPE_VIU_422) == VIDTYPE_VIU_422) { |
| pr_info("%s:no support VIDTYPE_VIU_422\n", __func__); |
| return 0; |
| } else if ((ge2d_buf->type & VIDTYPE_VIU_444) == VIDTYPE_VIU_444) { |
| if ((Y_BUFFER_SIZE < (cd.width * cd.height))) { |
| pr_info |
| ("[%s::%d] error:data>buf size: %x,%x,%x, %x,%x\n", |
| __func__, __LINE__, Y_BUFFER_SIZE, |
| U_BUFFER_SIZE, V_BUFFER_SIZE, |
| cd.width, cd.height); |
| return 0; |
| } |
| ge2d_keeplastframe_block(cur_index, GE2D_FORMAT_S24_YUV444); |
| if (get_video_debug_flags() & DEBUG_FLAG_BLACKOUT) |
| pr_info("%s: VIDTYPE_VIU_444\n", __func__); |
| } else if ((ge2d_buf->type & VIDTYPE_VIU_NV21) == VIDTYPE_VIU_NV21) { |
| canvas_read(y_index, &cs0); |
| canvas_read(u_index, &cs1); |
| if ((Y_BUFFER_SIZE < (cs0.width * cs0.height)) |
| || (U_BUFFER_SIZE < (cs1.width * cs1.height))) { |
| pr_info("## [%s::%d] error: yuv data size larger", |
| __func__, __LINE__); |
| return 0; |
| } |
| ge2d_keeplastframe_block(cur_index, GE2D_FORMAT_M24_NV21); |
| if (get_video_debug_flags() & DEBUG_FLAG_BLACKOUT) |
| pr_info("%s: VIDTYPE_VIU_NV21\n", __func__); |
| } else { |
| canvas_read(y_index, &cs0); |
| canvas_read(u_index, &cs1); |
| canvas_read(v_index, &cs2); |
| |
| if ((Y_BUFFER_SIZE < (cs0.width * cs0.height)) |
| || (U_BUFFER_SIZE < (cs1.width * cs1.height)) |
| || (V_BUFFER_SIZE < (cs2.width * cs2.height))) { |
| pr_info("## [%s::%d] error: yuv data size larger", |
| __func__, __LINE__); |
| return 0; |
| } |
| ge2d_keeplastframe_block(cur_index, GE2D_FORMAT_M24_YUV420); |
| if (get_video_debug_flags() & DEBUG_FLAG_BLACKOUT) |
| pr_info("%s: VIDTYPE_VIU_420\n", __func__); |
| } |
| pr_info("%s: use ge2d keep video\n", __func__); |
| return 1; |
| |
| } |
| #endif |
| |
| static unsigned int vf_keep_current_locked( |
| struct vframe_s *cur_buf, |
| struct vframe_s *cur_buf_el) |
| { |
| int ret; |
| |
| if (!cur_buf) { |
| pr_info("keep exit without cur_buf\n"); |
| return 0; |
| } |
| |
| if (get_video_debug_flags() & |
| DEBUG_FLAG_TOGGLE_SKIP_KEEP_CURRENT) { |
| pr_info("keep exit is skip current\n"); |
| return 0; |
| } |
| |
| #ifdef CONFIG_AMLOGIC_MEDIA_VIDEOCAPTURE |
| ext_frame_capture_poll(1); /*pull if have capture end frame */ |
| #endif |
| |
| if (get_blackout_policy()) { |
| pr_info("keep exit is skip current\n"); |
| return 0; |
| } |
| |
| #if 1 |
| if (cur_buf->type & VIDTYPE_PRE_INTERLACE) { |
| if (cur_buf->flag & VFRAME_FLAG_DOUBLE_FRAM) { |
| ret = video_keeper_frame_keep_locked( |
| cur_buf->vf_ext, |
| cur_buf_el); |
| pr_info("keep di_dec buffer\n"); |
| return ret; |
| } |
| pr_info("keep exit is di\n"); |
| return 2; |
| } |
| |
| #else |
| if (VSYNC_RD_MPEG_REG(DI_IF1_GEN_REG) & 0x1) { |
| pr_info("keep exit is di\n"); |
| return 0; |
| } |
| #endif |
| if (cur_buf->source_type == VFRAME_SOURCE_TYPE_PPMGR) { |
| pr_info("ppmgr use ge2d keep frame!\n"); |
| ret = vf_ge2d_keep_frame_locked(cur_buf); |
| } else { |
| pr_info("use keep buffer keep frame!\n"); |
| ret = video_keeper_frame_keep_locked( |
| cur_buf, |
| cur_buf_el); |
| } |
| |
| if (ret) { |
| keep_video_on = 1; |
| pr_info("%s: keep video successful!\n", __func__); |
| } else { |
| keep_video_on = 0; |
| pr_info("%s: keep video failed!\n", __func__); |
| } |
| return ret; |
| } |
| |
| unsigned int vf_keep_pip_current_locked( |
| struct vframe_s *cur_buf, |
| struct vframe_s *cur_buf_el) |
| { |
| int ret; |
| |
| if (!cur_buf) { |
| pr_info("keep pip exit without cur_buf\n"); |
| return 0; |
| } |
| |
| if (get_video_debug_flags() & |
| DEBUG_FLAG_TOGGLE_SKIP_KEEP_CURRENT) { |
| pr_info("flag: keep pip exit is skip current\n"); |
| return 0; |
| } |
| |
| #ifdef CONFIG_AMLOGIC_MEDIA_VIDEOCAPTURE |
| ext_frame_capture_poll(1); /*pull if have capture end frame */ |
| #endif |
| |
| if (get_blackout_pip_policy()) { |
| pr_info("policy: keep exit is skip current\n"); |
| return 0; |
| } |
| |
| ret = video_pip_keeper_frame_keep_locked( |
| cur_buf, |
| cur_buf_el); |
| |
| if (ret) { |
| /*keeped ok with codec keeper!*/ |
| pr_info("keep pip buffer on!\n"); |
| keep_video_pip_on = 1; |
| return 1; |
| } |
| |
| keep_video_pip_on = 0; |
| return 0; |
| } |
| |
| unsigned int vf_keep_current( |
| struct vframe_s *cur_buf, |
| struct vframe_s *cur_buf2) |
| { |
| unsigned int ret; |
| |
| mutex_lock(&video_keeper_mutex); |
| ret = vf_keep_current_locked( |
| cur_buf, cur_buf2); |
| mutex_unlock(&video_keeper_mutex); |
| return ret; |
| } |
| |
| int video_keeper_init(void) |
| { |
| #ifdef CONFIG_AMLOGIC_MEDIA_GE2D |
| /* video_frame_getmem(); */ |
| ge2d_videotask_init(); |
| #endif |
| return 0; |
| } |
| void video_keeper_exit(void) |
| { |
| #ifdef CONFIG_AMLOGIC_MEDIA_GE2D |
| ge2d_videotask_release(); |
| #endif |
| } |
| |