9118 lines
236 KiB
C
9118 lines
236 KiB
C
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
/*
|
|
* Copyright (c) 2025 Amlogic, Inc. All rights reserved.
|
|
*/
|
|
|
|
#include <linux/version.h>
|
|
#include <linux/module.h>
|
|
#include <linux/types.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/semaphore.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/init.h>
|
|
#include <linux/device.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/major.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/cdev.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/list.h>
|
|
#include <linux/of_reserved_mem.h>
|
|
#include <linux/of_irq.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/of_fdt.h>
|
|
#include <linux/cma.h>
|
|
#include <linux/dma-map-ops.h>
|
|
#include <linux/ctype.h>
|
|
#include <linux/string.h>
|
|
#include <linux/amlogic/iomap.h>
|
|
#include <linux/amlogic/media/codec_mm/codec_mm.h>
|
|
/* media module used media/registers/cpu_version.h since kernel 5.4 */
|
|
#include <linux/amlogic/media/registers/cpu_version.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/canvas/canvas.h>
|
|
#include <linux/amlogic/media/canvas/canvas_mgr.h>
|
|
#include <linux/amlogic/media/frame_provider/tvin/tvin_v4l2.h>
|
|
#include <linux/amlogic/media/vout/vinfo.h>
|
|
#include <linux/amlogic/media/vout/vout_notify.h>
|
|
#include <linux/amlogic/media/vpu/vpu.h>
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_RDMA
|
|
#include <linux/amlogic/media/rdma/rdma_mgr.h>
|
|
#endif
|
|
#include <linux/amlogic/media/video_sink/video.h>
|
|
#include "register.h"
|
|
#include "register_nr4.h"
|
|
#include "deinterlace.h"
|
|
#include "deinterlace_dbg.h"
|
|
#include "nr_downscale.h"
|
|
#include "di_pps.h"
|
|
#include "di_pqa.h"
|
|
|
|
/*2018-07-18 add debugfs*/
|
|
#include <linux/seq_file.h>
|
|
#include <linux/debugfs.h>
|
|
/*2018-07-18 -----------*/
|
|
/*
|
|
#undef TRACE_INCLUDE_PATH
|
|
#undef TRACE_INCLUDE_FILE
|
|
#define TRACE_INCLUDE_PATH .
|
|
#define TRACE_INCLUDE_FILE deinterlace_trace
|
|
#include <trace/define_trace.h>
|
|
*/
|
|
|
|
#define CREATE_TRACE_POINTS
|
|
#include "deinterlace_trace.h"
|
|
|
|
#ifdef DET3D
|
|
#include "detect3d.h"
|
|
#endif
|
|
#define ENABLE_SPIN_LOCK_ALWAYS
|
|
|
|
#include <linux/amlogic/gki_module.h>
|
|
|
|
#define DEVICE_NAME "deinterlace"
|
|
#define CLASS_NAME "deinterlace"
|
|
|
|
static struct di_pre_stru_s di_pre_stru;
|
|
|
|
static struct di_post_stru_s di_post_stru;
|
|
|
|
static DEFINE_SPINLOCK(di_lock2);
|
|
|
|
#define di_lock_irqfiq_save(irq_flag) \
|
|
spin_lock_irqsave(&di_lock2, irq_flag)
|
|
|
|
#define di_unlock_irqfiq_restore(irq_flag) \
|
|
spin_unlock_irqrestore(&di_lock2, irq_flag)
|
|
|
|
#ifdef SUPPORT_MPEG_TO_VDIN
|
|
static int mpeg2vdin_flag;
|
|
static int mpeg2vdin_en;
|
|
#endif
|
|
|
|
static bool mc_mem_alloc;
|
|
static struct mutex di_event_mutex;
|
|
static atomic_t di_flag_unreg; //ary 2019-05-27
|
|
static atomic_t di_trig_free_mem;
|
|
|
|
|
|
static unsigned int di_pre_rdma_enable;
|
|
static int di_reg_unreg_cnt = 1000;
|
|
static unsigned int overturn;
|
|
static bool check_start_drop_prog;
|
|
static bool mcpre_en = true;
|
|
unsigned int di_force_bit_mode = 10;
|
|
bool force_prog = true;
|
|
bool combing_fix_en = true;
|
|
int cur_lev = 2;
|
|
static int pps_dstw;
|
|
static int pps_dsth;
|
|
static bool pps_en;
|
|
static unsigned int pps_position = 1;
|
|
static unsigned int pre_enable_mask = 3;/*bit0:ma bit1:mc*/
|
|
static bool pre_hsc_down_en;
|
|
static int pre_hsc_down_width = 480;
|
|
#ifdef DET3D
|
|
static unsigned int det3d_frame_cnt = 50;
|
|
#endif
|
|
static bool calc_mcinfo_en = 1;
|
|
static unsigned int colcfd_thr = 128;
|
|
static unsigned int post_blend;
|
|
static unsigned int post_ei;
|
|
static unsigned int post_cnt;
|
|
static bool post_refresh;
|
|
static bool nrds_en;
|
|
static int bypass_all;
|
|
static int bypass_trick_mode = 1;
|
|
static int bypass_3d = 1;
|
|
static int invert_top_bot;
|
|
static int skip_top_bot;/*1or2: may affect atv when bypass di*/
|
|
static int force_width;
|
|
static int force_height;
|
|
static int prog_proc_config = (1 << 5) | (1 << 1) | 1;
|
|
static int start_frame_drop_count = 2;
|
|
static long same_field_top_count;
|
|
static long same_field_bot_count;
|
|
static unsigned int di_debug_flag;/* enable rdma even di bypassed */
|
|
static unsigned int di_log_flag;
|
|
static unsigned int buf_state_log_threshold = 16;
|
|
static int bypass_state = 1;
|
|
static int di_vscale_skip_enable;
|
|
/*1:enable bypass pre,ei only;
|
|
* 2:debug force bypass pre,ei for post
|
|
*/
|
|
static int by_pass_pre;
|
|
|
|
static int bypass_post;
|
|
static bool post_wr_en;
|
|
static unsigned int post_wr_support;
|
|
static int bypass_post_state;
|
|
/* 0, use di_wr_buf still;
|
|
* 1, call pre_de_done_buf_clear to clear di_wr_buf;
|
|
* 2, do nothing
|
|
*/
|
|
static int use_2_interlace_buff;
|
|
/* prog_proc_config,
|
|
* bit[2:1]: when two field buffers are used,
|
|
* 0 use vpp for blending ,
|
|
* 1 use post_di module for blending
|
|
* 2 debug mode, bob with top field
|
|
* 3 debug mode, bot with bot field
|
|
* bit[0]:
|
|
* 0 "prog vdin" use two field buffers,
|
|
* 1 "prog vdin" use single frame buffer
|
|
* bit[4]:
|
|
* 0 "prog frame from decoder/vdin" use two field buffers,
|
|
* 1 use single frame buffer
|
|
* bit[5]:
|
|
* when two field buffers are used for decoder (bit[4] is 0):
|
|
* 1,handle prog frame as two interlace frames
|
|
* bit[6]:(bit[4] is 0,bit[5] is 0,use_2_interlace_buff is 0): 0,
|
|
* process progress frame as field,blend by post;
|
|
* 1, process progress frame as field,process by normal di
|
|
*/
|
|
/*
|
|
* for source include both progressive and interlace pictures,
|
|
* always use post_di module for blending
|
|
*/
|
|
static int frame_count;
|
|
static int debug_blend_mode = -1;
|
|
static unsigned int pldn_dly1 = 1;
|
|
static int di_vscale_skip_count;
|
|
static int di_vscale_skip_count_real;
|
|
static int vpp_3d_mode;
|
|
static bool det3d_en;
|
|
static int post_hold_line = 8; /*2019-01-10: from VLSI feijun from 17 to 8*/
|
|
static int post_urgent = 1;
|
|
static unsigned int di_printk_flag;
|
|
/*pre process speed debug */
|
|
static int pre_process_time;
|
|
static unsigned int force_recovery = 1;
|
|
static unsigned int force_recovery_count;
|
|
/* 0: not support nr10bit, 1: support nr10bit */
|
|
static unsigned int nr10bit_support;
|
|
static unsigned int nr_done_check_cnt = 5;
|
|
/************For Write register**********************/
|
|
static unsigned int di_stop_reg_flag;
|
|
static unsigned int num_di_stop_reg_addr = 4;
|
|
static unsigned int di_stop_reg_addr[4] = {0};
|
|
static unsigned int di_dbg_mask;
|
|
static bool full_422_pack;
|
|
static bool cma_print;
|
|
static bool pulldown_enable = true;
|
|
static unsigned int pldn_dly = 1;
|
|
|
|
/* destroy unnecessary frames before display */
|
|
static unsigned int hold_video;
|
|
|
|
static DEFINE_SPINLOCK(plist_lock);
|
|
|
|
static di_dev_t *de_devp;
|
|
static dev_t di_devno;
|
|
static struct class *di_clsp;
|
|
|
|
static const char version_s[] = "2019-06-20a: afbc switch from vpp";
|
|
|
|
|
|
/* add avoid vframe put/get error */
|
|
static int di_blocking;
|
|
/*
|
|
* bit[2]: enable bypass all when skip
|
|
* bit[1:0]: enable bypass post when skip
|
|
*/
|
|
|
|
#ifdef RUN_DI_PROCESS_IN_IRQ
|
|
/*
|
|
* di_process() run in irq,
|
|
* di_reg_process(), di_unreg_process() run in kernel thread
|
|
* di_reg_process_irq(), di_unreg_process_irq() run in irq
|
|
* di_vf_put(), di_vf_peek(), di_vf_get() run in irq
|
|
* di_receiver_event_fun() run in task or irq
|
|
*/
|
|
/*
|
|
* important:
|
|
* to set input2pre, VFRAME_EVENT_PROVIDER_VFRAME_READY of
|
|
* vdin should be sent in irq
|
|
*/
|
|
|
|
static int input2pre;
|
|
/*false:process progress by field;
|
|
* true: process progress by frame with 2 interlace buffer
|
|
*/
|
|
static int input2pre_buf_miss_count;
|
|
static int input2pre_proc_miss_count;
|
|
static int input2pre_throw_count;
|
|
static int input2pre_miss_policy;
|
|
/* 0, do not force pre_de_busy to 0, use di_wr_buf after de_irq happen;
|
|
* 1, force pre_de_busy to 0 and call pre_de_done_buf_clear to clear di_wr_buf
|
|
*/
|
|
#endif
|
|
/*false:process progress by field;
|
|
* bit0: process progress by frame with 2 interlace buffer
|
|
* bit1: temp add debug for 3d process FA,1:bit0 force to 1;
|
|
*/
|
|
|
|
#define is_handle_prog_frame_as_interlace(vframe) \
|
|
(((prog_proc_config & 0x30) == 0x20) && \
|
|
((vframe->type & VIDTYPE_VIU_422) == 0))
|
|
|
|
static int disp_frame_count;
|
|
|
|
/* static int start_frame_hold_count = 0; */
|
|
|
|
static int video_peek_cnt;
|
|
static unsigned long reg_unreg_timeout_cnt;
|
|
|
|
#ifdef DET3D
|
|
static unsigned int det3d_mode;
|
|
static void set3d_view(enum tvin_trans_fmt trans_fmt, struct vframe_s *vf);
|
|
#endif
|
|
int get_current_vscale_skip_count(struct vframe_s *vf);
|
|
|
|
static void di_pq_parm_destroy(struct di_pq_parm_s *pq_ptr);
|
|
static struct di_pq_parm_s *di_pq_parm_create(struct am_pq_parm_s *);
|
|
|
|
static uint init_flag;/*flag for di buferr*/
|
|
static unsigned int reg_flag;/*flag for vframe reg/unreg*/
|
|
static unsigned int unreg_cnt;/*cnt for vframe unreg*/
|
|
static unsigned int reg_cnt;/*cnt for vframe reg*/
|
|
static unsigned char active_flag;
|
|
static unsigned char recovery_flag;
|
|
static unsigned int recovery_log_reason;
|
|
static unsigned int recovery_log_queue_idx;
|
|
static struct di_buf_s *recovery_log_di_buf;
|
|
|
|
/* bit 0:
|
|
* 0, keep 3 buffers in pre_ready_list for checking;
|
|
* 1, keep 4 buffers in pre_ready_list for checking;
|
|
*/
|
|
|
|
|
|
static int di_receiver_event_fun(int type, void *data, void *arg);
|
|
static void di_uninit_buf(unsigned int disable_mirror);
|
|
static void log_buffer_state(unsigned char *tag);
|
|
/* static void put_get_disp_buf(void); */
|
|
static unsigned int isbypass_flag = true;
|
|
static unsigned int needbypass_flag = true;
|
|
|
|
static const
|
|
struct vframe_receiver_op_s di_vf_receiver = {
|
|
.event_cb = di_receiver_event_fun
|
|
};
|
|
|
|
static struct vframe_receiver_s di_vf_recv;
|
|
|
|
static vframe_t *di_vf_peek(void *arg);
|
|
static vframe_t *di_vf_get(void *arg);
|
|
static void di_vf_put(vframe_t *vf, void *arg);
|
|
static int di_event_cb(int type, void *data, void *private_data);
|
|
static int di_vf_states(struct vframe_states *states, void *arg);
|
|
static void di_process(void);
|
|
static void di_reg_process(void);
|
|
static void di_reg_process_irq(void);
|
|
static void di_unreg_process(void);
|
|
static void di_unreg_process_irq(void);
|
|
static struct queue_s *get_queue_by_idx(int idx);
|
|
static void dump_state(void);
|
|
static void recycle_keep_buffer(void);
|
|
|
|
static const
|
|
struct vframe_operations_s deinterlace_vf_provider = {
|
|
.peek = di_vf_peek,
|
|
.get = di_vf_get,
|
|
.put = di_vf_put,
|
|
.event_cb = di_event_cb,
|
|
.vf_states = di_vf_states,
|
|
};
|
|
|
|
static struct vframe_provider_s di_vf_prov;
|
|
|
|
static int di_sema_init_flag;
|
|
static struct semaphore di_sema;
|
|
static struct tasklet_struct di_pre_tasklet;
|
|
extern unsigned long long notrace sched_clock(void);
|
|
|
|
void trigger_pre_di_process(unsigned char idx)
|
|
{
|
|
if (di_sema_init_flag == 0)
|
|
return;
|
|
if (!active_flag)
|
|
return;
|
|
log_buffer_state((idx == 'i') ? "irq" : ((idx == 'p') ?
|
|
"put" : ((idx == 'r') ? "rdy" : "oth")));
|
|
|
|
/* tasklet_hi_schedule(&di_pre_tasklet); */
|
|
tasklet_schedule(&di_pre_tasklet);
|
|
de_devp->jiffy = jiffies_64;
|
|
/* trigger di_reg_process and di_unreg_process */
|
|
if ((idx != 'p') && (idx != 'i'))
|
|
up(&di_sema);
|
|
}
|
|
|
|
#define DI_PRE_INTERVAL (HZ / 100)
|
|
|
|
/*
|
|
* progressive frame process type config:
|
|
* 0, process by field;
|
|
* 1, process by frame (only valid for vdin source whose
|
|
* width/height does not change)
|
|
*/
|
|
static vframe_t *vframe_in[MAX_IN_BUF_NUM];
|
|
static vframe_t vframe_in_dup[MAX_IN_BUF_NUM];
|
|
static vframe_t vframe_local[MAX_LOCAL_BUF_NUM * 2];
|
|
static vframe_t vframe_post[MAX_POST_BUF_NUM];
|
|
static struct di_buf_s *cur_post_ready_di_buf;
|
|
|
|
static struct di_buf_s di_buf_local[MAX_LOCAL_BUF_NUM * 2];
|
|
static struct di_buf_s di_buf_in[MAX_IN_BUF_NUM];
|
|
static struct di_buf_s di_buf_post[MAX_POST_BUF_NUM];
|
|
|
|
unsigned int is_need_stop_reg(unsigned int addr)
|
|
{
|
|
int idx = 0;
|
|
|
|
if (di_stop_reg_flag) {
|
|
for (idx = 0; idx < num_di_stop_reg_addr; idx++) {
|
|
if (addr == di_stop_reg_addr[idx]) {
|
|
pr_dbg("stop write addr: %x\n", addr);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void DI_Wr(unsigned int addr, unsigned int val)
|
|
{
|
|
if (is_need_stop_reg(addr))
|
|
return;
|
|
|
|
Wr(addr, val);
|
|
}
|
|
|
|
void DI_Wr_reg_bits(unsigned int adr, unsigned int val,
|
|
unsigned int start, unsigned int len)
|
|
{
|
|
if (is_need_stop_reg(adr))
|
|
return;
|
|
|
|
Wr_reg_bits(adr, val, start, len);
|
|
}
|
|
|
|
void DI_VSYNC_WR_MPEG_REG(unsigned int addr, unsigned int val)
|
|
{
|
|
if (is_need_stop_reg(addr))
|
|
return;
|
|
if (post_wr_en && post_wr_support)
|
|
DI_Wr(addr, val);
|
|
else
|
|
VSYNC_WR_TABLE_REG(VIDEO_PARTITION_TABLE, addr, val);
|
|
}
|
|
|
|
void DI_VSYNC_WR_MPEG_REG_BITS(unsigned int addr, unsigned int val,
|
|
unsigned int start, unsigned int len)
|
|
{
|
|
if (is_need_stop_reg(addr))
|
|
return;
|
|
if (post_wr_en && post_wr_support)
|
|
DI_Wr_reg_bits(addr, val, start, len);
|
|
else
|
|
VSYNC_WR_TABLE_REG_BITS(VIDEO_PARTITION_TABLE, addr, val, start, len);
|
|
}
|
|
|
|
#if 0
|
|
unsigned int DI_POST_REG_RD(unsigned int addr)
|
|
{
|
|
if (IS_ERR_OR_NULL(de_devp))
|
|
return 0;
|
|
if (de_devp->flags & DI_SUSPEND_FLAG) {
|
|
pr_err("[DI] REG 0x%x access prohibited.\n", addr);
|
|
return 0;
|
|
}
|
|
return VSYNC_RD_TABLE_REG(VIDEO_PARTITION_TABLE, addr);
|
|
}
|
|
EXPORT_SYMBOL(DI_POST_REG_RD);
|
|
|
|
int DI_POST_WR_REG_BITS(u32 adr, u32 val, u32 start, u32 len)
|
|
{
|
|
if (IS_ERR_OR_NULL(de_devp))
|
|
return 0;
|
|
if (de_devp->flags & DI_SUSPEND_FLAG) {
|
|
pr_err("[DI] REG 0x%x access prohibited.\n", adr);
|
|
return -1;
|
|
}
|
|
return VSYNC_WR_TABLE_REG_BITS(VIDEO_PARTITION_TABLE, adr, val, start, len);
|
|
}
|
|
EXPORT_SYMBOL(DI_POST_WR_REG_BITS);
|
|
#else
|
|
static unsigned int lDI_POST_REG_RD(unsigned int addr)
|
|
{
|
|
if (IS_ERR_OR_NULL(de_devp))
|
|
return 0;
|
|
if (de_devp->flags & DI_SUSPEND_FLAG) {
|
|
pr_err("[DI] REG 0x%x access prohibited.\n", addr);
|
|
return 0;
|
|
}
|
|
return VSYNC_RD_TABLE_REG(VIDEO_PARTITION_TABLE, addr);
|
|
}
|
|
|
|
static int lDI_POST_WR_REG_BITS(u32 adr, u32 val, u32 start, u32 len)
|
|
{
|
|
if (IS_ERR_OR_NULL(de_devp))
|
|
return 0;
|
|
if (de_devp->flags & DI_SUSPEND_FLAG) {
|
|
pr_err("[DI] REG 0x%x access prohibited.\n", adr);
|
|
return -1;
|
|
}
|
|
return VSYNC_WR_TABLE_REG_BITS(VIDEO_PARTITION_TABLE, adr, val, start, len);
|
|
}
|
|
|
|
static const struct di_ext_ops di_ext = {
|
|
.di_post_reg_rd = lDI_POST_REG_RD,
|
|
.di_post_wr_reg_bits = lDI_POST_WR_REG_BITS,
|
|
.post_update_mc = di_patch_post_update_mc,
|
|
};
|
|
|
|
#endif
|
|
/**********************************/
|
|
|
|
/*****************************
|
|
* di attr management :
|
|
* enable
|
|
* mode
|
|
* reg
|
|
******************************/
|
|
/*config attr*/
|
|
static ssize_t
|
|
show_config(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int pos = 0;
|
|
|
|
return pos;
|
|
}
|
|
|
|
static ssize_t
|
|
store_config(struct device *dev, struct device_attribute *attr, const char *buf,
|
|
size_t count);
|
|
|
|
static int run_flag = DI_RUN_FLAG_RUN;
|
|
static int pre_run_flag = DI_RUN_FLAG_RUN;
|
|
static int dump_state_flag;
|
|
|
|
/*2018-08-17 add debugfs*/
|
|
/*add debugfs: get dump_state parameter*/
|
|
struct di_pre_stru_s *get_di_pre_stru(void)
|
|
{
|
|
return &di_pre_stru;
|
|
}
|
|
|
|
struct di_post_stru_s *get_di_post_stru(void)
|
|
{
|
|
return &di_post_stru;
|
|
}
|
|
|
|
struct di_dev_s *get_di_de_devp(void)
|
|
{
|
|
return de_devp;
|
|
}
|
|
|
|
const char *get_di_version_s(void)
|
|
{
|
|
return version_s;
|
|
}
|
|
|
|
int get_di_di_blocking(void)
|
|
{
|
|
return di_blocking;
|
|
}
|
|
|
|
int get_di_video_peek_cnt(void)
|
|
{
|
|
return video_peek_cnt;
|
|
}
|
|
|
|
unsigned long get_di_reg_unreg_timeout_cnt(void)
|
|
{
|
|
return reg_unreg_timeout_cnt;
|
|
}
|
|
|
|
uint get_di_init_flag(void)
|
|
{
|
|
return init_flag;
|
|
}
|
|
|
|
unsigned char get_di_recovery_flag(void)
|
|
{
|
|
return recovery_flag;
|
|
}
|
|
|
|
unsigned int get_di_recovery_log_reason(void)
|
|
{
|
|
return recovery_log_reason;
|
|
}
|
|
|
|
unsigned int get_di_recovery_log_queue_idx(void)
|
|
{
|
|
return recovery_log_queue_idx;
|
|
}
|
|
|
|
struct di_buf_s *get_di_recovery_log_di_buf(void)
|
|
{
|
|
return recovery_log_di_buf;
|
|
}
|
|
|
|
struct vframe_s **get_di_vframe_in(void)
|
|
{
|
|
return &vframe_in[0];
|
|
}
|
|
|
|
int get_di_dump_state_flag(void)
|
|
{
|
|
return dump_state_flag;
|
|
}
|
|
/********************************************
|
|
* function: for releas mirror mem
|
|
* need call this after unreg di
|
|
********************************************/
|
|
void di_trig_free_mirror_mem(void)
|
|
{
|
|
if (dil_get_diff_ver_flag())
|
|
return;
|
|
|
|
if (atomic_read(&di_flag_unreg)
|
|
&& de_devp->flag_cma != 2
|
|
&& de_devp->flag_cma != 0
|
|
&& active_flag) {
|
|
atomic_set(&di_trig_free_mem, 1);
|
|
up(&di_sema);
|
|
di_pr_info("%s\n", __func__);
|
|
}
|
|
|
|
if (atomic_read(&di_flag_unreg)) {
|
|
diwr_set_power_control_pst(0);
|
|
di_pr_info("disable pst pd\n");
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(di_trig_free_mirror_mem);
|
|
|
|
u32 di_api_get_instance_id(void)
|
|
{
|
|
u32 ret = 0;
|
|
|
|
if (dil_get_diff_ver_flag())
|
|
return ret;
|
|
|
|
if (de_devp)
|
|
ret = de_devp->instance_id;
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(di_api_get_instance_id);
|
|
|
|
static bool di_free_mem_pre(void)
|
|
{
|
|
|
|
if (!atomic_read(&di_trig_free_mem))
|
|
return false;
|
|
if (di_pre_stru.cma_alloc_done)
|
|
return false;
|
|
|
|
if (!di_post_stru.keep_buf
|
|
|| !atomic_read(&di_flag_unreg)) {
|
|
atomic_set(&di_trig_free_mem, 0);
|
|
return false;
|
|
}
|
|
|
|
/*free mirror memory*/
|
|
di_post_stru.keep_buf = NULL;
|
|
|
|
return true;
|
|
}
|
|
|
|
/*--------------------------*/
|
|
|
|
static void parse_param_di(char *buf_orig, char **parm)
|
|
{
|
|
char *ps, *token;
|
|
unsigned int n = 0;
|
|
char delim1[3] = " ";
|
|
char delim2[2] = "\n";
|
|
|
|
ps = buf_orig;
|
|
strcat(delim1, delim2);
|
|
while (1) {
|
|
token = strsep(&ps, delim1);
|
|
if (token == NULL)
|
|
break;
|
|
if (*token == '\0')
|
|
continue;
|
|
parm[n++] = token;
|
|
}
|
|
}
|
|
|
|
static ssize_t
|
|
store_dbg(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
u32 val;
|
|
char *buf_orig, *parm[8] = {NULL};
|
|
|
|
buf_orig = kstrdup(buf, GFP_KERNEL);
|
|
parse_param_di(buf_orig, (char **)&parm);
|
|
if (strncmp(buf, "buf", 3) == 0) {
|
|
struct di_buf_s *di_buf_tmp = 0;
|
|
|
|
if (kstrtoul(buf + 3, 16, (unsigned long *)&di_buf_tmp)) {
|
|
kfree(buf_orig);
|
|
return count;
|
|
}
|
|
dump_di_buf(di_buf_tmp);
|
|
} else if (strncmp(buf, "vframe", 6) == 0) {
|
|
vframe_t *vf = 0;
|
|
|
|
if (kstrtoul(buf + 6, 16, (unsigned long *)&vf)) {
|
|
kfree(buf_orig);
|
|
return count;
|
|
}
|
|
dump_vframe(vf);
|
|
} else if (strncmp(buf, "pool", 4) == 0) {
|
|
unsigned long idx = 0;
|
|
if (kstrtoul(buf + 4, 10, &idx)) {
|
|
kfree(buf_orig);
|
|
return count;
|
|
}
|
|
dump_pool(get_queue_by_idx(idx));
|
|
} else if (strncmp(buf, "state", 4) == 0) {
|
|
dump_state();
|
|
pr_info("add new debugfs: cat /sys/kernel/debug/di/state\n");
|
|
} else if (strncmp(buf, "prog_proc_config", 16) == 0) {
|
|
if (buf[16] == '1')
|
|
prog_proc_config = 1;
|
|
else
|
|
prog_proc_config = 0;
|
|
} else if (strncmp(buf, "init_flag", 9) == 0) {
|
|
if (buf[9] == '1')
|
|
init_flag = 1;
|
|
else
|
|
init_flag = 0;
|
|
} else if (strncmp(buf, "run", 3) == 0) {
|
|
/* timestamp_pcrscr_enable(1); */
|
|
run_flag = DI_RUN_FLAG_RUN;
|
|
} else if (strncmp(buf, "pause", 5) == 0) {
|
|
/* timestamp_pcrscr_enable(0); */
|
|
run_flag = DI_RUN_FLAG_PAUSE;
|
|
} else if (strncmp(buf, "step", 4) == 0) {
|
|
run_flag = DI_RUN_FLAG_STEP;
|
|
} else if (strncmp(buf, "prun", 4) == 0) {
|
|
pre_run_flag = DI_RUN_FLAG_RUN;
|
|
} else if (strncmp(buf, "ppause", 6) == 0) {
|
|
pre_run_flag = DI_RUN_FLAG_PAUSE;
|
|
} else if (strncmp(buf, "pstep", 5) == 0) {
|
|
pre_run_flag = DI_RUN_FLAG_STEP;
|
|
} else if (strncmp(buf, "dumpreg", 7) == 0) {
|
|
if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A)) {
|
|
dump_di_reg_g12();
|
|
dump_afbcd_reg();
|
|
} else
|
|
pr_info("add new debugfs: cat /sys/kernel/debug/di/dumpreg\n");
|
|
} else if (strncmp(buf, "dumpafbc", 8) == 0) {
|
|
dump_afbcd_reg();
|
|
} else if (strncmp(buf, "dumpmif", 7) == 0) {
|
|
dump_mif_size_state(&di_pre_stru, &di_post_stru);
|
|
} else if (strncmp(buf, "dumppostmif", 11) == 0) {
|
|
dump_post_mif_reg();
|
|
} else if (strncmp(buf, "recycle_buf", 11) == 0) {
|
|
recycle_keep_buffer();
|
|
} else if (strncmp(buf, "free_mirror", 11) == 0) {
|
|
di_trig_free_mirror_mem();
|
|
} else if (strncmp(buf, "recycle_post", 12) == 0) {
|
|
if (di_vf_peek(NULL))
|
|
di_vf_put(di_vf_get(NULL), NULL);
|
|
} else if (strncmp(buf, "mem_map", 7) == 0) {
|
|
dump_buf_addr(di_buf_local, MAX_LOCAL_BUF_NUM * 2);
|
|
} else if (strncmp(buf, "afbc_on", 7) == 0) {
|
|
if (kstrtoint(parm[1], 10, &val) < 0) {
|
|
kfree(buf_orig);
|
|
return count;
|
|
}
|
|
if (!val)
|
|
afbc_sw(false);
|
|
afbc_disable_flag = val > 0 ? 0:1;
|
|
pr_info("afbc_disable_flag:%d\n", afbc_disable_flag);
|
|
} else if (strncmp(buf, "reqafbc", 7) == 0) {
|
|
val = di_request_afbc(true);
|
|
di_pre_stru.wait_afbc = false;
|
|
pr_info("request_afbc(%d)\n", val);
|
|
} else if (strncmp(buf, "rlsafbc", 7) == 0) {
|
|
val = di_request_afbc(false);
|
|
di_pre_stru.wait_afbc = false;
|
|
pr_info("rlease_afbc(%d)\n", val);
|
|
} else {
|
|
pr_info("DI no support cmd %s\n", buf);
|
|
pr_info("supported cmd list:\n");
|
|
pr_info("\t vframe\n");
|
|
pr_info("\t state\n");
|
|
pr_info("\t prog_proc_config 0/1\n");
|
|
pr_info("\t init_flag 0/1\n");
|
|
pr_info("\t run\n");
|
|
pr_info("\t pause\n");
|
|
pr_info("\t step\n");
|
|
pr_info("\t prun\n");
|
|
pr_info("\t ppause\n");
|
|
pr_info("\t pstep\n");
|
|
pr_info("\t dumpreg\n");
|
|
pr_info("\t dumpmif\n");
|
|
pr_info("\t dumppostmif\n");
|
|
pr_info("\t recycle_buf\n");
|
|
pr_info("\t recycle_post\n");
|
|
pr_info("\t mem_map\n");
|
|
pr_info("\t reqafbc\n");
|
|
pr_info("\t rlsafbc\n");
|
|
pr_info("\n trigger val\n");
|
|
}
|
|
|
|
kfree(buf_orig);
|
|
return count;
|
|
}
|
|
|
|
static int di_read_canvas_reverse(char *str)
|
|
{
|
|
unsigned char *ptr = str;
|
|
|
|
pr_dbg("%s: bootargs is %s.\n", __func__, str);
|
|
if (strstr(ptr, "1")) {
|
|
invert_top_bot |= 0x1;
|
|
overturn = true;
|
|
} else {
|
|
invert_top_bot &= (~0x1);
|
|
overturn = false;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
__setup("video_reverse=", di_read_canvas_reverse);
|
|
|
|
static unsigned char *di_log_buf;
|
|
static unsigned int di_log_wr_pos;
|
|
static unsigned int di_log_rd_pos;
|
|
static unsigned int di_log_buf_size;
|
|
static unsigned int di_printk_flag;
|
|
static unsigned int buf_state_log_start;
|
|
/* set to 1 by condition of "post_ready count < buf_state_log_threshold",
|
|
* reset to 0 by set buf_state_log_threshold as 0
|
|
*/
|
|
|
|
static DEFINE_SPINLOCK(di_print_lock);
|
|
|
|
#define PRINT_TEMP_BUF_SIZE 128
|
|
|
|
int di_print_buf(char *buf, int len)
|
|
{
|
|
unsigned long flags;
|
|
int pos;
|
|
int di_log_rd_pos_;
|
|
|
|
if (di_log_buf_size == 0)
|
|
return 0;
|
|
|
|
spin_lock_irqsave(&di_print_lock, flags);
|
|
di_log_rd_pos_ = di_log_rd_pos;
|
|
if (di_log_wr_pos >= di_log_rd_pos)
|
|
di_log_rd_pos_ += di_log_buf_size;
|
|
|
|
for (pos = 0; pos < len && di_log_wr_pos < (di_log_rd_pos_ - 1);
|
|
pos++, di_log_wr_pos++) {
|
|
if (di_log_wr_pos >= di_log_buf_size)
|
|
di_log_buf[di_log_wr_pos - di_log_buf_size] = buf[pos];
|
|
else
|
|
di_log_buf[di_log_wr_pos] = buf[pos];
|
|
}
|
|
if (di_log_wr_pos >= di_log_buf_size)
|
|
di_log_wr_pos -= di_log_buf_size;
|
|
spin_unlock_irqrestore(&di_print_lock, flags);
|
|
return pos;
|
|
}
|
|
|
|
static u64 cur_to_msecs(void)
|
|
{
|
|
u64 cur = sched_clock();
|
|
|
|
do_div(cur, NSEC_PER_MSEC);
|
|
return cur;
|
|
}
|
|
|
|
/* static int log_seq = 0; */
|
|
int di_print(const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
int avail = PRINT_TEMP_BUF_SIZE;
|
|
char buf[PRINT_TEMP_BUF_SIZE];
|
|
int pos, len = 0;
|
|
|
|
if (di_printk_flag & 1) {
|
|
if (di_log_flag & DI_LOG_PRECISE_TIMESTAMP)
|
|
pr_dbg("%llums:", cur_to_msecs());
|
|
va_start(args, fmt);
|
|
vprintk(fmt, args);
|
|
va_end(args);
|
|
return 0;
|
|
}
|
|
|
|
if (di_log_buf_size == 0)
|
|
return 0;
|
|
|
|
/* len += snprintf(buf+len, avail-len, "%d:",log_seq++); */
|
|
if (di_log_flag & DI_LOG_TIMESTAMP)
|
|
len += snprintf(buf + len, avail - len, "%u:",
|
|
jiffies_to_msecs(jiffies_64));
|
|
|
|
va_start(args, fmt);
|
|
len += vsnprintf(buf + len, avail - len, fmt, args);
|
|
va_end(args);
|
|
|
|
if ((avail - len) <= 0)
|
|
buf[PRINT_TEMP_BUF_SIZE - 1] = '\0';
|
|
|
|
pos = di_print_buf(buf, len);
|
|
/* pr_dbg("di_print:%d %d\n", di_log_wr_pos, di_log_rd_pos); */
|
|
return pos;
|
|
}
|
|
|
|
static ssize_t read_log(char *buf)
|
|
{
|
|
unsigned long flags;
|
|
ssize_t read_size = 0;
|
|
|
|
if (di_log_buf_size == 0)
|
|
return 0;
|
|
/* pr_dbg("show_log:%d %d\n", di_log_wr_pos, di_log_rd_pos); */
|
|
spin_lock_irqsave(&di_print_lock, flags);
|
|
if (di_log_rd_pos < di_log_wr_pos)
|
|
read_size = di_log_wr_pos - di_log_rd_pos;
|
|
|
|
else if (di_log_rd_pos > di_log_wr_pos)
|
|
read_size = di_log_buf_size - di_log_rd_pos;
|
|
|
|
if (read_size > PAGE_SIZE)
|
|
read_size = PAGE_SIZE;
|
|
if (read_size > 0)
|
|
memcpy(buf, di_log_buf + di_log_rd_pos, read_size);
|
|
|
|
di_log_rd_pos += read_size;
|
|
if (di_log_rd_pos >= di_log_buf_size)
|
|
di_log_rd_pos = 0;
|
|
spin_unlock_irqrestore(&di_print_lock, flags);
|
|
return read_size;
|
|
}
|
|
|
|
static ssize_t
|
|
show_log(struct device *dev, struct device_attribute *attr, char *buf)
|
|
{
|
|
return read_log(buf);
|
|
}
|
|
|
|
static ssize_t
|
|
store_log(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
unsigned long flags, tmp;
|
|
|
|
if (strncmp(buf, "bufsize", 7) == 0) {
|
|
if (kstrtoul(buf + 7, 10, &tmp))
|
|
return count;
|
|
spin_lock_irqsave(&di_print_lock, flags);
|
|
kfree(di_log_buf);
|
|
di_log_buf = NULL;
|
|
di_log_buf_size = 0;
|
|
di_log_rd_pos = 0;
|
|
di_log_wr_pos = 0;
|
|
if (tmp >= 1024) {
|
|
di_log_buf_size = 0;
|
|
di_log_rd_pos = 0;
|
|
di_log_wr_pos = 0;
|
|
di_log_buf = kmalloc(tmp, GFP_KERNEL);
|
|
if (di_log_buf)
|
|
di_log_buf_size = tmp;
|
|
}
|
|
spin_unlock_irqrestore(&di_print_lock, flags);
|
|
pr_dbg("di_store:set bufsize tmp %lu %u\n",
|
|
tmp, di_log_buf_size);
|
|
} else if (strncmp(buf, "printk", 6) == 0) {
|
|
if (kstrtoul(buf + 6, 10, &tmp))
|
|
return count;
|
|
di_printk_flag = tmp;
|
|
} else {
|
|
di_print("%s", buf);
|
|
}
|
|
return 16;
|
|
}
|
|
|
|
static ssize_t
|
|
show_vframe_status(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
int ret = 0;
|
|
struct vframe_states states;
|
|
|
|
ret = vf_get_states_by_name(VFM_NAME, &states);
|
|
|
|
if (ret == 0) {
|
|
ret += sprintf(buf + ret, "vframe_pool_size=%d\n",
|
|
states.vf_pool_size);
|
|
ret += sprintf(buf + ret, "vframe buf_free_num=%d\n",
|
|
states.buf_free_num);
|
|
ret += sprintf(buf + ret, "vframe buf_recycle_num=%d\n",
|
|
states.buf_recycle_num);
|
|
ret += sprintf(buf + ret, "vframe buf_avail_num=%d\n",
|
|
states.buf_avail_num);
|
|
} else {
|
|
ret = 0;
|
|
ret += sprintf(buf + ret, "vframe no states\n");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t show_tvp_region(struct device *dev,
|
|
struct device_attribute *attr, char *buff)
|
|
{
|
|
ssize_t len = 0;
|
|
|
|
len = sprintf(buff, "segment DI:%lx - %lx (size:0x%x)\n",
|
|
de_devp->mem_start,
|
|
de_devp->mem_start + de_devp->mem_size - 1,
|
|
de_devp->mem_size);
|
|
return len;
|
|
}
|
|
|
|
static ssize_t store_dump_mem(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t len);
|
|
static DEVICE_ATTR(config, 0640, show_config, store_config);
|
|
static DEVICE_ATTR(debug, 0200, NULL, store_dbg);
|
|
static DEVICE_ATTR(dump_pic, 0200, NULL, store_dump_mem);
|
|
static DEVICE_ATTR(log, 0640, show_log, store_log);
|
|
static DEVICE_ATTR(provider_vframe_status, 0444, show_vframe_status, NULL);
|
|
static DEVICE_ATTR(tvp_region, 0444, show_tvp_region, NULL);
|
|
/***************************
|
|
* di buffer management
|
|
***************************/
|
|
|
|
static char *vframe_type_name[] = {
|
|
"", "di_buf_in", "di_buf_loc", "di_buf_post"
|
|
};
|
|
|
|
static unsigned int default_width = 1920;
|
|
static unsigned int default_height = 1080;
|
|
|
|
/*
|
|
* all buffers are in
|
|
* 1) list of local_free_list,in_free_list,pre_ready_list,recycle_list
|
|
* 2) di_pre_stru.di_inp_buf
|
|
* 3) di_pre_stru.di_wr_buf
|
|
* 4) cur_post_ready_di_buf
|
|
* 5) (struct di_buf_s*)(vframe->private_data)->di_buf[]
|
|
*
|
|
* 6) post_free_list_head
|
|
* 8) (struct di_buf_s*)(vframe->private_data)
|
|
*/
|
|
|
|
#define queue_t struct queue_s
|
|
static queue_t queue[QUEUE_NUM];
|
|
static struct di_buf_pool_s di_buf_pool[VFRAME_TYPE_NUM];
|
|
static struct queue_s *get_queue_by_idx(int idx)
|
|
{
|
|
if (idx < QUEUE_NUM)
|
|
return &(queue[idx]);
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
static void queue_init(int local_buffer_num)
|
|
{
|
|
int i, j;
|
|
|
|
for (i = 0; i < QUEUE_NUM; i++) {
|
|
queue_t *q = &queue[i];
|
|
|
|
for (j = 0; j < MAX_QUEUE_POOL_SIZE; j++)
|
|
q->pool[j] = 0;
|
|
|
|
q->in_idx = 0;
|
|
q->out_idx = 0;
|
|
q->num = 0;
|
|
q->type = 0;
|
|
if ((i == QUEUE_RECYCLE) ||
|
|
(i == QUEUE_DISPLAY) ||
|
|
(i == QUEUE_TMP) ||
|
|
(i == QUEUE_POST_DOING))
|
|
q->type = 1;
|
|
|
|
if ((i == QUEUE_LOCAL_FREE) && use_2_interlace_buff)
|
|
q->type = 2;
|
|
}
|
|
if (local_buffer_num > 0) {
|
|
di_buf_pool[VFRAME_TYPE_IN - 1].di_buf_ptr = &di_buf_in[0];
|
|
di_buf_pool[VFRAME_TYPE_IN - 1].size = MAX_IN_BUF_NUM;
|
|
|
|
di_buf_pool[VFRAME_TYPE_LOCAL-1].di_buf_ptr = &di_buf_local[0];
|
|
di_buf_pool[VFRAME_TYPE_LOCAL - 1].size = local_buffer_num;
|
|
|
|
di_buf_pool[VFRAME_TYPE_POST - 1].di_buf_ptr = &di_buf_post[0];
|
|
di_buf_pool[VFRAME_TYPE_POST - 1].size = MAX_POST_BUF_NUM;
|
|
}
|
|
}
|
|
|
|
struct di_buf_s *get_di_buf(int queue_idx, int *start_pos)
|
|
{
|
|
queue_t *q = &(queue[queue_idx]);
|
|
int idx = 0;
|
|
unsigned int pool_idx, di_buf_idx;
|
|
struct di_buf_s *di_buf = NULL;
|
|
int start_pos_init = *start_pos;
|
|
|
|
if (di_log_flag & DI_LOG_QUEUE)
|
|
di_print("%s:<%d:%d,%d,%d> %d\n", __func__, queue_idx,
|
|
q->num, q->in_idx, q->out_idx, *start_pos);
|
|
|
|
if (q->type == 0) {
|
|
if ((*start_pos) < q->num) {
|
|
idx = q->out_idx + (*start_pos);
|
|
if (idx >= MAX_QUEUE_POOL_SIZE)
|
|
idx -= MAX_QUEUE_POOL_SIZE;
|
|
|
|
(*start_pos)++;
|
|
} else {
|
|
idx = MAX_QUEUE_POOL_SIZE;
|
|
}
|
|
} else if ((q->type == 1) || (q->type == 2)) {
|
|
for (idx = (*start_pos); idx < MAX_QUEUE_POOL_SIZE; idx++) {
|
|
if (q->pool[idx] != 0) {
|
|
*start_pos = idx + 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (idx < MAX_QUEUE_POOL_SIZE) {
|
|
pool_idx = ((q->pool[idx] >> 8) & 0xff) - 1;
|
|
di_buf_idx = q->pool[idx] & 0xff;
|
|
if (pool_idx < VFRAME_TYPE_NUM) {
|
|
if (di_buf_idx < di_buf_pool[pool_idx].size)
|
|
di_buf =
|
|
&(di_buf_pool[pool_idx].di_buf_ptr[
|
|
di_buf_idx]);
|
|
}
|
|
}
|
|
|
|
if ((di_buf) && ((((pool_idx + 1) << 8) | di_buf_idx)
|
|
!= ((di_buf->type << 8) | (di_buf->index)))) {
|
|
pr_dbg("%s: Error (%x,%x)\n", __func__,
|
|
(((pool_idx + 1) << 8) | di_buf_idx),
|
|
((di_buf->type << 8) | (di_buf->index)));
|
|
if (recovery_flag == 0) {
|
|
recovery_log_reason = 1;
|
|
recovery_log_queue_idx = (start_pos_init<<8)|queue_idx;
|
|
recovery_log_di_buf = di_buf;
|
|
}
|
|
recovery_flag++;
|
|
di_buf = NULL;
|
|
}
|
|
|
|
if (di_log_flag & DI_LOG_QUEUE) {
|
|
if (di_buf)
|
|
di_print("%s: 0x%p(%d,%d)\n", __func__, di_buf,
|
|
pool_idx, di_buf_idx);
|
|
else
|
|
di_print("%s: 0x%p\n", __func__, di_buf);
|
|
}
|
|
|
|
return di_buf;
|
|
}
|
|
|
|
static struct di_buf_s *get_di_buf_head(int queue_idx)
|
|
{
|
|
queue_t *q = &(queue[queue_idx]);
|
|
int idx;
|
|
unsigned int pool_idx, di_buf_idx;
|
|
struct di_buf_s *di_buf = NULL;
|
|
|
|
if (di_log_flag & DI_LOG_QUEUE)
|
|
di_print("%s:<%d:%d,%d,%d>\n", __func__, queue_idx,
|
|
q->num, q->in_idx, q->out_idx);
|
|
|
|
if (q->num > 0) {
|
|
if (q->type == 0) {
|
|
idx = q->out_idx;
|
|
} else {
|
|
for (idx = 0; idx < MAX_QUEUE_POOL_SIZE; idx++)
|
|
if (q->pool[idx] != 0)
|
|
break;
|
|
}
|
|
if (idx < MAX_QUEUE_POOL_SIZE) {
|
|
pool_idx = ((q->pool[idx] >> 8) & 0xff) - 1;
|
|
di_buf_idx = q->pool[idx] & 0xff;
|
|
if (pool_idx < VFRAME_TYPE_NUM) {
|
|
if (di_buf_idx < di_buf_pool[pool_idx].size)
|
|
di_buf = &(di_buf_pool[pool_idx].
|
|
di_buf_ptr[di_buf_idx]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((di_buf) && ((((pool_idx + 1) << 8) | di_buf_idx) !=
|
|
((di_buf->type << 8) | (di_buf->index)))) {
|
|
|
|
pr_dbg("%s: Error (%x,%x)\n", __func__,
|
|
(((pool_idx + 1) << 8) | di_buf_idx),
|
|
((di_buf->type << 8) | (di_buf->index)));
|
|
|
|
if (recovery_flag == 0) {
|
|
recovery_log_reason = 2;
|
|
recovery_log_queue_idx = queue_idx;
|
|
recovery_log_di_buf = di_buf;
|
|
}
|
|
recovery_flag++;
|
|
di_buf = NULL;
|
|
}
|
|
|
|
if (di_log_flag & DI_LOG_QUEUE) {
|
|
if (di_buf)
|
|
di_print("%s: 0x%p(%d,%d)\n", __func__, di_buf,
|
|
pool_idx, di_buf_idx);
|
|
else
|
|
di_print("%s: 0x%p\n", __func__, di_buf);
|
|
}
|
|
|
|
return di_buf;
|
|
}
|
|
|
|
static void queue_out(struct di_buf_s *di_buf)
|
|
{
|
|
int i;
|
|
queue_t *q;
|
|
|
|
if (di_buf == NULL) {
|
|
|
|
pr_dbg("%s:Error\n", __func__);
|
|
|
|
if (recovery_flag == 0)
|
|
recovery_log_reason = 3;
|
|
|
|
recovery_flag++;
|
|
return;
|
|
}
|
|
if (di_buf->queue_index >= 0 && di_buf->queue_index < QUEUE_NUM) {
|
|
q = &(queue[di_buf->queue_index]);
|
|
|
|
if (di_log_flag & DI_LOG_QUEUE)
|
|
di_print("%s:<%d:%d,%d,%d> 0x%p\n", __func__,
|
|
di_buf->queue_index, q->num, q->in_idx,
|
|
q->out_idx, di_buf);
|
|
|
|
if (q->num > 0) {
|
|
if (q->type == 0) {
|
|
if (q->pool[q->out_idx] ==
|
|
((di_buf->type << 8) | (di_buf->index))) {
|
|
q->num--;
|
|
q->pool[q->out_idx] = 0;
|
|
q->out_idx++;
|
|
if (q->out_idx >= MAX_QUEUE_POOL_SIZE)
|
|
q->out_idx = 0;
|
|
di_buf->queue_index = -1;
|
|
} else {
|
|
|
|
pr_dbg(
|
|
"%s: Error (%d, %x,%x)\n",
|
|
__func__,
|
|
di_buf->queue_index,
|
|
q->pool[q->out_idx],
|
|
((di_buf->type << 8) |
|
|
(di_buf->index)));
|
|
|
|
if (recovery_flag == 0) {
|
|
recovery_log_reason = 4;
|
|
recovery_log_queue_idx =
|
|
di_buf->queue_index;
|
|
recovery_log_di_buf = di_buf;
|
|
}
|
|
recovery_flag++;
|
|
}
|
|
} else if (q->type == 1) {
|
|
int pool_val =
|
|
(di_buf->type << 8) | (di_buf->index);
|
|
for (i = 0; i < MAX_QUEUE_POOL_SIZE; i++) {
|
|
if (q->pool[i] == pool_val) {
|
|
q->num--;
|
|
q->pool[i] = 0;
|
|
di_buf->queue_index = -1;
|
|
break;
|
|
}
|
|
}
|
|
if (i == MAX_QUEUE_POOL_SIZE) {
|
|
|
|
pr_dbg("%s: Error\n", __func__);
|
|
|
|
if (recovery_flag == 0) {
|
|
recovery_log_reason = 5;
|
|
recovery_log_queue_idx =
|
|
di_buf->queue_index;
|
|
recovery_log_di_buf = di_buf;
|
|
}
|
|
recovery_flag++;
|
|
}
|
|
} else if (q->type == 2) {
|
|
int pool_val =
|
|
(di_buf->type << 8) | (di_buf->index);
|
|
if ((di_buf->index < MAX_QUEUE_POOL_SIZE) &&
|
|
(q->pool[di_buf->index] == pool_val)) {
|
|
q->num--;
|
|
q->pool[di_buf->index] = 0;
|
|
di_buf->queue_index = -1;
|
|
} else {
|
|
|
|
pr_dbg("%s: Error\n", __func__);
|
|
|
|
if (recovery_flag == 0) {
|
|
recovery_log_reason = 5;
|
|
recovery_log_queue_idx =
|
|
di_buf->queue_index;
|
|
recovery_log_di_buf = di_buf;
|
|
}
|
|
recovery_flag++;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
|
|
pr_dbg("%s: Error, queue_index %d is not right\n",
|
|
__func__, di_buf->queue_index);
|
|
|
|
if (recovery_flag == 0) {
|
|
recovery_log_reason = 6;
|
|
recovery_log_queue_idx = 0;
|
|
recovery_log_di_buf = di_buf;
|
|
}
|
|
recovery_flag++;
|
|
}
|
|
|
|
if (di_log_flag & DI_LOG_QUEUE)
|
|
di_print("%s done\n", __func__);
|
|
|
|
}
|
|
|
|
static void queue_in(struct di_buf_s *di_buf, int queue_idx)
|
|
{
|
|
queue_t *q = NULL;
|
|
|
|
if (di_buf == NULL) {
|
|
pr_dbg("%s:Error\n", __func__);
|
|
if (recovery_flag == 0) {
|
|
recovery_log_reason = 7;
|
|
recovery_log_queue_idx = queue_idx;
|
|
recovery_log_di_buf = di_buf;
|
|
}
|
|
recovery_flag++;
|
|
return;
|
|
}
|
|
if (di_buf->queue_index != -1) {
|
|
pr_dbg("%s:%s[%d] Error, queue_index(%d) is not -1\n",
|
|
__func__, vframe_type_name[di_buf->type],
|
|
di_buf->index, di_buf->queue_index);
|
|
if (recovery_flag == 0) {
|
|
recovery_log_reason = 8;
|
|
recovery_log_queue_idx = queue_idx;
|
|
recovery_log_di_buf = di_buf;
|
|
}
|
|
recovery_flag++;
|
|
return;
|
|
}
|
|
q = &(queue[queue_idx]);
|
|
if (di_log_flag & DI_LOG_QUEUE)
|
|
di_print("%s:<%d:%d,%d,%d> 0x%p\n", __func__, queue_idx,
|
|
q->num, q->in_idx, q->out_idx, di_buf);
|
|
|
|
if (q->type == 0) {
|
|
q->pool[q->in_idx] = (di_buf->type << 8) | (di_buf->index);
|
|
di_buf->queue_index = queue_idx;
|
|
q->in_idx++;
|
|
if (q->in_idx >= MAX_QUEUE_POOL_SIZE)
|
|
q->in_idx = 0;
|
|
|
|
q->num++;
|
|
} else if (q->type == 1) {
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_QUEUE_POOL_SIZE; i++) {
|
|
if (q->pool[i] == 0) {
|
|
q->pool[i] = (di_buf->type<<8)|(di_buf->index);
|
|
di_buf->queue_index = queue_idx;
|
|
q->num++;
|
|
break;
|
|
}
|
|
}
|
|
if (i == MAX_QUEUE_POOL_SIZE) {
|
|
pr_dbg("%s: Error\n", __func__);
|
|
if (recovery_flag == 0) {
|
|
recovery_log_reason = 9;
|
|
recovery_log_queue_idx = queue_idx;
|
|
}
|
|
recovery_flag++;
|
|
}
|
|
} else if (q->type == 2) {
|
|
if ((di_buf->index < MAX_QUEUE_POOL_SIZE) &&
|
|
(q->pool[di_buf->index] == 0)) {
|
|
q->pool[di_buf->index] =
|
|
(di_buf->type << 8) | (di_buf->index);
|
|
di_buf->queue_index = queue_idx;
|
|
q->num++;
|
|
} else {
|
|
pr_dbg("%s: Error\n", __func__);
|
|
if (recovery_flag == 0) {
|
|
recovery_log_reason = 9;
|
|
recovery_log_queue_idx = queue_idx;
|
|
}
|
|
recovery_flag++;
|
|
}
|
|
}
|
|
|
|
if (di_log_flag & DI_LOG_QUEUE)
|
|
di_print("%s done\n", __func__);
|
|
}
|
|
|
|
static int list_count(int queue_idx)
|
|
{
|
|
return queue[queue_idx].num;
|
|
}
|
|
|
|
static bool queue_empty(int queue_idx)
|
|
{
|
|
bool ret = (queue[queue_idx].num == 0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static bool is_in_queue(struct di_buf_s *di_buf, int queue_idx)
|
|
{
|
|
bool ret = 0;
|
|
struct di_buf_s *p = NULL;
|
|
int itmp;
|
|
unsigned int overflow_cnt;
|
|
|
|
overflow_cnt = 0;
|
|
if ((di_buf == NULL) || (queue_idx < 0) || (queue_idx >= QUEUE_NUM)) {
|
|
ret = 0;
|
|
di_print("%s: not in queue:%d!!!\n", __func__, queue_idx);
|
|
return ret;
|
|
}
|
|
queue_for_each_entry(p, ptmp, queue_idx, list) {
|
|
if (p == di_buf) {
|
|
ret = 1;
|
|
break;
|
|
}
|
|
if (overflow_cnt++ > MAX_QUEUE_POOL_SIZE) {
|
|
ret = 0;
|
|
di_print("%s: overflow_cnt!!!\n", __func__);
|
|
break;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
//---------------------------
|
|
u8 *di_vmap(ulong addr, u32 size, bool *bflg)
|
|
{
|
|
u8 *vaddr = NULL;
|
|
ulong phys = addr;
|
|
u32 offset = phys & ~PAGE_MASK;
|
|
u32 npages = PAGE_ALIGN(size) / PAGE_SIZE;
|
|
struct page **pages = NULL;
|
|
pgprot_t pgprot;
|
|
int i;
|
|
|
|
if (!PageHighMem(phys_to_page(phys)))
|
|
return phys_to_virt(phys);
|
|
|
|
if (offset)
|
|
npages++;
|
|
|
|
pages = vmalloc(sizeof(struct page *) * npages);
|
|
if (!pages)
|
|
return NULL;
|
|
|
|
for (i = 0; i < npages; i++) {
|
|
pages[i] = phys_to_page(phys);
|
|
phys += PAGE_SIZE;
|
|
}
|
|
|
|
/*nocache*/
|
|
pgprot = pgprot_writecombine(PAGE_KERNEL);
|
|
|
|
vaddr = vmap(pages, npages, VM_MAP, pgprot);
|
|
if (!vaddr) {
|
|
pr_err("the phy(%lx) vmaped fail, size: %d\n",
|
|
addr - offset, npages << PAGE_SHIFT);
|
|
vfree(pages);
|
|
return NULL;
|
|
}
|
|
|
|
vfree(pages);
|
|
|
|
// if (debug_mode & 0x20) {
|
|
// di_print("[HIGH-MEM-MAP] %s, pa(%lx) to va(%p), size: %d\n",
|
|
// __func__, addr, vaddr + offset, npages << PAGE_SHIFT);
|
|
// }
|
|
*bflg = true;
|
|
|
|
return vaddr + offset;
|
|
}
|
|
|
|
void di_unmap_phyaddr(u8 *vaddr)
|
|
{
|
|
void *addr = (void *)(PAGE_MASK & (ulong)vaddr);
|
|
|
|
vunmap(addr);
|
|
}
|
|
//-------------------------
|
|
static ssize_t
|
|
store_dump_mem(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t len)
|
|
{
|
|
#ifdef CONFIG_AMLOGIC_ENABLE_MEDIA_FILE
|
|
unsigned int n = 0, canvas_w = 0, canvas_h = 0;
|
|
unsigned long nr_size = 0, dump_adr = 0;
|
|
struct di_buf_s *di_buf = NULL;
|
|
struct vframe_s *post_vf = NULL;
|
|
char *buf_orig, *ps, *token;
|
|
char *parm[3] = { NULL };
|
|
char delim1[3] = " ";
|
|
char delim2[2] = "\n";
|
|
struct file *filp = NULL;
|
|
loff_t pos = 0;
|
|
void *buff = NULL;
|
|
mm_segment_t old_fs;
|
|
bool bflg_vmap = false;
|
|
|
|
buf_orig = kstrdup(buf, GFP_KERNEL);
|
|
ps = buf_orig;
|
|
strcat(delim1, delim2);
|
|
while (1) {
|
|
token = strsep(&ps, delim1);
|
|
if (token == NULL)
|
|
break;
|
|
if (*token == '\0')
|
|
continue;
|
|
parm[n++] = token;
|
|
}
|
|
if (strcmp(parm[0], "capture") == 0)
|
|
di_buf = di_pre_stru.di_mem_buf_dup_p;
|
|
else if (strcmp(parm[0], "capture_post") == 0) {
|
|
if (di_vf_peek(NULL)) {
|
|
post_vf = di_vf_get(NULL);
|
|
if (!IS_ERR_OR_NULL(post_vf)) {
|
|
di_buf = post_vf->private_data;
|
|
di_vf_put(post_vf, NULL);
|
|
}
|
|
post_vf = NULL;
|
|
}
|
|
} else if (strcmp(parm[0], "capture_nrds") == 0)
|
|
get_nr_ds_buf(&dump_adr, &nr_size);
|
|
else {
|
|
pr_err("wrong dump cmd\n");
|
|
return len;
|
|
}
|
|
if (nr_size == 0) {
|
|
if (unlikely(di_buf == NULL))
|
|
return len;
|
|
canvas_w = di_buf->canvas_width[NR_CANVAS];
|
|
canvas_h = di_buf->canvas_height;
|
|
nr_size = canvas_w * canvas_h * 2;
|
|
dump_adr = di_buf->nr_adr;
|
|
}
|
|
old_fs = get_fs();
|
|
set_fs(KERNEL_DS);
|
|
/* pr_dbg("dump path =%s\n",dump_path); */
|
|
filp = filp_open(parm[1], O_RDWR | O_CREAT, 0666);
|
|
if (IS_ERR(filp)) {
|
|
pr_err("create %s error.\n", parm[1]);
|
|
return len;
|
|
}
|
|
dump_state_flag = 1;
|
|
if (de_devp->flags & DI_MAP_FLAG) {
|
|
//buff = (void *)phys_to_virt(dump_adr);
|
|
buff = di_vmap(dump_adr, nr_size, &bflg_vmap);
|
|
if (buff == NULL) {
|
|
pr_info("di_vap err\n");
|
|
filp_close(filp, NULL);
|
|
return len;
|
|
|
|
}
|
|
} else {
|
|
buff = ioremap(dump_adr, nr_size);
|
|
}
|
|
if (IS_ERR_OR_NULL(buff))
|
|
pr_err("%s: ioremap error.\n", __func__);
|
|
vfs_write(filp, buff, nr_size, &pos);
|
|
/* pr_dbg("di_chan2_buf_dup_p:\n nr:%u,mtn:%u,cnt:%u\n",
|
|
* di_pre_stru.di_chan2_buf_dup_p->nr_adr,
|
|
* di_pre_stru.di_chan2_buf_dup_p->mtn_adr,
|
|
* di_pre_stru.di_chan2_buf_dup_p->cnt_adr);
|
|
* pr_dbg("di_inp_buf:\n nr:%u,mtn:%u,cnt:%u\n",
|
|
* di_pre_stru.di_inp_buf->nr_adr,
|
|
* di_pre_stru.di_inp_buf->mtn_adr,
|
|
* di_pre_stru.di_inp_buf->cnt_adr);
|
|
* pr_dbg("di_wr_buf:\n nr:%u,mtn:%u,cnt:%u\n",
|
|
* di_pre_stru.di_wr_buf->nr_adr,
|
|
* di_pre_stru.di_wr_buf->mtn_adr,
|
|
* di_pre_stru.di_wr_buf->cnt_adr);
|
|
* pr_dbg("di_mem_buf_dup_p:\n nr:%u,mtn:%u,cnt:%u\n",
|
|
* di_pre_stru.di_mem_buf_dup_p->nr_adr,
|
|
* di_pre_stru.di_mem_buf_dup_p->mtn_adr,
|
|
* di_pre_stru.di_mem_buf_dup_p->cnt_adr);
|
|
* pr_dbg("di_mem_start=%u\n",di_mem_start);
|
|
*/
|
|
vfs_fsync(filp, 0);
|
|
pr_info("write buffer 0x%lx to %s.\n", dump_adr, parm[1]);
|
|
if (bflg_vmap)
|
|
di_unmap_phyaddr(buff);
|
|
|
|
if (!(de_devp->flags & DI_MAP_FLAG))
|
|
iounmap(buff);
|
|
dump_state_flag = 0;
|
|
filp_close(filp, NULL);
|
|
set_fs(old_fs);
|
|
#endif
|
|
return len;
|
|
}
|
|
|
|
#define is_from_vdin(vframe) (vframe->type & VIDTYPE_VIU_422)
|
|
static void recycle_vframe_type_pre(struct di_buf_s *di_buf);
|
|
static void recycle_vframe_type_post(struct di_buf_s *di_buf);
|
|
static void add_dummy_vframe_type_pre(struct di_buf_s *src_buf);
|
|
#ifdef DI_BUFFER_DEBUG
|
|
static void
|
|
recycle_vframe_type_post_print(struct di_buf_s *di_buf,
|
|
const char *func,
|
|
const int line);
|
|
#endif
|
|
|
|
static void dis2_di(void)
|
|
{
|
|
ulong flags = 0, irq_flag2 = 0;
|
|
|
|
init_flag = 0;
|
|
di_lock_irqfiq_save(irq_flag2);
|
|
/* vf_unreg_provider(&di_vf_prov); */
|
|
vf_light_unreg_provider(&di_vf_prov);
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
reg_flag = 0;
|
|
spin_lock_irqsave(&plist_lock, flags);
|
|
di_lock_irqfiq_save(irq_flag2);
|
|
if (di_pre_stru.di_inp_buf) {
|
|
if (vframe_in[di_pre_stru.di_inp_buf->index]) {
|
|
vf_put(
|
|
vframe_in[di_pre_stru.di_inp_buf->index],
|
|
VFM_NAME);
|
|
vframe_in[di_pre_stru.di_inp_buf->index] = NULL;
|
|
vf_notify_provider(
|
|
VFM_NAME, VFRAME_EVENT_RECEIVER_PUT, NULL);
|
|
}
|
|
di_pre_stru.di_inp_buf->invert_top_bot_flag = 0;
|
|
queue_in(di_pre_stru.di_inp_buf, QUEUE_IN_FREE);
|
|
di_pre_stru.di_inp_buf = NULL;
|
|
}
|
|
di_uninit_buf(0);
|
|
if (get_blackout_policy()) {
|
|
DI_Wr(DI_CLKG_CTRL, 0x2);
|
|
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
|
|
if (is_meson_txlx_cpu() || is_meson_txhd_cpu()) {
|
|
enable_di_post_mif(GATE_OFF);
|
|
di_post_gate_control(false);
|
|
di_top_gate_control(false, false);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (post_wr_en && post_wr_support)
|
|
diwr_set_power_control(0);
|
|
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
spin_unlock_irqrestore(&plist_lock, flags);
|
|
}
|
|
|
|
static ssize_t
|
|
store_config(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
int rc = 0;
|
|
char *parm[2] = { NULL }, *buf_orig;
|
|
|
|
buf_orig = kstrdup(buf, GFP_KERNEL);
|
|
parse_cmd_params(buf_orig, (char **)(&parm));
|
|
|
|
if (strncmp(buf, "disable", 7) == 0) {
|
|
|
|
di_print("%s: disable\n", __func__);
|
|
|
|
if (init_flag) {
|
|
di_pre_stru.disable_req_flag = 1;
|
|
|
|
trigger_pre_di_process(TRIGGER_PRE_BY_DEBUG_DISABLE);
|
|
while (di_pre_stru.disable_req_flag)
|
|
usleep_range(1000, 1001);
|
|
}
|
|
} else if (strncmp(buf, "dis2", 4) == 0) {
|
|
dis2_di();
|
|
} else if (strcmp(parm[0], "hold_video") == 0) {
|
|
pr_info("%s(%s %s)\n", __func__, parm[0], parm[1]);
|
|
rc = kstrtouint(parm[1], 10, &hold_video);
|
|
}
|
|
kfree(buf_orig);
|
|
return count;
|
|
}
|
|
|
|
static unsigned char is_progressive(vframe_t *vframe)
|
|
{
|
|
unsigned char ret = 0;
|
|
|
|
ret = ((vframe->type & VIDTYPE_TYPEMASK) == VIDTYPE_PROGRESSIVE);
|
|
return ret;
|
|
}
|
|
|
|
static unsigned char is_source_change(vframe_t *vframe)
|
|
{
|
|
#define VFRAME_FORMAT_MASK \
|
|
(VIDTYPE_VIU_422 | VIDTYPE_VIU_SINGLE_PLANE | VIDTYPE_VIU_444 | \
|
|
VIDTYPE_MVC)
|
|
if ((di_pre_stru.cur_width != vframe->width) ||
|
|
(di_pre_stru.cur_height != vframe->height) ||
|
|
(((di_pre_stru.cur_inp_type & VFRAME_FORMAT_MASK) !=
|
|
(vframe->type & VFRAME_FORMAT_MASK)) &&
|
|
(!is_handle_prog_frame_as_interlace(vframe))) ||
|
|
(di_pre_stru.cur_source_type != vframe->source_type)) {
|
|
/* video format changed */
|
|
return 1;
|
|
} else if (
|
|
((di_pre_stru.cur_prog_flag != is_progressive(vframe)) &&
|
|
(!is_handle_prog_frame_as_interlace(vframe))) ||
|
|
((di_pre_stru.cur_inp_type & VIDTYPE_VIU_FIELD) !=
|
|
(vframe->type & VIDTYPE_VIU_FIELD))
|
|
) {
|
|
/* just scan mode changed */
|
|
if (!di_pre_stru.force_interlace)
|
|
pr_dbg("DI I<->P.\n");
|
|
return 2;
|
|
}
|
|
return 0;
|
|
}
|
|
/*
|
|
* static unsigned char is_vframe_type_change(vframe_t* vframe)
|
|
* {
|
|
* if(
|
|
* (di_pre_stru.cur_prog_flag!=is_progressive(vframe))||
|
|
* ((di_pre_stru.cur_inp_type&VFRAME_FORMAT_MASK)!=
|
|
* (vframe->type&VFRAME_FORMAT_MASK))
|
|
* )
|
|
* return 1;
|
|
*
|
|
* return 0;
|
|
* }
|
|
*/
|
|
static int trick_mode;
|
|
|
|
unsigned char is_bypass(vframe_t *vf_in)
|
|
{
|
|
unsigned int vtype = 0;
|
|
int ret = 0;
|
|
static vframe_t vf_tmp;
|
|
|
|
isbypass_flag = true;
|
|
if (di_debug_flag & 0x10000) /* for debugging */
|
|
return (di_debug_flag >> 17) & 0x1;
|
|
|
|
if (bypass_all)
|
|
return 1;
|
|
if (di_pre_stru.cur_prog_flag &&
|
|
(
|
|
(di_pre_stru.cur_width > 1920) || (di_pre_stru.cur_height > 1080)
|
|
|| (di_pre_stru.cur_inp_type & VIDTYPE_VIU_444))
|
|
)
|
|
return 1;
|
|
|
|
if ((di_pre_stru.cur_width < 16) || (di_pre_stru.cur_height < 16))
|
|
return 1;
|
|
|
|
if (di_pre_stru.cur_inp_type & VIDTYPE_MVC)
|
|
return 1;
|
|
|
|
if (di_pre_stru.cur_source_type == VFRAME_SOURCE_TYPE_PPMGR)
|
|
return 1;
|
|
|
|
if (bypass_trick_mode) {
|
|
int trick_mode_fffb = 0;
|
|
int trick_mode_i = 0;
|
|
|
|
if (bypass_trick_mode&0x1)
|
|
query_video_status(0, &trick_mode_fffb);
|
|
if (bypass_trick_mode&0x2)
|
|
query_video_status(1, &trick_mode_i);
|
|
trick_mode = trick_mode_fffb | (trick_mode_i << 1);
|
|
if (trick_mode)
|
|
return 1;
|
|
}
|
|
|
|
if (bypass_3d &&
|
|
(di_pre_stru.source_trans_fmt != 0))
|
|
return 1;
|
|
|
|
/*prot is conflict with di post*/
|
|
if (vf_in && vf_in->video_angle)
|
|
return 1;
|
|
if (vf_in && (vf_in->type & VIDTYPE_PIC))
|
|
return 1;
|
|
#if 0
|
|
if (vf_in && (vf_in->type & VIDTYPE_COMPRESS))
|
|
return 1;
|
|
#endif
|
|
if ((di_vscale_skip_enable & 0x4) &&
|
|
vf_in && !post_wr_en) {
|
|
//--------------------------------------
|
|
if (vf_in->type & VIDTYPE_COMPRESS) {
|
|
vf_tmp.width = vf_in->compWidth;
|
|
vf_tmp.height = vf_in->compHeight;
|
|
if (vf_tmp.width > 1920 || vf_tmp.height > 1088)
|
|
return 1;
|
|
|
|
}
|
|
//--------------------------------------
|
|
/*backup vtype,set type as progressive*/
|
|
vtype = vf_in->type;
|
|
vf_in->type &= (~VIDTYPE_TYPEMASK);
|
|
vf_in->type &= (~VIDTYPE_VIU_NV21);
|
|
vf_in->type |= VIDTYPE_VIU_SINGLE_PLANE;
|
|
vf_in->type |= VIDTYPE_VIU_FIELD;
|
|
vf_in->type |= VIDTYPE_PRE_INTERLACE;
|
|
vf_in->type |= VIDTYPE_VIU_422;
|
|
ret = get_current_vscale_skip_count(vf_in);
|
|
di_vscale_skip_count = (ret&0xff);
|
|
vpp_3d_mode = ((ret>>8)&0xff);
|
|
vf_in->type = vtype;
|
|
if (di_vscale_skip_count > 0 ||
|
|
(vpp_3d_mode
|
|
#ifdef DET3D
|
|
&& (!det3d_en)
|
|
#endif
|
|
)
|
|
)
|
|
return 1;
|
|
}
|
|
isbypass_flag = false;
|
|
return 0;
|
|
}
|
|
|
|
static unsigned char is_bypass_post(void)
|
|
{
|
|
if (di_debug_flag & 0x40000) /* for debugging */
|
|
return (di_debug_flag >> 19) & 0x1;
|
|
|
|
/*prot is conflict with di post*/
|
|
if (di_pre_stru.orientation)
|
|
return 1;
|
|
if (bypass_post)
|
|
return 1;
|
|
|
|
#ifdef DET3D
|
|
if (di_pre_stru.vframe_interleave_flag != 0)
|
|
return 1;
|
|
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
#ifdef RUN_DI_PROCESS_IN_IRQ
|
|
static unsigned char is_input2pre(void)
|
|
{
|
|
if (input2pre
|
|
&& di_pre_stru.cur_prog_flag
|
|
&& di_pre_stru.vdin_source
|
|
&& (bypass_state == 0))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#ifdef DI_USE_FIXED_CANVAS_IDX
|
|
static int di_post_idx[2][6];
|
|
static int di_pre_idx[2][10];
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
|
|
static unsigned int di_inp_idx[3];
|
|
#else
|
|
static int di_wr_idx;
|
|
#endif
|
|
static int di_get_canvas(void)
|
|
{
|
|
unsigned int pre_num = 7, post_num = 6, i = 0;
|
|
|
|
if (mcpre_en) {
|
|
/* mem/chan2/nr/mtn/contrd/contrd2/
|
|
* contw/mcinfrd/mcinfow/mcvecw
|
|
*/
|
|
pre_num = 10;
|
|
/* buf0/buf1/buf2/mtnp/mcvec */
|
|
post_num = 6;
|
|
}
|
|
if (canvas_pool_alloc_canvas_table("di_pre",
|
|
&di_pre_idx[0][0], pre_num, CANVAS_MAP_TYPE_1)) {
|
|
pr_err("%s allocate di pre canvas error.\n", __func__);
|
|
return 1;
|
|
}
|
|
if (di_pre_rdma_enable) {
|
|
if (canvas_pool_alloc_canvas_table("di_pre",
|
|
&di_pre_idx[1][0], pre_num, CANVAS_MAP_TYPE_1)) {
|
|
pr_err("%s allocate di pre canvas error.\n", __func__);
|
|
return 1;
|
|
}
|
|
} else {
|
|
for (i = 0; i < pre_num; i++)
|
|
di_pre_idx[1][i] = di_pre_idx[0][i];
|
|
}
|
|
if (canvas_pool_alloc_canvas_table("di_post",
|
|
&di_post_idx[0][0], post_num, CANVAS_MAP_TYPE_1)) {
|
|
pr_err("%s allocate di post canvas error.\n", __func__);
|
|
return 1;
|
|
}
|
|
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA
|
|
if (canvas_pool_alloc_canvas_table("di_post",
|
|
&di_post_idx[1][0], post_num, CANVAS_MAP_TYPE_1)) {
|
|
pr_err("%s allocate di post canvas error.\n", __func__);
|
|
return 1;
|
|
}
|
|
#else
|
|
for (i = 0; i < post_num; i++)
|
|
di_post_idx[1][i] = di_post_idx[0][i];
|
|
#endif
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
|
|
if (canvas_pool_alloc_canvas_table("di_inp", &di_inp_idx[0], 3,
|
|
CANVAS_MAP_TYPE_1)) {
|
|
pr_err("%s allocat di inp canvas error.\n", __func__);
|
|
return 1;
|
|
}
|
|
pr_info("DI: support multi decoding %u~%u~%u.\n",
|
|
di_inp_idx[0], di_inp_idx[1], di_inp_idx[2]);
|
|
#endif
|
|
if (de_devp->post_wr_support == 0)
|
|
return 0;
|
|
|
|
#ifndef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
|
|
if (canvas_pool_alloc_canvas_table("di_wr",
|
|
&di_wr_idx, 1, CANVAS_MAP_TYPE_1)) {
|
|
pr_err("%s allocat di write back canvas error.\n",
|
|
__func__);
|
|
return 1;
|
|
}
|
|
pr_info("DI: support post write back %u.\n", di_wr_idx);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static void config_canvas_idx(struct di_buf_s *di_buf, int nr_canvas_idx,
|
|
int mtn_canvas_idx)
|
|
{
|
|
unsigned int height = 0;
|
|
|
|
if (!di_buf)
|
|
return;
|
|
if (di_buf->canvas_config_flag == 1) {
|
|
if (nr_canvas_idx >= 0) {
|
|
/* linked two interlace buffer should double height*/
|
|
if (di_buf->di_wr_linked_buf)
|
|
height = (di_buf->canvas_height << 1);
|
|
else
|
|
height = di_buf->canvas_height;
|
|
di_buf->nr_canvas_idx = nr_canvas_idx;
|
|
canvas_config(nr_canvas_idx, di_buf->nr_adr,
|
|
di_buf->canvas_width[NR_CANVAS], height, 0, 0);
|
|
}
|
|
} else if (di_buf->canvas_config_flag == 2) {
|
|
if (nr_canvas_idx >= 0) {
|
|
di_buf->nr_canvas_idx = nr_canvas_idx;
|
|
canvas_config(nr_canvas_idx, di_buf->nr_adr,
|
|
di_buf->canvas_width[NR_CANVAS],
|
|
di_buf->canvas_height, 0, 0);
|
|
}
|
|
if (mtn_canvas_idx >= 0) {
|
|
di_buf->mtn_canvas_idx = mtn_canvas_idx;
|
|
canvas_config(mtn_canvas_idx, di_buf->mtn_adr,
|
|
di_buf->canvas_width[MTN_CANVAS],
|
|
di_buf->canvas_height, 0, 0);
|
|
}
|
|
}
|
|
if (nr_canvas_idx >= 0) {
|
|
di_buf->vframe->canvas0Addr = di_buf->nr_canvas_idx;
|
|
di_buf->vframe->canvas1Addr = di_buf->nr_canvas_idx;
|
|
}
|
|
}
|
|
|
|
static void config_cnt_canvas_idx(struct di_buf_s *di_buf,
|
|
unsigned int cnt_canvas_idx)
|
|
{
|
|
|
|
if (!di_buf)
|
|
return;
|
|
|
|
di_buf->cnt_canvas_idx = cnt_canvas_idx;
|
|
canvas_config(
|
|
cnt_canvas_idx, di_buf->cnt_adr,
|
|
di_buf->canvas_width[MTN_CANVAS],
|
|
di_buf->canvas_height, 0, 0);
|
|
}
|
|
|
|
static void config_mcinfo_canvas_idx(struct di_buf_s *di_buf,
|
|
int mcinfo_canvas_idx)
|
|
{
|
|
|
|
if (!di_buf)
|
|
return;
|
|
|
|
di_buf->mcinfo_canvas_idx = mcinfo_canvas_idx;
|
|
canvas_config(
|
|
mcinfo_canvas_idx, di_buf->mcinfo_adr,
|
|
di_buf->canvas_height, 2, 0, 0);
|
|
}
|
|
static void config_mcvec_canvas_idx(struct di_buf_s *di_buf,
|
|
int mcvec_canvas_idx)
|
|
{
|
|
|
|
if (!di_buf)
|
|
return;
|
|
|
|
di_buf->mcvec_canvas_idx = mcvec_canvas_idx;
|
|
canvas_config(
|
|
mcvec_canvas_idx, di_buf->mcvec_adr,
|
|
di_buf->canvas_width[MV_CANVAS],
|
|
di_buf->canvas_height, 0, 0);
|
|
}
|
|
|
|
#else
|
|
|
|
static void config_canvas(struct di_buf_s *di_buf)
|
|
{
|
|
unsigned int height = 0;
|
|
|
|
if (!di_buf)
|
|
return;
|
|
|
|
if (di_buf->canvas_config_flag == 1) {
|
|
/* linked two interlace buffer should double height*/
|
|
if (di_buf->di_wr_linked_buf)
|
|
height = (di_buf->canvas_height << 1);
|
|
else
|
|
height = di_buf->canvas_height;
|
|
canvas_config(di_buf->nr_canvas_idx, di_buf->nr_adr,
|
|
di_buf->canvas_width[NR_CANVAS], height, 0, 0);
|
|
di_buf->canvas_config_flag = 0;
|
|
} else if (di_buf->canvas_config_flag == 2) {
|
|
canvas_config(di_buf->nr_canvas_idx, di_buf->nr_adr,
|
|
di_buf->canvas_width[MV_CANVAS],
|
|
di_buf->canvas_height, 0, 0);
|
|
canvas_config(di_buf->mtn_canvas_idx, di_buf->mtn_adr,
|
|
di_buf->canvas_width[MTN_CANVAS],
|
|
di_buf->canvas_height, 0, 0);
|
|
di_buf->canvas_config_flag = 0;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
#ifdef CONFIG_CMA
|
|
/**********************************************************
|
|
* ./include/linux/amlogic/media/codec_mm/codec_mm.h:
|
|
* unsigned long codec_mm_alloc_for_dma(const char *owner,
|
|
* int page_cnt,
|
|
* int align2n,
|
|
* int memflags);
|
|
* int codec_mm_free_for_dma(const char *owner,
|
|
* unsigned long phy_addr);
|
|
* void *codec_mm_phys_to_virt(unsigned long phy_addr);
|
|
***********************************************************/
|
|
|
|
#define TVP_MEM_PAGES 0xffff
|
|
/**********************************************************
|
|
* alloc mm from codec mm
|
|
* o: out:
|
|
* return:
|
|
* true: seccuss
|
|
* false: failed
|
|
***********************************************************/
|
|
static bool mm_codec_alloc(const char *owner, size_t count,
|
|
int cma_mode,
|
|
struct di_mm_s *o)
|
|
{
|
|
int flags = 0;
|
|
bool istvp = false;
|
|
|
|
if (codec_mm_video_tvp_enabled()) {
|
|
istvp = true;
|
|
flags |= CODEC_MM_FLAGS_TVP;
|
|
} else {
|
|
flags |= CODEC_MM_FLAGS_RESERVED | CODEC_MM_FLAGS_CPU;
|
|
}
|
|
|
|
if (cma_mode == 4 && !istvp)
|
|
flags = CODEC_MM_FLAGS_CMA_FIRST |
|
|
CODEC_MM_FLAGS_CPU;
|
|
|
|
o->addr = codec_mm_alloc_for_dma(owner,
|
|
count,
|
|
0,
|
|
flags);
|
|
|
|
if (o->addr == 0) {
|
|
/*failed*/
|
|
pr_err("di:%s: failed\n", __func__);
|
|
return false;
|
|
}
|
|
|
|
if (istvp)
|
|
o->ppage = (struct page *) TVP_MEM_PAGES;
|
|
else
|
|
o->ppage = codec_mm_phys_to_virt(o->addr);
|
|
|
|
//pr_info("%s:page:0x%p,add:0x%lx\n", __func__, o->ppage, o->addr);
|
|
return true;
|
|
}
|
|
|
|
/**********************************************************
|
|
* ./include/linux/dma-contiguous.h:
|
|
* struct page *dma_alloc_from_contiguous(struct device *dev,
|
|
* size_t count,
|
|
* unsigned int order);
|
|
* bool dma_release_from_contiguous(struct device *dev,
|
|
* struct page *pages,
|
|
* int count);
|
|
*
|
|
***********************************************************/
|
|
|
|
/**********************************************************
|
|
* alloc mm by cma
|
|
* o: out:
|
|
* return:
|
|
* true: seccuss
|
|
* false: failed
|
|
***********************************************************/
|
|
static bool mm_cma_alloc(struct device *dev, size_t count,
|
|
struct di_mm_s *o)
|
|
{
|
|
o->ppage = dma_alloc_from_contiguous(dev, count, 0, 0);
|
|
if (o->ppage) {
|
|
o->addr = page_to_phys(o->ppage);
|
|
return true;
|
|
}
|
|
pr_err("di:%s: failed\n", __func__);
|
|
return false;
|
|
}
|
|
|
|
bool di_mm_alloc(int cma_mode, size_t count, struct di_mm_s *o)
|
|
{
|
|
bool ret;
|
|
|
|
if (cma_mode == 3 || cma_mode == 4)
|
|
ret = mm_codec_alloc(DEVICE_NAME,
|
|
count,
|
|
cma_mode,
|
|
o);
|
|
else
|
|
ret = mm_cma_alloc(&(de_devp->pdev->dev), count, o);
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool di_mm_release(int cma_mode,
|
|
struct page *pages,
|
|
int count,
|
|
unsigned long addr)
|
|
{
|
|
bool ret = true;
|
|
|
|
if (cma_mode == 3 || cma_mode == 4)
|
|
codec_mm_free_for_dma(DEVICE_NAME, addr);
|
|
else
|
|
ret = dma_release_from_contiguous(&(de_devp->pdev->dev),
|
|
pages,
|
|
count);
|
|
return ret;
|
|
}
|
|
/***********************************************************/
|
|
static unsigned int di_cma_alloc_total(struct di_dev_s *de_devp)
|
|
{
|
|
#if 0
|
|
de_devp->total_pages =
|
|
dma_alloc_from_contiguous(&(de_devp->pdev->dev),
|
|
de_devp->mem_size >> PAGE_SHIFT, 0);
|
|
if (de_devp->total_pages) {
|
|
de_devp->mem_start =
|
|
page_to_phys(de_devp->total_pages);
|
|
pr_dbg("%s:DI CMA allocate addr:0x%lx ok.\n",
|
|
__func__, de_devp->mem_start);
|
|
return 1;
|
|
}
|
|
pr_err("%s:xxxxxx DI CMA allocate fail.\n", __func__);
|
|
if (de_devp->flag_cma != 0 && de_devp->nrds_enable) {
|
|
nr_ds_buf_init(de_devp->flag_cma, 0,
|
|
&(de_devp->pdev->dev));
|
|
}
|
|
|
|
return 0;
|
|
#else
|
|
/*****************************************************/
|
|
struct di_mm_s omm;
|
|
bool ret;
|
|
|
|
ret = di_mm_alloc(de_devp->flag_cma,
|
|
de_devp->mem_size >> PAGE_SHIFT,
|
|
&omm);
|
|
|
|
if (!ret) /*failed*/
|
|
return 0;
|
|
|
|
de_devp->total_pages = omm.ppage;
|
|
de_devp->mem_start = omm.addr;
|
|
|
|
if (de_devp->flag_cma != 0 && de_devp->nrds_enable) {
|
|
nr_ds_buf_init(de_devp->flag_cma, 0,
|
|
&(de_devp->pdev->dev));
|
|
}
|
|
|
|
return 1;
|
|
#endif
|
|
}
|
|
|
|
static unsigned int di_cma_alloc(struct di_dev_s *devp)
|
|
{
|
|
unsigned int start_time, end_time, delta_time;
|
|
struct di_buf_s *buf_p = NULL;
|
|
int itmp, alloc_cnt = 0;
|
|
u8 *tmp;
|
|
bool aret;
|
|
struct di_mm_s omm;
|
|
|
|
start_time = jiffies_to_msecs(jiffies);
|
|
queue_for_each_entry(buf_p, ptmp, QUEUE_LOCAL_FREE, list) {
|
|
#if 0
|
|
if (buf_p->pages == NULL) {
|
|
buf_p->pages =
|
|
dma_alloc_from_contiguous(&(devp->pdev->dev),
|
|
devp->buffer_size >> PAGE_SHIFT, 0);
|
|
if (IS_ERR_OR_NULL(buf_p->pages)) {
|
|
buf_p->pages = NULL;
|
|
pr_err("xxxxxxxxx DI CMA allocate %d fail.\n",
|
|
buf_p->index);
|
|
return 0;
|
|
} else {
|
|
alloc_cnt++;
|
|
if (cma_print)
|
|
pr_info("DI CMA allocate buf[%d]page:0x%p\n",
|
|
buf_p->index, buf_p->pages);
|
|
}
|
|
} else {
|
|
if (cma_print) {
|
|
pr_err("DI buf[%d] page:0x%p cma alloced skip\n",
|
|
buf_p->index, buf_p->pages);
|
|
}
|
|
}
|
|
buf_p->nr_adr = page_to_phys(buf_p->pages);
|
|
#else
|
|
if (buf_p->pages != NULL) {
|
|
pr_err("di:err1:%s:buf[%d] page:0x%p alloced skip\n",
|
|
__func__, buf_p->index, buf_p->pages);
|
|
continue;
|
|
}
|
|
|
|
aret = di_mm_alloc(devp->flag_cma,
|
|
devp->buffer_size >> PAGE_SHIFT,
|
|
&omm);
|
|
|
|
if (!aret) {
|
|
buf_p->pages = NULL;
|
|
pr_err("di:err2:%s: alloc failed %d fail.\n",
|
|
__func__,
|
|
buf_p->index);
|
|
return 0;
|
|
}
|
|
|
|
buf_p->pages = omm.ppage;
|
|
buf_p->nr_adr = omm.addr;
|
|
alloc_cnt++;
|
|
if (cma_print)
|
|
pr_info("DI CMA allocate buf[%d]page:0x%p\n",
|
|
buf_p->index, buf_p->pages);
|
|
|
|
#endif
|
|
if (cma_print)
|
|
pr_info(" addr 0x%lx ok.\n", buf_p->nr_adr);
|
|
if (di_pre_stru.buf_alloc_mode == 0) {
|
|
buf_p->mtn_adr = buf_p->nr_adr +
|
|
di_pre_stru.nr_size;
|
|
buf_p->cnt_adr = buf_p->nr_adr +
|
|
di_pre_stru.nr_size +
|
|
di_pre_stru.mtn_size;
|
|
if (mc_mem_alloc) {
|
|
buf_p->mcvec_adr = buf_p->nr_adr +
|
|
di_pre_stru.nr_size +
|
|
di_pre_stru.mtn_size +
|
|
di_pre_stru.count_size;
|
|
buf_p->mcinfo_adr =
|
|
buf_p->nr_adr +
|
|
di_pre_stru.nr_size +
|
|
di_pre_stru.mtn_size +
|
|
di_pre_stru.count_size +
|
|
di_pre_stru.mv_size;
|
|
tmp = di_vmap(buf_p->mcinfo_adr,
|
|
di_pre_stru.mcinfo_size,
|
|
&buf_p->bflg_vmap);
|
|
|
|
if (buf_p->bflg_vmap == true)
|
|
buf_p->mcinfo_vaddr =
|
|
(unsigned short *)tmp;
|
|
else {
|
|
buf_p->mcinfo_vaddr = NULL;
|
|
pr_err("DI: %s vmap fail\n",
|
|
__func__);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (post_wr_en && post_wr_support) {
|
|
queue_for_each_entry(buf_p, ptmp, QUEUE_POST_FREE, list) {
|
|
#if 0
|
|
if (buf_p->pages == NULL) {
|
|
buf_p->pages =
|
|
dma_alloc_from_contiguous(
|
|
&(devp->pdev->dev),
|
|
devp->post_buffer_size>>PAGE_SHIFT,
|
|
0);
|
|
if (IS_ERR_OR_NULL(buf_p->pages)) {
|
|
buf_p->pages = NULL;
|
|
pr_err("xxxxxxxxx DI CMA allocate %d fail.\n",
|
|
buf_p->index);
|
|
return 0;
|
|
}
|
|
alloc_cnt++;
|
|
if (cma_print)
|
|
pr_info("DI CMA allocate buf[%d]page:0x%p\n",
|
|
buf_p->index,
|
|
buf_p->pages);
|
|
} else {
|
|
pr_err("DI buf[%d] page:0x%p cma alloced skip\n",
|
|
buf_p->index, buf_p->pages);
|
|
}
|
|
buf_p->nr_adr = page_to_phys(buf_p->pages);
|
|
|
|
#else
|
|
if (buf_p->pages != NULL) {
|
|
pr_err("di:err3:%s:buf[%d] page:0x%p skip\n",
|
|
__func__,
|
|
buf_p->index, buf_p->pages);
|
|
continue;
|
|
}
|
|
|
|
aret = di_mm_alloc(devp->flag_cma,
|
|
devp->post_buffer_size>>PAGE_SHIFT,
|
|
&omm);
|
|
|
|
if (!aret) {
|
|
buf_p->pages = NULL;
|
|
pr_err("di:err4:%s: alloc failed %d fail.\n",
|
|
__func__,
|
|
buf_p->index);
|
|
return 0;
|
|
}
|
|
|
|
buf_p->pages = omm.ppage;
|
|
buf_p->nr_adr = omm.addr;
|
|
alloc_cnt++;
|
|
if (cma_print)
|
|
pr_info("di:%s:pbuf[%d]page:0x%p\n",
|
|
__func__,
|
|
buf_p->index, buf_p->pages);
|
|
#endif
|
|
if (cma_print)
|
|
pr_info(" addr 0x%lx ok.\n", buf_p->nr_adr);
|
|
}
|
|
}
|
|
if (de_devp->flag_cma != 0 && de_devp->nrds_enable) {
|
|
nr_ds_buf_init(de_devp->flag_cma, 0,
|
|
&(de_devp->pdev->dev));
|
|
}
|
|
|
|
end_time = jiffies_to_msecs(jiffies);
|
|
delta_time = end_time - start_time;
|
|
pr_info("%s:alloc %u buffer use %u ms(%u~%u)\n",
|
|
__func__, alloc_cnt, delta_time, start_time, end_time);
|
|
return 1;
|
|
}
|
|
|
|
static void di_cma_release(struct di_dev_s *devp)
|
|
{
|
|
unsigned int i, ii, rels_cnt = 0, start_time, end_time, delta_time;
|
|
struct di_buf_s *buf_p, *keep_buf;
|
|
bool ret;
|
|
|
|
keep_buf = di_post_stru.keep_buf;
|
|
start_time = jiffies_to_msecs(jiffies);
|
|
for (i = 0; (i < devp->buf_num_avail); i++) {
|
|
buf_p = &(di_buf_local[i]);
|
|
ii = USED_LOCAL_BUF_MAX;
|
|
if (!IS_ERR_OR_NULL(keep_buf)) {
|
|
for (ii = 0; ii < USED_LOCAL_BUF_MAX; ii++) {
|
|
if (buf_p == keep_buf->di_buf_dup_p[ii]) {
|
|
pr_dbg("%s skip buf[%d].\n\n",
|
|
__func__, i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ((ii >= USED_LOCAL_BUF_MAX) &&
|
|
(buf_p->pages != NULL)) {
|
|
|
|
if (buf_p->bflg_vmap == true) {
|
|
di_unmap_phyaddr((u8 *)buf_p->mcinfo_vaddr);
|
|
buf_p->bflg_vmap = false;
|
|
}
|
|
#if 0
|
|
if (dma_release_from_contiguous(&(devp->pdev->dev),
|
|
buf_p->pages,
|
|
devp->buffer_size >> PAGE_SHIFT)) {
|
|
buf_p->pages = NULL;
|
|
rels_cnt++;
|
|
if (cma_print)
|
|
pr_info(
|
|
"DI CMA release buf[%d] ok.\n", i);
|
|
} else {
|
|
pr_err("DI CMA release buf[%d] fail.\n", i);
|
|
}
|
|
#else
|
|
|
|
ret = di_mm_release(devp->flag_cma, buf_p->pages,
|
|
devp->buffer_size >> PAGE_SHIFT,
|
|
buf_p->nr_adr);
|
|
if (ret) {
|
|
buf_p->pages = NULL;
|
|
rels_cnt++;
|
|
if (cma_print)
|
|
pr_info(
|
|
"DI release buf[%d] ok.\n", i);
|
|
} else {
|
|
pr_err("di:err:%s:release buf[%d] fail.\n",
|
|
__func__, i);
|
|
}
|
|
#endif
|
|
} else {
|
|
if (!IS_ERR_OR_NULL(buf_p->pages) && cma_print) {
|
|
pr_info("DI buf[%d] page:0x%p no release.\n",
|
|
buf_p->index, buf_p->pages);
|
|
}
|
|
}
|
|
}
|
|
if (post_wr_en && post_wr_support) {
|
|
for (i = 0; i < di_post_stru.di_post_num; i++) {
|
|
buf_p = &(di_buf_post[i]);
|
|
#if 0
|
|
if (buf_p->pages != NULL) {
|
|
if (dma_release_from_contiguous(
|
|
&(devp->pdev->dev),
|
|
buf_p->pages,
|
|
devp->post_buffer_size>>
|
|
PAGE_SHIFT)) {
|
|
buf_p->pages = NULL;
|
|
rels_cnt++;
|
|
if (cma_print)
|
|
pr_info(
|
|
"DI CMA release post buf[%d] ok.\n", i);
|
|
} else {
|
|
pr_err("DI CMA release post buf[%d] fail.\n",
|
|
i);
|
|
}
|
|
}
|
|
#else
|
|
if (buf_p->pages == NULL) {
|
|
pr_err("di:err2:%s:post buf[%d] is null\n",
|
|
__func__, i);
|
|
continue;
|
|
}
|
|
|
|
ret = di_mm_release(devp->flag_cma,
|
|
buf_p->pages,
|
|
devp->post_buffer_size >> PAGE_SHIFT,
|
|
buf_p->nr_adr);
|
|
if (ret) {
|
|
buf_p->pages = NULL;
|
|
rels_cnt++;
|
|
if (cma_print)
|
|
pr_info(
|
|
"DI release post buf[%d] ok.\n", i);
|
|
} else {
|
|
pr_err("di:err:%s:release post buf[%d] fail\n",
|
|
__func__, i);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
if (de_devp->nrds_enable) {
|
|
nr_ds_buf_uninit(de_devp->flag_cma,
|
|
&(de_devp->pdev->dev));
|
|
}
|
|
|
|
end_time = jiffies_to_msecs(jiffies);
|
|
delta_time = end_time - start_time;
|
|
pr_info("%s:release %u buffer use %u ms(%u~%u)\n",
|
|
__func__, rels_cnt, delta_time, start_time, end_time);
|
|
}
|
|
#endif
|
|
|
|
static void di_patch_mov_ini(void)
|
|
{
|
|
struct di_patch_mov_s *pmov;
|
|
|
|
if (!de_devp)
|
|
return;
|
|
|
|
pmov = &de_devp->mov;
|
|
if (!cpu_after_eq(MESON_CPU_MAJOR_ID_TL1)) {
|
|
pmov->en_support = false;
|
|
return;
|
|
}
|
|
pmov->en_support = true;
|
|
pmov->mode = -1;
|
|
pmov->nub = 3;
|
|
pmov->reg_addr[0] = DI_NR_CTRL1;
|
|
pmov->reg_addr[1] = DI_NR_CTRL2;
|
|
pmov->reg_addr[2] = NR4_TOP_CTRL;
|
|
}
|
|
|
|
bool di_patch_mov_db(unsigned int addr, unsigned int val)
|
|
{
|
|
bool ret = false;
|
|
int i;
|
|
struct di_patch_mov_s *pmov;
|
|
struct di_patch_mov_d_s *pmv;
|
|
|
|
if (!de_devp)
|
|
return ret;
|
|
|
|
pmov = &de_devp->mov;
|
|
|
|
if (!pmov->en_support || !pmov->nub)
|
|
return ret;
|
|
|
|
for (i = 0; i < pmov->nub; i++) {
|
|
if (addr == pmov->reg_addr[i]) {
|
|
pmv = &pmov->val_db[i];
|
|
pmv->val = val;
|
|
pmv->en = true;
|
|
pmv->mask = 0xffffffff;
|
|
ret = true;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void di_patch_mov_setreg(unsigned int nub, unsigned int *preg)
|
|
{
|
|
struct di_patch_mov_s *pmov;
|
|
unsigned int i;
|
|
|
|
if (!de_devp)
|
|
return;
|
|
|
|
pmov = &de_devp->mov;
|
|
|
|
if (!pmov->en_support)
|
|
return;
|
|
|
|
pmov->nub = nub;
|
|
if (nub > DI_PATCH_MOV_MAX_NUB) {
|
|
pr_error("err: %s:nub is overflow %d\n",
|
|
__func__, nub);
|
|
pmov->nub = DI_PATCH_MOV_MAX_NUB;
|
|
}
|
|
|
|
pmov->mode = -1;
|
|
for (i = 0; i < pmov->nub; i++) {
|
|
pmov->reg_addr[i] = preg[i];
|
|
di_pr_info("reg:0x%x\n", preg[i]);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(di_patch_mov_setreg);
|
|
|
|
/**************************************************
|
|
* pdate:
|
|
* value / mask
|
|
* value / mask
|
|
* need keep same order with di_patch_mov_setreg
|
|
**************************************************/
|
|
bool di_api_mov_sel(unsigned int mode, unsigned int *pdate)
|
|
{
|
|
struct di_patch_mov_s *pmov;
|
|
int i;
|
|
struct di_patch_mov_d_s *pmv;
|
|
bool ret = true;
|
|
|
|
if (!de_devp)
|
|
return false;
|
|
|
|
pmov = &de_devp->mov;
|
|
|
|
if (!pmov ||
|
|
!pmov->en_support ||
|
|
!init_flag)
|
|
return false;
|
|
|
|
switch (mode) {
|
|
case 0:/*setting from db*/
|
|
pmov->mode = 0;
|
|
pmov->update = 1;
|
|
break;
|
|
case 1:/*setting from pq*/
|
|
pmov->update = 0;
|
|
for (i = 0; i < pmov->nub; i++) {
|
|
pmv = &pmov->val_pq[i];
|
|
pmv->val = pdate[i * 2];
|
|
pmv->mask = pdate[i * 2 + 1];
|
|
pmv->en = true;
|
|
}
|
|
pmov->mode = 1;
|
|
pmov->update = true;
|
|
|
|
break;
|
|
default:
|
|
ret = false;
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(di_api_mov_sel);
|
|
|
|
static void di_patch_mov_setting(void)
|
|
{
|
|
struct di_patch_mov_s *pmov;
|
|
int i;
|
|
struct di_patch_mov_d_s *pmv;
|
|
unsigned int val;
|
|
|
|
if (!de_devp)
|
|
return;
|
|
|
|
pmov = &de_devp->mov;
|
|
|
|
if (!pmov ||
|
|
!pmov->en_support ||
|
|
pmov->mode < 0 ||
|
|
pmov->mode > 1 ||
|
|
!pmov->update)
|
|
return;
|
|
|
|
if (pmov->mode == 0)
|
|
pmv = &pmov->val_db[0];
|
|
else
|
|
pmv = &pmov->val_pq[0];
|
|
|
|
for (i = 0; i < pmov->nub; i++) {
|
|
if (pmv->en) {
|
|
if (pmv->mask != 0xffffffff) {
|
|
val = ((RDMA_RD(pmov->reg_addr[i]) &
|
|
(~(pmv->mask))) |
|
|
(pmv->val & pmv->mask));
|
|
} else {
|
|
val = pmv->val;
|
|
}
|
|
DI_Wr(pmov->reg_addr[i], val);
|
|
}
|
|
pmv++;
|
|
}
|
|
pmov->update = 0;
|
|
}
|
|
|
|
void di_set_comb_mode(unsigned int mode)
|
|
{
|
|
di_pre_stru.comb_mode = mode;
|
|
}
|
|
EXPORT_SYMBOL(di_set_comb_mode);
|
|
|
|
static int di_init_buf(int width, int height, unsigned char prog_flag)
|
|
{
|
|
int i;
|
|
int canvas_height = height + 8;
|
|
struct page *tmp_page = NULL;
|
|
unsigned int di_buf_size = 0, di_post_buf_size = 0, mtn_size = 0;
|
|
unsigned int nr_size = 0, count_size = 0, mv_size = 0, mc_size = 0;
|
|
unsigned int nr_width = width, mtn_width = width, mv_width = width;
|
|
unsigned int nr_canvas_width = width, mtn_canvas_width = width;
|
|
unsigned int mv_canvas_width = width, canvas_align_width = 32;
|
|
unsigned long di_post_mem = 0, nrds_mem = 0;
|
|
struct di_buf_s *keep_buf = di_post_stru.keep_buf;
|
|
u8 *tmp;
|
|
|
|
if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A))
|
|
canvas_align_width = 64;
|
|
pr_info("di: %s -S\n", __func__);
|
|
frame_count = 0;
|
|
disp_frame_count = 0;
|
|
cur_post_ready_di_buf = NULL;
|
|
/* decoder'buffer had been release no need put */
|
|
for (i = 0; i < MAX_IN_BUF_NUM; i++)
|
|
vframe_in[i] = NULL;
|
|
memset(&di_pre_stru, 0, sizeof(di_pre_stru));
|
|
if (nr10bit_support) {
|
|
if (full_422_pack)
|
|
nr_width = (width * 5) / 4;
|
|
else
|
|
nr_width = (width * 3) / 2;
|
|
} else {
|
|
nr_width = width;
|
|
}
|
|
/* make sure canvas width must be divided by 256bit|32byte align */
|
|
nr_canvas_width = nr_width << 1;
|
|
mtn_canvas_width = mtn_width >> 1;
|
|
mv_canvas_width = (mv_width << 1) / 5;
|
|
nr_canvas_width = roundup(nr_canvas_width, canvas_align_width);
|
|
mtn_canvas_width = roundup(mtn_canvas_width, canvas_align_width);
|
|
mv_canvas_width = roundup(mv_canvas_width, canvas_align_width);
|
|
nr_width = nr_canvas_width >> 1;
|
|
mtn_width = mtn_canvas_width << 1;
|
|
mv_width = (mv_canvas_width * 5) >> 1;
|
|
|
|
if (prog_flag) {
|
|
di_pre_stru.prog_proc_type = 1;
|
|
di_pre_stru.buf_alloc_mode = 1;
|
|
di_buf_size = nr_width * canvas_height * 2;
|
|
di_buf_size = roundup(di_buf_size, PAGE_SIZE);
|
|
de_devp->buf_num_avail = de_devp->mem_size / di_buf_size;
|
|
if (de_devp->buf_num_avail > (2 * MAX_LOCAL_BUF_NUM))
|
|
de_devp->buf_num_avail = 2 * MAX_LOCAL_BUF_NUM;
|
|
|
|
} else {
|
|
di_pre_stru.prog_proc_type = 0;
|
|
di_pre_stru.buf_alloc_mode = 0;
|
|
/*nr_size(bits)=w*active_h*8*2(yuv422)
|
|
* mtn(bits)=w*active_h*4
|
|
* cont(bits)=w*active_h*4 mv(bits)=w*active_h/5*16
|
|
* mcinfo(bits)=active_h*16
|
|
*/
|
|
nr_size = (nr_width * canvas_height)*8*2/16;
|
|
mtn_size = (mtn_width * canvas_height)*4/16;
|
|
count_size = (mtn_width * canvas_height)*4/16;
|
|
mv_size = (mv_width * canvas_height)/5;
|
|
mc_size = roundup(canvas_height >> 1, canvas_align_width) << 1;
|
|
|
|
if (mc_mem_alloc) {
|
|
di_buf_size = nr_size + mtn_size + count_size +
|
|
mv_size + mc_size;
|
|
} else {
|
|
di_buf_size = nr_size + mtn_size + count_size;
|
|
}
|
|
di_buf_size = roundup(di_buf_size, PAGE_SIZE);
|
|
de_devp->buf_num_avail = de_devp->mem_size / di_buf_size;
|
|
|
|
if (post_wr_en && post_wr_support) {
|
|
de_devp->buf_num_avail = (de_devp->mem_size +
|
|
(nr_width*canvas_height<<2)) /
|
|
(di_buf_size + (nr_width*canvas_height<<1));
|
|
}
|
|
|
|
if (de_devp->buf_num_avail > MAX_LOCAL_BUF_NUM)
|
|
de_devp->buf_num_avail = MAX_LOCAL_BUF_NUM;
|
|
|
|
}
|
|
de_devp->buffer_size = di_buf_size;
|
|
di_pre_stru.nr_size = nr_size;
|
|
di_pre_stru.count_size = count_size;
|
|
di_pre_stru.mtn_size = mtn_size;
|
|
di_pre_stru.mv_size = mv_size;
|
|
di_pre_stru.mcinfo_size = mc_size;
|
|
same_field_top_count = 0;
|
|
same_field_bot_count = 0;
|
|
|
|
queue_init(de_devp->buf_num_avail);
|
|
for (i = 0; i < de_devp->buf_num_avail; i++) {
|
|
struct di_buf_s *di_buf = &(di_buf_local[i]);
|
|
int ii = USED_LOCAL_BUF_MAX;
|
|
if (!IS_ERR_OR_NULL(keep_buf)) {
|
|
for (ii = 0; ii < USED_LOCAL_BUF_MAX; ii++) {
|
|
if (di_buf == keep_buf->di_buf_dup_p[ii]) {
|
|
di_print("%s skip %d\n", __func__, i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ii >= USED_LOCAL_BUF_MAX) {
|
|
/* backup cma pages */
|
|
tmp_page = di_buf->pages;
|
|
memset(di_buf, 0, sizeof(struct di_buf_s));
|
|
di_buf->pages = tmp_page;
|
|
di_buf->type = VFRAME_TYPE_LOCAL;
|
|
di_buf->pre_ref_count = 0;
|
|
di_buf->post_ref_count = 0;
|
|
di_buf->canvas_width[NR_CANVAS] = nr_canvas_width;
|
|
di_buf->canvas_width[MTN_CANVAS] = mtn_canvas_width;
|
|
di_buf->canvas_width[MV_CANVAS] = mv_canvas_width;
|
|
|
|
if (prog_flag) {
|
|
di_buf->canvas_height = canvas_height;
|
|
|
|
//use reserved memory
|
|
if (de_devp->flag_cma == 0)
|
|
di_buf->nr_adr = de_devp->mem_start +
|
|
di_buf_size * i;
|
|
|
|
di_buf->canvas_config_flag = 1;
|
|
} else {
|
|
di_buf->canvas_height = (canvas_height>>1);
|
|
di_buf->canvas_height =
|
|
roundup(di_buf->canvas_height,
|
|
canvas_align_width);
|
|
|
|
//use reserved memory
|
|
if (de_devp->flag_cma == 0) {
|
|
di_buf->nr_adr = de_devp->mem_start +
|
|
di_buf_size * i;
|
|
di_buf->mtn_adr = de_devp->mem_start +
|
|
di_buf_size * i +
|
|
nr_size;
|
|
di_buf->cnt_adr = de_devp->mem_start +
|
|
di_buf_size * i +
|
|
nr_size + mtn_size;
|
|
|
|
if (mc_mem_alloc) {
|
|
di_buf->mcvec_adr =
|
|
de_devp->mem_start +
|
|
di_buf_size * i +
|
|
nr_size + mtn_size +
|
|
count_size;
|
|
di_buf->mcinfo_adr =
|
|
de_devp->mem_start +
|
|
di_buf_size * i +
|
|
nr_size +
|
|
mtn_size +
|
|
count_size + mv_size;
|
|
tmp = di_vmap(
|
|
di_buf->mcinfo_adr,
|
|
di_pre_stru.
|
|
mcinfo_size,
|
|
&di_buf->bflg_vmap);
|
|
|
|
if (di_buf->bflg_vmap == true)
|
|
di_buf->mcinfo_vaddr =
|
|
(unsigned short *)tmp;
|
|
else {
|
|
di_buf->mcinfo_vaddr = NULL;
|
|
pr_err("DI: %s vmap fail\n",
|
|
__func__);
|
|
}
|
|
}
|
|
}
|
|
|
|
di_buf->canvas_config_flag = 2;
|
|
}
|
|
|
|
di_buf->index = i;
|
|
di_buf->vframe = &(vframe_local[i]);
|
|
di_buf->vframe->private_data = di_buf;
|
|
di_buf->vframe->canvas0Addr = di_buf->nr_canvas_idx;
|
|
di_buf->vframe->canvas1Addr = di_buf->nr_canvas_idx;
|
|
di_buf->queue_index = -1;
|
|
di_buf->invert_top_bot_flag = 0;
|
|
queue_in(di_buf, QUEUE_LOCAL_FREE);
|
|
}
|
|
}
|
|
#ifdef CONFIG_CMA
|
|
if (de_devp->flag_cma == 1 || (de_devp->flag_cma == 4) ||
|
|
(de_devp->flag_cma == 3)) {
|
|
pr_dbg("%s:cma alloc req time: %u ms\n",
|
|
__func__, jiffies_to_msecs(jiffies));
|
|
atomic_set(&de_devp->mem_flag, 0);
|
|
di_pre_stru.cma_alloc_req = 1;
|
|
up(&di_sema);
|
|
}
|
|
#endif
|
|
|
|
//use reserved memory
|
|
if (de_devp->flag_cma == 0)
|
|
di_post_mem = de_devp->mem_start +
|
|
di_buf_size*de_devp->buf_num_avail;
|
|
if (post_wr_en && post_wr_support) {
|
|
di_post_buf_size = nr_width * canvas_height * 2;
|
|
/* pre buffer must 2 more than post buffer */
|
|
if ((de_devp->buf_num_avail - 2) > MAX_POST_BUF_NUM)
|
|
di_post_stru.di_post_num = MAX_POST_BUF_NUM;
|
|
else
|
|
di_post_stru.di_post_num = (de_devp->buf_num_avail - 2);
|
|
pr_info("DI: di post buffer size %u byte.\n", di_post_buf_size);
|
|
} else {
|
|
di_post_stru.di_post_num = MAX_POST_BUF_NUM;
|
|
di_post_buf_size = 0;
|
|
}
|
|
de_devp->post_buffer_size = di_post_buf_size;
|
|
for (i = 0; i < MAX_IN_BUF_NUM; i++) {
|
|
struct di_buf_s *di_buf = &(di_buf_in[i]);
|
|
|
|
if (di_buf) {
|
|
memset(di_buf, 0, sizeof(struct di_buf_s));
|
|
di_buf->type = VFRAME_TYPE_IN;
|
|
di_buf->pre_ref_count = 0;
|
|
di_buf->post_ref_count = 0;
|
|
di_buf->vframe = &(vframe_in_dup[i]);
|
|
di_buf->vframe->private_data = di_buf;
|
|
di_buf->index = i;
|
|
di_buf->queue_index = -1;
|
|
di_buf->invert_top_bot_flag = 0;
|
|
queue_in(di_buf, QUEUE_IN_FREE);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < di_post_stru.di_post_num; i++) {
|
|
struct di_buf_s *di_buf = &(di_buf_post[i]);
|
|
|
|
if (di_buf) {
|
|
if (di_buf != keep_buf) {
|
|
memset(di_buf, 0, sizeof(struct di_buf_s));
|
|
di_buf->type = VFRAME_TYPE_POST;
|
|
di_buf->index = i;
|
|
di_buf->vframe = &(vframe_post[i]);
|
|
di_buf->vframe->private_data = di_buf;
|
|
di_buf->queue_index = -1;
|
|
di_buf->invert_top_bot_flag = 0;
|
|
if (post_wr_en && post_wr_support) {
|
|
di_buf->canvas_width[NR_CANVAS] =
|
|
(nr_width << 1);
|
|
di_buf->canvas_height = canvas_height;
|
|
di_buf->canvas_config_flag = 1;
|
|
|
|
//use reserved memory
|
|
if (de_devp->flag_cma == 0)
|
|
di_buf->nr_adr = di_post_mem +
|
|
di_post_buf_size*i;
|
|
}
|
|
queue_in(di_buf, QUEUE_POST_FREE);
|
|
}
|
|
}
|
|
}
|
|
if (de_devp->flag_cma == 0 && de_devp->nrds_enable) {
|
|
nrds_mem = di_post_mem +
|
|
di_post_stru.di_post_num * di_post_buf_size;
|
|
nr_ds_buf_init(de_devp->flag_cma, nrds_mem,
|
|
&(de_devp->pdev->dev));
|
|
}
|
|
pr_info("di: %s -E\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
static void keep_mirror_buffer(void)
|
|
{
|
|
struct di_buf_s *p = NULL;
|
|
int i = 0, ii = 0, itmp;
|
|
|
|
queue_for_each_entry(p, ptmp, QUEUE_DISPLAY, list) {
|
|
if (p->di_buf[0]->type != VFRAME_TYPE_IN &&
|
|
(p->process_fun_index != PROCESS_FUN_NULL) &&
|
|
(ii < USED_LOCAL_BUF_MAX) &&
|
|
(p->index == di_post_stru.cur_disp_index)) {
|
|
di_post_stru.keep_buf = p;
|
|
for (i = 0; i < USED_LOCAL_BUF_MAX; i++) {
|
|
if (IS_ERR_OR_NULL(p->di_buf_dup_p[i]))
|
|
continue;
|
|
/* prepare for recycle
|
|
* the keep buffer
|
|
*/
|
|
p->di_buf_dup_p[i]->pre_ref_count = 0;
|
|
p->di_buf_dup_p[i]->post_ref_count = 0;
|
|
if ((p->di_buf_dup_p[i]->queue_index >= 0) &&
|
|
(p->di_buf_dup_p[i]->queue_index < QUEUE_NUM)) {
|
|
if (is_in_queue(p->di_buf_dup_p[i],
|
|
p->di_buf_dup_p[i]->queue_index))
|
|
queue_out(p->di_buf_dup_p[i]);
|
|
}
|
|
ii++;
|
|
if (p->di_buf_dup_p[i]->di_wr_linked_buf)
|
|
p->di_buf_dup_p[i+1] =
|
|
p->di_buf_dup_p[i]->di_wr_linked_buf;
|
|
}
|
|
queue_out(p);
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
static void di_uninit_buf(unsigned int disable_mirror)
|
|
{
|
|
struct di_buf_s *keep_buf = NULL;
|
|
int i = 0;
|
|
|
|
if (!queue_empty(QUEUE_DISPLAY) || disable_mirror)
|
|
di_post_stru.keep_buf = NULL;
|
|
|
|
if (disable_mirror != 1)
|
|
keep_mirror_buffer();
|
|
|
|
if (!IS_ERR_OR_NULL(di_post_stru.keep_buf)) {
|
|
keep_buf = di_post_stru.keep_buf;
|
|
pr_dbg("%s keep cur di_buf %d (",
|
|
__func__, keep_buf->index);
|
|
for (i = 0; i < USED_LOCAL_BUF_MAX; i++) {
|
|
/*coverity[var_deref_op] null pointer has been judged*/
|
|
if (!IS_ERR_OR_NULL(keep_buf->di_buf_dup_p[i]))
|
|
pr_dbg("%d\t",
|
|
keep_buf->di_buf_dup_p[i]->index);
|
|
}
|
|
pr_dbg(")\n");
|
|
}
|
|
queue_init(0);
|
|
/* decoder'buffer had been release no need put */
|
|
for (i = 0; i < MAX_IN_BUF_NUM; i++)
|
|
vframe_in[i] = NULL;
|
|
di_pre_stru.pre_de_process_done = 0;
|
|
di_pre_stru.pre_de_process_flag = 0;
|
|
if (post_wr_en && post_wr_support) {
|
|
di_post_stru.cur_post_buf = NULL;
|
|
di_post_stru.post_de_busy = 0;
|
|
di_post_stru.de_post_process_done = 0;
|
|
di_post_stru.post_wr_cnt = 0;
|
|
}
|
|
if (de_devp->flag_cma == 0 && de_devp->nrds_enable) {
|
|
nr_ds_buf_uninit(de_devp->flag_cma,
|
|
&(de_devp->pdev->dev));
|
|
}
|
|
}
|
|
|
|
static void log_buffer_state(unsigned char *tag)
|
|
{
|
|
if (di_log_flag & DI_LOG_BUFFER_STATE) {
|
|
struct di_buf_s *p = NULL;/* , *ptmp; */
|
|
int itmp;
|
|
int in_free = 0;
|
|
int local_free = 0;
|
|
int pre_ready = 0;
|
|
int post_free = 0;
|
|
int post_ready = 0;
|
|
int post_ready_ext = 0;
|
|
int display = 0;
|
|
int display_ext = 0;
|
|
int recycle = 0;
|
|
int di_inp = 0;
|
|
int di_wr = 0;
|
|
ulong irq_flag2 = 0;
|
|
|
|
di_lock_irqfiq_save(irq_flag2);
|
|
in_free = list_count(QUEUE_IN_FREE);
|
|
local_free = list_count(QUEUE_LOCAL_FREE);
|
|
pre_ready = list_count(QUEUE_PRE_READY);
|
|
post_free = list_count(QUEUE_POST_FREE);
|
|
post_ready = list_count(QUEUE_POST_READY);
|
|
queue_for_each_entry(p, ptmp, QUEUE_POST_READY, list) {
|
|
if (p->di_buf[0])
|
|
post_ready_ext++;
|
|
|
|
if (p->di_buf[1])
|
|
post_ready_ext++;
|
|
}
|
|
queue_for_each_entry(p, ptmp, QUEUE_DISPLAY, list) {
|
|
display++;
|
|
if (p->di_buf[0])
|
|
display_ext++;
|
|
|
|
if (p->di_buf[1])
|
|
display_ext++;
|
|
}
|
|
recycle = list_count(QUEUE_RECYCLE);
|
|
|
|
if (di_pre_stru.di_inp_buf)
|
|
di_inp++;
|
|
if (di_pre_stru.di_wr_buf)
|
|
di_wr++;
|
|
|
|
if (buf_state_log_threshold == 0)
|
|
buf_state_log_start = 0;
|
|
else if (post_ready < buf_state_log_threshold)
|
|
buf_state_log_start = 1;
|
|
|
|
if (buf_state_log_start) {
|
|
di_print(
|
|
"[%s]i i_f %d/%d, l_f %d/%d, pre_r %d, post_f %d/%d,",
|
|
tag,
|
|
in_free, MAX_IN_BUF_NUM,
|
|
local_free, de_devp->buf_num_avail,
|
|
pre_ready,
|
|
post_free, MAX_POST_BUF_NUM);
|
|
di_print(
|
|
"post_r (%d:%d), disp (%d:%d),rec %d, di_i %d, di_w %d\n",
|
|
post_ready, post_ready_ext,
|
|
display, display_ext,
|
|
recycle,
|
|
di_inp, di_wr
|
|
);
|
|
}
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
}
|
|
}
|
|
|
|
static void dump_state(void)
|
|
{
|
|
struct di_buf_s *p = NULL, *keep_buf;
|
|
int itmp, i;
|
|
|
|
dump_state_flag = 1;
|
|
pr_info("version %s, init_flag %d, is_bypass %d\n",
|
|
version_s, init_flag, is_bypass(NULL));
|
|
pr_info("isbypass_flag %d, needbypass_flag %d\n",
|
|
isbypass_flag, needbypass_flag);
|
|
pr_info("di_pre_stru.bypass_flag=%d\n",
|
|
di_pre_stru.bypass_flag);
|
|
pr_info("afbcd support %d\n", afbc_is_supported());
|
|
pr_info("recovery_flag = %d, recovery_log_reason=%d, di_blocking=%d",
|
|
recovery_flag, recovery_log_reason, di_blocking);
|
|
pr_info("recovery_log_queue_idx=%d, recovery_log_di_buf=0x%p\n",
|
|
recovery_log_queue_idx, recovery_log_di_buf);
|
|
pr_info("buffer_size=%d, mem_flag=%d, cma_flag=%d\n",
|
|
de_devp->buffer_size, atomic_read(&de_devp->mem_flag),
|
|
de_devp->flag_cma);
|
|
keep_buf = di_post_stru.keep_buf;
|
|
pr_info("used_post_buf_index %d(0x%p),",
|
|
IS_ERR_OR_NULL(keep_buf) ?
|
|
-1 : keep_buf->index, keep_buf);
|
|
if (!IS_ERR_OR_NULL(keep_buf)) {
|
|
pr_info("used_local_buf_index:\n");
|
|
for (i = 0; i < USED_LOCAL_BUF_MAX; i++) {
|
|
p = keep_buf->di_buf_dup_p[i];
|
|
pr_info("%d(0x%p) ",
|
|
IS_ERR_OR_NULL(p) ? -1 : p->index, p);
|
|
}
|
|
}
|
|
pr_info("\nin_free_list (max %d):\n", MAX_IN_BUF_NUM);
|
|
queue_for_each_entry(p, ptmp, QUEUE_IN_FREE, list) {
|
|
pr_info("index %2d, 0x%p, type %d\n",
|
|
p->index, p, p->type);
|
|
}
|
|
pr_info("local_free_list (max %d):\n", de_devp->buf_num_avail);
|
|
queue_for_each_entry(p, ptmp, QUEUE_LOCAL_FREE, list) {
|
|
pr_info("index %2d, 0x%p, type %d\n", p->index, p, p->type);
|
|
}
|
|
|
|
pr_info("post_doing_list:\n");
|
|
queue_for_each_entry(p, ptmp, QUEUE_POST_DOING, list) {
|
|
print_di_buf(p, 2);
|
|
}
|
|
pr_info("pre_ready_list:\n");
|
|
queue_for_each_entry(p, ptmp, QUEUE_PRE_READY, list) {
|
|
print_di_buf(p, 2);
|
|
}
|
|
pr_info("post_free_list (max %d):\n", di_post_stru.di_post_num);
|
|
queue_for_each_entry(p, ptmp, QUEUE_POST_FREE, list) {
|
|
pr_info("index %2d, 0x%p, type %d, vframetype 0x%x\n",
|
|
p->index, p, p->type, p->vframe->type);
|
|
}
|
|
pr_info("post_ready_list:\n");
|
|
queue_for_each_entry(p, ptmp, QUEUE_POST_READY, list) {
|
|
print_di_buf(p, 2);
|
|
print_di_buf(p->di_buf[0], 1);
|
|
print_di_buf(p->di_buf[1], 1);
|
|
}
|
|
pr_info("display_list:\n");
|
|
queue_for_each_entry(p, ptmp, QUEUE_DISPLAY, list) {
|
|
print_di_buf(p, 2);
|
|
print_di_buf(p->di_buf[0], 1);
|
|
print_di_buf(p->di_buf[1], 1);
|
|
}
|
|
pr_info("recycle_list:\n");
|
|
queue_for_each_entry(p, ptmp, QUEUE_RECYCLE, list) {
|
|
pr_info(
|
|
"index %d, 0x%p, type %d, vframetype 0x%x pre_ref_count %d post_ref_count %d\n",
|
|
p->index, p, p->type,
|
|
p->vframe->type,
|
|
p->pre_ref_count,
|
|
p->post_ref_count);
|
|
if (p->di_wr_linked_buf) {
|
|
pr_info(
|
|
"linked index %2d, 0x%p, type %d pre_ref_count %d post_ref_count %d\n",
|
|
p->di_wr_linked_buf->index,
|
|
p->di_wr_linked_buf,
|
|
p->di_wr_linked_buf->type,
|
|
p->di_wr_linked_buf->pre_ref_count,
|
|
p->di_wr_linked_buf->post_ref_count);
|
|
}
|
|
}
|
|
if (di_pre_stru.di_inp_buf) {
|
|
pr_info("di_inp_buf:index %d, 0x%p, type %d\n",
|
|
di_pre_stru.di_inp_buf->index,
|
|
di_pre_stru.di_inp_buf,
|
|
di_pre_stru.di_inp_buf->type);
|
|
} else {
|
|
pr_info("di_inp_buf: NULL\n");
|
|
}
|
|
if (di_pre_stru.di_wr_buf) {
|
|
pr_info("di_wr_buf:index %d, 0x%p, type %d\n",
|
|
di_pre_stru.di_wr_buf->index,
|
|
di_pre_stru.di_wr_buf,
|
|
di_pre_stru.di_wr_buf->type);
|
|
} else {
|
|
pr_info("di_wr_buf: NULL\n");
|
|
}
|
|
dump_di_pre_stru(&di_pre_stru);
|
|
dump_di_post_stru(&di_post_stru);
|
|
pr_info("vframe_in[]:");
|
|
|
|
for (i = 0; i < MAX_IN_BUF_NUM; i++)
|
|
pr_info("0x%p ", vframe_in[i]);
|
|
|
|
pr_info("\n");
|
|
pr_info("vf_peek()=>0x%p, video_peek_cnt = %d\n",
|
|
vf_peek(VFM_NAME), video_peek_cnt);
|
|
pr_info("reg_unreg_timerout = %lu\n", reg_unreg_timeout_cnt);
|
|
dump_state_flag = 0;
|
|
}
|
|
|
|
static unsigned char check_di_buf(struct di_buf_s *di_buf, int reason)
|
|
{
|
|
int error = 0;
|
|
|
|
if (di_buf == NULL) {
|
|
pr_dbg("%s: Error %d, di_buf is NULL\n", __func__, reason);
|
|
return 1;
|
|
}
|
|
|
|
if (di_buf->type == VFRAME_TYPE_IN) {
|
|
if (di_buf->vframe != &vframe_in_dup[di_buf->index])
|
|
error = 1;
|
|
} else if (di_buf->type == VFRAME_TYPE_LOCAL) {
|
|
if (di_buf->vframe !=
|
|
&vframe_local[di_buf->index])
|
|
error = 1;
|
|
} else if (di_buf->type == VFRAME_TYPE_POST) {
|
|
if (di_buf->vframe != &vframe_post[di_buf->index])
|
|
error = 1;
|
|
} else {
|
|
error = 1;
|
|
}
|
|
|
|
if (error) {
|
|
pr_dbg(
|
|
"%s: Error %d, di_buf wrong\n", __func__,
|
|
reason);
|
|
if (recovery_flag == 0)
|
|
recovery_log_reason = reason;
|
|
recovery_flag++;
|
|
dump_di_buf(di_buf);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
/*
|
|
* di pre process
|
|
*/
|
|
static void
|
|
config_di_mcinford_mif(struct DI_MC_MIF_s *di_mcinford_mif,
|
|
struct di_buf_s *di_buf)
|
|
{
|
|
if (di_buf) {
|
|
di_mcinford_mif->size_x = (di_buf->vframe->height + 2) / 4 - 1;
|
|
di_mcinford_mif->size_y = 1;
|
|
di_mcinford_mif->canvas_num = di_buf->mcinfo_canvas_idx;
|
|
}
|
|
}
|
|
static void
|
|
config_di_pre_mc_mif(struct DI_MC_MIF_s *di_mcinfo_mif,
|
|
struct DI_MC_MIF_s *di_mcvec_mif,
|
|
struct di_buf_s *di_buf)
|
|
{
|
|
unsigned int pre_size_w = 0, pre_size_h = 0;
|
|
|
|
if (di_buf) {
|
|
pre_size_w = di_buf->vframe->width;
|
|
pre_size_h = (di_buf->vframe->height + 1) / 2;
|
|
di_mcinfo_mif->size_x = (pre_size_h + 1) / 2 - 1;
|
|
di_mcinfo_mif->size_y = 1;
|
|
di_mcinfo_mif->canvas_num = di_buf->mcinfo_canvas_idx;
|
|
|
|
di_mcvec_mif->size_x = (pre_size_w + 4) / 5 - 1;
|
|
di_mcvec_mif->size_y = pre_size_h - 1;
|
|
di_mcvec_mif->canvas_num = di_buf->mcvec_canvas_idx;
|
|
}
|
|
}
|
|
|
|
static void config_di_cnt_mif(struct DI_SIM_MIF_s *di_cnt_mif,
|
|
struct di_buf_s *di_buf)
|
|
{
|
|
if (di_buf) {
|
|
di_cnt_mif->start_x = 0;
|
|
di_cnt_mif->end_x = di_buf->vframe->width - 1;
|
|
di_cnt_mif->start_y = 0;
|
|
di_cnt_mif->end_y = di_buf->vframe->height / 2 - 1;
|
|
di_cnt_mif->canvas_num = di_buf->cnt_canvas_idx;
|
|
}
|
|
}
|
|
|
|
static void
|
|
config_di_wr_mif(struct DI_SIM_MIF_s *di_nrwr_mif,
|
|
struct DI_SIM_MIF_s *di_mtnwr_mif,
|
|
struct di_buf_s *di_buf)
|
|
{
|
|
vframe_t *vf = di_buf->vframe;
|
|
di_nrwr_mif->canvas_num = di_buf->nr_canvas_idx;
|
|
di_nrwr_mif->start_x = 0;
|
|
di_nrwr_mif->end_x = vf->width - 1;
|
|
di_nrwr_mif->start_y = 0;
|
|
if (di_buf->vframe->bitdepth & BITDEPTH_Y10)
|
|
di_nrwr_mif->bit_mode =
|
|
(di_buf->vframe->bitdepth & FULL_PACK_422_MODE)?3:1;
|
|
else
|
|
di_nrwr_mif->bit_mode = 0;
|
|
if (di_pre_stru.prog_proc_type == 0)
|
|
di_nrwr_mif->end_y = vf->height / 2 - 1;
|
|
else
|
|
di_nrwr_mif->end_y = vf->height - 1;
|
|
if (di_pre_stru.prog_proc_type == 0) {
|
|
di_mtnwr_mif->start_x = 0;
|
|
di_mtnwr_mif->end_x = vf->width - 1;
|
|
di_mtnwr_mif->start_y = 0;
|
|
di_mtnwr_mif->end_y = vf->height / 2 - 1;
|
|
di_mtnwr_mif->canvas_num = di_buf->mtn_canvas_idx;
|
|
}
|
|
}
|
|
|
|
static void config_di_mif(struct DI_MIF_s *di_mif, struct di_buf_s *di_buf)
|
|
{
|
|
if (di_buf == NULL)
|
|
return;
|
|
di_mif->canvas0_addr0 =
|
|
di_buf->vframe->canvas0Addr & 0xff;
|
|
di_mif->canvas0_addr1 =
|
|
(di_buf->vframe->canvas0Addr >> 8) & 0xff;
|
|
di_mif->canvas0_addr2 =
|
|
(di_buf->vframe->canvas0Addr >> 16) & 0xff;
|
|
|
|
di_mif->nocompress = (di_buf->vframe->type & VIDTYPE_COMPRESS)?0:1;
|
|
|
|
if (di_buf->vframe->bitdepth & BITDEPTH_Y10) {
|
|
if (di_buf->vframe->type & VIDTYPE_VIU_444)
|
|
di_mif->bit_mode =
|
|
(di_buf->vframe->bitdepth & FULL_PACK_422_MODE)?3:2;
|
|
else if (di_buf->vframe->type & VIDTYPE_VIU_422)
|
|
di_mif->bit_mode =
|
|
(di_buf->vframe->bitdepth & FULL_PACK_422_MODE)?3:1;
|
|
} else {
|
|
di_mif->bit_mode = 0;
|
|
}
|
|
if (di_buf->vframe->type & VIDTYPE_VIU_422) {
|
|
/* from vdin or local vframe */
|
|
if ((!is_progressive(di_buf->vframe))
|
|
|| (di_pre_stru.prog_proc_type)
|
|
) {
|
|
di_mif->video_mode = 0;
|
|
di_mif->set_separate_en = 0;
|
|
di_mif->src_field_mode = 0;
|
|
di_mif->output_field_num = 0;
|
|
di_mif->luma_x_start0 = 0;
|
|
di_mif->luma_x_end0 =
|
|
di_buf->vframe->width - 1;
|
|
di_mif->luma_y_start0 = 0;
|
|
if (di_pre_stru.prog_proc_type)
|
|
di_mif->luma_y_end0 =
|
|
di_buf->vframe->height - 1;
|
|
else
|
|
di_mif->luma_y_end0 =
|
|
di_buf->vframe->height / 2 - 1;
|
|
di_mif->chroma_x_start0 = 0;
|
|
di_mif->chroma_x_end0 = 0;
|
|
di_mif->chroma_y_start0 = 0;
|
|
di_mif->chroma_y_end0 = 0;
|
|
di_mif->canvas0_addr0 =
|
|
di_buf->vframe->canvas0Addr & 0xff;
|
|
di_mif->canvas0_addr1 =
|
|
(di_buf->vframe->canvas0Addr >> 8) & 0xff;
|
|
di_mif->canvas0_addr2 =
|
|
(di_buf->vframe->canvas0Addr >> 16) & 0xff;
|
|
}
|
|
} else {
|
|
if (di_buf->vframe->type & VIDTYPE_VIU_444)
|
|
di_mif->video_mode = 1;
|
|
else
|
|
di_mif->video_mode = 0;
|
|
if (di_buf->vframe->type & VIDTYPE_VIU_NV21)
|
|
di_mif->set_separate_en = 2;
|
|
else
|
|
di_mif->set_separate_en = 1;
|
|
|
|
if (is_progressive(di_buf->vframe) &&
|
|
(di_pre_stru.prog_proc_type)) {
|
|
di_mif->src_field_mode = 0;
|
|
di_mif->output_field_num = 0; /* top */
|
|
di_mif->luma_x_start0 = 0;
|
|
di_mif->luma_x_end0 =
|
|
di_buf->vframe->width - 1;
|
|
di_mif->luma_y_start0 = 0;
|
|
di_mif->luma_y_end0 =
|
|
di_buf->vframe->height - 1;
|
|
di_mif->chroma_x_start0 = 0;
|
|
di_mif->chroma_x_end0 =
|
|
di_buf->vframe->width / 2 - 1;
|
|
di_mif->chroma_y_start0 = 0;
|
|
di_mif->chroma_y_end0 =
|
|
di_buf->vframe->height / 2 - 1;
|
|
} else {
|
|
if (di_pre_stru.cur_inp_type & VIDTYPE_INTERLACE)
|
|
di_mif->src_prog = 0;
|
|
else
|
|
di_mif->src_prog = force_prog?1:0;
|
|
di_mif->src_field_mode = 1;
|
|
if (
|
|
(di_buf->vframe->type & VIDTYPE_TYPEMASK) ==
|
|
VIDTYPE_INTERLACE_TOP) {
|
|
di_mif->output_field_num = 0; /* top */
|
|
di_mif->luma_x_start0 = 0;
|
|
di_mif->luma_x_end0 =
|
|
di_buf->vframe->width - 1;
|
|
di_mif->luma_y_start0 = 0;
|
|
di_mif->luma_y_end0 =
|
|
di_buf->vframe->height - 2;
|
|
di_mif->chroma_x_start0 = 0;
|
|
di_mif->chroma_x_end0 =
|
|
di_buf->vframe->width / 2 - 1;
|
|
di_mif->chroma_y_start0 = 0;
|
|
di_mif->chroma_y_end0 =
|
|
di_buf->vframe->height / 2
|
|
- (di_mif->src_prog?1:2);
|
|
} else {
|
|
di_mif->output_field_num = 1;
|
|
/* bottom */
|
|
di_mif->luma_x_start0 = 0;
|
|
di_mif->luma_x_end0 =
|
|
di_buf->vframe->width - 1;
|
|
di_mif->luma_y_start0 = 1;
|
|
di_mif->luma_y_end0 =
|
|
di_buf->vframe->height - 1;
|
|
di_mif->chroma_x_start0 = 0;
|
|
di_mif->chroma_x_end0 =
|
|
di_buf->vframe->width / 2 - 1;
|
|
di_mif->chroma_y_start0 =
|
|
(di_mif->src_prog?0:1);
|
|
di_mif->chroma_y_end0 =
|
|
di_buf->vframe->height / 2 - 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void di_pre_size_change(unsigned short width,
|
|
unsigned short height, unsigned short vf_type);
|
|
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
|
|
static void pre_inp_canvas_config(struct vframe_s *vf);
|
|
#endif
|
|
|
|
static void pre_de_process(void)
|
|
{
|
|
ulong irq_flag2 = 0;
|
|
unsigned short pre_width = 0, pre_height = 0;
|
|
unsigned char chan2_field_num = 1;
|
|
int canvases_idex = di_pre_stru.field_count_for_cont % 2;
|
|
unsigned short cur_inp_field_type = VIDTYPE_TYPEMASK;
|
|
unsigned short int_mask = 0x7f;
|
|
|
|
di_pre_stru.pre_de_process_flag = 1;
|
|
di_pre_stru.pre_de_busy_timer_count = 0;
|
|
ddbg_mod_save(eDI_DBG_MOD_PRE_SETB, 0, di_pre_stru.in_seq);/*dbg*/
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
|
|
pre_inp_canvas_config(di_pre_stru.di_inp_buf->vframe);
|
|
#endif
|
|
|
|
config_di_mif(&di_pre_stru.di_inp_mif, di_pre_stru.di_inp_buf);
|
|
/* pr_dbg("set_separate_en=%d vframe->type %d\n",
|
|
* di_pre_stru.di_inp_mif.set_separate_en,
|
|
* di_pre_stru.di_inp_buf->vframe->type);
|
|
*/
|
|
#ifdef DI_USE_FIXED_CANVAS_IDX
|
|
if (di_pre_stru.di_mem_buf_dup_p != NULL &&
|
|
di_pre_stru.di_mem_buf_dup_p != di_pre_stru.di_inp_buf) {
|
|
config_canvas_idx(di_pre_stru.di_mem_buf_dup_p,
|
|
di_pre_idx[canvases_idex][0], -1);
|
|
config_cnt_canvas_idx(di_pre_stru.di_mem_buf_dup_p,
|
|
di_pre_idx[canvases_idex][1]);
|
|
} else {
|
|
config_cnt_canvas_idx(di_pre_stru.di_wr_buf,
|
|
di_pre_idx[canvases_idex][1]);
|
|
config_di_cnt_mif(&di_pre_stru.di_contp2rd_mif,
|
|
di_pre_stru.di_wr_buf);
|
|
|
|
}
|
|
if (di_pre_stru.di_chan2_buf_dup_p != NULL) {
|
|
config_canvas_idx(di_pre_stru.di_chan2_buf_dup_p,
|
|
di_pre_idx[canvases_idex][2], -1);
|
|
config_cnt_canvas_idx(di_pre_stru.di_chan2_buf_dup_p,
|
|
di_pre_idx[canvases_idex][3]);
|
|
} else {
|
|
config_cnt_canvas_idx(di_pre_stru.di_wr_buf,
|
|
di_pre_idx[canvases_idex][3]);
|
|
}
|
|
config_canvas_idx(di_pre_stru.di_wr_buf,
|
|
di_pre_idx[canvases_idex][4], di_pre_idx[canvases_idex][5]);
|
|
config_cnt_canvas_idx(di_pre_stru.di_wr_buf,
|
|
di_pre_idx[canvases_idex][6]);
|
|
if (mcpre_en) {
|
|
if (di_pre_stru.di_chan2_buf_dup_p != NULL)
|
|
config_mcinfo_canvas_idx(di_pre_stru.di_chan2_buf_dup_p,
|
|
di_pre_idx[canvases_idex][7]);
|
|
else
|
|
config_mcinfo_canvas_idx(di_pre_stru.di_wr_buf,
|
|
di_pre_idx[canvases_idex][7]);
|
|
|
|
config_mcinfo_canvas_idx(di_pre_stru.di_wr_buf,
|
|
di_pre_idx[canvases_idex][8]);
|
|
config_mcvec_canvas_idx(di_pre_stru.di_wr_buf,
|
|
di_pre_idx[canvases_idex][9]);
|
|
}
|
|
#endif
|
|
config_di_mif(&di_pre_stru.di_mem_mif, di_pre_stru.di_mem_buf_dup_p);
|
|
if (di_pre_stru.di_chan2_buf_dup_p == NULL) {
|
|
config_di_mif(&di_pre_stru.di_chan2_mif,
|
|
di_pre_stru.di_inp_buf);
|
|
} else
|
|
config_di_mif(&di_pre_stru.di_chan2_mif,
|
|
di_pre_stru.di_chan2_buf_dup_p);
|
|
|
|
config_di_wr_mif(&di_pre_stru.di_nrwr_mif, &di_pre_stru.di_mtnwr_mif,
|
|
di_pre_stru.di_wr_buf);
|
|
|
|
if (di_pre_stru.di_chan2_buf_dup_p)
|
|
config_di_cnt_mif(&di_pre_stru.di_contprd_mif,
|
|
di_pre_stru.di_chan2_buf_dup_p);
|
|
else
|
|
config_di_cnt_mif(&di_pre_stru.di_contprd_mif,
|
|
di_pre_stru.di_wr_buf);
|
|
|
|
config_di_cnt_mif(&di_pre_stru.di_contwr_mif, di_pre_stru.di_wr_buf);
|
|
if (mcpre_en) {
|
|
if (di_pre_stru.di_chan2_buf_dup_p)
|
|
config_di_mcinford_mif(&di_pre_stru.di_mcinford_mif,
|
|
di_pre_stru.di_chan2_buf_dup_p);
|
|
else
|
|
config_di_mcinford_mif(&di_pre_stru.di_mcinford_mif,
|
|
di_pre_stru.di_wr_buf);
|
|
|
|
config_di_pre_mc_mif(&di_pre_stru.di_mcinfowr_mif,
|
|
&di_pre_stru.di_mcvecwr_mif, di_pre_stru.di_wr_buf);
|
|
}
|
|
|
|
if ((di_pre_stru.di_chan2_buf_dup_p) &&
|
|
((di_pre_stru.di_chan2_buf_dup_p->vframe->type & VIDTYPE_TYPEMASK)
|
|
== VIDTYPE_INTERLACE_TOP))
|
|
chan2_field_num = 0;
|
|
pre_width = di_pre_stru.di_nrwr_mif.end_x + 1;
|
|
pre_height = di_pre_stru.di_nrwr_mif.end_y + 1;
|
|
if (di_pre_stru.input_size_change_flag) {
|
|
cur_inp_field_type =
|
|
(di_pre_stru.di_inp_buf->vframe->type & VIDTYPE_TYPEMASK);
|
|
cur_inp_field_type =
|
|
di_pre_stru.cur_prog_flag ? VIDTYPE_PROGRESSIVE : cur_inp_field_type;
|
|
di_pre_size_change(pre_width, pre_height,
|
|
cur_inp_field_type);
|
|
di_pre_stru.input_size_change_flag = false;
|
|
}
|
|
|
|
di_patch_mov_setting();
|
|
if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A)) {
|
|
if (de_devp->nrds_enable) {
|
|
nr_ds_mif_config();
|
|
nr_ds_hw_ctrl(true);
|
|
int_mask = 0x3f;
|
|
} else {
|
|
nr_ds_hw_ctrl(false);
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_TVIN
|
|
/*patch for SECAM signal format from vlsi-feijun for all IC*/
|
|
di_nr_opl()->secam_cfr_adjust(di_pre_stru.di_inp_buf->vframe->sig_fmt,
|
|
di_pre_stru.di_inp_buf->vframe->type);
|
|
#endif
|
|
|
|
/* set interrupt mask for pre module.
|
|
* we need to only leave one mask open
|
|
* to prevent multiple entry for de_irq
|
|
*/
|
|
enable_di_pre_aml(&di_pre_stru.di_inp_mif,
|
|
&di_pre_stru.di_mem_mif,
|
|
&di_pre_stru.di_chan2_mif,
|
|
&di_pre_stru.di_nrwr_mif,
|
|
&di_pre_stru.di_mtnwr_mif,
|
|
&di_pre_stru.di_contp2rd_mif,
|
|
&di_pre_stru.di_contprd_mif,
|
|
&di_pre_stru.di_contwr_mif,
|
|
di_pre_stru.madi_enable,
|
|
chan2_field_num,
|
|
di_pre_stru.vdin2nr);
|
|
|
|
enable_afbc_input(di_pre_stru.di_inp_buf->vframe);
|
|
|
|
if (mcpre_en) {
|
|
if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A))
|
|
enable_mc_di_pre_g12(
|
|
&di_pre_stru.di_mcinford_mif,
|
|
&di_pre_stru.di_mcinfowr_mif,
|
|
&di_pre_stru.di_mcvecwr_mif,
|
|
di_pre_stru.mcdi_enable);
|
|
else
|
|
enable_mc_di_pre(
|
|
&di_pre_stru.di_mcinford_mif,
|
|
&di_pre_stru.di_mcinfowr_mif,
|
|
&di_pre_stru.di_mcvecwr_mif,
|
|
di_pre_stru.mcdi_enable);
|
|
}
|
|
|
|
di_pre_stru.field_count_for_cont++;
|
|
if (di_pre_stru.field_count_for_cont >= 5)
|
|
DI_Wr_reg_bits(DI_MTN_CTRL, 0, 30, 1);
|
|
|
|
di_txl_patch_prog(di_pre_stru.cur_prog_flag,
|
|
di_pre_stru.field_count_for_cont, mcpre_en);
|
|
|
|
#ifdef SUPPORT_MPEG_TO_VDIN
|
|
if (mpeg2vdin_flag) {
|
|
struct vdin_arg_s vdin_arg;
|
|
struct vdin_v4l2_ops_s *vdin_ops = get_vdin_v4l2_ops();
|
|
|
|
vdin_arg.cmd = VDIN_CMD_FORCE_GO_FIELD;
|
|
if (vdin_ops->tvin_vdin_func)
|
|
vdin_ops->tvin_vdin_func(0, &vdin_arg);
|
|
}
|
|
#endif
|
|
/* must make sure follow part issue without interrupts,
|
|
* otherwise may cause watch dog reboot
|
|
*/
|
|
di_lock_irqfiq_save(irq_flag2);
|
|
if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A))
|
|
pre_frame_reset_g12(di_pre_stru.madi_enable,
|
|
di_pre_stru.mcdi_enable);
|
|
else
|
|
pre_frame_reset();
|
|
|
|
/* enable mc pre mif*/
|
|
enable_di_pre_mif(true, mcpre_en);
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
/*reinit pre busy flag*/
|
|
di_pre_stru.pre_de_busy_timer_count = 0;
|
|
di_pre_stru.pre_de_busy = 1;
|
|
#ifdef SUPPORT_MPEG_TO_VDIN
|
|
if (mpeg2vdin_flag)
|
|
RDMA_WR_BITS(DI_PRE_CTRL, 1, 13, 1);
|
|
#endif
|
|
di_pre_stru.irq_time[0] = cur_to_msecs();
|
|
di_pre_stru.irq_time[1] = cur_to_msecs();
|
|
ddbg_mod_save(eDI_DBG_MOD_PRE_SETE, 0, di_pre_stru.in_seq);/*dbg*/
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_RDMA
|
|
if (di_pre_rdma_enable & 0x2)
|
|
rdma_config(de_devp->rdma_handle, RDMA_TRIGGER_MANUAL);
|
|
else if (di_pre_rdma_enable & 1)
|
|
rdma_config(de_devp->rdma_handle, RDMA_DEINT_IRQ);
|
|
#endif
|
|
di_pre_stru.pre_de_process_flag = 0;
|
|
}
|
|
|
|
static void pre_de_done_buf_clear(void)
|
|
{
|
|
struct di_buf_s *wr_buf = NULL;
|
|
|
|
if (di_pre_stru.di_wr_buf) {
|
|
wr_buf = di_pre_stru.di_wr_buf;
|
|
if ((di_pre_stru.prog_proc_type == 2) &&
|
|
wr_buf->di_wr_linked_buf) {
|
|
wr_buf->di_wr_linked_buf->pre_ref_count = 0;
|
|
wr_buf->di_wr_linked_buf->post_ref_count = 0;
|
|
queue_in(wr_buf->di_wr_linked_buf, QUEUE_RECYCLE);
|
|
wr_buf->di_wr_linked_buf = NULL;
|
|
}
|
|
wr_buf->pre_ref_count = 0;
|
|
wr_buf->post_ref_count = 0;
|
|
queue_in(wr_buf, QUEUE_RECYCLE);
|
|
di_pre_stru.di_wr_buf = NULL;
|
|
}
|
|
if (di_pre_stru.di_inp_buf) {
|
|
if (di_pre_stru.di_mem_buf_dup_p == di_pre_stru.di_inp_buf)
|
|
di_pre_stru.di_mem_buf_dup_p = NULL;
|
|
|
|
queue_in(di_pre_stru.di_inp_buf, QUEUE_RECYCLE);
|
|
di_pre_stru.di_inp_buf = NULL;
|
|
}
|
|
}
|
|
|
|
static void top_bot_config(struct di_buf_s *di_buf)
|
|
{
|
|
vframe_t *vframe = di_buf->vframe;
|
|
|
|
if (((invert_top_bot & 0x1) != 0) && (!is_progressive(vframe))) {
|
|
if (di_buf->invert_top_bot_flag == 0) {
|
|
if (
|
|
(vframe->type & VIDTYPE_TYPEMASK) ==
|
|
VIDTYPE_INTERLACE_TOP) {
|
|
vframe->type &= (~VIDTYPE_TYPEMASK);
|
|
vframe->type |= VIDTYPE_INTERLACE_BOTTOM;
|
|
} else {
|
|
vframe->type &= (~VIDTYPE_TYPEMASK);
|
|
vframe->type |= VIDTYPE_INTERLACE_TOP;
|
|
}
|
|
di_buf->invert_top_bot_flag = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void pre_de_done_buf_config(void)
|
|
{
|
|
ulong irq_flag2 = 0;
|
|
struct di_buf_s *post_wr_buf = NULL;
|
|
unsigned int glb_frame_mot_num = 0;
|
|
unsigned int glb_field_mot_num = 0;
|
|
unsigned int pull_down_info = 0;
|
|
|
|
ddbg_mod_save(eDI_DBG_MOD_PRE_DONEB, 0, di_pre_stru.in_seq);/*dbg*/
|
|
if (di_pre_stru.di_wr_buf) {
|
|
if (di_pre_stru.pre_throw_flag > 0) {
|
|
di_pre_stru.di_wr_buf->throw_flag = 1;
|
|
di_pre_stru.pre_throw_flag--;
|
|
} else {
|
|
di_pre_stru.di_wr_buf->throw_flag = 0;
|
|
}
|
|
#ifdef DET3D
|
|
if (di_pre_stru.di_wr_buf->vframe->trans_fmt == 0 &&
|
|
di_pre_stru.det3d_trans_fmt != 0 && det3d_en) {
|
|
di_pre_stru.di_wr_buf->vframe->trans_fmt =
|
|
di_pre_stru.det3d_trans_fmt;
|
|
set3d_view(di_pre_stru.det3d_trans_fmt,
|
|
di_pre_stru.di_wr_buf->vframe);
|
|
}
|
|
#endif
|
|
if (!di_pre_rdma_enable)
|
|
di_pre_stru.di_post_wr_buf = di_pre_stru.di_wr_buf;
|
|
post_wr_buf = di_pre_stru.di_post_wr_buf;
|
|
|
|
if (post_wr_buf) {
|
|
post_wr_buf->vframe->di_pulldown = 0;
|
|
post_wr_buf->vframe->di_gmv = 0;
|
|
post_wr_buf->vframe->di_cm_cnt = 0;
|
|
}
|
|
if (IS_ERR_OR_NULL(post_wr_buf))
|
|
return;
|
|
if (post_wr_buf && !di_pre_stru.cur_prog_flag) {
|
|
read_pulldown_info(&glb_frame_mot_num,
|
|
&glb_field_mot_num);
|
|
if (pulldown_enable) {
|
|
pull_down_info = pulldown_detection(
|
|
&post_wr_buf->pd_config,
|
|
di_pre_stru.mtn_status, overturn,
|
|
di_pre_stru.di_inp_buf->vframe);
|
|
post_wr_buf->vframe->di_pulldown
|
|
= pull_down_info;
|
|
|
|
}
|
|
post_wr_buf->vframe->di_pulldown |= 0x08;
|
|
|
|
post_wr_buf->vframe->di_gmv = glb_frame_mot_num;
|
|
post_wr_buf->vframe->di_cm_cnt = di_rd_mcdi_fldcnt();
|
|
if (di_pre_stru.combing_fix_en)
|
|
cur_lev = adaptive_combing_fixing(
|
|
di_pre_stru.mtn_status,
|
|
glb_field_mot_num,
|
|
glb_frame_mot_num,
|
|
di_force_bit_mode);
|
|
if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXLX))
|
|
di_nr_opl()->adaptive_cue_adjust(glb_frame_mot_num,
|
|
glb_field_mot_num);
|
|
pulldown_info_clear_g12a();
|
|
}
|
|
|
|
if (di_pre_stru.cur_prog_flag) {
|
|
if (di_pre_stru.prog_proc_type == 0) {
|
|
/* di_mem_buf_dup->vfrme
|
|
* is either local vframe,
|
|
* or bot field of vframe from in_list
|
|
*/
|
|
di_pre_stru.di_mem_buf_dup_p->pre_ref_count = 0;
|
|
di_pre_stru.di_mem_buf_dup_p
|
|
= di_pre_stru.di_chan2_buf_dup_p;
|
|
di_pre_stru.di_chan2_buf_dup_p
|
|
= di_pre_stru.di_wr_buf;
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print("%s:set di_mem to di_chan2,",
|
|
__func__);
|
|
di_print("%s:set di_chan2 to di_wr_buf\n",
|
|
__func__);
|
|
#endif
|
|
} else {
|
|
di_pre_stru.di_mem_buf_dup_p->pre_ref_count = 0;
|
|
/*recycle the progress throw buffer*/
|
|
if (di_pre_stru.di_wr_buf->throw_flag) {
|
|
di_pre_stru.di_wr_buf->
|
|
pre_ref_count = 0;
|
|
di_pre_stru.di_mem_buf_dup_p = NULL;
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print(
|
|
"%s set throw %s[%d] pre_ref_count to 0.\n",
|
|
__func__,
|
|
vframe_type_name[di_pre_stru.di_wr_buf->type],
|
|
di_pre_stru.di_wr_buf->index);
|
|
#endif
|
|
} else {
|
|
di_pre_stru.di_mem_buf_dup_p
|
|
= di_pre_stru.di_wr_buf;
|
|
}
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print(
|
|
"%s: set di_mem_buf_dup_p to di_wr_buf\n",
|
|
__func__);
|
|
#endif
|
|
}
|
|
|
|
di_pre_stru.di_wr_buf->seq
|
|
= di_pre_stru.pre_ready_seq++;
|
|
di_pre_stru.di_wr_buf->post_ref_count = 0;
|
|
di_pre_stru.di_wr_buf->left_right
|
|
= di_pre_stru.left_right;
|
|
if (di_pre_stru.source_change_flag) {
|
|
di_pre_stru.di_wr_buf->new_format_flag = 1;
|
|
di_pre_stru.source_change_flag = 0;
|
|
} else {
|
|
di_pre_stru.di_wr_buf->new_format_flag = 0;
|
|
}
|
|
if (bypass_state == 1) {
|
|
di_pre_stru.di_wr_buf->new_format_flag = 1;
|
|
bypass_state = 0;
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print(
|
|
"%s:bypass_state->0, is_bypass() %d\n",
|
|
__func__, is_bypass(NULL));
|
|
di_print(
|
|
"trick_mode %d bypass_all %d\n",
|
|
trick_mode, bypass_all);
|
|
#endif
|
|
}
|
|
if (di_pre_stru.di_post_wr_buf)
|
|
queue_in(di_pre_stru.di_post_wr_buf,
|
|
QUEUE_PRE_READY);
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print(
|
|
"%s: %s[%d] => pre_ready_list\n", __func__,
|
|
vframe_type_name[di_pre_stru.di_wr_buf->type],
|
|
di_pre_stru.di_wr_buf->index);
|
|
#endif
|
|
if (di_pre_stru.di_wr_buf) {
|
|
if (di_pre_rdma_enable)
|
|
di_pre_stru.di_post_wr_buf =
|
|
di_pre_stru.di_wr_buf;
|
|
else
|
|
di_pre_stru.di_post_wr_buf = NULL;
|
|
di_pre_stru.di_wr_buf = NULL;
|
|
}
|
|
} else {
|
|
di_pre_stru.di_mem_buf_dup_p->pre_ref_count = 0;
|
|
di_pre_stru.di_mem_buf_dup_p = NULL;
|
|
if (di_pre_stru.di_chan2_buf_dup_p) {
|
|
di_pre_stru.di_mem_buf_dup_p =
|
|
di_pre_stru.di_chan2_buf_dup_p;
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print(
|
|
"%s: di_mem_buf_dup_p = di_chan2_buf_dup_p\n",
|
|
__func__);
|
|
#endif
|
|
}
|
|
di_pre_stru.di_chan2_buf_dup_p = di_pre_stru.di_wr_buf;
|
|
|
|
if (di_pre_stru.source_change_flag) {
|
|
/* add dummy buf, will not be displayed */
|
|
/*coverity[var_deref_model] post_wr_buf has been judged*/
|
|
add_dummy_vframe_type_pre(post_wr_buf);
|
|
}
|
|
di_pre_stru.di_wr_buf->seq =
|
|
di_pre_stru.pre_ready_seq++;
|
|
di_pre_stru.di_wr_buf->left_right =
|
|
di_pre_stru.left_right;
|
|
di_pre_stru.di_wr_buf->post_ref_count = 0;
|
|
if (di_pre_stru.source_change_flag) {
|
|
di_pre_stru.di_wr_buf->new_format_flag = 1;
|
|
di_pre_stru.source_change_flag = 0;
|
|
} else {
|
|
di_pre_stru.di_wr_buf->new_format_flag = 0;
|
|
}
|
|
if (bypass_state == 1) {
|
|
di_pre_stru.di_wr_buf->new_format_flag = 1;
|
|
bypass_state = 0;
|
|
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print(
|
|
"%s:bypass_state->0, is_bypass() %d\n",
|
|
__func__, is_bypass(NULL));
|
|
di_print(
|
|
"trick_mode %d bypass_all %d\n",
|
|
trick_mode, bypass_all);
|
|
#endif
|
|
}
|
|
|
|
if (di_pre_stru.di_post_wr_buf)
|
|
queue_in(di_pre_stru.di_post_wr_buf,
|
|
QUEUE_PRE_READY);
|
|
|
|
di_print("%s: %s[%d] => pre_ready_list\n", __func__,
|
|
vframe_type_name[di_pre_stru.di_wr_buf->type],
|
|
di_pre_stru.di_wr_buf->index);
|
|
|
|
if (di_pre_stru.di_wr_buf) {
|
|
if (di_pre_rdma_enable)
|
|
di_pre_stru.di_post_wr_buf =
|
|
di_pre_stru.di_wr_buf;
|
|
else
|
|
di_pre_stru.di_post_wr_buf = NULL;
|
|
di_pre_stru.di_wr_buf = NULL;
|
|
}
|
|
}
|
|
}
|
|
if (di_pre_stru.di_post_inp_buf && di_pre_rdma_enable) {
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print("%s: %s[%d] => recycle_list\n", __func__,
|
|
vframe_type_name[di_pre_stru.di_post_inp_buf->type],
|
|
di_pre_stru.di_post_inp_buf->index);
|
|
#endif
|
|
di_lock_irqfiq_save(irq_flag2);
|
|
queue_in(di_pre_stru.di_post_inp_buf, QUEUE_RECYCLE);
|
|
di_pre_stru.di_post_inp_buf = NULL;
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
}
|
|
if (di_pre_stru.di_inp_buf) {
|
|
if (!di_pre_rdma_enable) {
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print("%s: %s[%d] => recycle_list\n", __func__,
|
|
vframe_type_name[di_pre_stru.di_inp_buf->type],
|
|
di_pre_stru.di_inp_buf->index);
|
|
#endif
|
|
di_lock_irqfiq_save(irq_flag2);
|
|
queue_in(di_pre_stru.di_inp_buf, QUEUE_RECYCLE);
|
|
di_pre_stru.di_inp_buf = NULL;
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
} else {
|
|
di_pre_stru.di_post_inp_buf = di_pre_stru.di_inp_buf;
|
|
di_pre_stru.di_inp_buf = NULL;
|
|
}
|
|
}
|
|
ddbg_mod_save(eDI_DBG_MOD_PRE_DONEE, 0, di_pre_stru.in_seq);/*dbg*/
|
|
}
|
|
|
|
static void recycle_vframe_type_pre(struct di_buf_s *di_buf)
|
|
{
|
|
ulong irq_flag2 = 0;
|
|
|
|
di_lock_irqfiq_save(irq_flag2);
|
|
|
|
queue_in(di_buf, QUEUE_RECYCLE);
|
|
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
}
|
|
/*
|
|
* add dummy buffer to pre ready queue
|
|
*/
|
|
static void add_dummy_vframe_type_pre(struct di_buf_s *src_buf)
|
|
{
|
|
struct di_buf_s *di_buf_tmp = NULL;
|
|
|
|
if (!queue_empty(QUEUE_LOCAL_FREE)) {
|
|
di_buf_tmp = get_di_buf_head(QUEUE_LOCAL_FREE);
|
|
if (di_buf_tmp) {
|
|
queue_out(di_buf_tmp);
|
|
di_buf_tmp->pre_ref_count = 0;
|
|
di_buf_tmp->post_ref_count = 0;
|
|
di_buf_tmp->post_proc_flag = 3;
|
|
di_buf_tmp->new_format_flag = 0;
|
|
if (!IS_ERR_OR_NULL(src_buf))
|
|
memcpy(di_buf_tmp->vframe, src_buf->vframe,
|
|
sizeof(vframe_t));
|
|
queue_in(di_buf_tmp, QUEUE_PRE_READY);
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print("%s: dummy %s[%d] => pre_ready_list\n",
|
|
__func__,
|
|
vframe_type_name[di_buf_tmp->type],
|
|
di_buf_tmp->index);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* it depend on local buffer queue type is 2
|
|
*/
|
|
static int peek_free_linked_buf(void)
|
|
{
|
|
struct di_buf_s *p = NULL;
|
|
int itmp, p_index = -2;
|
|
|
|
if (list_count(QUEUE_LOCAL_FREE) < 2)
|
|
return -1;
|
|
|
|
queue_for_each_entry(p, ptmp, QUEUE_LOCAL_FREE, list) {
|
|
if (abs(p->index - p_index) == 1)
|
|
return min(p->index, p_index);
|
|
p_index = p->index;
|
|
}
|
|
return -1;
|
|
}
|
|
/*
|
|
* it depend on local buffer queue type is 2
|
|
*/
|
|
static struct di_buf_s *get_free_linked_buf(int idx)
|
|
{
|
|
struct di_buf_s *di_buf = NULL, *di_buf_linked = NULL;
|
|
int pool_idx = 0, di_buf_idx = 0;
|
|
|
|
queue_t *q = &(queue[QUEUE_LOCAL_FREE]);
|
|
|
|
if (list_count(QUEUE_LOCAL_FREE) < 2)
|
|
return NULL;
|
|
if (q->pool[idx] != 0 && q->pool[idx + 1] != 0) {
|
|
pool_idx = ((q->pool[idx] >> 8) & 0xff) - 1;
|
|
di_buf_idx = q->pool[idx] & 0xff;
|
|
if (pool_idx < VFRAME_TYPE_NUM) {
|
|
if (di_buf_idx < di_buf_pool[pool_idx].size) {
|
|
di_buf = &(di_buf_pool[pool_idx].
|
|
di_buf_ptr[di_buf_idx]);
|
|
queue_out(di_buf);
|
|
}
|
|
}
|
|
pool_idx = ((q->pool[idx + 1] >> 8) & 0xff) - 1;
|
|
di_buf_idx = q->pool[idx + 1] & 0xff;
|
|
if (pool_idx < VFRAME_TYPE_NUM) {
|
|
if (di_buf_idx < di_buf_pool[pool_idx].size) {
|
|
di_buf_linked = &(di_buf_pool[pool_idx].
|
|
di_buf_ptr[di_buf_idx]);
|
|
queue_out(di_buf_linked);
|
|
}
|
|
}
|
|
/*coverity[FORWARD_NULL] di_buf has been judged empty*/
|
|
if (IS_ERR_OR_NULL(di_buf))
|
|
return NULL;
|
|
di_buf->di_wr_linked_buf = di_buf_linked;
|
|
}
|
|
return di_buf;
|
|
}
|
|
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
|
|
static void pre_inp_canvas_config(struct vframe_s *vf)
|
|
{
|
|
if (vf->canvas0Addr == (u32)-1) {
|
|
canvas_config_config(di_inp_idx[0],
|
|
&vf->canvas0_config[0]);
|
|
canvas_config_config(di_inp_idx[1],
|
|
&vf->canvas0_config[1]);
|
|
vf->canvas0Addr = (di_inp_idx[1]<<8)|(di_inp_idx[0]);
|
|
if (vf->plane_num == 2) {
|
|
vf->canvas0Addr |= (di_inp_idx[1]<<16);
|
|
} else if (vf->plane_num == 3) {
|
|
canvas_config_config(di_inp_idx[2],
|
|
&vf->canvas0_config[2]);
|
|
vf->canvas0Addr |= (di_inp_idx[2]<<16);
|
|
}
|
|
vf->canvas1Addr = vf->canvas0Addr;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
u32 di_request_afbc(u32 onoff)
|
|
{
|
|
u32 afbc_busy;
|
|
|
|
if (onoff)
|
|
afbc_busy = di_request_afbc_hw(afbc_get_decnub(), true);
|
|
else
|
|
afbc_busy = di_request_afbc_hw(afbc_get_decnub(), false);
|
|
|
|
return afbc_busy;
|
|
}
|
|
|
|
static unsigned char pre_de_buf_config(void)
|
|
{
|
|
struct di_buf_s *di_buf = NULL;
|
|
vframe_t *vframe;
|
|
int i, di_linked_buf_idx = -1;
|
|
unsigned char change_type = 0;
|
|
bool bit10_pack_patch = false;
|
|
unsigned int width_roundup = 2;
|
|
u32 rls_timeout;
|
|
u32 afbc_busy;
|
|
u32 is_afbc_mode = 0;
|
|
bool flg_1080i = false;
|
|
bool flg_480i = false;
|
|
|
|
if (di_blocking || !atomic_read(&de_devp->mem_flag))
|
|
return 0;
|
|
if ((list_count(QUEUE_IN_FREE) < 2 && (!di_pre_stru.di_inp_buf_next)) ||
|
|
(queue_empty(QUEUE_LOCAL_FREE)))
|
|
return 0;
|
|
|
|
if (is_bypass(NULL)) {
|
|
/* some provider has problem if receiver
|
|
* get all buffers of provider
|
|
*/
|
|
int in_buf_num = 0;
|
|
cur_lev = 0;
|
|
for (i = 0; i < MAX_IN_BUF_NUM; i++)
|
|
if (vframe_in[i] != NULL)
|
|
in_buf_num++;
|
|
if (in_buf_num > BYPASS_GET_MAX_BUF_NUM
|
|
#ifdef DET3D
|
|
&& (di_pre_stru.vframe_interleave_flag == 0)
|
|
#endif
|
|
)
|
|
return 0;
|
|
|
|
di_patch_post_update_mc_sw(DI_MC_SW_OTHER, false);
|
|
} else if (di_pre_stru.prog_proc_type == 2) {
|
|
di_linked_buf_idx = peek_free_linked_buf();
|
|
if (di_linked_buf_idx == -1 &&
|
|
!IS_ERR_OR_NULL(di_post_stru.keep_buf)) {
|
|
recycle_keep_buffer();
|
|
pr_info("%s: recycle keep buffer for peek null linked buf\n",
|
|
__func__);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (di_pre_stru.di_inp_buf_next) {
|
|
di_pre_stru.di_inp_buf = di_pre_stru.di_inp_buf_next;
|
|
di_pre_stru.di_inp_buf_next = NULL;
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print("%s: di_inp_buf_next %s[%d] => di_inp_buf\n",
|
|
__func__,
|
|
vframe_type_name[di_pre_stru.di_inp_buf->type],
|
|
di_pre_stru.di_inp_buf->index);
|
|
#endif
|
|
if (di_pre_stru.di_mem_buf_dup_p == NULL) {/* use n */
|
|
di_pre_stru.di_mem_buf_dup_p = di_pre_stru.di_inp_buf;
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print(
|
|
"%s: set di_mem_buf_dup_p to be di_inp_buf\n",
|
|
__func__);
|
|
#endif
|
|
}
|
|
} else {
|
|
/* check if source change */
|
|
vframe = vf_peek(VFM_NAME);
|
|
|
|
if (vframe && is_from_vdin(vframe)) {
|
|
#ifdef RUN_DI_PROCESS_IN_IRQ
|
|
di_pre_stru.vdin2nr = is_input2pre();
|
|
#endif
|
|
}
|
|
|
|
vframe = vf_get(VFM_NAME);
|
|
|
|
if (vframe == NULL)
|
|
return 0;
|
|
|
|
/*for support compress from dec*/
|
|
if (IS_COMP_MODE(vframe->type) &&
|
|
!is_bypass(vframe)) {
|
|
is_afbc_mode = true;
|
|
if (IS_VDIN_SRC(vframe->source_type)
|
|
&& IS_I_SRC(vframe->type)) {
|
|
vframe->width = vframe->compWidth;
|
|
vframe->height = vframe->compHeight*2;
|
|
} else {
|
|
vframe->width = vframe->compWidth;
|
|
vframe->height = vframe->compHeight;
|
|
}
|
|
}
|
|
|
|
di_print("DI: get %dth vf[0x%p] from frontend %u ms.\n",
|
|
di_pre_stru.in_seq, vframe,
|
|
jiffies_to_msecs(jiffies_64 - vframe->ready_jiffies64));
|
|
vframe->prog_proc_config = (prog_proc_config&0x20) >> 5;
|
|
|
|
if (vframe->width > 10000 || vframe->height > 10000 ||
|
|
hold_video || di_pre_stru.bad_frame_throw_count > 0) {
|
|
if (vframe->width > 10000 || vframe->height > 10000)
|
|
di_pre_stru.bad_frame_throw_count = 10;
|
|
di_pre_stru.bad_frame_throw_count--;
|
|
|
|
vf_put(vframe, VFM_NAME);
|
|
vf_notify_provider(
|
|
VFM_NAME, VFRAME_EVENT_RECEIVER_PUT, NULL);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* for afbc used by vpp and di, when di use it,
|
|
* vpp need release afbc, waitting vpp release
|
|
*/
|
|
if (di_pre_stru.wait_afbc) {
|
|
/*check time out and afbc release status*/
|
|
rls_timeout =
|
|
jiffies_to_msecs(jiffies_64 -
|
|
di_pre_stru.afbc_rls_time);
|
|
afbc_busy = di_request_afbc(true);
|
|
if (afbc_busy && (rls_timeout < 80)) {
|
|
vf_put(vframe, VFM_NAME);
|
|
vf_notify_provider(
|
|
VFM_NAME, VFRAME_EVENT_RECEIVER_PUT, NULL);
|
|
pr_info("di: drop vframe (%d) t:%d\n",
|
|
afbc_busy, rls_timeout);
|
|
return 0;
|
|
} else if (!afbc_busy) {
|
|
/*afbc_busy = di_request_afbc(false);*/
|
|
di_pre_stru.wait_afbc = false;
|
|
pr_info("di: afbc hw free\n");
|
|
} else {
|
|
di_pre_stru.wait_afbc = false;
|
|
pr_info("di: afbc wait timeout\n");
|
|
}
|
|
}
|
|
|
|
bit10_pack_patch = (is_meson_gxtvbb_cpu() ||
|
|
is_meson_gxl_cpu() ||
|
|
is_meson_gxm_cpu());
|
|
width_roundup = bit10_pack_patch ? 16 : width_roundup;
|
|
if (di_force_bit_mode == 10)
|
|
force_width = roundup(vframe->width, width_roundup);
|
|
else
|
|
force_width = 0;
|
|
di_pre_stru.source_trans_fmt = vframe->trans_fmt;
|
|
di_pre_stru.left_right = di_pre_stru.left_right ? 0 : 1;
|
|
di_pre_stru.invert_flag =
|
|
(vframe->type & TB_DETECT_MASK) ? true : false;
|
|
vframe->type &= ~TB_DETECT_MASK;
|
|
|
|
if ((((invert_top_bot & 0x2) != 0) ||
|
|
di_pre_stru.invert_flag) &&
|
|
(!is_progressive(vframe))) {
|
|
if (
|
|
(vframe->type & VIDTYPE_TYPEMASK) ==
|
|
VIDTYPE_INTERLACE_TOP) {
|
|
vframe->type &= (~VIDTYPE_TYPEMASK);
|
|
vframe->type |= VIDTYPE_INTERLACE_BOTTOM;
|
|
} else {
|
|
vframe->type &= (~VIDTYPE_TYPEMASK);
|
|
vframe->type |= VIDTYPE_INTERLACE_TOP;
|
|
}
|
|
}
|
|
/*di_pre_stru.width_bk = vframe->width;*/
|
|
if (force_width)
|
|
vframe->width = force_width;
|
|
if (force_height)
|
|
vframe->height = force_height;
|
|
|
|
/* backup frame motion info */
|
|
vframe->combing_cur_lev = cur_lev;
|
|
|
|
di_print("%s: vf_get => 0x%p\n", __func__, vframe);
|
|
|
|
di_buf = get_di_buf_head(QUEUE_IN_FREE);
|
|
|
|
if (check_di_buf(di_buf, 10))
|
|
return 0;
|
|
|
|
if (di_log_flag & DI_LOG_VFRAME)
|
|
dump_vframe(vframe);
|
|
|
|
#ifdef SUPPORT_MPEG_TO_VDIN
|
|
if (
|
|
(!is_from_vdin(vframe)) &&
|
|
(vframe->sig_fmt == TVIN_SIG_FMT_NULL) &&
|
|
mpeg2vdin_flag) {
|
|
struct vdin_arg_s vdin_arg;
|
|
struct vdin_v4l2_ops_s *vdin_ops = get_vdin_v4l2_ops();
|
|
|
|
vdin_arg.cmd = VDIN_CMD_GET_HISTGRAM;
|
|
vdin_arg.private = (unsigned int)vframe;
|
|
if (vdin_ops->tvin_vdin_func)
|
|
vdin_ops->tvin_vdin_func(0, &vdin_arg);
|
|
}
|
|
#endif
|
|
memcpy(di_buf->vframe, vframe, sizeof(vframe_t));
|
|
di_buf->width_bk = vframe->width;
|
|
di_buf->vframe->private_data = di_buf;
|
|
vframe_in[di_buf->index] = vframe;
|
|
di_buf->seq = di_pre_stru.in_seq;
|
|
di_pre_stru.in_seq++;
|
|
queue_out(di_buf);
|
|
change_type = is_source_change(vframe);
|
|
/* source change, when i mix p,force p as i*/
|
|
if (change_type == 1 || (change_type == 2 &&
|
|
di_pre_stru.cur_prog_flag == 1)) {
|
|
|
|
di_pre_stru.field_count_for_cont = 0;
|
|
|
|
if (di_pre_stru.di_mem_buf_dup_p) {
|
|
/*avoid only 2 i field then p field*/
|
|
if (
|
|
(di_pre_stru.cur_prog_flag == 0) &&
|
|
use_2_interlace_buff)
|
|
di_pre_stru.di_mem_buf_dup_p->
|
|
post_proc_flag = -1;
|
|
di_pre_stru.di_mem_buf_dup_p->pre_ref_count = 0;
|
|
di_pre_stru.di_mem_buf_dup_p = NULL;
|
|
}
|
|
if (di_pre_stru.di_chan2_buf_dup_p) {
|
|
/*avoid only 1 i field then p field*/
|
|
if (
|
|
(di_pre_stru.cur_prog_flag == 0) &&
|
|
use_2_interlace_buff)
|
|
di_pre_stru.di_chan2_buf_dup_p->
|
|
post_proc_flag = -1;
|
|
di_pre_stru.di_chan2_buf_dup_p->pre_ref_count =
|
|
0;
|
|
di_pre_stru.di_chan2_buf_dup_p = NULL;
|
|
}
|
|
#if 0
|
|
/* channel change will occur between atv and dtv,
|
|
* that need mirror
|
|
*/
|
|
if (!IS_ERR_OR_NULL(di_post_stru.keep_buf)) {
|
|
if (di_post_stru.keep_buf->vframe
|
|
->source_type !=
|
|
di_buf->vframe->source_type) {
|
|
recycle_keep_buffer();
|
|
pr_info("%s: source type changed recycle buffer!!!\n",
|
|
__func__);
|
|
}
|
|
}
|
|
#endif
|
|
pr_info(
|
|
"%s:%ums %dth source change: 0x%x/%d/%d/%d=>0x%x/%d/%d/%d\n",
|
|
__func__,
|
|
jiffies_to_msecs(jiffies_64),
|
|
di_pre_stru.in_seq,
|
|
di_pre_stru.cur_inp_type,
|
|
di_pre_stru.cur_width,
|
|
di_pre_stru.cur_height,
|
|
di_pre_stru.cur_source_type,
|
|
di_buf->vframe->type,
|
|
di_buf->vframe->width,
|
|
di_buf->vframe->height,
|
|
di_buf->vframe->source_type);
|
|
|
|
if (IS_COMP_MODE(di_buf->vframe->type) &&
|
|
!is_bypass(vframe)) {
|
|
if (IS_VDIN_SRC(di_buf->vframe->source_type) &&
|
|
IS_I_SRC(di_buf->vframe->type)) {
|
|
di_pre_stru.cur_width =
|
|
di_buf->vframe->compWidth;
|
|
di_pre_stru.cur_height =
|
|
di_buf->vframe->compHeight*2;
|
|
} else {
|
|
di_pre_stru.cur_width =
|
|
di_buf->vframe->compWidth;
|
|
di_pre_stru.cur_height =
|
|
di_buf->vframe->compHeight;
|
|
}
|
|
} else {
|
|
di_pre_stru.cur_width = di_buf->vframe->width;
|
|
di_pre_stru.cur_height = di_buf->vframe->height;
|
|
}
|
|
|
|
di_pre_stru.cur_prog_flag =
|
|
is_progressive(di_buf->vframe);
|
|
if (di_pre_stru.cur_prog_flag) {
|
|
if ((use_2_interlace_buff) &&
|
|
!(prog_proc_config & 0x10))
|
|
di_pre_stru.prog_proc_type = 2;
|
|
else
|
|
di_pre_stru.prog_proc_type
|
|
= prog_proc_config & 0x10;
|
|
} else
|
|
di_pre_stru.prog_proc_type = 0;
|
|
di_pre_stru.cur_inp_type = di_buf->vframe->type;
|
|
di_pre_stru.cur_source_type =
|
|
di_buf->vframe->source_type;
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_TVIN
|
|
di_pre_stru.cur_sig_fmt = di_buf->vframe->sig_fmt;
|
|
#endif
|
|
di_pre_stru.orientation = di_buf->vframe->video_angle;
|
|
di_pre_stru.source_change_flag = 1;
|
|
di_pre_stru.input_size_change_flag = true;
|
|
#ifdef SUPPORT_MPEG_TO_VDIN
|
|
if ((!is_from_vdin(vframe)) &&
|
|
(vframe->sig_fmt == TVIN_SIG_FMT_NULL) &&
|
|
(mpeg2vdin_en)) {
|
|
struct vdin_arg_s vdin_arg;
|
|
struct vdin_v4l2_ops_s *vdin_ops =
|
|
get_vdin_v4l2_ops();
|
|
vdin_arg.cmd = VDIN_CMD_MPEGIN_START;
|
|
vdin_arg.h_active = di_pre_stru.cur_width;
|
|
vdin_arg.v_active = di_pre_stru.cur_height;
|
|
if (vdin_ops->tvin_vdin_func)
|
|
vdin_ops->tvin_vdin_func(0, &vdin_arg);
|
|
mpeg2vdin_flag = 1;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* for afbc used by vpp and di, when di use it,
|
|
* vpp need release afbc, waitting vpp release
|
|
*/
|
|
if (is_meson_tl1_cpu() || is_meson_sm1_cpu()) {
|
|
/*compress mode and format changed*/
|
|
if (!is_bypass(di_buf->vframe) &&
|
|
di_pre_stru.source_change_flag &&
|
|
IS_COMP_MODE(di_pre_stru.cur_inp_type)
|
|
&& !afbc_is_free()
|
|
&& !di_pre_stru.wait_afbc) {
|
|
afbc_busy = di_request_afbc(true);
|
|
vf_put(vframe, VFM_NAME);
|
|
vf_notify_provider(VFM_NAME,
|
|
VFRAME_EVENT_RECEIVER_PUT, NULL);
|
|
recycle_vframe_type_pre(di_buf);
|
|
di_pre_stru.afbc_rls_time = jiffies_64;
|
|
di_pre_stru.wait_afbc = true;
|
|
pr_info("di req afbc:%d\n", afbc_busy);
|
|
return 0;
|
|
}
|
|
}
|
|
/*di_pre_stru.field_count_for_cont = 0;*/
|
|
} else if (di_pre_stru.cur_prog_flag == 0) {
|
|
/* check if top/bot interleaved */
|
|
if (change_type == 2)
|
|
/* source is i interleaves p fields */
|
|
di_pre_stru.force_interlace = true;
|
|
if ((di_pre_stru.cur_inp_type &
|
|
VIDTYPE_TYPEMASK) == (di_buf->vframe->type &
|
|
VIDTYPE_TYPEMASK)) {
|
|
if ((di_buf->vframe->type &
|
|
VIDTYPE_TYPEMASK) ==
|
|
VIDTYPE_INTERLACE_TOP)
|
|
same_field_top_count++;
|
|
else
|
|
same_field_bot_count++;
|
|
}
|
|
di_pre_stru.cur_inp_type = di_buf->vframe->type;
|
|
} else {
|
|
di_pre_stru.cur_inp_type = di_buf->vframe->type;
|
|
}
|
|
|
|
if (is_bypass(di_buf->vframe)) {
|
|
/* bypass progressive */
|
|
di_buf->seq = di_pre_stru.pre_ready_seq++;
|
|
di_buf->post_ref_count = 0;
|
|
cur_lev = 0;
|
|
if (di_pre_stru.source_change_flag) {
|
|
di_buf->new_format_flag = 1;
|
|
di_pre_stru.source_change_flag = 0;
|
|
} else {
|
|
di_buf->new_format_flag = 0;
|
|
}
|
|
|
|
if (bypass_state == 0) {
|
|
if (di_pre_stru.di_mem_buf_dup_p) {
|
|
di_pre_stru.di_mem_buf_dup_p->
|
|
pre_ref_count = 0;
|
|
di_pre_stru.di_mem_buf_dup_p = NULL;
|
|
}
|
|
if (di_pre_stru.di_chan2_buf_dup_p) {
|
|
di_pre_stru.di_chan2_buf_dup_p->
|
|
pre_ref_count = 0;
|
|
di_pre_stru.di_chan2_buf_dup_p = NULL;
|
|
}
|
|
|
|
if (di_pre_stru.di_wr_buf) {
|
|
di_pre_stru.di_wr_buf->pre_ref_count =
|
|
0;
|
|
di_pre_stru.di_wr_buf->post_ref_count =
|
|
0;
|
|
recycle_vframe_type_pre(
|
|
di_pre_stru.di_wr_buf);
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print(
|
|
"%s: %s[%d] => recycle_list\n",
|
|
__func__,
|
|
vframe_type_name[di_pre_stru.
|
|
di_wr_buf->type],
|
|
di_pre_stru.di_wr_buf->index);
|
|
#endif
|
|
di_pre_stru.di_wr_buf = NULL;
|
|
}
|
|
|
|
di_buf->new_format_flag = 1;
|
|
bypass_state = 1;
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print(
|
|
"%s:bypass_state = 1, is_bypass() %d\n",
|
|
__func__, is_bypass(NULL));
|
|
di_print(
|
|
"trick_mode %d bypass_all %d\n",
|
|
trick_mode, bypass_all);
|
|
#endif
|
|
}
|
|
|
|
top_bot_config(di_buf);
|
|
queue_in(di_buf, QUEUE_PRE_READY);
|
|
/*if previous isn't bypass post_wr_buf not recycled */
|
|
if (di_pre_stru.di_post_wr_buf && di_pre_rdma_enable) {
|
|
queue_in(
|
|
di_pre_stru.di_post_inp_buf,
|
|
QUEUE_RECYCLE);
|
|
di_pre_stru.di_post_inp_buf = NULL;
|
|
}
|
|
|
|
if (
|
|
(by_pass_pre & 0x2) &&
|
|
!di_pre_stru.cur_prog_flag)
|
|
di_buf->post_proc_flag = -2;
|
|
else
|
|
di_buf->post_proc_flag = 0;
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print(
|
|
"%s: %s[%d] => pre_ready_list\n", __func__,
|
|
vframe_type_name[di_buf->type], di_buf->index);
|
|
#endif
|
|
return 0;
|
|
} else if (is_progressive(di_buf->vframe)) {
|
|
if (
|
|
is_handle_prog_frame_as_interlace(vframe) &&
|
|
(is_progressive(vframe))) {
|
|
struct di_buf_s *di_buf_tmp = NULL;
|
|
|
|
vframe_in[di_buf->index] = NULL;
|
|
di_buf->vframe->type &=
|
|
(~VIDTYPE_TYPEMASK);
|
|
di_buf->vframe->type |=
|
|
VIDTYPE_INTERLACE_TOP;
|
|
di_buf->post_proc_flag = 0;
|
|
|
|
di_buf_tmp =
|
|
get_di_buf_head(QUEUE_IN_FREE);
|
|
if (check_di_buf(di_buf_tmp, 10)) {
|
|
recycle_vframe_type_pre(di_buf);
|
|
pr_err("DI:no free in_buffer for progressive skip.\n");
|
|
return 0;
|
|
}
|
|
queue_out(di_buf_tmp);
|
|
di_buf_tmp->vframe->private_data
|
|
= di_buf_tmp;
|
|
di_buf_tmp->seq = di_pre_stru.in_seq;
|
|
di_pre_stru.in_seq++;
|
|
vframe_in[di_buf_tmp->index] = vframe;
|
|
memcpy(
|
|
di_buf_tmp->vframe, vframe,
|
|
sizeof(vframe_t));
|
|
di_pre_stru.di_inp_buf_next
|
|
= di_buf_tmp;
|
|
di_buf_tmp->vframe->type
|
|
&= (~VIDTYPE_TYPEMASK);
|
|
di_buf_tmp->vframe->type
|
|
|= VIDTYPE_INTERLACE_BOTTOM;
|
|
di_buf_tmp->post_proc_flag = 0;
|
|
|
|
di_pre_stru.di_inp_buf = di_buf;
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print(
|
|
"%s: %s[%d] => di_inp_buf; %s[%d] => di_inp_buf_next\n",
|
|
__func__,
|
|
vframe_type_name[di_buf->type],
|
|
di_buf->index,
|
|
vframe_type_name[di_buf_tmp->type],
|
|
di_buf_tmp->index);
|
|
#endif
|
|
if (di_pre_stru.di_mem_buf_dup_p == NULL) {
|
|
di_pre_stru.di_mem_buf_dup_p = di_buf;
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print(
|
|
"%s: set di_mem_buf_dup_p to be di_inp_buf\n",
|
|
__func__);
|
|
#endif
|
|
}
|
|
} else {
|
|
di_buf->post_proc_flag = 0;
|
|
if ((prog_proc_config & 0x40) ||
|
|
di_pre_stru.force_interlace)
|
|
di_buf->post_proc_flag = 1;
|
|
di_pre_stru.di_inp_buf = di_buf;
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print(
|
|
"%s: %s[%d] => di_inp_buf\n",
|
|
__func__,
|
|
vframe_type_name[di_buf->type],
|
|
di_buf->index);
|
|
#endif
|
|
if (
|
|
di_pre_stru.di_mem_buf_dup_p == NULL) {
|
|
/* use n */
|
|
di_pre_stru.di_mem_buf_dup_p
|
|
= di_buf;
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print(
|
|
"%s: set di_mem_buf_dup_p to be di_inp_buf\n",
|
|
__func__);
|
|
#endif
|
|
}
|
|
}
|
|
} else {
|
|
/*********************************/
|
|
if ((di_buf->vframe->width >= 1920) &&
|
|
(di_buf->vframe->height >= 1080))
|
|
flg_1080i = true;
|
|
else if ((di_buf->vframe->width == 720) &&
|
|
(di_buf->vframe->height == 480))
|
|
flg_480i = true;
|
|
|
|
/*********************************/
|
|
if (di_pre_stru.di_chan2_buf_dup_p == NULL) {
|
|
di_pre_stru.field_count_for_cont = 0;
|
|
di_pre_stru.source_change_flag = 1;
|
|
di_pre_stru.input_size_change_flag = true;
|
|
//di_buf->new_format_flag = 1;
|
|
di_pr_info("set cnt 0;");
|
|
/* ignore contp2rd and contprd */
|
|
}
|
|
di_buf->post_proc_flag = 1;
|
|
di_pre_stru.di_inp_buf = di_buf;
|
|
di_print("%s: %s[%d] => di_inp_buf\n", __func__,
|
|
vframe_type_name[di_buf->type], di_buf->index);
|
|
|
|
if (di_pre_stru.di_mem_buf_dup_p == NULL) {/* use n */
|
|
di_pre_stru.di_mem_buf_dup_p = di_buf;
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print(
|
|
"%s: set di_mem_buf_dup_p to be di_inp_buf\n",
|
|
__func__);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
/* di_wr_buf */
|
|
if (di_pre_stru.prog_proc_type == 2) {
|
|
di_linked_buf_idx = peek_free_linked_buf();
|
|
if (di_linked_buf_idx != -1)
|
|
di_buf = get_free_linked_buf(di_linked_buf_idx);
|
|
else
|
|
di_buf = NULL;
|
|
if (di_buf == NULL) {
|
|
/* recycle_vframe_type_pre(di_pre_stru.di_inp_buf);
|
|
*save for next process
|
|
*/
|
|
recycle_keep_buffer();
|
|
di_pre_stru.di_inp_buf_next = di_pre_stru.di_inp_buf;
|
|
return 0;
|
|
}
|
|
di_buf->post_proc_flag = 0;
|
|
di_buf->di_wr_linked_buf->pre_ref_count = 0;
|
|
di_buf->di_wr_linked_buf->post_ref_count = 0;
|
|
di_buf->canvas_config_flag = 1;
|
|
} else {
|
|
di_buf = get_di_buf_head(QUEUE_LOCAL_FREE);
|
|
if (check_di_buf(di_buf, 11)) {
|
|
/* recycle_keep_buffer();
|
|
* pr_dbg("%s:recycle keep buffer\n", __func__);
|
|
*/
|
|
recycle_vframe_type_pre(di_pre_stru.di_inp_buf);
|
|
return 0;
|
|
}
|
|
queue_out(di_buf);
|
|
if (di_pre_stru.prog_proc_type & 0x10)
|
|
di_buf->canvas_config_flag = 1;
|
|
else
|
|
di_buf->canvas_config_flag = 2;
|
|
di_buf->di_wr_linked_buf = NULL;
|
|
}
|
|
|
|
di_pre_stru.di_wr_buf = di_buf;
|
|
di_pre_stru.di_wr_buf->pre_ref_count = 1;
|
|
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print("%s: %s[%d] => di_wr_buf\n", __func__,
|
|
vframe_type_name[di_buf->type], di_buf->index);
|
|
if (di_buf->di_wr_linked_buf)
|
|
di_print("%s: linked %s[%d] => di_wr_buf\n", __func__,
|
|
vframe_type_name[di_buf->di_wr_linked_buf->type],
|
|
di_buf->di_wr_linked_buf->index);
|
|
#endif
|
|
|
|
/*for support compress from dec, not from vdin*/
|
|
if (IS_COMP_MODE(di_pre_stru.cur_inp_type) &&
|
|
(!(di_pre_stru.cur_inp_type & VIDTYPE_VIU_422))) {
|
|
/*compress type and not from vdin*/
|
|
di_pre_stru.di_inp_buf->vframe->width =
|
|
di_pre_stru.di_inp_buf->vframe->compWidth;
|
|
di_pre_stru.di_inp_buf->vframe->height =
|
|
di_pre_stru.di_inp_buf->vframe->compHeight;
|
|
}
|
|
|
|
memcpy(di_buf->vframe,
|
|
di_pre_stru.di_inp_buf->vframe, sizeof(vframe_t));
|
|
di_buf->vframe->private_data = di_buf;
|
|
di_buf->vframe->canvas0Addr = di_buf->nr_canvas_idx;
|
|
di_buf->vframe->canvas1Addr = di_buf->nr_canvas_idx;
|
|
/* set vframe bit info */
|
|
di_buf->vframe->bitdepth &= ~(BITDEPTH_YMASK);
|
|
di_buf->vframe->bitdepth &= ~(FULL_PACK_422_MODE);
|
|
di_buf->width_bk = di_buf->vframe->width;
|
|
if (de_devp->pps_enable && pps_position) {
|
|
if (pps_dstw != di_buf->vframe->width) {
|
|
di_buf->vframe->width = pps_dstw;
|
|
/*di_pre_stru.width_bk = pps_dstw;*/
|
|
di_buf->width_bk = pps_dstw;
|
|
}
|
|
if (pps_dsth != di_buf->vframe->height)
|
|
di_buf->vframe->height = pps_dsth;
|
|
} else if (de_devp->h_sc_down_en) {
|
|
if (pre_hsc_down_width != di_buf->vframe->width) {
|
|
pr_info("di: hscd %d to %d\n", di_buf->vframe->width,
|
|
pre_hsc_down_width);
|
|
di_buf->vframe->width = pre_hsc_down_width;
|
|
/*di_pre_stru.width_bk = pre_hsc_down_width;*/
|
|
di_buf->width_bk = pre_hsc_down_width;
|
|
}
|
|
}
|
|
if (di_force_bit_mode == 10) {
|
|
di_buf->vframe->bitdepth |= (BITDEPTH_Y10);
|
|
if (full_422_pack)
|
|
di_buf->vframe->bitdepth |= (FULL_PACK_422_MODE);
|
|
} else
|
|
di_buf->vframe->bitdepth |= (BITDEPTH_Y8);
|
|
|
|
if (di_pre_stru.prog_proc_type) {
|
|
di_buf->vframe->type = VIDTYPE_PROGRESSIVE |
|
|
VIDTYPE_VIU_422 |
|
|
VIDTYPE_VIU_SINGLE_PLANE |
|
|
VIDTYPE_VIU_FIELD;
|
|
if (di_pre_stru.cur_inp_type & VIDTYPE_PRE_INTERLACE)
|
|
di_buf->vframe->type |= VIDTYPE_PRE_INTERLACE;
|
|
} else {
|
|
if (
|
|
((di_pre_stru.di_inp_buf->vframe->type &
|
|
VIDTYPE_TYPEMASK) ==
|
|
VIDTYPE_INTERLACE_TOP))
|
|
di_buf->vframe->type = VIDTYPE_INTERLACE_TOP |
|
|
VIDTYPE_VIU_422 |
|
|
VIDTYPE_VIU_SINGLE_PLANE |
|
|
VIDTYPE_VIU_FIELD;
|
|
else
|
|
di_buf->vframe->type = VIDTYPE_INTERLACE_BOTTOM |
|
|
VIDTYPE_VIU_422 |
|
|
VIDTYPE_VIU_SINGLE_PLANE |
|
|
VIDTYPE_VIU_FIELD;
|
|
/*add for vpp skip line ref*/
|
|
if (bypass_state == 0)
|
|
di_buf->vframe->type |= VIDTYPE_PRE_INTERLACE;
|
|
}
|
|
|
|
if (is_afbc_mode) {
|
|
di_buf->vframe->type |= VIDTYPE_PRE_DI_AFBC;
|
|
/*pr_info("vf type:0x%x\n", di_buf->vframe->type);*/
|
|
}
|
|
|
|
if (is_bypass_post()) {
|
|
if (bypass_post_state == 0)
|
|
di_pre_stru.source_change_flag = 1;
|
|
|
|
bypass_post_state = 1;
|
|
} else {
|
|
if (bypass_post_state)
|
|
di_pre_stru.source_change_flag = 1;
|
|
|
|
bypass_post_state = 0;
|
|
}
|
|
|
|
if (di_pre_stru.di_inp_buf->post_proc_flag == 0) {
|
|
di_pre_stru.madi_enable = 0;
|
|
di_pre_stru.mcdi_enable = 0;
|
|
di_buf->post_proc_flag = 0;
|
|
di_patch_post_update_mc_sw(DI_MC_SW_OTHER, false);
|
|
} else if (bypass_post_state) {
|
|
di_pre_stru.madi_enable = 0;
|
|
di_pre_stru.mcdi_enable = 0;
|
|
di_buf->post_proc_flag = 0;
|
|
di_patch_post_update_mc_sw(DI_MC_SW_OTHER, false);
|
|
} else {
|
|
di_pre_stru.madi_enable = (pre_enable_mask&1);
|
|
di_pre_stru.mcdi_enable = ((pre_enable_mask>>1)&1);
|
|
di_buf->post_proc_flag = 1;
|
|
di_patch_post_update_mc_sw(DI_MC_SW_OTHER, mcpre_en);//en
|
|
}
|
|
|
|
if ((di_pre_stru.di_mem_buf_dup_p == di_pre_stru.di_wr_buf) ||
|
|
(di_pre_stru.di_chan2_buf_dup_p == di_pre_stru.di_wr_buf)) {
|
|
pr_dbg("+++++++++++++++++++++++\n");
|
|
if (recovery_flag == 0)
|
|
recovery_log_reason = 12;
|
|
|
|
recovery_flag++;
|
|
return 0;
|
|
}
|
|
if (is_meson_tl1_cpu() &&
|
|
di_pre_stru.comb_mode &&
|
|
flg_1080i) {
|
|
di_pre_stru.combing_fix_en = false;
|
|
fix_tl1_1080i_patch_sel(di_pre_stru.comb_mode);
|
|
} else {
|
|
di_pre_stru.combing_fix_en = combing_fix_en;
|
|
}
|
|
|
|
if (di_pre_stru.combing_fix_en) {
|
|
if (flg_1080i)
|
|
com_patch_pre_sw_set(1);
|
|
else if (flg_480i)
|
|
com_patch_pre_sw_set(2);
|
|
else
|
|
com_patch_pre_sw_set(0);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int check_recycle_buf(void)
|
|
{
|
|
struct di_buf_s *di_buf = NULL;/* , *ptmp; */
|
|
int itmp;
|
|
int ret = 0;
|
|
bool blk_flg = 0;
|
|
|
|
#ifdef DI_KEEP_HIS
|
|
if (di_blocking)
|
|
return ret;
|
|
#endif
|
|
queue_for_each_entry(di_buf, ptmp, QUEUE_RECYCLE, list) {
|
|
if (di_blocking)
|
|
blk_flg = 1;
|
|
|
|
if ((di_buf->pre_ref_count == 0) &&
|
|
(di_buf->post_ref_count == 0)) {
|
|
if (di_buf->type == VFRAME_TYPE_IN) {
|
|
queue_out(di_buf);
|
|
if (vframe_in[di_buf->index]) {
|
|
vf_put(
|
|
vframe_in[di_buf->index],
|
|
VFM_NAME);
|
|
vf_notify_provider(VFM_NAME,
|
|
VFRAME_EVENT_RECEIVER_PUT,
|
|
NULL);
|
|
di_print(
|
|
"%s: vf_put(%d) 0x%p, %u ms\n",
|
|
__func__,
|
|
di_pre_stru.recycle_seq,
|
|
vframe_in[di_buf->index],
|
|
jiffies_to_msecs(jiffies_64 -
|
|
vframe_in[di_buf->index]->ready_jiffies64));
|
|
vframe_in[di_buf->index] = NULL;
|
|
}
|
|
di_buf->invert_top_bot_flag = 0;
|
|
queue_in(di_buf, QUEUE_IN_FREE);
|
|
di_pre_stru.recycle_seq++;
|
|
ret |= 1;
|
|
} else {
|
|
queue_out(di_buf);
|
|
di_buf->invert_top_bot_flag = 0;
|
|
queue_in(di_buf, QUEUE_LOCAL_FREE);
|
|
if (di_buf->di_wr_linked_buf) {
|
|
queue_in(
|
|
di_buf->di_wr_linked_buf,
|
|
QUEUE_LOCAL_FREE);
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print(
|
|
"%s: linked %s[%d]=>recycle_list\n",
|
|
__func__,
|
|
vframe_type_name[
|
|
di_buf->di_wr_linked_buf->type],
|
|
di_buf->di_wr_linked_buf->index
|
|
);
|
|
#endif
|
|
di_buf->di_wr_linked_buf = NULL;
|
|
}
|
|
ret |= 2;
|
|
}
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print("%s: recycle %s[%d]\n", __func__,
|
|
vframe_type_name[di_buf->type], di_buf->index);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (blk_flg)
|
|
pr_info("di:blk:recycle\n");
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifdef DET3D
|
|
static void set3d_view(enum tvin_trans_fmt trans_fmt, struct vframe_s *vf)
|
|
{
|
|
struct vframe_view_s *left_eye, *right_eye;
|
|
|
|
left_eye = &vf->left_eye;
|
|
right_eye = &vf->right_eye;
|
|
|
|
switch (trans_fmt) {
|
|
case TVIN_TFMT_3D_DET_LR:
|
|
case TVIN_TFMT_3D_LRH_OLOR:
|
|
left_eye->start_x = 0;
|
|
left_eye->start_y = 0;
|
|
left_eye->width = vf->width >> 1;
|
|
left_eye->height = vf->height;
|
|
right_eye->start_x = vf->width >> 1;
|
|
right_eye->start_y = 0;
|
|
right_eye->width = vf->width >> 1;
|
|
right_eye->height = vf->height;
|
|
break;
|
|
case TVIN_TFMT_3D_DET_TB:
|
|
case TVIN_TFMT_3D_TB:
|
|
left_eye->start_x = 0;
|
|
left_eye->start_y = 0;
|
|
left_eye->width = vf->width;
|
|
left_eye->height = vf->height >> 1;
|
|
right_eye->start_x = 0;
|
|
right_eye->start_y = vf->height >> 1;
|
|
right_eye->width = vf->width;
|
|
right_eye->height = vf->height >> 1;
|
|
break;
|
|
case TVIN_TFMT_3D_DET_INTERLACE:
|
|
left_eye->start_x = 0;
|
|
left_eye->start_y = 0;
|
|
left_eye->width = vf->width;
|
|
left_eye->height = vf->height >> 1;
|
|
right_eye->start_x = 0;
|
|
right_eye->start_y = 0;
|
|
right_eye->width = vf->width;
|
|
right_eye->height = vf->height >> 1;
|
|
break;
|
|
case TVIN_TFMT_3D_DET_CHESSBOARD:
|
|
/***
|
|
* LRLRLR LRLRLR
|
|
* LRLRLR or RLRLRL
|
|
* LRLRLR LRLRLR
|
|
* LRLRLR RLRLRL
|
|
*/
|
|
break;
|
|
default: /* 2D */
|
|
left_eye->start_x = 0;
|
|
left_eye->start_y = 0;
|
|
left_eye->width = 0;
|
|
left_eye->height = 0;
|
|
right_eye->start_x = 0;
|
|
right_eye->start_y = 0;
|
|
right_eye->width = 0;
|
|
right_eye->height = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* static int get_3d_info(struct vframe_s *vf)
|
|
* {
|
|
* int ret = 0;
|
|
*
|
|
* vf->trans_fmt = det3d_fmt_detect();
|
|
* pr_dbg("[det3d..]new 3d fmt: %d\n", vf->trans_fmt);
|
|
*
|
|
* vdin_set_view(vf->trans_fmt, vf);
|
|
*
|
|
* return ret;
|
|
* }
|
|
*/
|
|
|
|
static void det3d_irq(void)
|
|
{
|
|
unsigned int data32 = 0, likely_val = 0;
|
|
unsigned long frame_sum = 0;
|
|
|
|
if (!det3d_en)
|
|
return;
|
|
|
|
data32 = det3d_fmt_detect();
|
|
switch (data32) {
|
|
case TVIN_TFMT_3D_DET_LR:
|
|
case TVIN_TFMT_3D_LRH_OLOR:
|
|
di_pre_stru.det_lr++;
|
|
break;
|
|
case TVIN_TFMT_3D_DET_TB:
|
|
case TVIN_TFMT_3D_TB:
|
|
di_pre_stru.det_tp++;
|
|
break;
|
|
case TVIN_TFMT_3D_DET_INTERLACE:
|
|
di_pre_stru.det_la++;
|
|
break;
|
|
default:
|
|
di_pre_stru.det_null++;
|
|
break;
|
|
}
|
|
|
|
if (det3d_mode != data32) {
|
|
det3d_mode = data32;
|
|
di_print("[det3d..]new 3d fmt: %d\n", det3d_mode);
|
|
}
|
|
if (frame_count > 20) {
|
|
frame_sum = di_pre_stru.det_lr + di_pre_stru.det_tp
|
|
+ di_pre_stru.det_la
|
|
+ di_pre_stru.det_null;
|
|
if ((frame_count%det3d_frame_cnt) || (frame_sum > UINT_MAX))
|
|
return;
|
|
likely_val = max3(di_pre_stru.det_lr,
|
|
di_pre_stru.det_tp,
|
|
di_pre_stru.det_la);
|
|
if (di_pre_stru.det_null >= likely_val)
|
|
det3d_mode = 0;
|
|
else if (likely_val == di_pre_stru.det_lr)
|
|
det3d_mode = TVIN_TFMT_3D_LRH_OLOR;
|
|
else if (likely_val == di_pre_stru.det_tp)
|
|
det3d_mode = TVIN_TFMT_3D_TB;
|
|
else
|
|
det3d_mode = TVIN_TFMT_3D_DET_INTERLACE;
|
|
di_pre_stru.det3d_trans_fmt = det3d_mode;
|
|
} else {
|
|
di_pre_stru.det3d_trans_fmt = 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
unsigned int ro_mcdi_col_cfd[26];
|
|
static void get_mcinfo_from_reg_in_irq(void)
|
|
{
|
|
unsigned int i = 0, ncolcrefsum = 0, blkcount = 0, *reg = NULL;
|
|
|
|
/*get info for current field process by post*/
|
|
di_pre_stru.di_wr_buf->curr_field_mcinfo.highvertfrqflg =
|
|
(Rd(MCDI_RO_HIGH_VERT_FRQ_FLG) & 0x1);
|
|
/* post:MCDI_MC_REL_GAIN_OFFST_0 */
|
|
di_pre_stru.di_wr_buf->curr_field_mcinfo.motionparadoxflg =
|
|
(Rd(MCDI_RO_MOTION_PARADOX_FLG) & 0x1);
|
|
/* post:MCDI_MC_REL_GAIN_OFFST_0 */
|
|
reg = di_pre_stru.di_wr_buf->curr_field_mcinfo.regs;
|
|
for (i = 0; i < 26; i++) {
|
|
ro_mcdi_col_cfd[i] = Rd(0x2fb0 + i);
|
|
di_pre_stru.di_wr_buf->curr_field_mcinfo.regs[i] = 0;
|
|
if (!calc_mcinfo_en)
|
|
*(reg + i) = ro_mcdi_col_cfd[i];
|
|
}
|
|
if (calc_mcinfo_en) {
|
|
blkcount = (di_pre_stru.cur_width + 4) / 5;
|
|
for (i = 0; i < blkcount; i++) {
|
|
ncolcrefsum +=
|
|
((ro_mcdi_col_cfd[i / 32] >> (i % 32)) & 0x1);
|
|
if (
|
|
((ncolcrefsum + (blkcount >> 1)) << 8) /
|
|
blkcount > colcfd_thr)
|
|
for (i = 0; i < blkcount; i++)
|
|
*(reg + i / 32) += (1 << (i % 32));
|
|
}
|
|
}
|
|
}
|
|
|
|
static unsigned int bit_reverse(unsigned int val)
|
|
{
|
|
unsigned int i = 0, res = 0;
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
res |= (((val&(1<<i))>>i)<<(31-i));
|
|
res |= (((val&(1<<(31-i)))<<i)>>(31-i));
|
|
}
|
|
return res;
|
|
}
|
|
|
|
static void set_post_mcinfo(struct mcinfo_pre_s *curr_field_mcinfo)
|
|
{
|
|
unsigned int i = 0, value = 0;
|
|
|
|
DI_VSYNC_WR_MPEG_REG_BITS(MCDI_MC_REL_GAIN_OFFST_0,
|
|
curr_field_mcinfo->highvertfrqflg, 24, 1);
|
|
DI_VSYNC_WR_MPEG_REG_BITS(MCDI_MC_REL_GAIN_OFFST_0,
|
|
curr_field_mcinfo->motionparadoxflg, 25, 1);
|
|
for (i = 0; i < 26; i++) {
|
|
if (overturn)
|
|
value = bit_reverse(curr_field_mcinfo->regs[i]);
|
|
else
|
|
value = curr_field_mcinfo->regs[i];
|
|
DI_VSYNC_WR_MPEG_REG(0x2f78 + i, value);
|
|
}
|
|
}
|
|
static unsigned char intr_mode;
|
|
static irqreturn_t de_irq(int irq, void *dev_instance)
|
|
{
|
|
#ifndef CHECK_DI_DONE
|
|
unsigned int data32 = Rd(DI_INTR_CTRL);
|
|
unsigned int mask32 = (data32 >> 16) & 0x3ff;
|
|
unsigned int flag = 0;
|
|
|
|
data32 &= 0x3fffffff;
|
|
if ((data32 & 1) == 0 && di_dbg_mask&8)
|
|
pr_info("irq[%d]pre|post=0 write done.\n", irq);
|
|
if (di_pre_stru.pre_de_busy) {
|
|
/* only one interrupt mask should be enable */
|
|
if ((data32 & 2) && !(mask32 & 2)) {
|
|
di_print("== MTNWR ==\n");
|
|
flag = 1;
|
|
} else if ((data32 & 1) && !(mask32 & 1)) {
|
|
di_print("== NRWR ==\n");
|
|
flag = 1;
|
|
} else {
|
|
di_print("== DI IRQ 0x%x ==\n", data32);
|
|
flag = 0;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
ddbg_mod_save(eDI_DBG_MOD_PRE_IRQB, 0, di_pre_stru.in_seq);
|
|
#ifdef DET3D
|
|
if (det3d_en) {
|
|
if ((data32 & 0x100) && !(mask32 & 0x100) && flag) {
|
|
DI_Wr(DI_INTR_CTRL, data32);
|
|
det3d_irq();
|
|
} else {
|
|
goto end;
|
|
}
|
|
} else {
|
|
DI_Wr(DI_INTR_CTRL, data32);
|
|
}
|
|
#else
|
|
if (flag)
|
|
DI_Wr(DI_INTR_CTRL, (data32&0xfffffffb)|(intr_mode<<30));
|
|
#endif
|
|
|
|
if (di_pre_stru.pre_de_busy == 0) {
|
|
pr_err("di:err:%s: enter %x\n", __func__, Rd(DI_INTR_CTRL));
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
if (flag) {
|
|
di_pre_stru.irq_time[0] =
|
|
(cur_to_msecs() - di_pre_stru.irq_time[0]);
|
|
trace_di_pre("PRE-IRQ-0",
|
|
di_pre_stru.field_count_for_cont,
|
|
di_pre_stru.irq_time[0]);
|
|
/*add from valsi wang.feng*/
|
|
di_arb_sw(false);
|
|
di_arb_sw(true);
|
|
|
|
if (mcpre_en) {
|
|
get_mcinfo_from_reg_in_irq();
|
|
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
|
|
if ((is_meson_gxlx_cpu() &&
|
|
di_pre_stru.field_count_for_cont >= 4) ||
|
|
is_meson_txhd_cpu())
|
|
mc_pre_mv_irq();
|
|
#endif
|
|
calc_lmv_base_mcinfo((di_pre_stru.cur_height>>1),
|
|
di_pre_stru.di_wr_buf->mcinfo_vaddr);
|
|
}
|
|
di_nr_opl()->nr_process_in_irq();
|
|
if ((data32&0x200) && de_devp->nrds_enable)
|
|
nr_ds_irq();
|
|
/* disable mif */
|
|
enable_di_pre_mif(false, mcpre_en);
|
|
di_pre_stru.pre_de_process_done = 1;
|
|
di_pre_stru.pre_de_busy = 0;
|
|
|
|
if (init_flag)
|
|
/* pr_dbg("%s:up di sema\n", __func__); */
|
|
trigger_pre_di_process(TRIGGER_PRE_BY_DE_IRQ);
|
|
}
|
|
ddbg_mod_save(eDI_DBG_MOD_PRE_IRQE, 0, di_pre_stru.in_seq);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static irqreturn_t post_irq(int irq, void *dev_instance)
|
|
{
|
|
unsigned int data32 = Rd(DI_INTR_CTRL);
|
|
|
|
data32 &= 0x3fffffff;
|
|
if ((data32 & 4) == 0) {
|
|
if (di_dbg_mask&8)
|
|
pr_info("irq[%d]post write undone.\n", irq);
|
|
return IRQ_HANDLED;
|
|
}
|
|
ddbg_mod_save(eDI_DBG_MOD_POST_IRQB, 0, 0);
|
|
if ((post_wr_en && post_wr_support) && (data32&0x4)) {
|
|
di_post_stru.de_post_process_done = 1;
|
|
di_post_stru.post_de_busy = 0;
|
|
di_post_stru.irq_time =
|
|
(cur_to_msecs() - di_post_stru.irq_time);
|
|
trace_di_post("POST-IRQ-1",
|
|
di_post_stru.post_wr_cnt,
|
|
di_post_stru.irq_time);
|
|
DI_Wr(DI_INTR_CTRL, (data32&0xffff0004)|(intr_mode<<30));
|
|
/* disable wr back avoid pps read in g12a */
|
|
DI_Wr_reg_bits(DI_POST_CTRL, 0, 7, 1);
|
|
}
|
|
ddbg_mod_save(eDI_DBG_MOD_POST_IRQE, 0, 0);
|
|
|
|
if (init_flag)
|
|
trigger_pre_di_process(TRIGGER_PRE_BY_DE_IRQ);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
/*
|
|
* di post process
|
|
*/
|
|
static void inc_post_ref_count(struct di_buf_s *di_buf)
|
|
{
|
|
/* int post_blend_mode; */
|
|
|
|
if (IS_ERR_OR_NULL(di_buf)) {
|
|
pr_dbg("%s: Error\n", __func__);
|
|
if (recovery_flag == 0)
|
|
recovery_log_reason = 13;
|
|
|
|
recovery_flag++;
|
|
return;
|
|
}
|
|
|
|
if (di_buf->di_buf_dup_p[1])
|
|
di_buf->di_buf_dup_p[1]->post_ref_count++;
|
|
|
|
if (di_buf->di_buf_dup_p[0])
|
|
di_buf->di_buf_dup_p[0]->post_ref_count++;
|
|
|
|
if (di_buf->di_buf_dup_p[2])
|
|
di_buf->di_buf_dup_p[2]->post_ref_count++;
|
|
}
|
|
|
|
static void dec_post_ref_count(struct di_buf_s *di_buf)
|
|
{
|
|
if (IS_ERR_OR_NULL(di_buf)) {
|
|
pr_dbg("%s: Error\n", __func__);
|
|
if (recovery_flag == 0)
|
|
recovery_log_reason = 14;
|
|
|
|
recovery_flag++;
|
|
return;
|
|
}
|
|
if (di_buf->pd_config.global_mode == PULL_DOWN_BUF1)
|
|
return;
|
|
if (di_buf->di_buf_dup_p[1])
|
|
di_buf->di_buf_dup_p[1]->post_ref_count--;
|
|
|
|
if (di_buf->di_buf_dup_p[0] &&
|
|
di_buf->di_buf_dup_p[0]->post_proc_flag != -2)
|
|
di_buf->di_buf_dup_p[0]->post_ref_count--;
|
|
|
|
if (di_buf->di_buf_dup_p[2])
|
|
di_buf->di_buf_dup_p[2]->post_ref_count--;
|
|
}
|
|
|
|
static void vscale_skip_disable_post(struct di_buf_s *di_buf, vframe_t *disp_vf)
|
|
{
|
|
struct di_buf_s *di_buf_i = NULL;
|
|
int canvas_height = di_buf->di_buf[0]->canvas_height;
|
|
|
|
if (di_vscale_skip_enable & 0x2) {/* drop the bottom field */
|
|
if ((di_buf->di_buf_dup_p[0]) && (di_buf->di_buf_dup_p[1]))
|
|
di_buf_i =
|
|
(di_buf->di_buf_dup_p[1]->vframe->type &
|
|
VIDTYPE_TYPEMASK) ==
|
|
VIDTYPE_INTERLACE_TOP ? di_buf->di_buf_dup_p[1]
|
|
: di_buf->di_buf_dup_p[0];
|
|
else
|
|
di_buf_i = di_buf->di_buf[0];
|
|
} else {
|
|
if ((di_buf->di_buf[0]->post_proc_flag > 0)
|
|
&& (di_buf->di_buf_dup_p[1]))
|
|
di_buf_i = di_buf->di_buf_dup_p[1];
|
|
else
|
|
di_buf_i = di_buf->di_buf[0];
|
|
}
|
|
disp_vf->type = di_buf_i->vframe->type;
|
|
/* pr_dbg("%s (%x %x) (%x %x)\n", __func__,
|
|
* disp_vf, disp_vf->type, di_buf_i->vframe,
|
|
* di_buf_i->vframe->type);
|
|
*/
|
|
disp_vf->width = di_buf_i->vframe->width;
|
|
disp_vf->height = di_buf_i->vframe->height;
|
|
disp_vf->duration = di_buf_i->vframe->duration;
|
|
disp_vf->pts = di_buf_i->vframe->pts;
|
|
disp_vf->flag = di_buf_i->vframe->flag;
|
|
disp_vf->canvas0Addr = di_post_idx[di_post_stru.canvas_id][0];
|
|
disp_vf->canvas1Addr = di_post_idx[di_post_stru.canvas_id][0];
|
|
canvas_config(
|
|
di_post_idx[di_post_stru.canvas_id][0],
|
|
di_buf_i->nr_adr, di_buf_i->canvas_width[NR_CANVAS],
|
|
canvas_height, 0, 0);
|
|
disable_post_deinterlace_2();
|
|
di_post_stru.vscale_skip_flag = true;
|
|
}
|
|
static void process_vscale_skip(struct di_buf_s *di_buf, vframe_t *disp_vf)
|
|
{
|
|
int ret = 0, vpp_3d_mode = 0;
|
|
|
|
if ((di_buf->di_buf[0] != NULL) && (di_vscale_skip_enable & 0x5) &&
|
|
(di_buf->process_fun_index != PROCESS_FUN_NULL)) {
|
|
ret = get_current_vscale_skip_count(disp_vf);
|
|
di_vscale_skip_count = (ret & 0xff);
|
|
vpp_3d_mode = ((ret >> 8) & 0xff);
|
|
if (((di_vscale_skip_count > 0) &&
|
|
(di_vscale_skip_enable & 0x5))
|
|
|| (di_vscale_skip_enable >> 16)
|
|
) {
|
|
if ((di_vscale_skip_enable & 0x8) || vpp_3d_mode) {
|
|
vscale_skip_disable_post(di_buf, disp_vf);
|
|
} else {
|
|
if (di_buf->di_buf_dup_p[1] &&
|
|
di_buf->pd_config.global_mode !=
|
|
PULL_DOWN_BUF1)
|
|
di_buf->pd_config.global_mode =
|
|
PULL_DOWN_EI;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
static int do_post_wr_fun(void *arg, vframe_t *disp_vf)
|
|
{
|
|
di_post_stru.toggle_flag = true;
|
|
return 1;
|
|
}
|
|
static int de_post_disable_fun(void *arg, vframe_t *disp_vf)
|
|
{
|
|
struct di_buf_s *di_buf = (struct di_buf_s *)arg;
|
|
|
|
di_post_stru.vscale_skip_flag = false;
|
|
di_post_stru.toggle_flag = true;
|
|
|
|
process_vscale_skip(di_buf, disp_vf);
|
|
/* for atv static image flickering */
|
|
if (di_buf->process_fun_index == PROCESS_FUN_NULL)
|
|
disable_post_deinterlace_2();
|
|
|
|
return 1;
|
|
/* called for new_format_flag, make
|
|
* video set video_property_changed
|
|
*/
|
|
}
|
|
|
|
void di_api_post_disable(void)
|
|
{
|
|
if (dil_get_diff_ver_flag())
|
|
return;
|
|
|
|
di_print("%s:\n", __func__);
|
|
disable_post_deinterlace_2();
|
|
}
|
|
EXPORT_SYMBOL(di_api_post_disable);
|
|
|
|
static int do_nothing_fun(void *arg, vframe_t *disp_vf)
|
|
{
|
|
struct di_buf_s *di_buf = (struct di_buf_s *)arg;
|
|
|
|
di_post_stru.vscale_skip_flag = false;
|
|
di_post_stru.toggle_flag = true;
|
|
|
|
process_vscale_skip(di_buf, disp_vf);
|
|
|
|
if (di_buf->process_fun_index == PROCESS_FUN_NULL) {
|
|
if (Rd(DI_IF1_GEN_REG) & 0x1 || Rd(DI_POST_CTRL) & 0xf)
|
|
disable_post_deinterlace_2();
|
|
/*if(di_buf->pulldown_mode == PULL_DOWN_EI && Rd(DI_IF1_GEN_REG)&0x1)
|
|
* DI_VSYNC_WR_MPEG_REG(DI_IF1_GEN_REG, 0x3 << 30);
|
|
*/
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int do_pre_only_fun(void *arg, vframe_t *disp_vf)
|
|
{
|
|
di_post_stru.vscale_skip_flag = false;
|
|
di_post_stru.toggle_flag = true;
|
|
|
|
#ifdef DI_USE_FIXED_CANVAS_IDX
|
|
if (arg) {
|
|
struct di_buf_s *di_buf = (struct di_buf_s *)arg;
|
|
vframe_t *vf = di_buf->vframe;
|
|
int width, canvas_height;
|
|
|
|
if ((vf == NULL) || (di_buf->di_buf[0] == NULL)) {
|
|
di_print("error:%s,NULL point!!\n", __func__);
|
|
return 0;
|
|
}
|
|
width = di_buf->di_buf[0]->canvas_width[NR_CANVAS];
|
|
/* linked two interlace buffer should double height*/
|
|
if (di_buf->di_buf[0]->di_wr_linked_buf)
|
|
canvas_height =
|
|
(di_buf->di_buf[0]->canvas_height << 1);
|
|
else
|
|
canvas_height =
|
|
di_buf->di_buf[0]->canvas_height;
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA
|
|
if (is_vsync_rdma_enable()) {
|
|
di_post_stru.canvas_id = di_post_stru.next_canvas_id;
|
|
} else {
|
|
di_post_stru.canvas_id = 0;
|
|
di_post_stru.next_canvas_id = 1;
|
|
if (post_wr_en && post_wr_support)
|
|
di_post_stru.canvas_id =
|
|
di_post_stru.next_canvas_id;
|
|
}
|
|
#endif
|
|
|
|
canvas_config(
|
|
di_post_idx[di_post_stru.canvas_id][0],
|
|
di_buf->di_buf[0]->nr_adr,
|
|
di_buf->di_buf[0]->canvas_width[NR_CANVAS],
|
|
canvas_height, 0, 0);
|
|
|
|
vf->canvas0Addr =
|
|
di_post_idx[di_post_stru.canvas_id][0];
|
|
vf->canvas1Addr =
|
|
di_post_idx[di_post_stru.canvas_id][0];
|
|
#ifdef DET3D
|
|
if (di_pre_stru.vframe_interleave_flag && di_buf->di_buf[1]) {
|
|
canvas_config(
|
|
di_post_idx[di_post_stru.canvas_id][1],
|
|
di_buf->di_buf[1]->nr_adr,
|
|
di_buf->di_buf[1]->canvas_width[NR_CANVAS],
|
|
canvas_height, 0, 0);
|
|
vf->canvas1Addr =
|
|
di_post_idx[di_post_stru.canvas_id][1];
|
|
vf->duration <<= 1;
|
|
}
|
|
#endif
|
|
di_post_stru.next_canvas_id = di_post_stru.canvas_id ? 0 : 1;
|
|
|
|
if (di_buf->process_fun_index == PROCESS_FUN_NULL) {
|
|
if (Rd(DI_IF1_GEN_REG) & 0x1 ||
|
|
Rd(DI_POST_CTRL) & 0x10f)
|
|
disable_post_deinterlace_2();
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void get_vscale_skip_count(unsigned int par)
|
|
{
|
|
di_vscale_skip_count_real = (par >> 24) & 0xff;
|
|
}
|
|
|
|
#define get_vpp_reg_update_flag(par) ((par >> 16) & 0x1)
|
|
|
|
unsigned int di_last_display;
|
|
|
|
static int
|
|
de_post_process(void *arg, unsigned int zoom_start_x_lines,
|
|
unsigned int zoom_end_x_lines, unsigned int zoom_start_y_lines,
|
|
unsigned int zoom_end_y_lines, vframe_t *disp_vf)
|
|
{
|
|
struct di_buf_s *di_buf = (struct di_buf_s *)arg;
|
|
struct di_buf_s *di_pldn_buf = NULL;
|
|
unsigned int di_width, di_height, di_start_x, di_end_x, mv_offset;
|
|
unsigned int di_start_y, di_end_y, hold_line = post_hold_line;
|
|
unsigned int post_blend_en = 0, post_blend_mode = 0,
|
|
blend_mtn_en = 0, ei_en = 0, post_field_num = 0;
|
|
int di_vpp_en, di_ddr_en;
|
|
unsigned char mc_pre_flag = 0;
|
|
bool invert_mv = false;
|
|
static int post_index = -1;
|
|
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
|
|
unsigned char tmp_idx = 0;
|
|
#endif
|
|
post_cnt++;
|
|
if (di_post_stru.vscale_skip_flag)
|
|
return 0;
|
|
|
|
get_vscale_skip_count(zoom_start_x_lines);
|
|
|
|
if (IS_ERR_OR_NULL(di_buf))
|
|
return 0;
|
|
else if (IS_ERR_OR_NULL(di_buf->di_buf_dup_p[0]))
|
|
return 0;
|
|
di_pldn_buf = di_buf->di_buf_dup_p[pldn_dly];
|
|
|
|
if (is_in_queue(di_buf, QUEUE_POST_FREE) &&
|
|
post_index != di_buf->index) {
|
|
post_index = di_buf->index;
|
|
pr_info("%s post_buf[%d] is in post free list.\n",
|
|
__func__, di_buf->index);
|
|
return 0;
|
|
}
|
|
|
|
if (di_post_stru.toggle_flag && di_buf->di_buf_dup_p[1])
|
|
top_bot_config(di_buf->di_buf_dup_p[1]);
|
|
|
|
di_post_stru.toggle_flag = false;
|
|
|
|
di_post_stru.cur_disp_index = di_buf->index;
|
|
|
|
di_last_display = di_buf->index;/*tmp for keep buf*/
|
|
if (get_vpp_reg_update_flag(zoom_start_x_lines) || post_refresh)
|
|
di_post_stru.update_post_reg_flag = 1;
|
|
|
|
zoom_start_x_lines = zoom_start_x_lines & 0xffff;
|
|
zoom_end_x_lines = zoom_end_x_lines & 0xffff;
|
|
zoom_start_y_lines = zoom_start_y_lines & 0xffff;
|
|
zoom_end_y_lines = zoom_end_y_lines & 0xffff;
|
|
|
|
if (init_flag == 0 && IS_ERR_OR_NULL(di_post_stru.keep_buf))
|
|
return 0;
|
|
|
|
ddbg_mod_save(eDI_DBG_MOD_POST_SETB, 0, frame_count);/*dbg*/
|
|
di_start_x = zoom_start_x_lines;
|
|
di_end_x = zoom_end_x_lines;
|
|
di_width = di_end_x - di_start_x + 1;
|
|
di_start_y = zoom_start_y_lines;
|
|
di_end_y = zoom_end_y_lines;
|
|
di_height = di_end_y - di_start_y + 1;
|
|
di_height = di_height / (di_vscale_skip_count_real + 1);
|
|
|
|
/* make sure the height is even number */
|
|
if (di_height%2) {
|
|
/*for skip mode,post only half line-1*/
|
|
if (((di_height > 150) && (di_height < 1080)) &&
|
|
di_vscale_skip_count_real)
|
|
di_height = di_height - 3;
|
|
else
|
|
di_height++;
|
|
}
|
|
|
|
if (Rd(DI_POST_SIZE) != ((di_width - 1) | ((di_height - 1) << 16)) ||
|
|
di_post_stru.buf_type != di_buf->di_buf_dup_p[0]->type ||
|
|
(di_post_stru.di_buf0_mif.luma_x_start0 != di_start_x) ||
|
|
(di_post_stru.di_buf0_mif.luma_y_start0 != di_start_y / 2)) {
|
|
ddbg_mod_save(eDI_DBG_MOD_POST_RESIZE, 0,
|
|
frame_count);/*dbg*/
|
|
di_post_stru.buf_type = di_buf->di_buf_dup_p[0]->type;
|
|
|
|
initial_di_post_2(di_width, di_height,
|
|
hold_line,
|
|
(post_wr_en && post_wr_support));
|
|
|
|
if ((di_buf->di_buf_dup_p[0]->vframe == NULL) ||
|
|
(di_buf->vframe == NULL))
|
|
return 0;
|
|
/* bit mode config */
|
|
if (di_buf->vframe->bitdepth & BITDEPTH_Y10) {
|
|
if (di_buf->vframe->type & VIDTYPE_VIU_444) {
|
|
di_post_stru.di_buf0_mif.bit_mode =
|
|
(di_buf->vframe->bitdepth & FULL_PACK_422_MODE)?3:2;
|
|
di_post_stru.di_buf1_mif.bit_mode =
|
|
(di_buf->vframe->bitdepth & FULL_PACK_422_MODE)?3:2;
|
|
di_post_stru.di_buf2_mif.bit_mode =
|
|
(di_buf->vframe->bitdepth & FULL_PACK_422_MODE)?3:2;
|
|
di_post_stru.di_diwr_mif.bit_mode =
|
|
(di_buf->vframe->bitdepth & FULL_PACK_422_MODE)?3:2;
|
|
|
|
} else {
|
|
di_post_stru.di_buf0_mif.bit_mode =
|
|
(di_buf->vframe->bitdepth & FULL_PACK_422_MODE)?3:1;
|
|
di_post_stru.di_buf1_mif.bit_mode =
|
|
(di_buf->vframe->bitdepth & FULL_PACK_422_MODE)?3:1;
|
|
di_post_stru.di_buf2_mif.bit_mode =
|
|
(di_buf->vframe->bitdepth & FULL_PACK_422_MODE)?3:1;
|
|
di_post_stru.di_diwr_mif.bit_mode =
|
|
(di_buf->vframe->bitdepth & FULL_PACK_422_MODE)?3:1;
|
|
}
|
|
} else {
|
|
di_post_stru.di_buf0_mif.bit_mode = 0;
|
|
di_post_stru.di_buf1_mif.bit_mode = 0;
|
|
di_post_stru.di_buf2_mif.bit_mode = 0;
|
|
di_post_stru.di_diwr_mif.bit_mode = 0;
|
|
}
|
|
if (di_buf->vframe->type & VIDTYPE_VIU_444) {
|
|
di_post_stru.di_buf0_mif.video_mode = 1;
|
|
di_post_stru.di_buf1_mif.video_mode = 1;
|
|
di_post_stru.di_buf2_mif.video_mode = 1;
|
|
} else {
|
|
di_post_stru.di_buf0_mif.video_mode = 0;
|
|
di_post_stru.di_buf1_mif.video_mode = 0;
|
|
di_post_stru.di_buf2_mif.video_mode = 0;
|
|
}
|
|
if (di_post_stru.buf_type == VFRAME_TYPE_IN &&
|
|
!(di_buf->di_buf_dup_p[0]->vframe->type &
|
|
VIDTYPE_VIU_FIELD)) {
|
|
if (di_buf->vframe->type & VIDTYPE_VIU_NV21) {
|
|
di_post_stru.di_buf0_mif.set_separate_en = 1;
|
|
di_post_stru.di_buf1_mif.set_separate_en = 1;
|
|
di_post_stru.di_buf2_mif.set_separate_en = 1;
|
|
} else {
|
|
di_post_stru.di_buf0_mif.set_separate_en = 0;
|
|
di_post_stru.di_buf1_mif.set_separate_en = 0;
|
|
di_post_stru.di_buf2_mif.set_separate_en = 0;
|
|
}
|
|
di_post_stru.di_buf0_mif.luma_y_start0 = di_start_y;
|
|
di_post_stru.di_buf0_mif.luma_y_end0 = di_end_y;
|
|
} else { /* from vdin or local vframe process by di pre */
|
|
di_post_stru.di_buf0_mif.set_separate_en = 0;
|
|
di_post_stru.di_buf0_mif.luma_y_start0 =
|
|
di_start_y >> 1;
|
|
di_post_stru.di_buf0_mif.luma_y_end0 = di_end_y >> 1;
|
|
di_post_stru.di_buf1_mif.set_separate_en = 0;
|
|
di_post_stru.di_buf1_mif.luma_y_start0 =
|
|
di_start_y >> 1;
|
|
di_post_stru.di_buf1_mif.luma_y_end0 = di_end_y >> 1;
|
|
di_post_stru.di_buf2_mif.set_separate_en = 0;
|
|
di_post_stru.di_buf2_mif.luma_y_end0 = di_end_y >> 1;
|
|
di_post_stru.di_buf2_mif.luma_y_start0 =
|
|
di_start_y >> 1;
|
|
}
|
|
di_post_stru.di_buf0_mif.luma_x_start0 = di_start_x;
|
|
di_post_stru.di_buf0_mif.luma_x_end0 = di_end_x;
|
|
di_post_stru.di_buf1_mif.luma_x_start0 = di_start_x;
|
|
di_post_stru.di_buf1_mif.luma_x_end0 = di_end_x;
|
|
di_post_stru.di_buf2_mif.luma_x_start0 = di_start_x;
|
|
di_post_stru.di_buf2_mif.luma_x_end0 = di_end_x;
|
|
|
|
if (post_wr_en && post_wr_support) {
|
|
if (de_devp->pps_enable && pps_position == 0) {
|
|
di_pps_config(0, di_width, di_height,
|
|
pps_dstw, pps_dsth);
|
|
di_post_stru.di_diwr_mif.start_x = 0;
|
|
di_post_stru.di_diwr_mif.end_x = pps_dstw - 1;
|
|
di_post_stru.di_diwr_mif.start_y = 0;
|
|
di_post_stru.di_diwr_mif.end_y = pps_dsth - 1;
|
|
} else {
|
|
di_post_stru.di_diwr_mif.start_x = di_start_x;
|
|
di_post_stru.di_diwr_mif.end_x = di_end_x;
|
|
di_post_stru.di_diwr_mif.start_y = di_start_y;
|
|
di_post_stru.di_diwr_mif.end_y = di_end_y;
|
|
}
|
|
}
|
|
|
|
di_post_stru.di_mtnprd_mif.start_x = di_start_x;
|
|
di_post_stru.di_mtnprd_mif.end_x = di_end_x;
|
|
di_post_stru.di_mtnprd_mif.start_y = di_start_y >> 1;
|
|
di_post_stru.di_mtnprd_mif.end_y = di_end_y >> 1;
|
|
if (mcpre_en) {
|
|
di_post_stru.di_mcvecrd_mif.start_x = di_start_x / 5;
|
|
mv_offset = (di_start_x % 5) ? (5 - di_start_x % 5) : 0;
|
|
di_post_stru.di_mcvecrd_mif.vecrd_offset =
|
|
overturn ? (di_end_x + 1) % 5 : mv_offset;
|
|
di_post_stru.di_mcvecrd_mif.start_y =
|
|
(di_start_y >> 1);
|
|
di_post_stru.di_mcvecrd_mif.size_x =
|
|
(di_end_x + 1 + 4) / 5 - 1 - di_start_x / 5;
|
|
di_post_stru.di_mcvecrd_mif.end_y =
|
|
(di_end_y >> 1);
|
|
}
|
|
di_post_stru.update_post_reg_flag = 1;
|
|
/* if height decrease, mtn will not enough */
|
|
if ((di_buf->pd_config.global_mode
|
|
!= PULL_DOWN_BUF1) &&
|
|
!di_buf->di_buf_dup_p[2] &&
|
|
!post_wr_en)
|
|
di_buf->pd_config.global_mode = PULL_DOWN_EI;
|
|
}
|
|
|
|
#ifdef DI_USE_FIXED_CANVAS_IDX
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA
|
|
if (is_vsync_rdma_enable()) {
|
|
di_post_stru.canvas_id = di_post_stru.next_canvas_id;
|
|
} else {
|
|
di_post_stru.canvas_id = 0;
|
|
di_post_stru.next_canvas_id = 1;
|
|
if (post_wr_en && post_wr_support)
|
|
di_post_stru.canvas_id =
|
|
di_post_stru.next_canvas_id;
|
|
}
|
|
#endif
|
|
post_blend = di_buf->pd_config.global_mode;
|
|
switch (post_blend) {
|
|
case PULL_DOWN_BLEND_0:
|
|
case PULL_DOWN_NORMAL:
|
|
config_canvas_idx(
|
|
di_buf->di_buf_dup_p[1],
|
|
di_post_idx[di_post_stru.canvas_id][0], -1);
|
|
config_canvas_idx(
|
|
di_buf->di_buf_dup_p[2], -1,
|
|
di_post_idx[di_post_stru.canvas_id][2]);
|
|
config_canvas_idx(
|
|
di_buf->di_buf_dup_p[0],
|
|
di_post_idx[di_post_stru.canvas_id][1], -1);
|
|
config_canvas_idx(
|
|
di_buf->di_buf_dup_p[2],
|
|
di_post_idx[di_post_stru.canvas_id][3], -1);
|
|
if (mcpre_en)
|
|
config_mcvec_canvas_idx(
|
|
di_buf->di_buf_dup_p[2],
|
|
di_post_idx[di_post_stru.canvas_id][4]);
|
|
break;
|
|
case PULL_DOWN_BLEND_2:
|
|
case PULL_DOWN_NORMAL_2:
|
|
config_canvas_idx(
|
|
di_buf->di_buf_dup_p[0],
|
|
di_post_idx[di_post_stru.canvas_id][3], -1);
|
|
config_canvas_idx(
|
|
di_buf->di_buf_dup_p[1],
|
|
di_post_idx[di_post_stru.canvas_id][0], -1);
|
|
config_canvas_idx(
|
|
di_buf->di_buf_dup_p[2], -1,
|
|
di_post_idx[di_post_stru.canvas_id][2]);
|
|
config_canvas_idx(
|
|
di_buf->di_buf_dup_p[2],
|
|
di_post_idx[di_post_stru.canvas_id][1], -1);
|
|
if (mcpre_en)
|
|
config_mcvec_canvas_idx(
|
|
di_buf->di_buf_dup_p[2],
|
|
di_post_idx[di_post_stru.canvas_id][4]);
|
|
break;
|
|
case PULL_DOWN_MTN:
|
|
config_canvas_idx(
|
|
di_buf->di_buf_dup_p[1],
|
|
di_post_idx[di_post_stru.canvas_id][0], -1);
|
|
config_canvas_idx(
|
|
di_buf->di_buf_dup_p[2], -1,
|
|
di_post_idx[di_post_stru.canvas_id][2]);
|
|
config_canvas_idx(
|
|
di_buf->di_buf_dup_p[0],
|
|
di_post_idx[di_post_stru.canvas_id][1], -1);
|
|
break;
|
|
case PULL_DOWN_BUF1:/* wave with buf1 */
|
|
config_canvas_idx(
|
|
di_buf->di_buf_dup_p[1],
|
|
di_post_idx[di_post_stru.canvas_id][0], -1);
|
|
config_canvas_idx(
|
|
di_buf->di_buf_dup_p[1], -1,
|
|
di_post_idx[di_post_stru.canvas_id][2]);
|
|
config_canvas_idx(
|
|
di_buf->di_buf_dup_p[0],
|
|
di_post_idx[di_post_stru.canvas_id][1], -1);
|
|
break;
|
|
case PULL_DOWN_EI:
|
|
if (di_buf->di_buf_dup_p[1])
|
|
config_canvas_idx(
|
|
di_buf->di_buf_dup_p[1],
|
|
di_post_idx[di_post_stru.canvas_id][0], -1);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
di_post_stru.next_canvas_id = di_post_stru.canvas_id ? 0 : 1;
|
|
#endif
|
|
if (di_buf->di_buf_dup_p[1] == NULL)
|
|
return 0;
|
|
if ((di_buf->di_buf_dup_p[1]->vframe == NULL) ||
|
|
di_buf->di_buf_dup_p[0]->vframe == NULL)
|
|
return 0;
|
|
|
|
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
|
|
if (is_meson_txl_cpu() && overturn && di_buf->di_buf_dup_p[2]) {
|
|
/*sync from kernel 3.14 txl*/
|
|
if (post_blend == PULL_DOWN_BLEND_2)
|
|
post_blend = PULL_DOWN_BLEND_0;
|
|
else if (post_blend == PULL_DOWN_BLEND_0)
|
|
post_blend = PULL_DOWN_BLEND_2;
|
|
}
|
|
#endif
|
|
|
|
switch (post_blend) {
|
|
case PULL_DOWN_BLEND_0:
|
|
case PULL_DOWN_NORMAL:
|
|
post_field_num =
|
|
(di_buf->di_buf_dup_p[1]->vframe->type &
|
|
VIDTYPE_TYPEMASK)
|
|
== VIDTYPE_INTERLACE_TOP ? 0 : 1;
|
|
di_post_stru.di_buf0_mif.canvas0_addr0 =
|
|
di_buf->di_buf_dup_p[1]->nr_canvas_idx;
|
|
di_post_stru.di_buf1_mif.canvas0_addr0 =
|
|
di_buf->di_buf_dup_p[0]->nr_canvas_idx;
|
|
di_post_stru.di_buf2_mif.canvas0_addr0 =
|
|
di_buf->di_buf_dup_p[2]->nr_canvas_idx;
|
|
di_post_stru.di_mtnprd_mif.canvas_num =
|
|
di_buf->di_buf_dup_p[2]->mtn_canvas_idx;
|
|
//mc_pre_flag = is_meson_txl_cpu()?2:(overturn?0:1);
|
|
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
|
|
if (is_meson_txl_cpu() && overturn) {
|
|
/* swap if1&if2 mean negation of mv for normal di*/
|
|
tmp_idx = di_post_stru.di_buf1_mif.canvas0_addr0;
|
|
di_post_stru.di_buf1_mif.canvas0_addr0 =
|
|
di_post_stru.di_buf2_mif.canvas0_addr0;
|
|
di_post_stru.di_buf2_mif.canvas0_addr0 = tmp_idx;
|
|
}
|
|
#endif
|
|
mc_pre_flag = overturn?0:1;
|
|
if (di_buf->pd_config.global_mode == PULL_DOWN_NORMAL) {
|
|
post_blend_mode = 3;
|
|
/*if pulldown, mcdi_mcpreflag is 1,*/
|
|
/*it means use previous field for MC*/
|
|
/*else not pulldown,mcdi_mcpreflag is 2*/
|
|
/*it means use forward & previous field for MC*/
|
|
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXHD))
|
|
mc_pre_flag = 2;
|
|
} else {
|
|
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXHD))
|
|
mc_pre_flag = 1;
|
|
post_blend_mode = 1;
|
|
}
|
|
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
|
|
if (is_meson_txl_cpu() && overturn)
|
|
mc_pre_flag = 1;
|
|
#endif
|
|
if (mcpre_en) {
|
|
di_post_stru.di_mcvecrd_mif.canvas_num =
|
|
di_buf->di_buf_dup_p[2]->mcvec_canvas_idx;
|
|
}
|
|
blend_mtn_en = 1;
|
|
post_ei = ei_en = 1;
|
|
post_blend_en = 1;
|
|
break;
|
|
case PULL_DOWN_BLEND_2:
|
|
case PULL_DOWN_NORMAL_2:
|
|
post_field_num =
|
|
(di_buf->di_buf_dup_p[1]->vframe->type &
|
|
VIDTYPE_TYPEMASK)
|
|
== VIDTYPE_INTERLACE_TOP ? 0 : 1;
|
|
di_post_stru.di_buf0_mif.canvas0_addr0 =
|
|
di_buf->di_buf_dup_p[1]->nr_canvas_idx;
|
|
di_post_stru.di_buf1_mif.canvas0_addr0 =
|
|
di_buf->di_buf_dup_p[2]->nr_canvas_idx;
|
|
di_post_stru.di_buf2_mif.canvas0_addr0 =
|
|
di_buf->di_buf_dup_p[0]->nr_canvas_idx;
|
|
di_post_stru.di_mtnprd_mif.canvas_num =
|
|
di_buf->di_buf_dup_p[2]->mtn_canvas_idx;
|
|
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
|
|
if (is_meson_txl_cpu() && overturn) {
|
|
di_post_stru.di_buf1_mif.canvas0_addr0 =
|
|
di_post_stru.di_buf2_mif.canvas0_addr0;
|
|
}
|
|
#endif
|
|
if (mcpre_en) {
|
|
di_post_stru.di_mcvecrd_mif.canvas_num =
|
|
di_buf->di_buf_dup_p[2]->mcvec_canvas_idx;
|
|
mc_pre_flag = is_meson_txl_cpu()?0:(overturn?1:0);
|
|
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXLX))
|
|
invert_mv = true;
|
|
else if (!overturn)
|
|
di_post_stru.di_buf2_mif.canvas0_addr0 =
|
|
di_buf->di_buf_dup_p[2]->nr_canvas_idx;
|
|
}
|
|
if (di_buf->pd_config.global_mode == PULL_DOWN_NORMAL_2) {
|
|
post_blend_mode = 3;
|
|
/*if pulldown, mcdi_mcpreflag is 1,*/
|
|
/*it means use previous field for MC*/
|
|
/*else not pulldown,mcdi_mcpreflag is 2*/
|
|
/*it means use forward & previous field for MC*/
|
|
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXHD))
|
|
mc_pre_flag = 2;
|
|
} else {
|
|
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXHD))
|
|
mc_pre_flag = 1;
|
|
post_blend_mode = 1;
|
|
}
|
|
blend_mtn_en = 1;
|
|
post_ei = ei_en = 1;
|
|
post_blend_en = 1;
|
|
break;
|
|
case PULL_DOWN_MTN:
|
|
post_field_num =
|
|
(di_buf->di_buf_dup_p[1]->vframe->type &
|
|
VIDTYPE_TYPEMASK)
|
|
== VIDTYPE_INTERLACE_TOP ? 0 : 1;
|
|
di_post_stru.di_buf0_mif.canvas0_addr0 =
|
|
di_buf->di_buf_dup_p[1]->nr_canvas_idx;
|
|
di_post_stru.di_buf1_mif.canvas0_addr0 =
|
|
di_buf->di_buf_dup_p[0]->nr_canvas_idx;
|
|
di_post_stru.di_mtnprd_mif.canvas_num =
|
|
di_buf->di_buf_dup_p[2]->mtn_canvas_idx;
|
|
post_blend_mode = 0;
|
|
blend_mtn_en = 1;
|
|
post_ei = ei_en = 1;
|
|
post_blend_en = 1;
|
|
break;
|
|
case PULL_DOWN_BUF1:
|
|
post_field_num =
|
|
(di_buf->di_buf_dup_p[1]->vframe->type &
|
|
VIDTYPE_TYPEMASK)
|
|
== VIDTYPE_INTERLACE_TOP ? 0 : 1;
|
|
di_post_stru.di_buf0_mif.canvas0_addr0 =
|
|
di_buf->di_buf_dup_p[1]->nr_canvas_idx;
|
|
di_post_stru.di_mtnprd_mif.canvas_num =
|
|
di_buf->di_buf_dup_p[1]->mtn_canvas_idx;
|
|
di_post_stru.di_buf1_mif.canvas0_addr0 =
|
|
di_buf->di_buf_dup_p[0]->nr_canvas_idx;
|
|
post_blend_mode = 1;
|
|
blend_mtn_en = 0;
|
|
post_ei = ei_en = 0;
|
|
post_blend_en = 0;
|
|
break;
|
|
case PULL_DOWN_EI:
|
|
if (di_buf->di_buf_dup_p[1]) {
|
|
di_post_stru.di_buf0_mif.canvas0_addr0 =
|
|
di_buf->di_buf_dup_p[1]->nr_canvas_idx;
|
|
post_field_num =
|
|
(di_buf->di_buf_dup_p[1]->vframe->type &
|
|
VIDTYPE_TYPEMASK)
|
|
== VIDTYPE_INTERLACE_TOP ? 0 : 1;
|
|
} else {
|
|
post_field_num =
|
|
(di_buf->di_buf_dup_p[0]->vframe->type &
|
|
VIDTYPE_TYPEMASK)
|
|
== VIDTYPE_INTERLACE_TOP ? 0 : 1;
|
|
di_post_stru.di_buf0_mif.src_field_mode
|
|
= post_field_num;
|
|
}
|
|
post_blend_mode = 2;
|
|
blend_mtn_en = 0;
|
|
post_ei = ei_en = 1;
|
|
post_blend_en = 0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (post_wr_en && post_wr_support) {
|
|
config_canvas_idx(di_buf,
|
|
di_post_idx[di_post_stru.canvas_id][5], -1);
|
|
di_post_stru.di_diwr_mif.canvas_num = di_buf->nr_canvas_idx;
|
|
di_vpp_en = 0;
|
|
di_ddr_en = 1;
|
|
} else {
|
|
di_vpp_en = 1;
|
|
di_ddr_en = 0;
|
|
}
|
|
|
|
/* if post size < MIN_POST_WIDTH, force ei */
|
|
if ((di_width < MIN_BLEND_WIDTH) &&
|
|
(di_buf->pd_config.global_mode == PULL_DOWN_BLEND_0 ||
|
|
di_buf->pd_config.global_mode == PULL_DOWN_BLEND_2 ||
|
|
di_buf->pd_config.global_mode == PULL_DOWN_NORMAL
|
|
)) {
|
|
post_blend_mode = 1;
|
|
blend_mtn_en = 0;
|
|
post_ei = ei_en = 0;
|
|
post_blend_en = 0;
|
|
}
|
|
|
|
if (mcpre_en)
|
|
di_post_stru.di_mcvecrd_mif.blend_en = post_blend_en;
|
|
invert_mv = overturn ? (!invert_mv) : invert_mv;
|
|
if (di_post_stru.update_post_reg_flag) {
|
|
enable_di_post_2(
|
|
&di_post_stru.di_buf0_mif,
|
|
&di_post_stru.di_buf1_mif,
|
|
&di_post_stru.di_buf2_mif,
|
|
&di_post_stru.di_diwr_mif,
|
|
&di_post_stru.di_mtnprd_mif,
|
|
ei_en, /* ei enable */
|
|
post_blend_en, /* blend enable */
|
|
blend_mtn_en, /* blend mtn enable */
|
|
post_blend_mode, /* blend mode. */
|
|
di_vpp_en, /* di_vpp_en. */
|
|
di_ddr_en, /* di_ddr_en. */
|
|
post_field_num, /* 1 bottom generate top */
|
|
hold_line,
|
|
post_urgent,
|
|
(invert_mv?1:0),
|
|
di_vscale_skip_count_real
|
|
);
|
|
if (mcpre_en) {
|
|
if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A))
|
|
enable_mc_di_post_g12(
|
|
&di_post_stru.di_mcvecrd_mif,
|
|
post_urgent,
|
|
overturn, (invert_mv?1:0));
|
|
else
|
|
enable_mc_di_post(
|
|
&di_post_stru.di_mcvecrd_mif,
|
|
post_urgent,
|
|
overturn, (invert_mv?1:0));
|
|
} else if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXLX))
|
|
DI_VSYNC_WR_MPEG_REG_BITS(MCDI_MC_CRTL, 0, 0, 2);
|
|
} else {
|
|
di_post_switch_buffer(
|
|
&di_post_stru.di_buf0_mif,
|
|
&di_post_stru.di_buf1_mif,
|
|
&di_post_stru.di_buf2_mif,
|
|
&di_post_stru.di_diwr_mif,
|
|
&di_post_stru.di_mtnprd_mif,
|
|
&di_post_stru.di_mcvecrd_mif,
|
|
ei_en, /* ei enable */
|
|
post_blend_en, /* blend enable */
|
|
blend_mtn_en, /* blend mtn enable */
|
|
post_blend_mode, /* blend mode. */
|
|
di_vpp_en, /* di_vpp_en. */
|
|
di_ddr_en, /* di_ddr_en. */
|
|
post_field_num, /* 1 bottom generate top */
|
|
hold_line,
|
|
post_urgent,
|
|
(invert_mv?1:0),
|
|
pulldown_enable,
|
|
mcpre_en,
|
|
di_vscale_skip_count_real
|
|
);
|
|
}
|
|
|
|
if (is_meson_gxtvbb_cpu() ||
|
|
is_meson_txl_cpu() ||
|
|
is_meson_txlx_cpu() ||
|
|
is_meson_gxlx_cpu() ||
|
|
is_meson_txhd_cpu() ||
|
|
is_meson_g12a_cpu() ||
|
|
is_meson_g12b_cpu() ||
|
|
is_meson_tl1_cpu() ||
|
|
is_meson_tm2_cpu() ||
|
|
is_meson_sm1_cpu()) {
|
|
di_post_read_reverse_irq(overturn, mc_pre_flag,
|
|
post_blend_en ? mcpre_en : false);
|
|
/* disable mc for first 2 fieldes mv unreliable */
|
|
if (di_buf->seq < 2)
|
|
DI_VSYNC_WR_MPEG_REG_BITS(MCDI_MC_CRTL, 0, 0, 2);
|
|
}
|
|
if (mcpre_en) {
|
|
if (di_buf->di_buf_dup_p[2])
|
|
set_post_mcinfo(&di_buf->di_buf_dup_p[2]
|
|
->curr_field_mcinfo);
|
|
} else if (is_meson_gxlx_cpu()
|
|
|| is_meson_txl_cpu()
|
|
|| is_meson_txlx_cpu())
|
|
DI_VSYNC_WR_MPEG_REG_BITS(MCDI_MC_CRTL, 0, 0, 2);
|
|
|
|
/* set pull down region (f(t-1) */
|
|
|
|
if (di_pldn_buf && pulldown_enable &&
|
|
!di_pre_stru.cur_prog_flag) {
|
|
unsigned short offset = (di_start_y>>1);
|
|
|
|
if (overturn)
|
|
offset = ((di_buf->vframe->height - di_end_y)>>1);
|
|
else
|
|
offset = 0;
|
|
pulldown_vof_win_vshift(&di_pldn_buf->pd_config, offset);
|
|
pulldown_vof_win_config(&di_pldn_buf->pd_config);
|
|
}
|
|
|
|
if (di_post_stru.update_post_reg_flag > 0)
|
|
di_post_stru.update_post_reg_flag--;
|
|
ddbg_mod_save(eDI_DBG_MOD_POST_SETE, 0, frame_count);/*dbg*/
|
|
return 0;
|
|
}
|
|
|
|
static void post_de_done_buf_config(void)
|
|
{
|
|
ulong irq_flag2 = 0;
|
|
struct di_buf_s *di_buf = NULL;
|
|
|
|
if (di_post_stru.cur_post_buf == NULL)
|
|
return;
|
|
ddbg_mod_save(eDI_DBG_MOD_POST_DB, 0, frame_count);/*dbg*/
|
|
|
|
di_lock_irqfiq_save(irq_flag2);
|
|
queue_out(di_post_stru.cur_post_buf);
|
|
di_buf = di_post_stru.cur_post_buf;
|
|
if (de_devp->pps_enable && pps_position == 0) {
|
|
di_buf->vframe->width = pps_dstw;
|
|
di_buf->vframe->height = pps_dsth;
|
|
}
|
|
queue_in(di_post_stru.cur_post_buf, QUEUE_POST_READY);
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
vf_notify_receiver(VFM_NAME, VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
|
|
di_post_stru.cur_post_buf = NULL;
|
|
ddbg_mod_save(eDI_DBG_MOD_POST_DE, 0, frame_count);/*dbg*/
|
|
|
|
}
|
|
|
|
static void di_post_process(void)
|
|
{
|
|
struct di_buf_s *di_buf = NULL;
|
|
vframe_t *vf_p = NULL;
|
|
|
|
if (di_post_stru.post_de_busy)
|
|
return;
|
|
if (queue_empty(QUEUE_POST_DOING)) {
|
|
di_post_stru.post_peek_underflow++;
|
|
return;
|
|
}
|
|
|
|
di_buf = get_di_buf_head(QUEUE_POST_DOING);
|
|
if (check_di_buf(di_buf, 20))
|
|
return;
|
|
vf_p = di_buf->vframe;
|
|
if (di_post_stru.run_early_proc_fun_flag) {
|
|
if (vf_p->early_process_fun)
|
|
vf_p->early_process_fun = do_post_wr_fun;
|
|
}
|
|
if (di_buf->process_fun_index) {
|
|
|
|
di_post_stru.post_wr_cnt++;
|
|
de_post_process(
|
|
di_buf, 0, vf_p->width-1,
|
|
0, vf_p->height-1, vf_p);
|
|
di_post_stru.post_de_busy = 1;
|
|
di_post_stru.irq_time = cur_to_msecs();
|
|
} else {
|
|
di_post_stru.de_post_process_done = 1;
|
|
}
|
|
di_post_stru.cur_post_buf = di_buf;
|
|
}
|
|
|
|
static void recycle_vframe_type_post(struct di_buf_s *di_buf)
|
|
{
|
|
int i;
|
|
|
|
if (di_buf == NULL) {
|
|
pr_dbg("%s:Error\n", __func__);
|
|
if (recovery_flag == 0)
|
|
recovery_log_reason = 15;
|
|
|
|
recovery_flag++;
|
|
return;
|
|
}
|
|
if (di_buf->process_fun_index == PROCESS_FUN_DI)
|
|
dec_post_ref_count(di_buf);
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
if (di_buf->di_buf[i])
|
|
queue_in(di_buf->di_buf[i], QUEUE_RECYCLE);
|
|
}
|
|
queue_out(di_buf); /* remove it from display_list_head */
|
|
di_buf->invert_top_bot_flag = 0;
|
|
queue_in(di_buf, QUEUE_POST_FREE);
|
|
}
|
|
|
|
#ifdef DI_BUFFER_DEBUG
|
|
static void
|
|
recycle_vframe_type_post_print(struct di_buf_s *di_buf,
|
|
const char *func,
|
|
const int line)
|
|
{
|
|
int i;
|
|
|
|
di_print("%s:%d ", func, line);
|
|
for (i = 0; i < 2; i++) {
|
|
if (di_buf->di_buf[i])
|
|
di_print("%s[%d]<%d>=>recycle_list; ",
|
|
vframe_type_name[di_buf->di_buf[i]->type],
|
|
di_buf->di_buf[i]->index, i);
|
|
}
|
|
di_print("%s[%d] =>post_free_list\n",
|
|
vframe_type_name[di_buf->type], di_buf->index);
|
|
}
|
|
#endif
|
|
static void set_pulldown_mode(struct di_buf_s *di_buf)
|
|
{
|
|
struct di_buf_s *pre_buf_p = di_buf->di_buf_dup_p[pldn_dly1];
|
|
|
|
if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXBB)) {
|
|
if (pulldown_enable && !di_pre_stru.cur_prog_flag) {
|
|
if (pre_buf_p) {
|
|
di_buf->pd_config.global_mode =
|
|
pre_buf_p->pd_config.global_mode;
|
|
} else {
|
|
pr_err("DI[%s]: index out of range.\n",
|
|
__func__);
|
|
}
|
|
} else {
|
|
di_buf->pd_config.global_mode
|
|
= PULL_DOWN_NORMAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
void drop_frame(int check_drop, int throw_flag, struct di_buf_s *di_buf)
|
|
{
|
|
ulong irq_flag2 = 0;
|
|
int i = 0, drop_flag = 0;
|
|
|
|
di_lock_irqfiq_save(irq_flag2);
|
|
if ((frame_count == 0) && check_drop)
|
|
di_post_stru.start_pts = di_buf->vframe->pts;
|
|
if ((check_drop && (frame_count < start_frame_drop_count))
|
|
|| throw_flag) {
|
|
drop_flag = 1;
|
|
} else {
|
|
if (check_drop && (frame_count == start_frame_drop_count)) {
|
|
if ((di_post_stru.start_pts)
|
|
&& (di_buf->vframe->pts == 0))
|
|
di_buf->vframe->pts = di_post_stru.start_pts;
|
|
di_post_stru.start_pts = 0;
|
|
}
|
|
for (i = 0; i < 3; i++) {
|
|
if (di_buf->di_buf_dup_p[i]) {
|
|
if (di_buf->di_buf_dup_p[i]->vframe->bitdepth !=
|
|
di_buf->vframe->bitdepth) {
|
|
pr_info("%s buf[%d] not match bit mode\n",
|
|
__func__, i);
|
|
drop_flag = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (drop_flag) {
|
|
queue_in(di_buf, QUEUE_TMP);
|
|
recycle_vframe_type_post(di_buf);
|
|
#ifdef DI_BUFFER_DEBUG
|
|
recycle_vframe_type_post_print(
|
|
di_buf, __func__,
|
|
__LINE__);
|
|
#endif
|
|
} else {
|
|
if (post_wr_en && post_wr_support)
|
|
queue_in(di_buf, QUEUE_POST_DOING);
|
|
else
|
|
queue_in(di_buf, QUEUE_POST_READY);
|
|
di_print("DI:%dth %s[%d] => post ready %u ms.\n",
|
|
frame_count, vframe_type_name[di_buf->type], di_buf->index,
|
|
jiffies_to_msecs(jiffies_64 - di_buf->vframe->ready_jiffies64));
|
|
|
|
}
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
}
|
|
|
|
static int process_post_vframe(void)
|
|
{
|
|
/*
|
|
* 1) get buf from post_free_list, config it according to buf
|
|
* in pre_ready_list, send it to post_ready_list
|
|
* (it will be send to post_free_list in di_vf_put())
|
|
* 2) get buf from pre_ready_list, attach it to buf from post_free_list
|
|
* (it will be send to recycle_list in di_vf_put() )
|
|
*/
|
|
ulong irq_flag2 = 0;
|
|
int i = 0;
|
|
int ret = 0;
|
|
int buffer_keep_count = 3;
|
|
struct di_buf_s *di_buf = NULL;
|
|
struct di_buf_s *ready_di_buf;
|
|
struct di_buf_s *p = NULL;/* , *ptmp; */
|
|
int itmp;
|
|
int ready_count = list_count(QUEUE_PRE_READY);
|
|
bool check_drop = false;
|
|
bool di_afbc = false;
|
|
|
|
if (queue_empty(QUEUE_POST_FREE))
|
|
return 0;
|
|
|
|
if (ready_count == 0)
|
|
return 0;
|
|
|
|
ready_di_buf = get_di_buf_head(QUEUE_PRE_READY);
|
|
if ((ready_di_buf == NULL) || (ready_di_buf->vframe == NULL)) {
|
|
|
|
pr_dbg("%s:Error1\n", __func__);
|
|
|
|
if (recovery_flag == 0)
|
|
recovery_log_reason = 16;
|
|
|
|
recovery_flag++;
|
|
return 0;
|
|
}
|
|
|
|
if (ready_di_buf->vframe->type & VIDTYPE_PRE_DI_AFBC) {
|
|
di_afbc = true;
|
|
/*pr_info("di afbc mode 0x%x\n", ready_di_buf->vframe->type);*/
|
|
}
|
|
|
|
if ((ready_di_buf->post_proc_flag) &&
|
|
(ready_count >= buffer_keep_count)) {
|
|
i = 0;
|
|
queue_for_each_entry(p, ptmp, QUEUE_PRE_READY, list) {
|
|
/* if(p->post_proc_flag == 0){ */
|
|
if (p->type == VFRAME_TYPE_IN) {
|
|
ready_di_buf->post_proc_flag = -1;
|
|
ready_di_buf->new_format_flag = 1;
|
|
}
|
|
i++;
|
|
if (i > 2)
|
|
break;
|
|
}
|
|
}
|
|
if (ready_di_buf->post_proc_flag > 0) {
|
|
if (ready_count >= buffer_keep_count) {
|
|
di_lock_irqfiq_save(irq_flag2);
|
|
di_buf = get_di_buf_head(QUEUE_POST_FREE);
|
|
if (check_di_buf(di_buf, 17)) {
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
return 0;
|
|
}
|
|
|
|
queue_out(di_buf);
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
|
|
i = 0;
|
|
queue_for_each_entry(
|
|
p, ptmp, QUEUE_PRE_READY, list) {
|
|
di_buf->di_buf_dup_p[i++] = p;
|
|
if (i >= buffer_keep_count)
|
|
break;
|
|
}
|
|
if (i < buffer_keep_count) {
|
|
|
|
pr_dbg("%s:Error3\n", __func__);
|
|
|
|
if (recovery_flag == 0)
|
|
recovery_log_reason = 18;
|
|
recovery_flag++;
|
|
return 0;
|
|
}
|
|
|
|
memcpy(di_buf->vframe,
|
|
di_buf->di_buf_dup_p[1]->vframe,
|
|
sizeof(vframe_t));
|
|
di_buf->vframe->private_data = di_buf;
|
|
if (di_buf->di_buf_dup_p[1]->post_proc_flag == 3) {
|
|
/* dummy, not for display */
|
|
inc_post_ref_count(di_buf);
|
|
di_buf->di_buf[0] = di_buf->di_buf_dup_p[0];
|
|
di_buf->di_buf[1] = NULL;
|
|
queue_out(di_buf->di_buf[0]);
|
|
di_lock_irqfiq_save(irq_flag2);
|
|
queue_in(di_buf, QUEUE_TMP);
|
|
recycle_vframe_type_post(di_buf);
|
|
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print("%s <dummy>: ", __func__);
|
|
#endif
|
|
} else {
|
|
if (di_buf->di_buf_dup_p[1]->
|
|
post_proc_flag == 2){
|
|
di_buf->pd_config.global_mode
|
|
= PULL_DOWN_BLEND_2;
|
|
/* blend with di_buf->di_buf_dup_p[2] */
|
|
} else {
|
|
set_pulldown_mode(di_buf);
|
|
}
|
|
di_buf->vframe->type =
|
|
VIDTYPE_PROGRESSIVE |
|
|
VIDTYPE_VIU_422 |
|
|
VIDTYPE_VIU_SINGLE_PLANE |
|
|
VIDTYPE_VIU_FIELD |
|
|
VIDTYPE_PRE_INTERLACE;
|
|
if (di_afbc)
|
|
di_buf->vframe->type |=
|
|
VIDTYPE_PRE_DI_AFBC;
|
|
di_buf->vframe->width =
|
|
di_buf->di_buf_dup_p[1]->width_bk;
|
|
if (
|
|
di_buf->di_buf_dup_p[1]->
|
|
new_format_flag) {
|
|
/* if (di_buf->di_buf_dup_p[1]
|
|
* ->post_proc_flag == 2) {
|
|
*/
|
|
di_buf->vframe->
|
|
early_process_fun
|
|
= de_post_disable_fun;
|
|
} else {
|
|
di_buf->vframe->
|
|
early_process_fun
|
|
= do_nothing_fun;
|
|
}
|
|
|
|
if (di_buf->di_buf_dup_p[1]->type
|
|
== VFRAME_TYPE_IN) {
|
|
/* next will be bypass */
|
|
di_buf->vframe->type
|
|
= VIDTYPE_PROGRESSIVE |
|
|
VIDTYPE_VIU_422 |
|
|
VIDTYPE_VIU_SINGLE_PLANE |
|
|
VIDTYPE_VIU_FIELD |
|
|
VIDTYPE_PRE_INTERLACE;
|
|
if (di_afbc)
|
|
di_buf->vframe->type |=
|
|
VIDTYPE_PRE_DI_AFBC;
|
|
|
|
di_buf->vframe->height >>= 1;
|
|
di_buf->vframe->canvas0Addr =
|
|
di_buf->di_buf_dup_p[0]
|
|
->nr_canvas_idx; /* top */
|
|
di_buf->vframe->canvas1Addr =
|
|
di_buf->di_buf_dup_p[0]
|
|
->nr_canvas_idx;
|
|
di_buf->vframe->process_fun =
|
|
NULL;
|
|
di_buf->process_fun_index =
|
|
PROCESS_FUN_NULL;
|
|
} else {
|
|
/*for debug*/
|
|
if (debug_blend_mode != -1)
|
|
di_buf->pd_config.global_mode
|
|
= debug_blend_mode;
|
|
|
|
di_buf->vframe->process_fun =
|
|
((post_wr_en && post_wr_support) ? NULL : de_post_process);
|
|
di_buf->process_fun_index =
|
|
PROCESS_FUN_DI;
|
|
inc_post_ref_count(di_buf);
|
|
}
|
|
di_buf->di_buf[0]
|
|
= di_buf->di_buf_dup_p[0];
|
|
di_buf->di_buf[1] = NULL;
|
|
queue_out(di_buf->di_buf[0]);
|
|
|
|
drop_frame(true,
|
|
(di_buf->di_buf_dup_p[0]->throw_flag) ||
|
|
(di_buf->di_buf_dup_p[1]->throw_flag) ||
|
|
(di_buf->di_buf_dup_p[2]->throw_flag),
|
|
di_buf);
|
|
|
|
frame_count++;
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print("%s <interlace>: ", __func__);
|
|
#endif
|
|
if (!(post_wr_en && post_wr_support))
|
|
vf_notify_receiver(VFM_NAME,
|
|
VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
|
|
}
|
|
ret = 1;
|
|
}
|
|
} else {
|
|
if (is_progressive(ready_di_buf->vframe) ||
|
|
ready_di_buf->type == VFRAME_TYPE_IN ||
|
|
ready_di_buf->post_proc_flag < 0 ||
|
|
bypass_post_state
|
|
){
|
|
int vframe_process_count = 1;
|
|
#ifdef DET3D
|
|
int dual_vframe_flag = 0;
|
|
|
|
if ((di_pre_stru.vframe_interleave_flag &&
|
|
ready_di_buf->left_right) ||
|
|
(bypass_post & 0x100)) {
|
|
dual_vframe_flag = 1;
|
|
vframe_process_count = 2;
|
|
}
|
|
#endif
|
|
if (skip_top_bot &&
|
|
(!is_progressive(ready_di_buf->vframe)))
|
|
vframe_process_count = 2;
|
|
|
|
if (ready_count >= vframe_process_count) {
|
|
struct di_buf_s *di_buf_i;
|
|
|
|
di_lock_irqfiq_save(irq_flag2);
|
|
di_buf = get_di_buf_head(QUEUE_POST_FREE);
|
|
if (check_di_buf(di_buf, 19)) {
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
return 0;
|
|
}
|
|
|
|
queue_out(di_buf);
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
|
|
i = 0;
|
|
queue_for_each_entry(
|
|
p, ptmp, QUEUE_PRE_READY, list){
|
|
di_buf->di_buf_dup_p[i++] = p;
|
|
if (i >= vframe_process_count) {
|
|
di_buf->di_buf_dup_p[i] = NULL;
|
|
di_buf->di_buf_dup_p[i+1] =
|
|
NULL;
|
|
break;
|
|
}
|
|
}
|
|
if (i < vframe_process_count) {
|
|
pr_dbg("%s:Error6\n", __func__);
|
|
if (recovery_flag == 0)
|
|
recovery_log_reason = 22;
|
|
|
|
recovery_flag++;
|
|
return 0;
|
|
}
|
|
|
|
di_buf_i = di_buf->di_buf_dup_p[0];
|
|
if (!is_progressive(ready_di_buf->vframe)
|
|
&& ((skip_top_bot == 1)
|
|
|| (skip_top_bot == 2))) {
|
|
unsigned int frame_type =
|
|
di_buf->di_buf_dup_p[1]->
|
|
vframe->type & VIDTYPE_TYPEMASK;
|
|
if (skip_top_bot == 1) {
|
|
di_buf_i = (frame_type ==
|
|
VIDTYPE_INTERLACE_TOP)
|
|
? di_buf->di_buf_dup_p[1]
|
|
: di_buf->di_buf_dup_p[0];
|
|
} else if (skip_top_bot == 2) {
|
|
di_buf_i = (frame_type ==
|
|
VIDTYPE_INTERLACE_BOTTOM)
|
|
? di_buf->di_buf_dup_p[1]
|
|
: di_buf->di_buf_dup_p[0];
|
|
}
|
|
}
|
|
|
|
memcpy(di_buf->vframe,
|
|
di_buf_i->vframe,
|
|
sizeof(vframe_t));
|
|
di_buf->vframe->width = di_buf_i->width_bk;
|
|
di_buf->vframe->private_data = di_buf;
|
|
|
|
if (ready_di_buf->new_format_flag &&
|
|
(ready_di_buf->type == VFRAME_TYPE_IN)) {
|
|
pr_info("DI:%d disable post.\n",
|
|
__LINE__);
|
|
di_buf->vframe->early_process_fun
|
|
= de_post_disable_fun;
|
|
} else {
|
|
if (ready_di_buf->type ==
|
|
VFRAME_TYPE_IN)
|
|
di_buf->vframe->
|
|
early_process_fun
|
|
= do_nothing_fun;
|
|
|
|
else
|
|
di_buf->vframe->
|
|
early_process_fun
|
|
= do_pre_only_fun;
|
|
}
|
|
if (ready_di_buf->post_proc_flag == -2) {
|
|
di_buf->vframe->type
|
|
|= VIDTYPE_VIU_FIELD;
|
|
di_buf->vframe->type
|
|
&= ~(VIDTYPE_TYPEMASK);
|
|
if (di_afbc)
|
|
di_buf->vframe->type |=
|
|
VIDTYPE_PRE_DI_AFBC;
|
|
|
|
di_buf->vframe->process_fun
|
|
= (post_wr_en && post_wr_support)?NULL:de_post_process;
|
|
di_buf->process_fun_index
|
|
= PROCESS_FUN_DI;
|
|
di_buf->pd_config.global_mode
|
|
= PULL_DOWN_EI;
|
|
} else {
|
|
di_buf->vframe->process_fun =
|
|
NULL;
|
|
di_buf->process_fun_index =
|
|
PROCESS_FUN_NULL;
|
|
di_buf->pd_config.global_mode =
|
|
PULL_DOWN_NORMAL;
|
|
}
|
|
di_buf->di_buf[0] = ready_di_buf;
|
|
di_buf->di_buf[1] = NULL;
|
|
queue_out(ready_di_buf);
|
|
|
|
#ifdef DET3D
|
|
if (dual_vframe_flag) {
|
|
di_buf->di_buf[1] =
|
|
di_buf->di_buf_dup_p[1];
|
|
queue_out(di_buf->di_buf[1]);
|
|
}
|
|
#endif
|
|
drop_frame(check_drop,
|
|
di_buf->di_buf[0]->throw_flag, di_buf);
|
|
|
|
frame_count++;
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print(
|
|
"%s <prog by frame>: ",
|
|
__func__);
|
|
#endif
|
|
ret = 1;
|
|
vf_notify_receiver(VFM_NAME,
|
|
VFRAME_EVENT_PROVIDER_VFRAME_READY,
|
|
NULL);
|
|
}
|
|
} else if (ready_count >= 2) {
|
|
/*for progressive input,type
|
|
* 1:separate tow fields,type
|
|
* 2:bypass post as frame
|
|
*/
|
|
unsigned char prog_tb_field_proc_type =
|
|
(prog_proc_config >> 1) & 0x3;
|
|
di_lock_irqfiq_save(irq_flag2);
|
|
di_buf = get_di_buf_head(QUEUE_POST_FREE);
|
|
|
|
if (check_di_buf(di_buf, 20)) {
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
return 0;
|
|
}
|
|
|
|
queue_out(di_buf);
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
|
|
i = 0;
|
|
queue_for_each_entry(
|
|
p, ptmp, QUEUE_PRE_READY, list) {
|
|
di_buf->di_buf_dup_p[i++] = p;
|
|
if (i >= 2) {
|
|
di_buf->di_buf_dup_p[i] = NULL;
|
|
break;
|
|
}
|
|
}
|
|
if (i < 2) {
|
|
pr_dbg("%s:Error6\n", __func__);
|
|
|
|
if (recovery_flag == 0)
|
|
recovery_log_reason = 21;
|
|
|
|
recovery_flag++;
|
|
return 0;
|
|
}
|
|
|
|
memcpy(di_buf->vframe,
|
|
di_buf->di_buf_dup_p[0]->vframe,
|
|
sizeof(vframe_t));
|
|
di_buf->vframe->private_data = di_buf;
|
|
|
|
/*separate one progressive frame
|
|
* as two interlace fields
|
|
*/
|
|
if (prog_tb_field_proc_type == 1) {
|
|
/* do weave by di post */
|
|
di_buf->vframe->type =
|
|
VIDTYPE_PROGRESSIVE |
|
|
VIDTYPE_VIU_422 |
|
|
VIDTYPE_VIU_SINGLE_PLANE |
|
|
VIDTYPE_VIU_FIELD |
|
|
VIDTYPE_PRE_INTERLACE;
|
|
if (di_afbc)
|
|
di_buf->vframe->type |=
|
|
VIDTYPE_PRE_DI_AFBC;
|
|
|
|
if (
|
|
di_buf->di_buf_dup_p[0]->
|
|
new_format_flag)
|
|
di_buf->vframe->
|
|
early_process_fun =
|
|
de_post_disable_fun;
|
|
else
|
|
di_buf->vframe->
|
|
early_process_fun =
|
|
do_nothing_fun;
|
|
|
|
di_buf->pd_config.global_mode =
|
|
PULL_DOWN_BUF1;
|
|
di_buf->vframe->process_fun =
|
|
(post_wr_en && post_wr_support)?NULL:de_post_process;
|
|
di_buf->process_fun_index =
|
|
PROCESS_FUN_DI;
|
|
} else if (prog_tb_field_proc_type == 0) {
|
|
/* to do: need change for
|
|
* DI_USE_FIXED_CANVAS_IDX
|
|
*/
|
|
/* do weave by vpp */
|
|
di_buf->vframe->type =
|
|
VIDTYPE_PROGRESSIVE |
|
|
VIDTYPE_VIU_422 |
|
|
VIDTYPE_VIU_SINGLE_PLANE;
|
|
if (di_afbc)
|
|
di_buf->vframe->type |=
|
|
VIDTYPE_PRE_DI_AFBC;
|
|
|
|
if (
|
|
(di_buf->di_buf_dup_p[0]->
|
|
new_format_flag) ||
|
|
(Rd(DI_IF1_GEN_REG) & 1))
|
|
di_buf->vframe->
|
|
early_process_fun =
|
|
de_post_disable_fun;
|
|
else
|
|
di_buf->vframe->
|
|
early_process_fun =
|
|
do_nothing_fun;
|
|
di_buf->vframe->process_fun = NULL;
|
|
di_buf->process_fun_index =
|
|
PROCESS_FUN_NULL;
|
|
di_buf->vframe->canvas0Addr =
|
|
di_buf->di_buf_dup_p[0]->
|
|
nr_canvas_idx;
|
|
di_buf->vframe->canvas1Addr =
|
|
di_buf->di_buf_dup_p[1]->
|
|
nr_canvas_idx;
|
|
} else {
|
|
/* to do: need change for
|
|
* DI_USE_FIXED_CANVAS_IDX
|
|
*/
|
|
di_buf->vframe->type =
|
|
VIDTYPE_PROGRESSIVE |
|
|
VIDTYPE_VIU_422 |
|
|
VIDTYPE_VIU_SINGLE_PLANE |
|
|
VIDTYPE_VIU_FIELD |
|
|
VIDTYPE_PRE_INTERLACE;
|
|
if (di_afbc)
|
|
di_buf->vframe->type |=
|
|
VIDTYPE_PRE_DI_AFBC;
|
|
|
|
di_buf->vframe->height >>= 1;
|
|
di_buf->vframe->width =
|
|
di_buf->di_buf_dup_p[0]->width_bk;
|
|
if (
|
|
(di_buf->di_buf_dup_p[0]->
|
|
new_format_flag) ||
|
|
(Rd(DI_IF1_GEN_REG) & 1))
|
|
di_buf->vframe->
|
|
early_process_fun =
|
|
de_post_disable_fun;
|
|
else
|
|
di_buf->vframe->
|
|
early_process_fun =
|
|
do_nothing_fun;
|
|
if (prog_tb_field_proc_type == 2) {
|
|
di_buf->vframe->canvas0Addr =
|
|
di_buf->di_buf_dup_p[0]
|
|
->nr_canvas_idx;
|
|
/* top */
|
|
di_buf->vframe->canvas1Addr =
|
|
di_buf->di_buf_dup_p[0]
|
|
->nr_canvas_idx;
|
|
} else {
|
|
di_buf->vframe->canvas0Addr =
|
|
di_buf->di_buf_dup_p[1]
|
|
->nr_canvas_idx; /* top */
|
|
di_buf->vframe->canvas1Addr =
|
|
di_buf->di_buf_dup_p[1]
|
|
->nr_canvas_idx;
|
|
}
|
|
}
|
|
|
|
di_buf->di_buf[0] = di_buf->di_buf_dup_p[0];
|
|
queue_out(di_buf->di_buf[0]);
|
|
/*check if the field is error,then drop*/
|
|
if (
|
|
(di_buf->di_buf_dup_p[0]->vframe->type &
|
|
VIDTYPE_TYPEMASK) ==
|
|
VIDTYPE_INTERLACE_BOTTOM) {
|
|
di_buf->di_buf[1] =
|
|
di_buf->di_buf_dup_p[1] = NULL;
|
|
queue_in(di_buf, QUEUE_TMP);
|
|
recycle_vframe_type_post(di_buf);
|
|
pr_dbg("%s drop field %d.\n", __func__,
|
|
di_buf->di_buf_dup_p[0]->seq);
|
|
} else {
|
|
di_buf->di_buf[1] =
|
|
di_buf->di_buf_dup_p[1];
|
|
queue_out(di_buf->di_buf[1]);
|
|
|
|
drop_frame(check_start_drop_prog,
|
|
(di_buf->di_buf_dup_p[0]->throw_flag) ||
|
|
(di_buf->di_buf_dup_p[1]->throw_flag),
|
|
di_buf);
|
|
}
|
|
frame_count++;
|
|
#ifdef DI_BUFFER_DEBUG
|
|
di_print("%s <prog by field>: ", __func__);
|
|
#endif
|
|
ret = 1;
|
|
vf_notify_receiver(VFM_NAME,
|
|
VFRAME_EVENT_PROVIDER_VFRAME_READY,
|
|
NULL);
|
|
}
|
|
}
|
|
|
|
#ifdef DI_BUFFER_DEBUG
|
|
if (di_buf) {
|
|
di_print("%s[%d](",
|
|
vframe_type_name[di_buf->type], di_buf->index);
|
|
for (i = 0; i < 2; i++) {
|
|
if (di_buf->di_buf[i])
|
|
di_print("%s[%d],",
|
|
vframe_type_name[di_buf->di_buf[i]->type],
|
|
di_buf->di_buf[i]->index);
|
|
}
|
|
di_print(")(vframe type %x dur %d)",
|
|
di_buf->vframe->type, di_buf->vframe->duration);
|
|
if (di_buf->di_buf_dup_p[1] &&
|
|
(di_buf->di_buf_dup_p[1]->post_proc_flag == 3))
|
|
di_print("=> recycle_list\n");
|
|
else
|
|
di_print("=> post_ready_list\n");
|
|
}
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
void di_vpu_dev_register(struct di_dev_s *vdevp)
|
|
{
|
|
vdevp->di_vpu_clk_gate_dev = vpu_dev_register(VPU_VPU_CLKB,
|
|
DEVICE_NAME);
|
|
vdevp->di_vpu_pd_dec = vpu_dev_register(VPU_AFBC_DEC,
|
|
DEVICE_NAME);
|
|
vdevp->di_vpu_pd_dec1 = vpu_dev_register(VPU_AFBC_DEC1,
|
|
DEVICE_NAME);
|
|
vdevp->di_vpu_pd_vd1 = vpu_dev_register(VPU_VIU_VD1,
|
|
DEVICE_NAME);
|
|
vdevp->di_vpu_pd_post = vpu_dev_register(VPU_DI_POST,
|
|
DEVICE_NAME);
|
|
}
|
|
/*
|
|
* di task
|
|
*/
|
|
static void di_unreg_process(void)
|
|
{
|
|
unsigned long start_jiffes = 0;
|
|
if (reg_flag) {
|
|
pr_dbg("%s unreg start %d.\n", __func__, reg_flag);
|
|
start_jiffes = jiffies_64;
|
|
vf_unreg_provider(&di_vf_prov);
|
|
pr_dbg("%s vf unreg cost %u ms.\n", __func__,
|
|
jiffies_to_msecs(jiffies_64 - start_jiffes));
|
|
unreg_cnt++;
|
|
if (unreg_cnt > 0x3fffffff)
|
|
unreg_cnt = 0;
|
|
pr_dbg("%s unreg stop %d.\n", __func__, reg_flag);
|
|
di_pre_stru.unreg_req_flag_irq = 1;
|
|
reg_flag = 0;
|
|
trigger_pre_di_process(TRIGGER_PRE_BY_UNREG);
|
|
} else {
|
|
di_pre_stru.force_unreg_req_flag = 0;
|
|
di_pre_stru.disable_req_flag = 0;
|
|
recovery_flag = 0;
|
|
di_pre_stru.unreg_req_flag = 0;
|
|
trigger_pre_di_process(TRIGGER_PRE_BY_UNREG);
|
|
}
|
|
}
|
|
|
|
static void di_unreg_process_irq(void)
|
|
{
|
|
ulong irq_flag2 = 0;
|
|
unsigned int mirror_disable = 0;
|
|
#if (defined ENABLE_SPIN_LOCK_ALWAYS)
|
|
ulong flags = 0;
|
|
spin_lock_irqsave(&plist_lock, flags);
|
|
#endif
|
|
init_flag = 0;
|
|
mirror_disable = get_blackout_policy();
|
|
di_lock_irqfiq_save(irq_flag2);
|
|
di_print("%s: di_uninit_buf\n", __func__);
|
|
di_uninit_buf(mirror_disable);
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_RDMA
|
|
if (di_pre_rdma_enable)
|
|
rdma_clear(de_devp->rdma_handle);
|
|
#endif
|
|
adpative_combing_exit();
|
|
enable_di_pre_mif(false, mcpre_en);
|
|
/*disable afbc module when afbc working in DI*/
|
|
afbc_reg_unreg_flag = 0;
|
|
#if 0
|
|
if (IS_COMP_MODE(di_pre_stru.cur_inp_type) &&
|
|
(!needbypass_flag && !isbypass_flag)) {
|
|
pr_info("DI: disable afbc\n");
|
|
afbc_reg_sw(false);
|
|
afbc_input_sw(false);
|
|
}
|
|
#endif
|
|
di_hw_uninit();
|
|
if (is_meson_txlx_cpu() || is_meson_txhd_cpu()
|
|
|| is_meson_g12a_cpu() || is_meson_g12b_cpu()
|
|
|| is_meson_tl1_cpu() || is_meson_sm1_cpu() ||
|
|
is_meson_tm2_cpu()) {
|
|
di_pre_gate_control(false, mcpre_en);
|
|
di_nr_opl()->nr_gate_control(false);
|
|
} else if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXTVBB)) {
|
|
DI_Wr(DI_CLKG_CTRL, 0x80f60000);
|
|
DI_Wr(DI_PRE_CTRL, 0);
|
|
}
|
|
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
|
|
else
|
|
DI_Wr(DI_CLKG_CTRL, 0xf60000);
|
|
#endif
|
|
/* nr/blend0/ei0/mtn0 clock gate */
|
|
if (mirror_disable) {
|
|
di_hw_disable(mcpre_en);
|
|
if (is_meson_txlx_cpu() || is_meson_txhd_cpu()
|
|
|| is_meson_g12a_cpu() || is_meson_g12b_cpu()
|
|
|| is_meson_tl1_cpu() || is_meson_sm1_cpu() ||
|
|
is_meson_tm2_cpu()) {
|
|
enable_di_post_mif(GATE_OFF);
|
|
di_post_gate_control(false);
|
|
di_top_gate_control(false, false);
|
|
} else {
|
|
DI_Wr(DI_CLKG_CTRL, 0x80000000);
|
|
}
|
|
if (!is_meson_gxl_cpu() && !is_meson_gxm_cpu() &&
|
|
!is_meson_gxbb_cpu() && !is_meson_txlx_cpu())
|
|
vpu_dev_clk_gate_off(de_devp->di_vpu_clk_gate_dev);
|
|
pr_info("%s disable di mirror image.\n", __func__);
|
|
}
|
|
if (post_wr_en && post_wr_support)
|
|
diwr_set_power_control(0);
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
|
|
#if (defined ENABLE_SPIN_LOCK_ALWAYS)
|
|
spin_unlock_irqrestore(&plist_lock, flags);
|
|
#endif
|
|
di_patch_post_update_mc_sw(DI_MC_SW_REG, false);
|
|
di_pre_stru.force_unreg_req_flag = 0;
|
|
di_pre_stru.disable_req_flag = 0;
|
|
recovery_flag = 0;
|
|
di_pre_stru.cur_prog_flag = 0;
|
|
di_pre_stru.unreg_req_flag = 0;
|
|
di_pre_stru.unreg_req_flag_irq = 0;
|
|
#ifdef CONFIG_CMA
|
|
if (de_devp->flag_cma == 1 ||
|
|
(de_devp->flag_cma == 3) ||
|
|
(de_devp->flag_cma == 4)) {
|
|
pr_dbg("%s:cma release req time: %d ms\n",
|
|
__func__, jiffies_to_msecs(jiffies));
|
|
di_pre_stru.cma_release_req = 1;
|
|
up(&di_sema);
|
|
}
|
|
#endif
|
|
/*dbg*/
|
|
pr_info("di:retry cnt=%d\n", di_pre_stru.retry_cnt);
|
|
}
|
|
|
|
static void di_reg_process(void)
|
|
{
|
|
/*get vout information first time*/
|
|
if (reg_flag == 1)
|
|
return;
|
|
vf_reg_provider(&di_vf_prov);
|
|
vf_notify_receiver(VFM_NAME, VFRAME_EVENT_PROVIDER_START, NULL);
|
|
reg_flag = 1;
|
|
di_pre_stru.bypass_flag = false;
|
|
reg_cnt++;
|
|
if (reg_cnt > 0x3fffffff)
|
|
reg_cnt = 0;
|
|
di_print("########%s\n", __func__);
|
|
}
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_RDMA
|
|
/* di pre rdma operation */
|
|
static void di_rdma_irq(void *arg)
|
|
{
|
|
struct di_dev_s *di_devp = (struct di_dev_s *)arg;
|
|
|
|
if (IS_ERR_OR_NULL(di_devp))
|
|
return;
|
|
if (di_devp->rdma_handle <= 0) {
|
|
pr_err("%s rdma handle %d error.\n", __func__,
|
|
di_devp->rdma_handle);
|
|
return;
|
|
}
|
|
if (di_printk_flag)
|
|
pr_dbg("%s...%d.\n", __func__,
|
|
di_pre_stru.field_count_for_cont);
|
|
}
|
|
|
|
static struct rdma_op_s di_rdma_op = {
|
|
di_rdma_irq,
|
|
NULL
|
|
};
|
|
#endif
|
|
|
|
static void di_load_pq_table(void)
|
|
{
|
|
struct di_pq_parm_s *pos = NULL, *tmp = NULL;
|
|
|
|
if (atomic_read(&de_devp->pq_flag) == 0 &&
|
|
(de_devp->flags & DI_LOAD_REG_FLAG)) {
|
|
atomic_set(&de_devp->pq_flag, 1);
|
|
list_for_each_entry_safe(pos, tmp,
|
|
&de_devp->pq_table_list, list) {
|
|
di_load_regs(pos);
|
|
list_del(&pos->list);
|
|
di_pq_parm_destroy(pos);
|
|
}
|
|
de_devp->flags &= ~DI_LOAD_REG_FLAG;
|
|
atomic_set(&de_devp->pq_flag, 0);
|
|
}
|
|
}
|
|
|
|
static void di_pre_size_change(unsigned short width,
|
|
unsigned short height, unsigned short vf_type)
|
|
{
|
|
unsigned int blkhsize = 0;
|
|
int pps_w = 0, pps_h = 0;
|
|
struct nr_cfg_s cfg_data;
|
|
struct nr_cfg_s *cfg = &cfg_data;
|
|
|
|
cfg->width = width;
|
|
cfg->height = height;
|
|
cfg->linkflag = 0;
|
|
di_nr_opl()->nr_all_config(vf_type, cfg);
|
|
#ifdef DET3D
|
|
det3d_config(det3d_en ? 1 : 0);
|
|
#endif
|
|
if (pulldown_enable) {
|
|
pulldown_init(width, height);
|
|
init_field_mode(height);
|
|
|
|
if (is_meson_txl_cpu() ||
|
|
is_meson_txlx_cpu() ||
|
|
is_meson_gxlx_cpu() ||
|
|
is_meson_txhd_cpu() ||
|
|
is_meson_g12a_cpu() ||
|
|
is_meson_g12b_cpu() ||
|
|
is_meson_tl1_cpu() || is_meson_tm2_cpu() ||
|
|
is_meson_sm1_cpu())
|
|
film_mode_win_config(width, height);
|
|
}
|
|
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXL))
|
|
combing_pd22_window_config(width, height);
|
|
RDMA_WR(DI_PRE_SIZE, (width - 1) |
|
|
((height - 1) << 16));
|
|
|
|
if (mcpre_en) {
|
|
blkhsize = (width + 4) / 5;
|
|
RDMA_WR(MCDI_HV_SIZEIN, height
|
|
| (width << 16));
|
|
RDMA_WR(MCDI_HV_BLKSIZEIN, (overturn ? 3 : 0) << 30
|
|
| blkhsize << 16 | height);
|
|
RDMA_WR(MCDI_BLKTOTAL, blkhsize * height);
|
|
if (is_meson_gxlx_cpu()) {
|
|
RDMA_WR(MCDI_PD_22_CHK_FLG_CNT, 0);
|
|
RDMA_WR(MCDI_FIELD_MV, 0);
|
|
}
|
|
}
|
|
|
|
di_load_pq_table();
|
|
|
|
if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A))
|
|
RDMA_WR(DI_PRE_GL_CTRL, 0x80000005);
|
|
if (de_devp->nrds_enable)
|
|
nr_ds_init(width, height);
|
|
if (de_devp->pps_enable && pps_position) {
|
|
pps_w = di_pre_stru.cur_width;
|
|
pps_h = di_pre_stru.cur_height>>1;
|
|
di_pps_config(1, pps_w, pps_h, pps_dstw, (pps_dsth>>1));
|
|
}
|
|
|
|
if (de_devp->h_sc_down_en) {
|
|
pps_w = di_pre_stru.cur_width;
|
|
di_inp_hsc_setting(pps_w, pre_hsc_down_width);
|
|
} else {
|
|
di_inp_hsc_setting(di_pre_stru.cur_width,
|
|
di_pre_stru.cur_width);
|
|
}
|
|
|
|
di_interrupt_ctrl(di_pre_stru.madi_enable,
|
|
det3d_en?1:0,
|
|
de_devp->nrds_enable,
|
|
post_wr_en,
|
|
di_pre_stru.mcdi_enable);
|
|
}
|
|
|
|
void di_vf_x_y(struct vframe_s *vf, unsigned int *x, unsigned int *y)
|
|
{
|
|
*x = 0;
|
|
*y = 0;
|
|
|
|
if (!vf)
|
|
return;
|
|
*x = vf->width;
|
|
*y = vf->height;
|
|
|
|
if (vf->type & VIDTYPE_COMPRESS) {
|
|
*x = vf->compWidth;
|
|
*y = vf->compHeight;
|
|
}
|
|
}
|
|
|
|
static bool need_bypass(struct vframe_s *vf)
|
|
{
|
|
unsigned int x, y;
|
|
|
|
needbypass_flag = true;
|
|
|
|
di_vf_x_y(vf, &x, &y);
|
|
|
|
if (vf->type & VIDTYPE_MVC)
|
|
return true;
|
|
|
|
if (vf->source_type == VFRAME_SOURCE_TYPE_PPMGR)
|
|
return true;
|
|
|
|
if (vf->type & VIDTYPE_VIU_444)
|
|
return true;
|
|
|
|
if (vf->type & VIDTYPE_PIC)
|
|
return true;
|
|
#if 0
|
|
if (vf->type & VIDTYPE_COMPRESS)
|
|
return true;
|
|
#else
|
|
/*support G12A and TXLX platform*/
|
|
if (vf->type & VIDTYPE_COMPRESS) {
|
|
if (!afbc_is_supported())
|
|
return true;
|
|
if ((y > (default_height + 8)) ||
|
|
x > default_width)
|
|
return true;
|
|
}
|
|
#endif
|
|
if ((vf->width > default_width) ||
|
|
(vf->height > (default_height + 8)))
|
|
return true;
|
|
|
|
/*true bypass for game mode*/
|
|
if (vf->flag & VFRAME_FLAG_GAME_MODE)
|
|
return true;
|
|
|
|
needbypass_flag = false;
|
|
return false;
|
|
}
|
|
|
|
static void di_reg_process_irq(void)
|
|
{
|
|
ulong irq_flag2 = 0;
|
|
#ifndef RUN_DI_PROCESS_IN_IRQ
|
|
ulong flags = 0;
|
|
#endif
|
|
vframe_t *vframe;
|
|
unsigned short nr_height = 0, first_field_type;
|
|
|
|
if ((pre_run_flag != DI_RUN_FLAG_RUN) &&
|
|
(pre_run_flag != DI_RUN_FLAG_STEP))
|
|
return;
|
|
if (pre_run_flag == DI_RUN_FLAG_STEP)
|
|
pre_run_flag = DI_RUN_FLAG_STEP_DONE;
|
|
|
|
di_pre_stru.reg_irq_busy = true;
|
|
|
|
vframe = vf_peek(VFM_NAME);
|
|
|
|
if (vframe) {
|
|
if (need_bypass(vframe) || ((di_debug_flag>>20) & 0x1)) {
|
|
if (!di_pre_stru.bypass_flag) {
|
|
pr_info("DI bypass all %ux%u-0x%x.",
|
|
vframe->width, vframe->height, vframe->type);
|
|
}
|
|
di_pre_stru.bypass_flag = true;
|
|
di_patch_post_update_mc_sw(DI_MC_SW_OTHER, false);
|
|
di_pre_stru.reg_irq_busy = false;
|
|
return;
|
|
} else {
|
|
di_pre_stru.bypass_flag = false;
|
|
}
|
|
/* patch for vdin progressive input */
|
|
if ((is_from_vdin(vframe) &&
|
|
is_progressive(vframe))
|
|
#ifdef DET3D
|
|
|| det3d_en
|
|
#endif
|
|
|| (use_2_interlace_buff & 0x2)
|
|
) {
|
|
use_2_interlace_buff = 1;
|
|
nr_height = vframe->height;
|
|
} else {
|
|
use_2_interlace_buff = 0;
|
|
nr_height = (vframe->height>>1);
|
|
}
|
|
de_devp->nrds_enable = nrds_en;
|
|
de_devp->pps_enable = pps_en;
|
|
/*di pre h scaling down: sm1 tm2*/
|
|
de_devp->h_sc_down_en = pre_hsc_down_en;
|
|
vpu_dev_clk_gate_on(de_devp->di_vpu_clk_gate_dev);
|
|
diwr_set_power_control_pst(1);
|
|
if (post_wr_en && post_wr_support)
|
|
diwr_set_power_control(1);
|
|
/* up for vpu clkb rate change */
|
|
up(&di_sema);
|
|
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXLX)) {
|
|
if (!use_2_interlace_buff) {
|
|
di_top_gate_control(true, true);
|
|
di_post_gate_control(true);
|
|
/* freerun for reg configuration */
|
|
enable_di_post_mif(GATE_AUTO);
|
|
} else {
|
|
di_top_gate_control(true, false);
|
|
}
|
|
de_devp->flags |= DI_VPU_CLKB_SET;
|
|
enable_di_pre_mif(false, mcpre_en);
|
|
di_pre_gate_control(true, mcpre_en);
|
|
di_rst_protect(true);/*2019-01-22 by VLSI feng.wang*/
|
|
di_pre_nr_wr_done_sel(true);
|
|
di_nr_opl()->nr_gate_control(true);
|
|
} else {
|
|
/* if mcdi enable DI_CLKG_CTRL should be 0xfef60000 */
|
|
DI_Wr(DI_CLKG_CTRL, 0xfef60001);
|
|
/* nr/blend0/ei0/mtn0 clock gate */
|
|
}
|
|
di_hdr2_hist_init();
|
|
if (di_printk_flag & 2)
|
|
di_printk_flag = 1;
|
|
|
|
di_print("%s: vframe come => di_init_buf\n", __func__);
|
|
if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXLX))
|
|
di_wr_cue_int();
|
|
|
|
if (is_progressive(vframe) && (prog_proc_config & 0x10)) {
|
|
#if (!(defined RUN_DI_PROCESS_IN_IRQ)) || (defined ENABLE_SPIN_LOCK_ALWAYS)
|
|
spin_lock_irqsave(&plist_lock, flags);
|
|
#endif
|
|
di_lock_irqfiq_save(irq_flag2);
|
|
/*
|
|
* 10 bit mode need 1.5 times buffer size of
|
|
* 8 bit mode, init the buffer size as 10 bit
|
|
* mode size, to make sure can switch bit mode
|
|
* smoothly.
|
|
*/
|
|
di_init_buf(default_width, default_height, 1);
|
|
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
|
|
#if (!(defined RUN_DI_PROCESS_IN_IRQ)) || (defined ENABLE_SPIN_LOCK_ALWAYS)
|
|
spin_unlock_irqrestore(&plist_lock, flags);
|
|
nr_height = vframe->height;
|
|
#endif
|
|
} else {
|
|
#if (!(defined RUN_DI_PROCESS_IN_IRQ)) || (defined ENABLE_SPIN_LOCK_ALWAYS)
|
|
spin_lock_irqsave(&plist_lock, flags);
|
|
#endif
|
|
di_lock_irqfiq_save(irq_flag2);
|
|
/*
|
|
* 10 bit mode need 1.5 times buffer size of
|
|
* 8 bit mode, init the buffer size as 10 bit
|
|
* mode size, to make sure can switch bit mode
|
|
* smoothly.
|
|
*/
|
|
di_init_buf(default_width, default_height, 0);
|
|
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
|
|
#if (!(defined RUN_DI_PROCESS_IN_IRQ)) || (defined ENABLE_SPIN_LOCK_ALWAYS)
|
|
spin_unlock_irqrestore(&plist_lock, flags);
|
|
#endif
|
|
}
|
|
if (!reg_flag)
|
|
pr_err("di: warning unreg in reg irq\n");
|
|
|
|
calc_lmv_init();
|
|
first_field_type = (vframe->type & VIDTYPE_TYPEMASK);
|
|
|
|
//pr_info("%s , %d\n", __func__, __LINE__);
|
|
//pr_info("filed type:0x%x, in H=%d, V=%d\n",
|
|
// first_field_type, vframe->width, nr_height);
|
|
di_pre_size_change(vframe->width, nr_height,
|
|
first_field_type);
|
|
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_TVIN
|
|
di_pre_stru.mtn_status =
|
|
adpative_combing_config(vframe->width,
|
|
(vframe->height>>1),
|
|
(vframe->source_type),
|
|
is_progressive(vframe),
|
|
vframe->sig_fmt);
|
|
#endif
|
|
|
|
di_patch_post_update_mc_sw(DI_MC_SW_REG, true);
|
|
di_nr_opl()->cue_int(vframe);
|
|
if (de_devp->flags & DI_LOAD_REG_FLAG)
|
|
up(&di_sema);
|
|
|
|
di_pre_stru.retry_en = false;
|
|
di_pre_stru.retry_cnt = 0;
|
|
di_pre_stru.retry_index = 0;
|
|
|
|
init_flag = 1;
|
|
/*di_pre_stru.reg_req_flag_irq = 1;*/
|
|
}
|
|
di_pre_stru.reg_irq_busy = false;
|
|
}
|
|
|
|
static void di_process(void)
|
|
{
|
|
ulong irq_flag2 = 0;
|
|
#ifndef RUN_DI_PROCESS_IN_IRQ
|
|
ulong flags = 0;
|
|
#endif
|
|
|
|
if (init_flag && (recovery_flag == 0) &&
|
|
(dump_state_flag == 0)) {
|
|
#if (!(defined RUN_DI_PROCESS_IN_IRQ)) || (defined ENABLE_SPIN_LOCK_ALWAYS)
|
|
spin_lock_irqsave(&plist_lock, flags);
|
|
#endif
|
|
if (di_pre_stru.pre_de_busy == 0) {
|
|
if (di_pre_stru.pre_de_process_done) {
|
|
#if 0/*def CHECK_DI_DONE*/
|
|
/* also for NEW_DI ? 7/15/2013 */
|
|
unsigned int data32 = Rd(DI_INTR_CTRL);
|
|
/*DI_INTR_CTRL[bit 0], NRWR_done, set by
|
|
* hardware when NRWR is done,clear by write 1
|
|
* by code;[bit 1]
|
|
* MTNWR_done, set by hardware when MTNWR
|
|
* is done, clear by write 1 by code;these two
|
|
* bits have nothing to do with
|
|
* DI_INTR_CTRL[16](NRW irq mask, 0 to enable
|
|
* irq) and DI_INTR_CTRL[17]
|
|
* (MTN irq mask, 0 to enable irq).two
|
|
* interrupts are raised if both
|
|
* DI_INTR_CTRL[16] and DI_INTR_CTRL[17] are 0
|
|
*/
|
|
if (
|
|
((data32 & 0x1) &&
|
|
((di_pre_stru.enable_mtnwr == 0)
|
|
|| (data32 &
|
|
0x2))) ||
|
|
(di_pre_stru.pre_de_clear_flag == 2)) {
|
|
RDMA_WR(DI_INTR_CTRL, data32);
|
|
#endif
|
|
if (di_pre_stru.pre_de_clear_flag == 2) {
|
|
di_pre_stru.retry_en = true;
|
|
} else {
|
|
pre_process_time =
|
|
di_pre_stru.pre_de_busy_timer_count;
|
|
pre_de_done_buf_config();
|
|
}
|
|
di_pre_stru.pre_de_process_done = 0;
|
|
di_pre_stru.pre_de_clear_flag = 0;
|
|
#ifdef CHECK_DI_DONE
|
|
}
|
|
#endif
|
|
} else if (di_pre_stru.pre_de_clear_flag == 1) {
|
|
di_lock_irqfiq_save(
|
|
irq_flag2);
|
|
pre_de_done_buf_clear();
|
|
di_unlock_irqfiq_restore(
|
|
irq_flag2);
|
|
di_pre_stru.pre_de_process_done = 0;
|
|
di_pre_stru.pre_de_clear_flag = 0;
|
|
}
|
|
}
|
|
|
|
di_lock_irqfiq_save(irq_flag2);
|
|
di_post_stru.check_recycle_buf_cnt = 0;
|
|
while (check_recycle_buf() & 1) {
|
|
if (di_post_stru.check_recycle_buf_cnt++ >
|
|
MAX_IN_BUF_NUM) {
|
|
di_pr_info("%s: check_recycle_buf time out!!\n",
|
|
__func__);
|
|
break;
|
|
}
|
|
}
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
|
|
/************/
|
|
if (di_pre_stru.retry_en &&
|
|
(di_pre_stru.pre_de_busy == 0) &&
|
|
(di_pre_stru.pre_de_process_done == 0) &&
|
|
!atomic_read(&di_flag_unreg) &&
|
|
(di_pre_stru.pre_de_process_flag == 0)) {
|
|
di_pre_stru.retry_index =
|
|
di_pre_stru.field_count_for_cont;
|
|
di_pre_stru.field_count_for_cont--;
|
|
di_print("di:retry set%d\n", di_pre_stru.retry_index);
|
|
pre_de_process();
|
|
di_pre_stru.retry_en = false;
|
|
di_pre_stru.retry_cnt++;
|
|
}
|
|
|
|
if ((di_pre_stru.pre_de_busy == 0) &&
|
|
(di_pre_stru.pre_de_process_done == 0)) {
|
|
if ((pre_run_flag == DI_RUN_FLAG_RUN) ||
|
|
(pre_run_flag == DI_RUN_FLAG_STEP)) {
|
|
if (pre_run_flag == DI_RUN_FLAG_STEP)
|
|
pre_run_flag = DI_RUN_FLAG_STEP_DONE;
|
|
if ((!atomic_read(&di_flag_unreg))
|
|
&& (di_pre_stru.pre_de_process_flag == 0)
|
|
&& pre_de_buf_config())
|
|
pre_de_process();
|
|
}
|
|
}
|
|
di_post_stru.di_post_process_cnt = 0;
|
|
while (process_post_vframe()) {
|
|
if (di_post_stru.di_post_process_cnt++ >
|
|
MAX_POST_BUF_NUM) {
|
|
di_pr_info("%s: process_post_vframe time out!!\n",
|
|
__func__);
|
|
break;
|
|
}
|
|
}
|
|
if (post_wr_en && post_wr_support) {
|
|
if (di_post_stru.post_de_busy == 0 &&
|
|
di_post_stru.de_post_process_done) {
|
|
post_de_done_buf_config();
|
|
di_post_stru.de_post_process_done = 0;
|
|
}
|
|
di_post_process();
|
|
}
|
|
|
|
#if (!(defined RUN_DI_PROCESS_IN_IRQ)) || (defined ENABLE_SPIN_LOCK_ALWAYS)
|
|
spin_unlock_irqrestore(&plist_lock, flags);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void di_pre_trigger_work(struct di_pre_stru_s *pre_stru_p)
|
|
{
|
|
|
|
if (pre_stru_p->pre_de_busy && init_flag) {
|
|
pre_stru_p->pre_de_busy_timer_count++;
|
|
if (pre_stru_p->pre_de_busy_timer_count >= nr_done_check_cnt &&
|
|
((cur_to_msecs() - di_pre_stru.irq_time[1]) >
|
|
(10*nr_done_check_cnt))) {
|
|
if (di_dbg_mask & 4) {
|
|
dump_mif_size_state(&di_pre_stru,
|
|
&di_post_stru);
|
|
}
|
|
ddbg_mod_save(eDI_DBG_MOD_PRE_TIMEOUT, 0, 0);
|
|
enable_di_pre_mif(false, mcpre_en);
|
|
if (de_devp->nrds_enable)
|
|
nr_ds_hw_ctrl(false);
|
|
pre_stru_p->pre_de_busy_timer_count = 0;
|
|
pre_stru_p->pre_de_irq_timeout_count++;
|
|
pre_stru_p->pre_de_process_done = 1;
|
|
pre_stru_p->pre_de_busy = 0;
|
|
pre_stru_p->pre_de_clear_flag = 2;
|
|
if ((pre_stru_p->field_count_for_cont < 10) ||
|
|
(di_dbg_mask&0x2)) {
|
|
pr_info("DI*****wait %d timeout 0x%x(%d ms)*****\n",
|
|
pre_stru_p->field_count_for_cont,
|
|
Rd(DI_INTR_CTRL),
|
|
(unsigned int)(cur_to_msecs() -
|
|
di_pre_stru.irq_time[1]));
|
|
pr_info("AFBCD0_MISC_CTRL=0x%x\n",
|
|
RDMA_RD(VD1_AFBCD0_MISC_CTRL));
|
|
}
|
|
}
|
|
} else {
|
|
pre_stru_p->pre_de_busy_timer_count = 0;
|
|
}
|
|
|
|
/* if(force_trig){ */
|
|
trigger_pre_di_process(TRIGGER_PRE_BY_TIMER);
|
|
/* } */
|
|
|
|
if (force_recovery) {
|
|
if (recovery_flag || (force_recovery & 0x2)) {
|
|
force_recovery_count++;
|
|
if (init_flag) {
|
|
pr_err("====== DI force recovery %u-%u =========\n",
|
|
recovery_log_reason,
|
|
recovery_log_queue_idx);
|
|
print_di_buf(recovery_log_di_buf, 2);
|
|
force_recovery &= (~0x2);
|
|
recovery_flag = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static int di_task_handle(void *data)
|
|
{
|
|
struct di_dev_s *devp;
|
|
int ret = 0;
|
|
devp = (struct di_dev_s *)data;
|
|
if (!devp)
|
|
return -1;
|
|
while (1) {
|
|
ret = down_interruptible(&di_sema);
|
|
if (ret != 0)
|
|
continue;
|
|
|
|
if (!de_devp)
|
|
continue;
|
|
|
|
if (!active_flag)
|
|
continue;
|
|
|
|
if ((di_pre_stru.unreg_req_flag ||
|
|
di_pre_stru.force_unreg_req_flag ||
|
|
di_pre_stru.disable_req_flag) &&
|
|
(di_pre_stru.pre_de_busy == 0)) {
|
|
di_unreg_process();
|
|
#if 0
|
|
/* if mirror mode, can't speed down the clk*/
|
|
/* set min rate for power saving */
|
|
if (de_devp->vpu_clkb) {
|
|
clk_set_rate(de_devp->vpu_clkb,
|
|
de_devp->clkb_min_rate);
|
|
}
|
|
#endif
|
|
}
|
|
if (/*di_pre_stru.reg_req_flag_irq ||*/
|
|
di_pre_stru.reg_req_flag) {
|
|
di_reg_process();
|
|
di_pre_stru.reg_req_flag = 0;
|
|
/*di_pre_stru.reg_req_flag_irq = 0;*/
|
|
}
|
|
#ifdef CONFIG_CMA
|
|
/* mutex_lock(&de_devp->cma_mutex);*/
|
|
if (di_pre_stru.cma_release_req) {
|
|
atomic_set(&devp->mem_flag, 0);
|
|
di_cma_release(devp);
|
|
di_pre_stru.cma_release_req = 0;
|
|
di_pre_stru.cma_alloc_done = 0;
|
|
}
|
|
if (di_pre_stru.cma_alloc_req) {
|
|
if (di_cma_alloc(devp))
|
|
atomic_set(&devp->mem_flag, 1);
|
|
else
|
|
atomic_set(&devp->mem_flag, 0);
|
|
di_pre_stru.cma_alloc_req = 0;
|
|
di_pre_stru.cma_alloc_done = 1;
|
|
}
|
|
if (di_free_mem_pre()) {
|
|
di_cma_release(devp);
|
|
di_pr_info("release mirror\n");
|
|
atomic_set(&di_trig_free_mem, 0);
|
|
}
|
|
/* mutex_unlock(&de_devp->cma_mutex); */
|
|
#endif
|
|
|
|
if (de_devp->flags & DI_VPU_CLKB_SET) {
|
|
if (is_meson_txlx_cpu()) {
|
|
if (!use_2_interlace_buff) {
|
|
#ifdef CLK_TREE_SUPPORT
|
|
clk_set_rate(de_devp->vpu_clkb,
|
|
de_devp->clkb_min_rate);
|
|
#endif
|
|
} else {
|
|
#ifdef CLK_TREE_SUPPORT
|
|
clk_set_rate(de_devp->vpu_clkb,
|
|
de_devp->clkb_max_rate);
|
|
#endif
|
|
}
|
|
}
|
|
if (is_meson_g12a_cpu() ||
|
|
is_meson_g12b_cpu() ||
|
|
is_meson_tl1_cpu() ||
|
|
is_meson_tm2_cpu() ||
|
|
is_meson_sm1_cpu()) {
|
|
#ifdef CLK_TREE_SUPPORT
|
|
clk_set_rate(de_devp->vpu_clkb,
|
|
de_devp->clkb_max_rate);
|
|
#endif
|
|
}
|
|
de_devp->flags &= (~DI_VPU_CLKB_SET);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void di_pre_process_irq(struct di_pre_stru_s *pre_stru_p)
|
|
{
|
|
int i;
|
|
|
|
if (active_flag) {
|
|
/* must wait pre de done or time out to clear the de_busy
|
|
* otherwise may appear watch dog reboot probability
|
|
* caused by disable mif in unreg_process_irq
|
|
*/
|
|
if (pre_stru_p->unreg_req_flag_irq &&
|
|
(di_pre_stru.pre_de_busy == 0))
|
|
di_unreg_process_irq();
|
|
if (init_flag == 0 /*&& pre_stru_p->reg_req_flag_irq == 0*/
|
|
&& (!atomic_read(&di_flag_unreg)))
|
|
di_reg_process_irq();
|
|
}
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
if (active_flag)
|
|
di_process();
|
|
}
|
|
log_buffer_state("pro");
|
|
}
|
|
static struct hrtimer di_pre_hrtimer;
|
|
|
|
static void pre_tasklet(unsigned long arg)
|
|
{
|
|
unsigned int hrtimer_time = 0;
|
|
|
|
hrtimer_time = jiffies_to_msecs(jiffies_64 - de_devp->jiffy);
|
|
if (hrtimer_time > 10)
|
|
pr_dbg("DI: tasklet schedule cost %ums.\n", hrtimer_time);
|
|
di_pre_process_irq((struct di_pre_stru_s *)arg);
|
|
}
|
|
|
|
static enum hrtimer_restart di_pre_hrtimer_func(struct hrtimer *timer)
|
|
{
|
|
if (!di_pre_stru.bypass_flag)
|
|
di_pre_trigger_work(&di_pre_stru);
|
|
hrtimer_forward_now(&di_pre_hrtimer, ms_to_ktime(10));
|
|
/*di_patch_post_update_mc();*/
|
|
return HRTIMER_RESTART;
|
|
}
|
|
|
|
static void post_display_buf_clear(void)
|
|
{
|
|
struct di_buf_s *p = NULL;
|
|
int itmp;
|
|
|
|
pr_info("%s:\n", __func__);
|
|
queue_for_each_entry(p, ptmp, QUEUE_DISPLAY, list) {
|
|
pr_info("\t%s,%d\n", vframe_type_name[p->type], p->index);
|
|
if (p->type == VFRAME_TYPE_POST) {
|
|
if (!atomic_dec_and_test(&p->di_cnt))
|
|
di_print("%s,di_cnt > 0\n", __func__);
|
|
recycle_vframe_type_post(p);
|
|
} else {
|
|
queue_in(p, QUEUE_RECYCLE);
|
|
di_print("%s: %s[%d] =>recycle_list\n", __func__,
|
|
vframe_type_name[p->type], p->index);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void dbg_check_list(void)
|
|
{
|
|
unsigned int post_display;
|
|
|
|
post_display = list_count(QUEUE_DISPLAY);
|
|
di_pr_info("display:%d\n", post_display);
|
|
}
|
|
|
|
/*
|
|
* provider/receiver interface
|
|
*/
|
|
char *vf_get_receiver_name(const char *provider_name);
|
|
static int di_receiver_event_fun(int type, void *data, void *arg)
|
|
{
|
|
int i;
|
|
ulong flags;
|
|
char *provider_name = (char *)data;
|
|
|
|
if (type == VFRAME_EVENT_PROVIDER_QUREY_VDIN2NR) {
|
|
return di_pre_stru.vdin2nr;
|
|
} else if (type == VFRAME_EVENT_PROVIDER_UNREG) {
|
|
mutex_lock(&di_event_mutex);
|
|
atomic_set(&di_flag_unreg, 1); //ary 2019-05-27
|
|
pr_dbg("%s , is_bypass() %d trick_mode %d bypass_all %d\n",
|
|
__func__, is_bypass(NULL), trick_mode, bypass_all);
|
|
di_pre_stru.vdin_source = false;
|
|
pr_info("DI: %s: unreg\n", __func__);
|
|
pr_info("DI: provider name:%s\n", provider_name);
|
|
ddbg_mod_save(eDI_DBG_MOD_UNREGB, 0, 0);
|
|
di_pre_stru.unreg_req_flag = 1;
|
|
di_pre_stru.vdin_source = false;
|
|
|
|
/*di_request_afbc(false);*/
|
|
trigger_pre_di_process(TRIGGER_PRE_BY_PROVIDER_UNREG);
|
|
di_pre_stru.unreg_req_flag_cnt = 0;
|
|
//wait 10ms:
|
|
if (di_pre_stru.pre_de_process_flag
|
|
|| di_pre_stru.pre_de_busy) {
|
|
pr_info("di:w10\n");
|
|
usleep_range(10000, 10001);
|
|
} else {
|
|
pr_info("di:no w\n");
|
|
}
|
|
di_pre_stru.wait_afbc = false;
|
|
while (di_pre_stru.unreg_req_flag ||
|
|
di_pre_stru.reg_irq_busy) {
|
|
usleep_range(1000, 1001);
|
|
if (di_pre_stru.unreg_req_flag_cnt++ >
|
|
di_reg_unreg_cnt) {
|
|
reg_unreg_timeout_cnt++;
|
|
pr_err("%s:unreg_reg_flag timeout!!!\n",
|
|
__func__);
|
|
di_unreg_process();
|
|
break;
|
|
}
|
|
}
|
|
#ifdef SUPPORT_MPEG_TO_VDIN
|
|
if (mpeg2vdin_flag) {
|
|
struct vdin_arg_s vdin_arg;
|
|
struct vdin_v4l2_ops_s *vdin_ops = get_vdin_v4l2_ops();
|
|
|
|
vdin_arg.cmd = VDIN_CMD_MPEGIN_STOP;
|
|
if (vdin_ops->tvin_vdin_func)
|
|
vdin_ops->tvin_vdin_func(0, &vdin_arg);
|
|
|
|
mpeg2vdin_flag = 0;
|
|
}
|
|
#endif
|
|
bypass_state = 1;
|
|
#ifdef RUN_DI_PROCESS_IN_IRQ
|
|
if (di_pre_stru.vdin_source)
|
|
DI_Wr_reg_bits(VDIN_WR_CTRL, 0x3, 24, 3);
|
|
#endif
|
|
ddbg_mod_save(eDI_DBG_MOD_UNREGE, 0, 0);
|
|
mutex_unlock(&di_event_mutex);
|
|
pr_info("DI: unreg f\n");
|
|
} else if (type == VFRAME_EVENT_PROVIDER_RESET) {
|
|
/*di_blocking = 1;*/
|
|
mutex_lock(&di_event_mutex);
|
|
pr_info("%s: VFRAME_EVENT_PROVIDER_RESET\n", __func__);
|
|
if (is_bypass(NULL)
|
|
|| bypass_state
|
|
|| di_pre_stru.bypass_flag) {
|
|
/* only if di is bypassed, then we send the message of
|
|
* VFRAME_EVENT_PROVIDER_RESET to video and notify
|
|
* it to keep the last canvas buffer which was
|
|
* alloced by codec not by di.
|
|
*/
|
|
vf_notify_receiver(VFM_NAME,
|
|
VFRAME_EVENT_PROVIDER_RESET,
|
|
NULL);
|
|
di_blocking = 1;
|
|
spin_lock_irqsave(&plist_lock, flags);
|
|
post_display_buf_clear();
|
|
spin_unlock_irqrestore(&plist_lock, flags);
|
|
}
|
|
di_blocking = 1;
|
|
/*-----------------------------------*/
|
|
spin_lock_irqsave(&plist_lock, flags);
|
|
for (i = 0; i < MAX_IN_BUF_NUM; i++) {
|
|
if (vframe_in[i])
|
|
pr_info("DI:clear vframe_in[%d]\n", i);
|
|
|
|
vframe_in[i] = NULL;
|
|
}
|
|
spin_unlock_irqrestore(&plist_lock, flags);
|
|
di_blocking = 0;
|
|
mutex_unlock(&di_event_mutex);
|
|
pr_info("\treset:end\n");
|
|
/*goto light_unreg;*/
|
|
} else if (type == VFRAME_EVENT_PROVIDER_LIGHT_UNREG) {
|
|
mutex_lock(&di_event_mutex);
|
|
di_blocking = 1;
|
|
|
|
pr_info("%s: LIGHT_UNREG\n", __func__);
|
|
|
|
/*light_unreg:*/
|
|
#if 1
|
|
spin_lock_irqsave(&plist_lock, flags);
|
|
for (i = 0; i < MAX_IN_BUF_NUM; i++) {
|
|
|
|
if (vframe_in[i])
|
|
pr_info("DI:clear vframe_in[%d]\n", i);
|
|
|
|
vframe_in[i] = NULL;
|
|
}
|
|
spin_unlock_irqrestore(&plist_lock, flags);
|
|
#endif
|
|
di_blocking = 0;
|
|
mutex_unlock(&di_event_mutex);
|
|
pr_info("\tlight unreg:end\n");
|
|
} else if (type == VFRAME_EVENT_PROVIDER_LIGHT_UNREG_RETURN_VFRAME) {
|
|
unsigned char vf_put_flag = 0;
|
|
|
|
pr_info("%s:LIGHT_UNREG_RETURN_VFRAME\n", __func__);
|
|
/*
|
|
* do not display garbage when 2d->3d or 3d->2d
|
|
*/
|
|
spin_lock_irqsave(&plist_lock, flags);
|
|
for (i = 0; i < MAX_IN_BUF_NUM; i++) {
|
|
if (vframe_in[i]) {
|
|
vf_put(vframe_in[i], VFM_NAME);
|
|
pr_dbg("DI:clear vframe_in[%d]\n", i);
|
|
vf_put_flag = 1;
|
|
}
|
|
vframe_in[i] = NULL;
|
|
}
|
|
if (vf_put_flag)
|
|
vf_notify_provider(VFM_NAME,
|
|
VFRAME_EVENT_RECEIVER_PUT, NULL);
|
|
|
|
spin_unlock_irqrestore(&plist_lock, flags);
|
|
} else if (type == VFRAME_EVENT_PROVIDER_VFRAME_READY) {
|
|
if (di_pre_stru.bypass_flag)
|
|
vf_notify_receiver(VFM_NAME,
|
|
VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
|
|
trigger_pre_di_process(TRIGGER_PRE_BY_VFRAME_READY);
|
|
|
|
#ifdef RUN_DI_PROCESS_IN_IRQ
|
|
#define INPUT2PRE_2_BYPASS_SKIP_COUNT 4
|
|
if (active_flag && di_pre_stru.vdin_source) {
|
|
if (is_bypass(NULL)) {
|
|
if (di_pre_stru.pre_de_busy == 0) {
|
|
DI_Wr_reg_bits(VDIN_WR_CTRL,
|
|
0x3, 24, 3);
|
|
di_pre_stru.vdin2nr = 0;
|
|
}
|
|
if (di_pre_stru.bypass_start_count <
|
|
INPUT2PRE_2_BYPASS_SKIP_COUNT) {
|
|
vframe_t *vframe_tmp = vf_get(VFM_NAME);
|
|
|
|
if (vframe_tmp != NULL) {
|
|
vf_put(vframe_tmp, VFM_NAME);
|
|
vf_notify_provider(VFM_NAME,
|
|
VFRAME_EVENT_RECEIVER_PUT,
|
|
NULL);
|
|
}
|
|
di_pre_stru.bypass_start_count++;
|
|
}
|
|
} else if (is_input2pre()) {
|
|
di_pre_stru.bypass_start_count = 0;
|
|
if ((di_pre_stru.pre_de_busy != 0) &&
|
|
(input2pre_miss_policy == 1 &&
|
|
frame_count < 30)) {
|
|
di_pre_stru.pre_de_clear_flag = 1;
|
|
di_pre_stru.pre_de_busy = 0;
|
|
input2pre_buf_miss_count++;
|
|
}
|
|
|
|
if (di_pre_stru.pre_de_busy == 0) {
|
|
DI_Wr_reg_bits(VDIN_WR_CTRL,
|
|
0x5, 24, 3);
|
|
di_pre_stru.vdin2nr = 1;
|
|
di_process();
|
|
log_buffer_state("pr_");
|
|
if (di_pre_stru.pre_de_busy == 0)
|
|
input2pre_proc_miss_count++;
|
|
} else {
|
|
vframe_t *vframe_tmp = vf_get(VFM_NAME);
|
|
|
|
if (vframe_tmp != NULL) {
|
|
vf_put(vframe_tmp, VFM_NAME);
|
|
vf_notify_provider(VFM_NAME,
|
|
VFRAME_EVENT_RECEIVER_PUT,
|
|
NULL);
|
|
}
|
|
input2pre_buf_miss_count++;
|
|
if ((di_pre_stru.cur_width > 720 &&
|
|
di_pre_stru.cur_height > 576) ||
|
|
(input2pre_throw_count & 0x10000))
|
|
di_pre_stru.pre_throw_flag =
|
|
input2pre_throw_count &
|
|
0xffff;
|
|
}
|
|
} else {
|
|
if (di_pre_stru.pre_de_busy == 0) {
|
|
DI_Wr_reg_bits(VDIN_WR_CTRL,
|
|
0x3, 24, 3);
|
|
di_pre_stru.vdin2nr = 0;
|
|
}
|
|
di_pre_stru.bypass_start_count =
|
|
INPUT2PRE_2_BYPASS_SKIP_COUNT;
|
|
}
|
|
}
|
|
#endif
|
|
} else if (type == VFRAME_EVENT_PROVIDER_QUREY_STATE) {
|
|
/*int in_buf_num = 0;*/
|
|
struct vframe_states states;
|
|
|
|
if (recovery_flag)
|
|
return RECEIVER_INACTIVE;
|
|
#if 1/*fix for ucode reset method be break by di.20151230*/
|
|
di_vf_states(&states, NULL);
|
|
if (states.buf_avail_num > 0)
|
|
return RECEIVER_ACTIVE;
|
|
|
|
if (vf_notify_receiver(
|
|
VFM_NAME,
|
|
VFRAME_EVENT_PROVIDER_QUREY_STATE,
|
|
NULL) == RECEIVER_ACTIVE)
|
|
return RECEIVER_ACTIVE;
|
|
return RECEIVER_INACTIVE;
|
|
|
|
#else
|
|
for (i = 0; i < MAX_IN_BUF_NUM; i++) {
|
|
if (vframe_in[i] != NULL)
|
|
in_buf_num++;
|
|
if (bypass_state == 1) {
|
|
if (in_buf_num > 1)
|
|
return RECEIVER_ACTIVE;
|
|
else
|
|
return RECEIVER_INACTIVE;
|
|
} else {
|
|
if (in_buf_num > 0)
|
|
return RECEIVER_ACTIVE;
|
|
else
|
|
return RECEIVER_INACTIVE;
|
|
}
|
|
#endif
|
|
} else if (type == VFRAME_EVENT_PROVIDER_REG) {
|
|
char *receiver_name = NULL;
|
|
|
|
mutex_lock(&di_event_mutex);
|
|
if (de_devp->flags & DI_SUSPEND_FLAG) {
|
|
pr_err("[DI] reg event device hasn't resumed\n");
|
|
mutex_unlock(&di_event_mutex);
|
|
return -1;
|
|
}
|
|
if (reg_flag) {
|
|
pr_err("[DI] no muti instance.\n");
|
|
mutex_unlock(&di_event_mutex);
|
|
dbg_check_list();
|
|
return -1;
|
|
}
|
|
pr_info("%s: vframe provider reg %s\n", __func__,
|
|
provider_name);
|
|
ddbg_mod_save(eDI_DBG_MOD_REGB, 0, 0);
|
|
di_pre_stru.wait_afbc = false;
|
|
atomic_set(&di_flag_unreg, 0); //ary
|
|
bypass_state = 0;
|
|
di_pre_stru.reg_req_flag = 1;
|
|
trigger_pre_di_process(TRIGGER_PRE_BY_PROVIDER_REG);
|
|
/*check unreg process*/
|
|
di_pre_stru.reg_req_flag_cnt = 0;
|
|
while (di_pre_stru.reg_req_flag) {
|
|
usleep_range(1000, 1001);
|
|
if (di_pre_stru.reg_req_flag_cnt++ > di_reg_unreg_cnt) {
|
|
reg_unreg_timeout_cnt++;
|
|
pr_dbg("%s:reg_req_flag timeout!!!\n",
|
|
__func__);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (strncmp(provider_name, "vdin0", 4) == 0) {
|
|
di_pre_stru.vdin_source = true;
|
|
} else {
|
|
di_pre_stru.vdin_source = false;
|
|
}
|
|
receiver_name = vf_get_receiver_name(VFM_NAME);
|
|
if (receiver_name) {
|
|
if (!strcmp(receiver_name, "amvideo")) {
|
|
di_post_stru.run_early_proc_fun_flag = 0;
|
|
if (post_wr_en && post_wr_support)
|
|
di_post_stru.run_early_proc_fun_flag
|
|
= 1;
|
|
} else {
|
|
di_post_stru.run_early_proc_fun_flag = 1;
|
|
pr_info("set run_early_proc_fun_flag to 1\n");
|
|
}
|
|
} else {
|
|
pr_info("%s error receiver is null.\n", __func__);
|
|
}
|
|
ddbg_mod_save(eDI_DBG_MOD_REGE, 0, 0);
|
|
mutex_unlock(&di_event_mutex);
|
|
pr_info("DI: reg f\n");
|
|
}
|
|
#ifdef DET3D
|
|
else if (type == VFRAME_EVENT_PROVIDER_SET_3D_VFRAME_INTERLEAVE) {
|
|
int flag = (long)data;
|
|
|
|
di_pre_stru.vframe_interleave_flag = flag;
|
|
}
|
|
#endif
|
|
else if (type == VFRAME_EVENT_PROVIDER_FR_HINT) {
|
|
vf_notify_receiver(VFM_NAME,
|
|
VFRAME_EVENT_PROVIDER_FR_HINT, data);
|
|
} else if (type == VFRAME_EVENT_PROVIDER_FR_END_HINT) {
|
|
vf_notify_receiver(VFM_NAME,
|
|
VFRAME_EVENT_PROVIDER_FR_END_HINT, data);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#if 0
|
|
static void fast_process(void)
|
|
{
|
|
int i;
|
|
ulong flags = 0, irq_flag2 = 0;
|
|
|
|
if (active_flag && is_bypass(NULL) && (BYPASS_GET_MAX_BUF_NUM <= 1) &&
|
|
init_flag && (recovery_flag == 0) &&
|
|
(dump_state_flag == 0)) {
|
|
if (vf_peek(VFM_NAME) == NULL)
|
|
return;
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
spin_lock_irqsave(&plist_lock, flags);
|
|
if (di_pre_stru.pre_de_process_done) {
|
|
pre_de_done_buf_config();
|
|
di_pre_stru.pre_de_process_done = 0;
|
|
}
|
|
|
|
di_lock_irqfiq_save(irq_flag2);
|
|
di_post_stru.check_recycle_buf_cnt = 0;
|
|
while (check_recycle_buf() & 1) {
|
|
if (di_post_stru.check_recycle_buf_cnt++ >
|
|
MAX_IN_BUF_NUM) {
|
|
di_pr_info("%s: check_recycle_buf time out!!\n",
|
|
__func__);
|
|
break;
|
|
}
|
|
}
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
|
|
if ((di_pre_stru.pre_de_busy == 0) &&
|
|
(di_pre_stru.pre_de_process_done == 0)) {
|
|
if ((pre_run_flag == DI_RUN_FLAG_RUN) ||
|
|
(pre_run_flag == DI_RUN_FLAG_STEP)) {
|
|
if (pre_run_flag == DI_RUN_FLAG_STEP)
|
|
pre_run_flag =
|
|
DI_RUN_FLAG_STEP_DONE;
|
|
if (pre_de_buf_config() &&
|
|
(di_pre_stru.pre_de_process_flag == 0))
|
|
pre_de_process();
|
|
}
|
|
}
|
|
di_post_stru.di_post_process_cnt = 0;
|
|
while (process_post_vframe()) {
|
|
if (di_post_stru.di_post_process_cnt++ >
|
|
MAX_POST_BUF_NUM) {
|
|
pr_info("%s: process_post_vframe time out!!\n",
|
|
__func__);
|
|
break;
|
|
}
|
|
}
|
|
|
|
spin_unlock_irqrestore(&plist_lock, flags);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
static vframe_t *di_vf_peek(void *arg)
|
|
{
|
|
vframe_t *vframe_ret = NULL;
|
|
struct di_buf_s *di_buf = NULL;
|
|
|
|
video_peek_cnt++;
|
|
if (di_pre_stru.bypass_flag)
|
|
return vf_peek(VFM_NAME);
|
|
if ((init_flag == 0) || recovery_flag ||
|
|
di_blocking || di_pre_stru.unreg_req_flag || dump_state_flag)
|
|
return NULL;
|
|
if ((run_flag == DI_RUN_FLAG_PAUSE) ||
|
|
(run_flag == DI_RUN_FLAG_STEP_DONE))
|
|
return NULL;
|
|
|
|
log_buffer_state("pek");
|
|
|
|
/*fast_process();*/
|
|
#ifdef SUPPORT_START_FRAME_HOLD
|
|
if ((disp_frame_count == 0) && (is_bypass(NULL) == 0)) {
|
|
int ready_count = list_count(QUEUE_POST_READY);
|
|
|
|
if (ready_count > start_frame_hold_count) {
|
|
di_buf = get_di_buf_head(QUEUE_POST_READY);
|
|
if (di_buf)
|
|
vframe_ret = di_buf->vframe;
|
|
}
|
|
} else
|
|
#endif
|
|
{
|
|
if (!queue_empty(QUEUE_POST_READY)) {
|
|
di_buf = get_di_buf_head(QUEUE_POST_READY);
|
|
if (di_buf)
|
|
vframe_ret = di_buf->vframe;
|
|
}
|
|
}
|
|
#ifdef DI_BUFFER_DEBUG
|
|
if (vframe_ret)
|
|
di_print("%s: %s[%d]:%x\n", __func__,
|
|
vframe_type_name[di_buf->type],
|
|
di_buf->index, vframe_ret);
|
|
#endif
|
|
|
|
return vframe_ret;
|
|
}
|
|
/*recycle the buffer for keeping buffer*/
|
|
static void recycle_keep_buffer(void)
|
|
{
|
|
ulong irq_flag2 = 0;
|
|
int i = 0;
|
|
struct di_buf_s *keep_buf;
|
|
|
|
keep_buf = di_post_stru.keep_buf;
|
|
if (!IS_ERR_OR_NULL(keep_buf)) {
|
|
if (keep_buf->type == VFRAME_TYPE_POST) {
|
|
pr_dbg("%s recycle keep cur di_buf %d (",
|
|
__func__, keep_buf->index);
|
|
di_lock_irqfiq_save(irq_flag2);
|
|
for (i = 0; i < USED_LOCAL_BUF_MAX; i++) {
|
|
if (keep_buf->di_buf_dup_p[i]) {
|
|
queue_in(
|
|
keep_buf->di_buf_dup_p[i],
|
|
QUEUE_RECYCLE);
|
|
pr_dbg(" %d ",
|
|
keep_buf->di_buf_dup_p[i]->index);
|
|
}
|
|
}
|
|
queue_in(keep_buf, QUEUE_POST_FREE);
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
pr_dbg(")\n");
|
|
}
|
|
di_post_stru.keep_buf = NULL;
|
|
}
|
|
}
|
|
static bool show_nrwr;
|
|
static vframe_t *di_vf_get(void *arg)
|
|
{
|
|
vframe_t *vframe_ret = NULL;
|
|
struct di_buf_s *di_buf = NULL, *nr_buf = NULL;
|
|
ulong irq_flag2 = 0;
|
|
|
|
if (di_pre_stru.bypass_flag)
|
|
return vf_get(VFM_NAME);
|
|
|
|
if ((init_flag == 0) || recovery_flag ||
|
|
di_blocking || di_pre_stru.unreg_req_flag || dump_state_flag)
|
|
return NULL;
|
|
|
|
if ((run_flag == DI_RUN_FLAG_PAUSE) ||
|
|
(run_flag == DI_RUN_FLAG_STEP_DONE))
|
|
return NULL;
|
|
|
|
#ifdef SUPPORT_START_FRAME_HOLD
|
|
if ((disp_frame_count == 0) && (is_bypass(NULL) == 0)) {
|
|
int ready_count = list_count(QUEUE_POST_READY);
|
|
|
|
if (ready_count > start_frame_hold_count)
|
|
goto get_vframe;
|
|
} else
|
|
#endif
|
|
if (!queue_empty(QUEUE_POST_READY)) {
|
|
#ifdef SUPPORT_START_FRAME_HOLD
|
|
get_vframe:
|
|
#endif
|
|
log_buffer_state("ge_");
|
|
di_lock_irqfiq_save(irq_flag2);
|
|
|
|
di_buf = get_di_buf_head(QUEUE_POST_READY);
|
|
if (check_di_buf(di_buf, 21)) {
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
return NULL;
|
|
}
|
|
queue_out(di_buf);
|
|
queue_in(di_buf, QUEUE_DISPLAY); /* add it into display_list */
|
|
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
|
|
if (di_buf) {
|
|
vframe_ret = di_buf->vframe;
|
|
nr_buf = di_buf->di_buf_dup_p[1];
|
|
if ((post_wr_en && post_wr_support) &&
|
|
(di_buf->process_fun_index != PROCESS_FUN_NULL)) {
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
|
|
vframe_ret->canvas0_config[0].phy_addr =
|
|
di_buf->nr_adr;
|
|
vframe_ret->canvas0_config[0].width =
|
|
di_buf->canvas_width[NR_CANVAS],
|
|
vframe_ret->canvas0_config[0].height =
|
|
di_buf->canvas_height;
|
|
vframe_ret->canvas0_config[0].block_mode = 0;
|
|
vframe_ret->plane_num = 1;
|
|
vframe_ret->canvas0Addr = -1;
|
|
vframe_ret->canvas1Addr = -1;
|
|
if (show_nrwr) {
|
|
vframe_ret->canvas0_config[0].phy_addr =
|
|
nr_buf->nr_adr;
|
|
vframe_ret->canvas0_config[0].width =
|
|
nr_buf->canvas_width[NR_CANVAS];
|
|
vframe_ret->canvas0_config[0].height =
|
|
nr_buf->canvas_height;
|
|
}
|
|
#else
|
|
config_canvas_idx(di_buf, di_wr_idx, -1);
|
|
vframe_ret->canvas0Addr = di_buf->nr_canvas_idx;
|
|
vframe_ret->canvas1Addr = di_buf->nr_canvas_idx;
|
|
if (show_nrwr) {
|
|
config_canvas_idx(nr_buf,
|
|
di_wr_idx, -1);
|
|
vframe_ret->canvas0Addr = di_wr_idx;
|
|
vframe_ret->canvas1Addr = di_wr_idx;
|
|
}
|
|
#endif
|
|
vframe_ret->early_process_fun = do_post_wr_fun;
|
|
vframe_ret->process_fun = NULL;
|
|
}
|
|
di_buf->seq = disp_frame_count;
|
|
atomic_set(&di_buf->di_cnt, 1);
|
|
}
|
|
disp_frame_count++;
|
|
if (run_flag == DI_RUN_FLAG_STEP)
|
|
run_flag = DI_RUN_FLAG_STEP_DONE;
|
|
|
|
log_buffer_state("get");
|
|
}
|
|
if (vframe_ret) {
|
|
di_print("%s: %s[%d]:0x%p %u ms\n", __func__,
|
|
vframe_type_name[di_buf->type],
|
|
di_buf->index, vframe_ret,
|
|
jiffies_to_msecs
|
|
(jiffies_64 - vframe_ret->ready_jiffies64));
|
|
}
|
|
|
|
if (!post_wr_en && di_post_stru.run_early_proc_fun_flag && vframe_ret) {
|
|
if (vframe_ret->early_process_fun == do_pre_only_fun)
|
|
vframe_ret->early_process_fun(
|
|
vframe_ret->private_data, vframe_ret);
|
|
}
|
|
|
|
return vframe_ret;
|
|
}
|
|
|
|
static void di_vf_put(vframe_t *vf, void *arg)
|
|
{
|
|
struct di_buf_s *di_buf = NULL;
|
|
ulong irq_flag2 = 0;
|
|
|
|
if (di_pre_stru.bypass_flag) {
|
|
vf_put(vf, VFM_NAME);
|
|
vf_notify_provider(VFM_NAME,
|
|
VFRAME_EVENT_RECEIVER_PUT, NULL);
|
|
#if 0
|
|
if (!IS_ERR_OR_NULL(di_post_stru.keep_buf))
|
|
recycle_keep_buffer();
|
|
#endif
|
|
return;
|
|
}
|
|
/* struct di_buf_s *p = NULL; */
|
|
/* int itmp = 0; */
|
|
if ((init_flag == 0) || recovery_flag ||
|
|
IS_ERR_OR_NULL(vf)) {
|
|
di_print("%s: 0x%p\n", __func__, vf);
|
|
return;
|
|
}
|
|
#ifdef DI_KEEP_HIS
|
|
if (di_blocking)
|
|
return;
|
|
#endif
|
|
log_buffer_state("pu_");
|
|
di_buf = (struct di_buf_s *)vf->private_data;
|
|
if (IS_ERR_OR_NULL(di_buf)) {
|
|
pr_info("%s: get vframe %p without di buf\n",
|
|
__func__, vf);
|
|
return;
|
|
}
|
|
if (di_post_stru.keep_buf &&
|
|
(di_post_stru.keep_buf == di_buf ||
|
|
di_last_display != di_post_stru.keep_buf->index)) {
|
|
/*if (di_post_stru.keep_buf == di_buf) {*/
|
|
pr_info("[DI]recycle buffer %d, get cnt %d.\n",
|
|
di_post_stru.keep_buf->index, disp_frame_count);
|
|
recycle_keep_buffer();
|
|
}
|
|
|
|
if (di_buf->type == VFRAME_TYPE_POST) {
|
|
di_lock_irqfiq_save(irq_flag2);
|
|
|
|
if (is_in_queue(di_buf, QUEUE_DISPLAY)) {
|
|
if (!atomic_dec_and_test(&di_buf->di_cnt))
|
|
di_print("%s,di_cnt > 0\n", __func__);
|
|
recycle_vframe_type_post(di_buf);
|
|
} else {
|
|
di_print("%s: %s[%d] not in display list\n", __func__,
|
|
vframe_type_name[di_buf->type], di_buf->index);
|
|
}
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
#ifdef DI_BUFFER_DEBUG
|
|
recycle_vframe_type_post_print(di_buf, __func__, __LINE__);
|
|
#endif
|
|
} else {
|
|
di_lock_irqfiq_save(irq_flag2);
|
|
queue_in(di_buf, QUEUE_RECYCLE);
|
|
di_unlock_irqfiq_restore(irq_flag2);
|
|
|
|
di_print("%s: %s[%d] =>recycle_list\n", __func__,
|
|
vframe_type_name[di_buf->type], di_buf->index);
|
|
}
|
|
|
|
trigger_pre_di_process(TRIGGER_PRE_BY_PUT);
|
|
}
|
|
|
|
static int di_event_cb(int type, void *data, void *private_data)
|
|
{
|
|
if (type == VFRAME_EVENT_RECEIVER_FORCE_UNREG) {
|
|
pr_info("%s: RECEIVER_FORCE_UNREG return\n",
|
|
__func__);
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int di_vf_states(struct vframe_states *states, void *arg)
|
|
{
|
|
if (!states)
|
|
return -1;
|
|
states->vf_pool_size = de_devp->buf_num_avail;
|
|
states->buf_free_num = list_count(QUEUE_LOCAL_FREE);
|
|
states->buf_avail_num = list_count(QUEUE_POST_READY);
|
|
states->buf_recycle_num = list_count(QUEUE_RECYCLE);
|
|
if (di_dbg_mask&0x1) {
|
|
di_pr_info("di-pre-ready-num:%d\n",
|
|
list_count(QUEUE_PRE_READY));
|
|
di_pr_info("di-display-num:%d\n", list_count(QUEUE_DISPLAY));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*****************************
|
|
* di driver file_operations
|
|
*
|
|
******************************/
|
|
static int di_open(struct inode *node, struct file *file)
|
|
{
|
|
di_dev_t *di_in_devp;
|
|
|
|
/* Get the per-device structure that contains this cdev */
|
|
di_in_devp = container_of(node->i_cdev, di_dev_t, cdev);
|
|
file->private_data = di_in_devp;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int di_release(struct inode *node, struct file *file)
|
|
{
|
|
/* di_dev_t *di_in_devp = file->private_data; */
|
|
|
|
/* Reset file pointer */
|
|
|
|
/* Release some other fields */
|
|
file->private_data = NULL;
|
|
return 0;
|
|
}
|
|
static struct di_pq_parm_s *di_pq_parm_create(struct am_pq_parm_s *pq_parm_p)
|
|
{
|
|
struct di_pq_parm_s *pq_ptr = NULL;
|
|
struct am_reg_s *am_reg_p = NULL;
|
|
size_t mem_size = 0;
|
|
|
|
pq_ptr = vzalloc(sizeof(struct di_pq_parm_s));
|
|
mem_size = sizeof(struct am_pq_parm_s);
|
|
memcpy(&pq_ptr->pq_parm, pq_parm_p, mem_size);
|
|
mem_size = sizeof(struct am_reg_s)*pq_parm_p->table_len;
|
|
am_reg_p = vzalloc(mem_size);
|
|
if (!am_reg_p) {
|
|
vfree(pq_ptr);
|
|
pr_err("[DI] alloc pq table memory errors\n");
|
|
return NULL;
|
|
}
|
|
pq_ptr->regs = am_reg_p;
|
|
|
|
return pq_ptr;
|
|
}
|
|
|
|
static void di_pq_parm_destroy(struct di_pq_parm_s *pq_ptr)
|
|
{
|
|
if (!pq_ptr) {
|
|
pr_err("[DI] %s pq parm pointer null.\n", __func__);
|
|
return;
|
|
}
|
|
vfree(pq_ptr->regs);
|
|
vfree(pq_ptr);
|
|
}
|
|
static long di_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
{
|
|
long ret = 0, tab_flag = 0;
|
|
di_dev_t *di_devp;
|
|
void __user *argp = (void __user *)arg;
|
|
size_t mm_size = 0;
|
|
struct am_pq_parm_s tmp_pq_s = {0};
|
|
struct di_pq_parm_s *di_pq_ptr = NULL;
|
|
|
|
if (_IOC_TYPE(cmd) != _DI_) {
|
|
pr_err("%s invalid command: %u\n", __func__, cmd);
|
|
return -EFAULT;
|
|
}
|
|
di_devp = file->private_data;
|
|
if (!di_devp || (di_devp->flags & DI_SUSPEND_FLAG))
|
|
return -EFAULT;
|
|
|
|
switch (cmd) {
|
|
case AMDI_IOC_SET_PQ_PARM:
|
|
mm_size = sizeof(struct am_pq_parm_s);
|
|
/*coverity[TAINTED_SCALAR] not a tainted data*/
|
|
if (copy_from_user(&tmp_pq_s, argp, mm_size)) {
|
|
pr_err("[DI] set pq parm errors\n");
|
|
return -EFAULT;
|
|
}
|
|
if (tmp_pq_s.table_len >= TABLE_LEN_MAX) {
|
|
pr_err("[DI] load 0x%x wrong pq table_len.\n",
|
|
tmp_pq_s.table_len);
|
|
return -EFAULT;
|
|
}
|
|
tab_flag = TABLE_NAME_DI | TABLE_NAME_NR | TABLE_NAME_MCDI |
|
|
TABLE_NAME_DEBLOCK | TABLE_NAME_DEMOSQUITO;
|
|
if (tmp_pq_s.table_name & tab_flag) {
|
|
pr_info("[DI] load 0x%x pq table len %u %s.\n",
|
|
tmp_pq_s.table_name, tmp_pq_s.table_len,
|
|
init_flag?"directly":"later");
|
|
} else {
|
|
pr_err("[DI] load 0x%x wrong pq table.\n",
|
|
tmp_pq_s.table_name);
|
|
return -EFAULT;
|
|
}
|
|
di_pq_ptr = di_pq_parm_create(&tmp_pq_s);
|
|
if (!di_pq_ptr) {
|
|
pr_err("[DI] allocat pq parm struct error.\n");
|
|
return -EFAULT;
|
|
}
|
|
argp = (void __user *)tmp_pq_s.table_ptr;
|
|
mm_size = tmp_pq_s.table_len * sizeof(struct am_reg_s);
|
|
if (copy_from_user(di_pq_ptr->regs, argp, mm_size)) {
|
|
pr_err("[DI] user copy pq table errors\n");
|
|
return -EFAULT;
|
|
}
|
|
if (init_flag) {
|
|
di_load_regs(di_pq_ptr);
|
|
di_pq_parm_destroy(di_pq_ptr);
|
|
break;
|
|
}
|
|
if (atomic_read(&de_devp->pq_flag) == 0) {
|
|
atomic_set(&de_devp->pq_flag, 1);
|
|
if (di_devp->flags & DI_LOAD_REG_FLAG) {
|
|
struct di_pq_parm_s *pos = NULL, *tmp = NULL;
|
|
list_for_each_entry_safe(pos, tmp,
|
|
&di_devp->pq_table_list, list) {
|
|
if (di_pq_ptr->pq_parm.table_name ==
|
|
pos->pq_parm.table_name) {
|
|
pr_info("[DI] remove 0x%x table.\n",
|
|
pos->pq_parm.table_name);
|
|
list_del(&pos->list);
|
|
di_pq_parm_destroy(pos);
|
|
}
|
|
}
|
|
}
|
|
list_add_tail(&di_pq_ptr->list,
|
|
&di_devp->pq_table_list);
|
|
di_devp->flags |= DI_LOAD_REG_FLAG;
|
|
atomic_set(&de_devp->pq_flag, 0);
|
|
} else {
|
|
pr_err("[DI] please retry table name 0x%x.\n",
|
|
di_pq_ptr->pq_parm.table_name);
|
|
di_pq_parm_destroy(di_pq_ptr);
|
|
ret = -EFAULT;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
#ifdef CONFIG_COMPAT
|
|
static long di_compat_ioctl(struct file *file, unsigned int cmd,
|
|
unsigned long arg)
|
|
{
|
|
unsigned long ret;
|
|
|
|
arg = (unsigned long)compat_ptr(arg);
|
|
ret = di_ioctl(file, cmd, arg);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
static const struct file_operations di_fops = {
|
|
.owner = THIS_MODULE,
|
|
.open = di_open,
|
|
.release = di_release,
|
|
.unlocked_ioctl = di_ioctl,
|
|
#ifdef CONFIG_COMPAT
|
|
.compat_ioctl = di_compat_ioctl,
|
|
#endif
|
|
};
|
|
|
|
static ssize_t
|
|
show_frame_format(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (init_flag)
|
|
ret += sprintf(buf + ret, "%s\n",
|
|
di_pre_stru.cur_prog_flag
|
|
? "progressive" : "interlace");
|
|
|
|
else
|
|
ret += sprintf(buf + ret, "%s\n", "null");
|
|
|
|
return ret;
|
|
}
|
|
static DEVICE_ATTR(frame_format, 0444, show_frame_format, NULL);
|
|
|
|
#if 0 /*move to di_local.c*/
|
|
static int __init rmem_di_device_init(struct reserved_mem *rmem,
|
|
struct device *dev)
|
|
{
|
|
di_dev_t *di_devp = dev_get_drvdata(dev);
|
|
|
|
if (di_devp) {
|
|
di_devp->mem_start = rmem->base;
|
|
di_devp->mem_size = rmem->size;
|
|
#ifdef MARK_HIS//mark for ko can't use the reserved mem
|
|
if (!of_get_flat_dt_prop(rmem->fdt_node, "no-map", NULL))
|
|
di_devp->flags |= DI_MAP_FLAG;
|
|
#endif
|
|
pr_dbg("di reverse memory 0x%lx, size %uMB.\n",
|
|
di_devp->mem_start, (di_devp->mem_size >> 20));
|
|
return 0;
|
|
}
|
|
/* pr_dbg("di reverse memory 0x%x, size %u B.\n",
|
|
* rmem->base, rmem->size);
|
|
*/
|
|
return 1;
|
|
}
|
|
|
|
static void rmem_di_device_release(struct reserved_mem *rmem,
|
|
struct device *dev)
|
|
{
|
|
di_dev_t *di_devp = dev_get_drvdata(dev);
|
|
|
|
if (di_devp) {
|
|
di_devp->mem_start = 0;
|
|
di_devp->mem_size = 0;
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_RDMA
|
|
unsigned int RDMA_RD_BITS(unsigned int adr, unsigned int start,
|
|
unsigned int len)
|
|
{
|
|
if (de_devp->rdma_handle && di_pre_rdma_enable)
|
|
return rdma_read_reg(de_devp->rdma_handle, adr) &
|
|
(((1 << len) - 1) << start);
|
|
else
|
|
return Rd_reg_bits(adr, start, len);
|
|
}
|
|
|
|
unsigned int RDMA_WR(unsigned int adr, unsigned int val)
|
|
{
|
|
if (is_need_stop_reg(adr))
|
|
return 0;
|
|
|
|
if (de_devp->rdma_handle > 0 && di_pre_rdma_enable) {
|
|
if (di_pre_stru.field_count_for_cont < 1)
|
|
DI_Wr(adr, val);
|
|
else
|
|
rdma_write_reg(de_devp->rdma_handle, adr, val);
|
|
return 0;
|
|
}
|
|
|
|
DI_Wr(adr, val);
|
|
return 1;
|
|
}
|
|
|
|
unsigned int RDMA_RD(unsigned int adr)
|
|
{
|
|
if (de_devp->rdma_handle > 0 && di_pre_rdma_enable)
|
|
return rdma_read_reg(de_devp->rdma_handle, adr);
|
|
else
|
|
return Rd(adr);
|
|
}
|
|
|
|
unsigned int RDMA_WR_BITS(unsigned int adr, unsigned int val,
|
|
unsigned int start, unsigned int len)
|
|
{
|
|
if (is_need_stop_reg(adr))
|
|
return 0;
|
|
|
|
if (de_devp->rdma_handle > 0 && di_pre_rdma_enable) {
|
|
if (di_pre_stru.field_count_for_cont < 1)
|
|
DI_Wr_reg_bits(adr, val, start, len);
|
|
else
|
|
rdma_write_reg_bits(de_devp->rdma_handle,
|
|
adr, val, start, len);
|
|
return 0;
|
|
}
|
|
DI_Wr_reg_bits(adr, val, start, len);
|
|
return 1;
|
|
}
|
|
#else
|
|
unsigned int RDMA_RD_BITS(unsigned int adr, unsigned int start,
|
|
unsigned int len)
|
|
{
|
|
return Rd_reg_bits(adr, start, len);
|
|
}
|
|
unsigned int RDMA_WR(unsigned int adr, unsigned int val)
|
|
{
|
|
DI_Wr(adr, val);
|
|
return 1;
|
|
}
|
|
|
|
unsigned int RDMA_RD(unsigned int adr)
|
|
{
|
|
return Rd(adr);
|
|
}
|
|
|
|
unsigned int RDMA_WR_BITS(unsigned int adr, unsigned int val,
|
|
unsigned int start, unsigned int len)
|
|
{
|
|
DI_Wr_reg_bits(adr, val, start, len);
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
static void set_di_flag(void)
|
|
{
|
|
if (is_meson_txl_cpu() ||
|
|
is_meson_txlx_cpu() ||
|
|
is_meson_gxlx_cpu() ||
|
|
is_meson_txhd_cpu() ||
|
|
is_meson_g12a_cpu() ||
|
|
is_meson_g12b_cpu() ||
|
|
is_meson_tl1_cpu() || is_meson_tm2_cpu() ||
|
|
is_meson_sm1_cpu()) {
|
|
mcpre_en = true;
|
|
mc_mem_alloc = true;
|
|
pulldown_enable = false;
|
|
di_pre_rdma_enable = false;
|
|
/*
|
|
* txlx atsc 1080i ei only will cause flicker
|
|
* when full to small win in home screen
|
|
*/
|
|
di_vscale_skip_enable = (is_meson_txlx_cpu()
|
|
|| is_meson_txhd_cpu())?12:4;
|
|
use_2_interlace_buff = is_meson_gxlx_cpu()?0:1;
|
|
if (is_meson_txl_cpu() ||
|
|
is_meson_txlx_cpu() ||
|
|
is_meson_gxlx_cpu() ||
|
|
is_meson_txhd_cpu() ||
|
|
is_meson_g12a_cpu() ||
|
|
is_meson_g12b_cpu() ||
|
|
is_meson_tl1_cpu() || is_meson_tm2_cpu() ||
|
|
is_meson_sm1_cpu()) {
|
|
full_422_pack = true;
|
|
}
|
|
|
|
if (nr10bit_support)
|
|
di_force_bit_mode = 10;
|
|
else {
|
|
di_force_bit_mode = 8;
|
|
full_422_pack = false;
|
|
}
|
|
post_hold_line =
|
|
(is_meson_g12a_cpu() || is_meson_g12b_cpu()
|
|
|| is_meson_tl1_cpu() || is_meson_tm2_cpu() ||
|
|
is_meson_sm1_cpu())?10:17;
|
|
} else {
|
|
post_hold_line = 8; /*2019-01-10: from VLSI feijun*/
|
|
mcpre_en = false;
|
|
pulldown_enable = false;
|
|
di_pre_rdma_enable = false;
|
|
di_vscale_skip_enable = 4;
|
|
use_2_interlace_buff = 0;
|
|
di_force_bit_mode = 8;
|
|
}
|
|
if (is_meson_tl1_cpu() || is_meson_tm2_cpu()
|
|
|| is_meson_g12a_cpu()
|
|
|| is_meson_g12b_cpu()
|
|
|| is_meson_sm1_cpu())
|
|
pulldown_enable = true;
|
|
|
|
if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A))
|
|
intr_mode = 3;
|
|
if (di_pre_rdma_enable) {
|
|
pldn_dly = 1;
|
|
pldn_dly1 = 1;
|
|
} else {
|
|
pldn_dly = 2;
|
|
pldn_dly1 = 2;
|
|
}
|
|
|
|
mtn_int_combing_glbmot();
|
|
}
|
|
|
|
#if 0 /*move to di_local.c*/
|
|
static const struct reserved_mem_ops rmem_di_ops = {
|
|
.device_init = rmem_di_device_init,
|
|
.device_release = rmem_di_device_release,
|
|
};
|
|
|
|
static int __init rmem_di_setup(struct reserved_mem *rmem)
|
|
{
|
|
rmem->ops = &rmem_di_ops;
|
|
/* rmem->priv = cma; */
|
|
|
|
di_pr_info(
|
|
"DI reserved memory: created CMA memory pool at %pa, size %ld MiB\n",
|
|
&rmem->base, (unsigned long)rmem->size / SZ_1M);
|
|
|
|
return 0;
|
|
}
|
|
RESERVEDMEM_OF_DECLARE(di, "amlogic, di-mem", rmem_di_setup);
|
|
#endif
|
|
static void di_get_vpu_clkb(struct device *dev, struct di_dev_s *pdev)
|
|
{
|
|
|
|
int ret = 0;
|
|
unsigned int tmp_clk[2] = {0, 0};
|
|
struct clk *vpu_clk = NULL;
|
|
struct clk *clkb_tmp_comp = NULL;
|
|
|
|
vpu_clk = clk_get(dev, "vpu_mux");
|
|
if (IS_ERR(vpu_clk))
|
|
pr_err("%s: get clk vpu error.\n", __func__);
|
|
else
|
|
clk_prepare_enable(vpu_clk);
|
|
|
|
ret = of_property_read_u32_array(dev->of_node, "clock-range",
|
|
tmp_clk, 2);
|
|
if (ret) {
|
|
pdev->clkb_min_rate = 250000000;
|
|
pdev->clkb_max_rate = 500000000;
|
|
} else {
|
|
pdev->clkb_min_rate = tmp_clk[0]*1000000;
|
|
pdev->clkb_max_rate = tmp_clk[1]*1000000;
|
|
}
|
|
pr_info("DI: vpu clkb <%lu, %lu>\n", pdev->clkb_min_rate,
|
|
pdev->clkb_max_rate);
|
|
#ifdef CLK_TREE_SUPPORT
|
|
pdev->vpu_clkb = clk_get(dev, "vpu_clkb");
|
|
if (is_meson_tl1_cpu()) {
|
|
clkb_tmp_comp = clk_get(dev, "vpu_clkb_tmp");
|
|
if (IS_ERR(clkb_tmp_comp))
|
|
pr_err("clkb_tmp_comp error\n");
|
|
else {
|
|
if (!IS_ERR(vpu_clk))
|
|
/*coverity[var_deref_mode]*/
|
|
clk_set_parent(clkb_tmp_comp, vpu_clk);
|
|
}
|
|
}
|
|
|
|
if (IS_ERR(pdev->vpu_clkb))
|
|
pr_err("%s: get vpu clkb gate error.\n", __func__);
|
|
else {
|
|
clk_set_rate(pdev->vpu_clkb, pdev->clkb_min_rate);
|
|
pr_info("get clkb rate:%ld\n", clk_get_rate(pdev->vpu_clkb));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static int di_probe(struct platform_device *pdev)
|
|
{
|
|
int ret = 0;
|
|
struct di_dev_s *di_devp = NULL;
|
|
|
|
di_pr_info("%s:\n", __func__);
|
|
|
|
#if 1 /*move from init*/
|
|
ret = alloc_chrdev_region(&di_devno, 0, DI_COUNT, DEVICE_NAME);
|
|
if (ret < 0) {
|
|
pr_err("%s: failed to allocate major number\n", __func__);
|
|
goto fail_alloc_cdev_region;
|
|
}
|
|
di_pr_info("%s: major %d\n", __func__, MAJOR(di_devno));
|
|
di_clsp = class_create(CLASS_NAME);
|
|
if (IS_ERR(di_clsp)) {
|
|
ret = PTR_ERR(di_clsp);
|
|
pr_err("%s: failed to create class\n", __func__);
|
|
goto fail_class_create;
|
|
}
|
|
#endif
|
|
|
|
di_devp = kmalloc(sizeof(struct di_dev_s), GFP_KERNEL);
|
|
if (!di_devp) {
|
|
pr_err("%s fail to allocate memory.\n", __func__);
|
|
goto fail_kmalloc_dev;
|
|
}
|
|
de_devp = di_devp;
|
|
memset(di_devp, 0, sizeof(struct di_dev_s));
|
|
di_devp->flags |= DI_SUSPEND_FLAG;
|
|
cdev_init(&(di_devp->cdev), &di_fops);
|
|
di_devp->cdev.owner = THIS_MODULE;
|
|
ret = cdev_add(&(di_devp->cdev), di_devno, DI_COUNT);
|
|
if (ret)
|
|
goto fail_cdev_add;
|
|
|
|
di_devp->devt = MKDEV(MAJOR(di_devno), 0);
|
|
di_devp->dev = device_create(di_clsp, &pdev->dev,
|
|
di_devp->devt, di_devp, "di%d", 0);
|
|
|
|
if (di_devp->dev == NULL) {
|
|
pr_error("device_create create error\n");
|
|
ret = -EEXIST;
|
|
return ret;
|
|
}
|
|
dev_set_drvdata(di_devp->dev, di_devp);
|
|
platform_set_drvdata(pdev, di_devp);
|
|
ret = of_reserved_mem_device_init(&pdev->dev);
|
|
if (ret != 0)
|
|
pr_info("DI no reserved mem.\n");
|
|
ret = of_property_read_u32(pdev->dev.of_node,
|
|
"flag_cma", &(di_devp->flag_cma));
|
|
if (ret)
|
|
pr_err("DI-%s: get flag_cma error.\n", __func__);
|
|
ret = of_property_read_u32(pdev->dev.of_node,
|
|
"nrds-enable", &(di_devp->nrds_enable));
|
|
ret = of_property_read_u32(pdev->dev.of_node,
|
|
"pps-enable", &(di_devp->pps_enable));
|
|
/*di pre h scaling down :sm1 tm2*/
|
|
di_devp->h_sc_down_en = pre_hsc_down_en;
|
|
|
|
pr_info("di:flag_cma=%d\n", di_devp->flag_cma);
|
|
if (di_devp->flag_cma >= 1) {
|
|
#ifdef CONFIG_CMA
|
|
di_devp->pdev = pdev;
|
|
di_devp->flags |= DI_MAP_FLAG;
|
|
if (di_devp->flag_cma == 1
|
|
|| di_devp->flag_cma == 2)
|
|
di_devp->mem_size
|
|
= dma_get_cma_size_int_byte(&pdev->dev);
|
|
|
|
if (di_devp->mem_size <= 0x800000) {
|
|
di_devp->mem_size = 0x2800000;
|
|
//(flag_cma ? 3) reserved in
|
|
//codec mm : cma in codec mm
|
|
if (di_devp->flag_cma != 3) {
|
|
//no di cma, try use
|
|
//cma from codec mm
|
|
di_devp->flag_cma = 4;
|
|
}
|
|
}
|
|
|
|
pr_info("DI: CMA size 0x%x.\n", di_devp->mem_size);
|
|
if (di_devp->flag_cma == 2) {
|
|
if (di_cma_alloc_total(di_devp))
|
|
atomic_set(&di_devp->mem_flag, 1);
|
|
} else
|
|
#endif
|
|
atomic_set(&di_devp->mem_flag, 0);
|
|
} else {
|
|
atomic_set(&di_devp->mem_flag, 1);
|
|
}
|
|
/* mutex_init(&di_devp->cma_mutex); */
|
|
INIT_LIST_HEAD(&di_devp->pq_table_list);
|
|
|
|
atomic_set(&di_devp->pq_flag, 0);
|
|
|
|
di_devp->pre_irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
|
|
pr_info("pre_irq:%d\n",
|
|
di_devp->pre_irq);
|
|
di_devp->post_irq = irq_of_parse_and_map(pdev->dev.of_node, 1);
|
|
pr_info("post_irq:%d\n",
|
|
di_devp->post_irq);
|
|
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_RDMA
|
|
/* rdma handle */
|
|
if (di_pre_rdma_enable) {
|
|
di_rdma_op.arg = di_devp;
|
|
di_devp->rdma_handle = rdma_register(&di_rdma_op,
|
|
di_devp, RDMA_TABLE_SIZE);
|
|
}
|
|
#endif
|
|
di_pr_info("%s allocate rdma channel %d.\n", __func__,
|
|
di_devp->rdma_handle);
|
|
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXL)) {
|
|
di_get_vpu_clkb(&pdev->dev, di_devp);
|
|
#ifdef CLK_TREE_SUPPORT
|
|
clk_prepare_enable(di_devp->vpu_clkb);
|
|
pr_info("DI:enable vpu clkb.\n");
|
|
#else
|
|
aml_write_hiubus(HHI_VPU_CLKB_CNTL, 0x1000100);
|
|
#endif
|
|
}
|
|
di_devp->flags &= (~DI_SUSPEND_FLAG);
|
|
ret = of_property_read_u32(pdev->dev.of_node,
|
|
"buffer-size", &(di_devp->buffer_size));
|
|
if (ret)
|
|
pr_err("DI-%s: get buffer size error.\n", __func__);
|
|
|
|
/* set flag to indicate that post_wr is supportted */
|
|
ret = of_property_read_u32(pdev->dev.of_node,
|
|
"post-wr-support",
|
|
&(di_devp->post_wr_support));
|
|
if (ret)
|
|
post_wr_support = 0;
|
|
else
|
|
post_wr_support = di_devp->post_wr_support;
|
|
|
|
ret = of_property_read_u32(pdev->dev.of_node,
|
|
"nr10bit-support",
|
|
&(di_devp->nr10bit_support));
|
|
if (ret)
|
|
nr10bit_support = 0;
|
|
else
|
|
nr10bit_support = di_devp->nr10bit_support;
|
|
|
|
memset(&di_post_stru, 0, sizeof(di_post_stru));
|
|
di_post_stru.next_canvas_id = 1;
|
|
#ifdef DI_USE_FIXED_CANVAS_IDX
|
|
if (di_get_canvas()) {
|
|
pr_dbg("DI get canvas error.\n");
|
|
ret = -EEXIST;
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
device_create_file(di_devp->dev, &dev_attr_config);
|
|
device_create_file(di_devp->dev, &dev_attr_debug);
|
|
device_create_file(di_devp->dev, &dev_attr_dump_pic);
|
|
device_create_file(di_devp->dev, &dev_attr_log);
|
|
device_create_file(di_devp->dev, &dev_attr_provider_vframe_status);
|
|
device_create_file(di_devp->dev, &dev_attr_frame_format);
|
|
device_create_file(di_devp->dev, &dev_attr_tvp_region);
|
|
pd_device_files_add(di_devp->dev);
|
|
di_nr_opl()->nr_drv_init(di_devp->dev);
|
|
mutex_init(&di_event_mutex);
|
|
di_vpu_dev_register(di_devp);
|
|
|
|
init_flag = 0;
|
|
reg_flag = 0;
|
|
|
|
di_devp->buf_num_avail = di_devp->mem_size / di_devp->buffer_size;
|
|
if (di_devp->buf_num_avail > MAX_LOCAL_BUF_NUM)
|
|
di_devp->buf_num_avail = MAX_LOCAL_BUF_NUM;
|
|
|
|
vf_receiver_init(&di_vf_recv, VFM_NAME, &di_vf_receiver, NULL);
|
|
vf_reg_receiver(&di_vf_recv);
|
|
vf_provider_init(&di_vf_prov, VFM_NAME, &deinterlace_vf_provider, NULL);
|
|
/*active_flag = 1;*/
|
|
sema_init(&di_sema, 1);
|
|
ret = request_irq(di_devp->pre_irq, &de_irq, IRQF_SHARED,
|
|
"pre_di", (void *)"pre_di");
|
|
if (di_devp->post_wr_support) {
|
|
ret = request_irq(di_devp->post_irq, &post_irq,
|
|
IRQF_SHARED, "post_di", (void *)"post_di");
|
|
}
|
|
//sema_init(&di_sema, 1);
|
|
di_sema_init_flag = 1;
|
|
di_hw_init(pulldown_enable, mcpre_en);
|
|
set_di_flag();
|
|
atomic_set(&di_flag_unreg, 0);
|
|
/* Disable MCDI when code does not support MCDI */
|
|
if (!mcpre_en)
|
|
DI_VSYNC_WR_MPEG_REG_BITS(MCDI_MC_CRTL, 0, 0, 1);
|
|
tasklet_init(&di_pre_tasklet, pre_tasklet,
|
|
(unsigned long)(&di_pre_stru));
|
|
tasklet_disable(&di_pre_tasklet);
|
|
hrtimer_init(&di_pre_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
|
di_pre_hrtimer.function = di_pre_hrtimer_func;
|
|
hrtimer_start(&di_pre_hrtimer, ms_to_ktime(10), HRTIMER_MODE_REL);
|
|
tasklet_enable(&di_pre_tasklet);
|
|
di_pr_info("%s:Di use HRTIMER\n", __func__);
|
|
di_devp->task = kthread_run(di_task_handle, di_devp, "kthread_di");
|
|
if (IS_ERR(di_devp->task))
|
|
pr_err("%s create kthread error.\n", __func__);
|
|
active_flag = 1;
|
|
di_debugfs_init(); /*2018-07-18 add debugfs*/
|
|
di_patch_post_update_mc_sw(DI_MC_SW_IC, true);
|
|
|
|
dil_attach_ext_api(&di_ext);
|
|
di_patch_mov_ini();
|
|
|
|
dil_set_diff_ver_flag(0);
|
|
|
|
di_pr_info("%s:ok\n", __func__);
|
|
return ret;
|
|
|
|
fail_cdev_add:
|
|
pr_info("%s:fail_cdev_add\n", __func__);
|
|
kfree(di_devp);
|
|
|
|
fail_kmalloc_dev:
|
|
#if 1 /*move from init*/
|
|
class_destroy(di_clsp);
|
|
fail_class_create:
|
|
unregister_chrdev_region(di_devno, DI_COUNT);
|
|
fail_alloc_cdev_region:
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
static void di_remove(struct platform_device *pdev)
|
|
{
|
|
struct di_dev_s *di_devp = NULL;
|
|
|
|
di_pr_info("%s:\n", __func__);
|
|
di_devp = platform_get_drvdata(pdev);
|
|
|
|
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXLX))
|
|
clk_disable_unprepare(di_devp->vpu_clkb);
|
|
di_hw_uninit();
|
|
di_devp->di_event = 0xff;
|
|
kthread_stop(di_devp->task);
|
|
hrtimer_cancel(&di_pre_hrtimer);
|
|
tasklet_kill(&di_pre_tasklet); //ary.sui
|
|
tasklet_disable(&di_pre_tasklet);
|
|
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_RDMA
|
|
/* rdma handle */
|
|
if (di_devp->rdma_handle > 0)
|
|
rdma_unregister(di_devp->rdma_handle);
|
|
#endif
|
|
|
|
vf_unreg_provider(&di_vf_prov);
|
|
vf_unreg_receiver(&di_vf_recv);
|
|
|
|
di_uninit_buf(1);
|
|
/* Remove the cdev */
|
|
device_remove_file(di_devp->dev, &dev_attr_config);
|
|
device_remove_file(di_devp->dev, &dev_attr_debug);
|
|
device_remove_file(di_devp->dev, &dev_attr_log);
|
|
device_remove_file(di_devp->dev, &dev_attr_dump_pic);
|
|
device_remove_file(di_devp->dev, &dev_attr_provider_vframe_status);
|
|
device_remove_file(di_devp->dev, &dev_attr_frame_format);
|
|
device_remove_file(di_devp->dev, &dev_attr_tvp_region);
|
|
pd_device_files_del(di_devp->dev);
|
|
di_nr_opl()->nr_drv_uninit(di_devp->dev);
|
|
cdev_del(&di_devp->cdev);
|
|
|
|
if (di_devp->flag_cma == 2) {
|
|
if (dma_release_from_contiguous(&(pdev->dev),
|
|
di_devp->total_pages,
|
|
di_devp->mem_size >> PAGE_SHIFT)) {
|
|
di_devp->total_pages = NULL;
|
|
di_devp->mem_start = 0;
|
|
pr_dbg("DI CMA total release ok.\n");
|
|
} else {
|
|
pr_dbg("DI CMA total release fail.\n");
|
|
}
|
|
if (de_devp->nrds_enable) {
|
|
nr_ds_buf_uninit(de_devp->flag_cma,
|
|
&(pdev->dev));
|
|
}
|
|
|
|
}
|
|
device_destroy(di_clsp, di_devno);
|
|
#if 1 /*move from exit*/
|
|
class_destroy(di_clsp);
|
|
di_debugfs_exit();
|
|
unregister_chrdev_region(di_devno, DI_COUNT);
|
|
#endif
|
|
kfree(di_devp);
|
|
/* free drvdata */
|
|
dev_set_drvdata(&pdev->dev, NULL);
|
|
platform_set_drvdata(pdev, NULL);
|
|
|
|
di_pr_info("%s:ok\n", __func__);
|
|
}
|
|
|
|
static void di_shutdown(struct platform_device *pdev)
|
|
{
|
|
struct di_dev_s *di_devp = NULL;
|
|
int ret = 0;
|
|
|
|
active_flag = 0;
|
|
|
|
di_devp = platform_get_drvdata(pdev);
|
|
ret = hrtimer_cancel(&di_pre_hrtimer);
|
|
pr_info("di pre hrtimer cancel %d.\n", ret);
|
|
tasklet_kill(&di_pre_tasklet);
|
|
tasklet_disable(&di_pre_tasklet);
|
|
|
|
init_flag = 0;
|
|
if (is_meson_txlx_cpu())
|
|
di_top_gate_control(true, true);
|
|
else
|
|
DI_Wr(DI_CLKG_CTRL, 0x2);
|
|
|
|
if (!is_meson_txlx_cpu())
|
|
vpu_dev_clk_gate_off(di_devp->di_vpu_clk_gate_dev);
|
|
kfree(di_devp);
|
|
di_devp = NULL;
|
|
pr_info("[DI] shutdown done.\n");
|
|
|
|
}
|
|
|
|
#ifdef CONFIG_PM
|
|
|
|
static void di_clear_for_suspend(struct di_dev_s *di_devp)
|
|
{
|
|
pr_info("%s\n", __func__);
|
|
|
|
di_unreg_process();/*have flag*/
|
|
if (di_pre_stru.unreg_req_flag_irq)
|
|
di_unreg_process_irq();
|
|
|
|
#ifdef CONFIG_CMA
|
|
if (di_pre_stru.cma_release_req) {
|
|
pr_info("\tcma_release\n");
|
|
atomic_set(&di_devp->mem_flag, 0);
|
|
di_cma_release(di_devp);
|
|
di_pre_stru.cma_release_req = 0;
|
|
di_pre_stru.cma_alloc_done = 0;
|
|
}
|
|
#endif
|
|
#ifdef DI_KEEP_HIS
|
|
hrtimer_cancel(&di_pre_hrtimer);
|
|
tasklet_kill(&di_pre_tasklet); //ary.sui
|
|
tasklet_disable(&di_pre_tasklet);
|
|
#endif
|
|
pr_info("%s end\n", __func__);
|
|
}
|
|
static int save_init_flag;
|
|
/* must called after lcd */
|
|
static int di_suspend(struct device *dev)
|
|
{
|
|
|
|
struct di_dev_s *di_devp = NULL;
|
|
|
|
di_devp = dev_get_drvdata(dev);
|
|
di_devp->flags |= DI_SUSPEND_FLAG;
|
|
|
|
di_clear_for_suspend(di_devp);//add
|
|
active_flag = 0;
|
|
|
|
/* fix suspend/resume crash problem */
|
|
save_init_flag = init_flag;
|
|
init_flag = 0;
|
|
|
|
hrtimer_cancel(&di_pre_hrtimer);
|
|
tasklet_kill(&di_pre_tasklet);
|
|
tasklet_disable(&di_pre_tasklet);
|
|
|
|
#if 0 /*2019-01-18*/
|
|
if (di_pre_stru.di_inp_buf) {
|
|
if (vframe_in[di_pre_stru.di_inp_buf->index]) {
|
|
vf_put(vframe_in[di_pre_stru.di_inp_buf->index],
|
|
VFM_NAME);
|
|
vframe_in[di_pre_stru.di_inp_buf->index] = NULL;
|
|
vf_notify_provider(VFM_NAME,
|
|
VFRAME_EVENT_RECEIVER_PUT, NULL);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (!is_meson_txlx_cpu())
|
|
vpu_dev_clk_gate_off(di_devp->di_vpu_clk_gate_dev);
|
|
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXHD))
|
|
clk_disable_unprepare(di_devp->vpu_clkb);
|
|
pr_info("di: di_suspend\n");
|
|
return 0;
|
|
}
|
|
/* must called before lcd */
|
|
static int di_resume(struct device *dev)
|
|
{
|
|
struct di_dev_s *di_devp = NULL;
|
|
|
|
di_devp = dev_get_drvdata(dev);
|
|
|
|
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXL))
|
|
clk_prepare_enable(di_devp->vpu_clkb);
|
|
init_flag = save_init_flag;
|
|
di_devp->flags &= ~DI_SUSPEND_FLAG;
|
|
/*2018-01-18*/
|
|
pr_info("%s\n", __func__);
|
|
tasklet_init(&di_pre_tasklet, pre_tasklet,
|
|
(unsigned long)(&di_pre_stru));
|
|
tasklet_disable(&di_pre_tasklet);
|
|
hrtimer_init(&di_pre_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
|
di_pre_hrtimer.function = di_pre_hrtimer_func;
|
|
hrtimer_start(&di_pre_hrtimer, ms_to_ktime(10), HRTIMER_MODE_REL);
|
|
tasklet_enable(&di_pre_tasklet);
|
|
active_flag = 1;
|
|
/************/
|
|
pr_info("di: resume module\n");
|
|
return 0;
|
|
}
|
|
|
|
static const struct dev_pm_ops di_pm_ops = {
|
|
.suspend_late = di_suspend,
|
|
.resume_early = di_resume,
|
|
};
|
|
#endif
|
|
|
|
/* #ifdef CONFIG_USE_OF */
|
|
static const struct of_device_id amlogic_deinterlace_dt_match[] = {
|
|
{ .compatible = "amlogic, deinterlace", },
|
|
{},
|
|
};
|
|
/* #else */
|
|
/* #define amlogic_deinterlace_dt_match NULL */
|
|
/* #endif */
|
|
|
|
static struct platform_driver di_driver = {
|
|
.probe = di_probe,
|
|
.remove = di_remove,
|
|
.shutdown = di_shutdown,
|
|
.driver = {
|
|
.name = DEVICE_NAME,
|
|
.owner = THIS_MODULE,
|
|
.of_match_table = amlogic_deinterlace_dt_match,
|
|
#ifdef CONFIG_PM
|
|
.pm = &di_pm_ops,
|
|
#endif
|
|
}
|
|
};
|
|
|
|
int __init di_module_init(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
pr_dbg("%s ok.\n", __func__);
|
|
#if 0 /*move to prob*/
|
|
ret = alloc_chrdev_region(&di_devno, 0, DI_COUNT, DEVICE_NAME);
|
|
if (ret < 0) {
|
|
pr_err("%s: failed to allocate major number\n", __func__);
|
|
goto fail_alloc_cdev_region;
|
|
}
|
|
di_pr_info("%s: major %d\n", __func__, MAJOR(di_devno));
|
|
di_clsp = class_create(THIS_MODULE, CLASS_NAME);
|
|
if (IS_ERR(di_clsp)) {
|
|
ret = PTR_ERR(di_clsp);
|
|
pr_err("%s: failed to create class\n", __func__);
|
|
goto fail_class_create;
|
|
}
|
|
#endif
|
|
ret = platform_driver_register(&di_driver);
|
|
if (ret != 0) {
|
|
pr_err("%s: failed to register driver\n", __func__);
|
|
return -ENODEV;//goto fail_pdrv_register;
|
|
}
|
|
return 0;
|
|
#if 0 /*move to prob*/
|
|
fail_pdrv_register:
|
|
class_destroy(di_clsp);
|
|
fail_class_create:
|
|
unregister_chrdev_region(di_devno, DI_COUNT);
|
|
fail_alloc_cdev_region:
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
void __exit di_module_exit(void)
|
|
{
|
|
#if 0 /*move to remove*/
|
|
class_destroy(di_clsp);
|
|
di_debugfs_exit();
|
|
unregister_chrdev_region(di_devno, DI_COUNT);
|
|
#endif
|
|
platform_driver_unregister(&di_driver);
|
|
}
|
|
//MODULE_DESCRIPTION("AMLOGIC DEINTERLACE driver");
|
|
//MODULE_LICENSE("GPL");
|
|
//MODULE_VERSION("4.0.0");
|