| /* |
| * drivers/amlogic/media/deinterlace/deinterlace.c |
| * |
| * Copyright (C) 2017 Amlogic, Inc. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| * more details. |
| * |
| */ |
| |
| #include <linux/version.h> |
| #include <linux/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-contiguous.h> |
| #include <linux/ctype.h> |
| #include <linux/string.h> |
| #include <linux/of_device.h> |
| #include <linux/amlogic/iomap.h> |
| #include <linux/amlogic/media/codec_mm/codec_mm.h> |
| #include <linux/amlogic/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 "../common/vfm/vfm.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" |
| |
| #include <linux/seq_file.h> |
| #include <linux/debugfs.h> |
| |
| #ifdef DET3D |
| #include "detect3d.h" |
| #endif |
| #define ENABLE_SPIN_LOCK_ALWAYS |
| |
| #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 int queue_print_flag = -1; |
| static int di_reg_unreg_cnt = 1000; |
| static bool overturn; |
| static bool check_start_drop_prog; |
| static bool mcpre_en = true; |
| |
| static bool mc_mem_alloc; |
| |
| static unsigned int di_pre_rdma_enable; |
| static struct mutex di_event_mutex; |
| static atomic_t di_flag_unreg; //ary 2019-05-27 |
| static atomic_t di_clear_unreg; |
| static atomic_t di_trig_free_mem; |
| |
| static unsigned int di_force_bit_mode = 10; |
| module_param(di_force_bit_mode, uint, 0664); |
| MODULE_PARM_DESC(di_force_bit_mode, "force DI bit mode to 8 or 10 bit"); |
| |
| static bool full_422_pack; |
| /* 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"; |
| |
| static int bypass_state = 1; |
| static int bypass_all; |
| /*1:enable bypass pre,ei only; |
| * 2:debug force bypass pre,ei for post |
| */ |
| static int bypass_pre; |
| 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 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 force_width; |
| static int force_height; |
| /* 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 |
| */ |
| static int di_vscale_skip_enable; |
| |
| /* 0: not support nr10bit, 1: support nr10bit */ |
| static unsigned int nr10bit_support; |
| |
| #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; |
| */ |
| 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 |
| */ |
| static int prog_proc_config = (1 << 5) | (1 << 1) | 1; |
| /* |
| * for source include both progressive and interlace pictures, |
| * always use post_di module for blending |
| */ |
| #define is_handle_prog_frame_as_interlace(vframe) \ |
| (((prog_proc_config & 0x30) == 0x20) && \ |
| ((vframe->type & VIDTYPE_VIU_422) == 0)) |
| |
| static int frame_count; |
| static int disp_frame_count; |
| static int start_frame_drop_count = 2; |
| /* static int start_frame_hold_count = 0; */ |
| |
| static int video_peek_cnt; |
| static unsigned long reg_unreg_timeout_cnt; |
| static int di_vscale_skip_count; |
| static int di_vscale_skip_count_real; |
| static int vpp_3d_mode; |
| static bool det3d_en; |
| |
| #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 force_recovery = 1; |
| static unsigned int force_recovery_count; |
| static unsigned int recovery_log_reason; |
| static unsigned int recovery_log_queue_idx; |
| static struct di_buf_s *recovery_log_di_buf; |
| |
| static long same_field_top_count; |
| static long same_field_bot_count; |
| /* bit 0: |
| * 0, keep 3 buffers in pre_ready_list for checking; |
| * 1, keep 4 buffers in pre_ready_list for checking; |
| */ |
| |
| static int post_hold_line = 8; /*2019-01-10: from VLSI feijun from 17 to 8*/ |
| static int post_urgent = 1; |
| |
| /*pre process speed debug */ |
| static int pre_process_time; |
| 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; |
| |
| unsigned int di_dbg_cfg = DI_NONE; |
| module_param(di_dbg_cfg, uint, 0664); |
| |
| static const |
| struct vframe_receiver_op_s di_vf_receiver = { |
| .event_cb = di_receiver_event_fun |
| }; |
| |
| int di_get_disp_cnt_demo(void) |
| { |
| return disp_frame_count; |
| } |
| |
| 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; |
| 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); |
| } |
| |
| static unsigned int di_printk_flag; |
| #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_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]; |
| |
| #define signal_color_primaries ((vframe->signal_type >> 16) & 0xff) |
| #define signal_transfer_characteristic ((vframe->signal_type >> 8) & 0xff) |
| |
| /************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; |
| |
| 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_MPEG_REG(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_MPEG_REG_BITS(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_MPEG_REG(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_MPEG_REG_BITS(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_MPEG_REG(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_MPEG_REG_BITS(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; |
| static int mirror_flag = DI_RUN_MIRROR_DIS; |
| /*2018-08-17 add debugfs*/ |
| /*add debugfs: get dump_state parameter*/ |
| int get_mirror_status(void) |
| { |
| return mirror_flag; |
| } |
| |
| 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; |
| } |
| |
| static inline struct div1_data_l_s *getv1_datal(void) |
| { |
| return (struct div1_data_l_s *)get_di_de_devp()->data_l; |
| } |
| |
| const struct afdv1_ops_s *di_afds(void) |
| { |
| if (!de_devp) |
| return NULL; |
| |
| return de_devp->afds; |
| } |
| |
| struct afbcdv1_ctr_s *div1_get_afd_ctr(void) |
| { |
| if (!de_devp) |
| return NULL; |
| |
| return &de_devp->di_afd.ctr; |
| } |
| |
| 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_diffver_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__); |
| } |
| } |
| EXPORT_SYMBOL(di_trig_free_mirror_mem); |
| |
| u32 di_api_get_instance_id(void) |
| { |
| u32 ret = 0; |
| |
| if (dil_get_diffver_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 = 0; |
| 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, "mirrorh", 7) == 0) { |
| mirror_flag = DI_RUN_MIRROR_H; |
| } else if (strncmp(buf, "mirrorv", 7) == 0) { |
| mirror_flag = DI_RUN_MIRROR_V; |
| } else if (strncmp(buf, "dismirror", 9) == 0) { |
| mirror_flag = DI_RUN_MIRROR_DIS; |
| } else if (strncmp(buf, "dumpreg", 7) == 0) { |
| if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A)) { |
| dump_di_reg_g12(); |
| /*dump_afbcd_reg();*/ |
| if (di_afds()) |
| di_afds()->dump_reg(); |
| } else |
| pr_info("add new debugfs: cat /sys/kernel/debug/di/dumpreg\n"); |
| } else if (strncmp(buf, "dumpafbc", 8) == 0) { |
| /*dump_afbcd_reg();*/ |
| if (di_afds()) |
| di_afds()->dump_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) { |
| } else if (strncmp(buf, "reqafbc", 7) == 0) { |
| if (di_afds()) |
| val = di_afds()->rqst_share(true); |
| |
| pr_info("request_afbc(%d)\n", val); |
| } else if (strncmp(buf, "rlsafbc", 7) == 0) { |
| if (di_afds()) |
| val = di_afds()->rqst_share(true); |
| |
| 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 __init di_read_canvas_reverse(char *str) |
| { |
| unsigned char *ptr = str; |
| |
| di_pr_info("%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 int di_debug_flag;/* enable rdma even di bypassed */ |
| 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 di_log_flag; |
| static unsigned int buf_state_log_threshold = 16; |
| 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) |
| { |
| 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); |
| 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); |
| 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); |
| } |
| } |
| |
| 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) || |
| ((di_pre_stru.cur_inp_type & VIDTYPE_INTERLACE_TOP) != |
| (vframe->type & VIDTYPE_INTERLACE_TOP))) { |
| /* 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 (vf_in && vf_in->type & VIDTYPE_COMPRESS) { |
| if (di_afds() && !di_afds()->is_supported()) |
| return 1; |
| } |
| |
| if (/*di_pre_stru.cur_prog_flag && */ |
| ((di_pre_stru.cur_width > default_width) || |
| (di_pre_stru.cur_height > (default_height + 8)) || |
| (di_pre_stru.cur_inp_type & VIDTYPE_VIU_444) || |
| (di_pre_stru.cur_inp_type & VIDTYPE_RGB_444))) |
| return 1; |
| |
| if ((di_pre_stru.cur_width < 128) || (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 ((is_meson_gxl_package_805X() || is_meson_gxl_package_805Y()) && |
| vf_in && is_progressive(vf_in)) |
| 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 ((di_pre_stru.is_tvp == -1) && |
| codec_mm_video_tvp_enabled()) { |
| istvp = true; |
| flags |= CODEC_MM_FLAGS_TVP; |
| } else if (di_pre_stru.is_tvp == 1) { |
| 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); |
| 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 s8 check_tvp_state(void) |
| { |
| struct provider_state_req_s req; |
| s8 ret = -1; |
| char *provider_name = vf_get_provider_name(VFM_NAME); |
| |
| while (provider_name) { |
| if (!vf_get_provider_name(provider_name)) |
| break; |
| provider_name = |
| vf_get_provider_name(provider_name); |
| } |
| if (provider_name) { |
| req.vf = NULL; |
| req.req_type = REQ_STATE_SECURE; |
| req.req_result[0] = 0xffffffff; |
| vf_notify_provider_by_name( |
| provider_name, |
| VFRAME_EVENT_RECEIVER_REQ_STATE, |
| (void *)&req); |
| if (req.req_result[0] == 0) |
| ret = 0; |
| else if (req.req_result[0] != 0xffffffff) |
| ret = 1; |
| } |
| return ret; |
| } |
| |
| static bool cma_print; |
| 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; |
| |
| di_pre_stru.is_tvp = check_tvp_state(); |
| |
| 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), tvp:%d\n", |
| __func__, alloc_cnt, delta_time, start_time, end_time, |
| di_pre_stru.is_tvp); |
| 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); |
| |
| /************************************************ |
| * di_limit_local |
| * 805x limit local buf: |
| * bit[7:0]: omx keep buf, max 8, now 6 |
| * bit[15:8]: di use local buf |
| * set 0: no use |
| ***********************************************/ |
| static unsigned int di_limit_local; |
| module_param_named(di_limit_local, di_limit_local, uint, 0664); |
| |
| static bool limit_is_s805x(void) |
| { |
| if (is_meson_gxl_package_805X() || is_meson_gxl_package_805Y()) |
| return true; |
| return false; |
| } |
| |
| static unsigned int limit_buf_cnt(void) |
| { |
| unsigned int cnt; |
| unsigned int omx_buf, local_buf; |
| /**************************************** |
| * omx_buf: omx keep buf number |
| * normal is 8 |
| ***************************************/ |
| if (di_limit_local & 0xff) |
| omx_buf = di_limit_local & 0xff; |
| else |
| omx_buf = 8; |
| |
| if (di_limit_local & 0xff00) |
| local_buf = (di_limit_local & 0xff00) >> 8; |
| else |
| local_buf = 10; |
| cnt = omx_buf + local_buf; |
| |
| return cnt; |
| } |
| |
| 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, *tmp_meta; |
| unsigned int buf_limit; /* for s805 */ |
| |
| 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 releae 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; |
| } |
| /**/ |
| if (limit_is_s805x()) { |
| buf_limit = limit_buf_cnt(); |
| if ((de_devp->buf_num_avail > buf_limit) && |
| (buf_limit > 4)) { |
| de_devp->buf_num_avail = buf_limit; |
| di_print("%s:avail[%d], limit[%d]\n", __func__, |
| de_devp->buf_num_avail, buf_limit); |
| } |
| } |
| 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); |
| tmp_meta = de_devp->local_meta_addr; |
| 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; |
| /*&(vframe_local[i]);*/ |
| di_buf->vframe = &de_devp->vfm_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; |
| if (de_devp->local_meta_addr) { |
| di_buf->local_meta = tmp_meta; |
| di_buf->local_meta_total_size = |
| LOCAL_META_BUFF_SIZE; |
| } else { |
| di_buf->local_meta = NULL; |
| di_buf->local_meta_total_size = 0; |
| } |
| di_buf->local_meta_used_size = 0; |
| queue_in(di_buf, QUEUE_LOCAL_FREE); |
| } else { |
| if (!di_buf->local_meta) { |
| if (de_devp->local_meta_addr) { |
| di_buf->local_meta = tmp_meta; |
| di_buf->local_meta_total_size = |
| LOCAL_META_BUFF_SIZE; |
| } else { |
| di_buf->local_meta = NULL; |
| di_buf->local_meta_total_size = 0; |
| } |
| di_buf->local_meta_used_size = 0; |
| } |
| if (di_buf->local_meta != tmp_meta) |
| pr_info("DI: local buf init, keep buffer meta %p, new:%p.\n", |
| di_buf->local_meta, tmp_meta); |
| } |
| if (tmp_meta) |
| tmp_meta += LOCAL_META_BUFF_SIZE; |
| } |
| #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; |
| tmp_meta = de_devp->local_meta_addr + |
| (MAX_LOCAL_BUF_NUM * LOCAL_META_BUFF_SIZE * 2); |
| 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 = &de_devp->vfm_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; |
| if (de_devp->local_meta_addr) { |
| di_buf->local_meta = tmp_meta; |
| di_buf->local_meta_total_size = |
| LOCAL_META_BUFF_SIZE; |
| } else { |
| di_buf->local_meta = NULL; |
| di_buf->local_meta_total_size = 0; |
| } |
| di_buf->local_meta_used_size = 0; |
| queue_in(di_buf, QUEUE_IN_FREE); |
| } |
| if (tmp_meta) |
| tmp_meta += LOCAL_META_BUFF_SIZE; |
| } |
| |
| tmp_meta = de_devp->local_meta_addr + |
| ((MAX_IN_BUF_NUM + |
| (MAX_LOCAL_BUF_NUM * 2)) * LOCAL_META_BUFF_SIZE); |
| 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 (de_devp->local_meta_addr) { |
| di_buf->local_meta = tmp_meta; |
| di_buf->local_meta_total_size = |
| LOCAL_META_BUFF_SIZE; |
| } else { |
| di_buf->local_meta = NULL; |
| di_buf->local_meta_total_size = 0; |
| } |
| di_buf->local_meta_used_size = 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); |
| } else { |
| if (!di_buf->local_meta) { |
| if (de_devp->local_meta_addr) { |
| di_buf->local_meta = tmp_meta; |
| di_buf->local_meta_total_size = |
| LOCAL_META_BUFF_SIZE; |
| } else { |
| di_buf->local_meta = NULL; |
| di_buf->local_meta_total_size = |
| 0; |
| } |
| di_buf->local_meta_used_size = 0; |
| } |
| if (di_buf->local_meta != tmp_meta) |
| pr_info("DI:post keep buffer meta %p\n", |
| keep_buf->local_meta); |
| pr_info("DI:post keep buffer new:%p.\n", |
| tmp_meta); |
| } |
| } |
| if (tmp_meta) |
| tmp_meta += LOCAL_META_BUFF_SIZE; |
| } |
| 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; |
| |
| #ifdef DI_KEEP_DEC_VF |
| /* dec vf keep */ |
| if (p->in_buf) { |
| vframe_in[p->in_buf->index] = NULL; |
| queue_in(p->in_buf, QUEUE_RECYCLE); |
| di_print("dec vf pd[%d]\n", |
| p->in_buf->vframe->index_disp); |
| p->in_buf = NULL; |
| } |
| #endif |
| |
| 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++) { |
| 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 releae 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", (di_afds() && di_afds()->is_supported()) ? |
| true : false); |
| 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 != &de_devp->vfm_in_dup[di_buf->index]) |
| error = 1; |
| } else if (di_buf->type == VFRAME_TYPE_LOCAL) { |
| if (di_buf->vframe != &de_devp->vfm_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 / 2; |
| di_mcinfo_mif->size_x = pre_size_h / 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 bool force_prog = true; |
| module_param_named(force_prog, force_prog, bool, 0664); |
| 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 + 1) / 2 - 1; |
| } else if ((di_pre_stru.cur_inp_type & VIDTYPE_INTERLACE) && |
| (di_pre_stru.cur_inp_type & VIDTYPE_VIU_FIELD)) { |
| di_mif->src_prog = 0; |
| 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 / 2 - 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 / 4 - 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 - 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 + 1) / 2 - 1; |
| } 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 + 1) / 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_inp_mif_w(struct DI_MIF_s *di_mif, struct vframe_s *vf); |
| |
| 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 |
| pre_inp_mif_w(&di_pre_stru.di_inp_mif, di_pre_stru.di_inp_buf->vframe); |
| 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; |
| } |
| |
| #ifdef DI_FILM_GRAIN |
| if (di_pre_stru.source_change_flag && (di_dbg_cfg & DBG_M_FG)) |
| di_fgrain_config(&di_pre_stru.di_inp_mif, |
| &di_pre_stru.fgrain_diset, |
| di_pre_stru.di_inp_buf->vframe); |
| #endif |
| 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); |
| } |
| } |
| |
| /*patch for SECAM signal format from vlsi-feijun for all IC*/ |
| secam_cfr_adjust(di_pre_stru.di_inp_buf->vframe->sig_fmt, |
| di_pre_stru.di_inp_buf->vframe->type); |
| |
| /* 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 (di_afds()) |
| di_afds()->en_pre_set(di_pre_stru.di_inp_buf->vframe, |
| di_pre_stru.di_mem_buf_dup_p->vframe, |
| di_pre_stru.di_wr_buf->vframe); |
| #ifdef DI_FILM_GRAIN |
| if (di_dbg_cfg & DBG_M_FG) { |
| if (di_pre_stru.source_change_flag) |
| di_fgrain_setting(&di_pre_stru.fgrain_diset, |
| di_pre_stru.di_inp_buf->vframe); |
| |
| di_fgrain_update_table(di_pre_stru.di_inp_buf->vframe); |
| } |
| #endif |
| 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); |
| if (di_afds()->is_cfg(EAFBCV1_CFG_PAUSE) && |
| di_pre_stru.field_count_for_cont == 2) { |
| pre_run_flag = DI_RUN_FLAG_PAUSE; |
| } |
| 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)) { |
| /* enable mc pre mif*/ |
| enable_di_pre_mif(true, mcpre_en); |
| 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*/ |
| di_tr_ops.pre_set(di_pre_stru.di_wr_buf->vframe->omx_index); |
| #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 bool pulldown_enable = true; |
| |
| static bool combing_fix_en = true; |
| module_param_named(combing_fix_en, combing_fix_en, bool, 0664); |
| |
| static int cur_lev = 2; |
| module_param_named(combing_cur_lev, cur_lev, int, 0444); |
| |
| 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) { |
| di_tr_ops.pre_cnt0(di_pre_stru.di_wr_buf->vframe->omx_index); |
| di_tr_ops.pre_cnt1(di_pre_stru.di_wr_buf->vframe->omx_index); |
| di_tr_ops.pre_ready(di_pre_stru.di_wr_buf->vframe->omx_index); |
| |
| 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 |
| #ifdef DI_KEEP_DEC_VF |
| /*dec vf keep*/ |
| if (di_pre_stru.di_inp_buf && |
| di_pre_stru.di_inp_buf->dec_vf_state) { |
| di_pre_stru.di_wr_buf->in_buf = di_pre_stru.di_inp_buf; |
| di_print("di:dec vf:la[%d]\n", |
| di_pre_stru.di_inp_buf->vframe->index_disp); |
| } |
| #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 (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)) |
| 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 */ |
| 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); |
| #ifdef DI_KEEP_DEC_VF /*dec vf keep*/ |
| if (!(di_pre_stru.di_inp_buf->dec_vf_state)) { |
| queue_in(di_pre_stru.di_inp_buf, QUEUE_RECYCLE); |
| di_pre_stru.di_inp_buf = NULL; |
| } |
| #else |
| queue_in(di_pre_stru.di_inp_buf, QUEUE_RECYCLE); |
| di_pre_stru.di_inp_buf = NULL; |
| #endif |
| 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); |
| } |
| } |
| 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 |
| |
| static void pre_inp_mif_w(struct DI_MIF_s *di_mif, struct vframe_s *vf) |
| { |
| if (vf->canvas0Addr != (u32)-1) |
| di_mif->canvas_w = canvas_get_width( |
| vf->canvas0Addr & 0xff); |
| else |
| di_mif->canvas_w = vf->canvas0_config[0].width; |
| } |
| |
| static int pps_dstw; |
| module_param_named(pps_dstw, pps_dstw, int, 0644); |
| static int pps_dsth; |
| module_param_named(pps_dsth, pps_dsth, int, 0644); |
| static bool pps_en; |
| module_param_named(pps_en, pps_en, bool, 0644); |
| static unsigned int pps_position = 1; |
| module_param_named(pps_position, pps_position, uint, 0644); |
| static unsigned int pre_enable_mask = 3;/*bit0:ma bit1:mc*/ |
| module_param_named(pre_enable_mask, pre_enable_mask, uint, 0644); |
| |
| static bool pre_hsc_down_en; |
| module_param_named(pre_hsc_down_en, pre_hsc_down_en, bool, 0644); |
| static int pre_hsc_down_width = 480; |
| module_param_named(pre_hsc_down_width, pre_hsc_down_width, int, 0644); |
| |
| 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; |
| bool flg_1080i = false; |
| bool flg_480i = false; |
| u32 cur_dw_width = 0xffff; |
| u32 cur_dw_height = 0xffff; |
| #ifdef DI_KEEP_DEC_VF |
| bool flg_2nd = false; |
| #endif |
| 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; |
| di_tr_ops.pre_get(vframe->omx_index); |
| /*for support compress from dec*/ |
| if (IS_COMP_MODE(vframe->type)) { |
| /*backup the orignal vf->width/height for bypass case */ |
| cur_dw_width = vframe->width; |
| cur_dw_height = vframe->height; |
| 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; |
| } |
| |
| 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; |
| #ifdef DI_KEEP_DEC_VF |
| di_buf->dec_vf_state = 0; /*dec vf keep*/ |
| #endif |
| 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->dw_width_bk = cur_dw_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++; |
| di_buf->local_meta_used_size = 0; |
| queue_out(di_buf); |
| if ((signal_transfer_characteristic == 0x30) && |
| ((signal_color_primaries == 9) || |
| (signal_color_primaries == 2))) { |
| struct provider_aux_req_s req; |
| char *provider_name = NULL, *tmp_name = NULL; |
| |
| provider_name = vf_get_provider_name(VFM_NAME); |
| while (provider_name) { |
| tmp_name = |
| vf_get_provider_name(provider_name); |
| if (!tmp_name) |
| break; |
| provider_name = tmp_name; |
| } |
| if (provider_name) { |
| req.vf = vframe; |
| req.bot_flag = 0; |
| req.aux_buf = NULL; |
| req.aux_size = 0; |
| req.dv_enhance_exist = 0; |
| vf_notify_provider_by_name( |
| provider_name, |
| VFRAME_EVENT_RECEIVER_GET_AUX_DATA, |
| (void *)&req); |
| } |
| if (req.aux_buf && req.aux_size && |
| di_buf->local_meta && |
| (di_buf->local_meta_total_size >= req.aux_size)) { |
| memcpy(di_buf->local_meta, |
| req.aux_buf, req.aux_size); |
| di_buf->local_meta_used_size = req.aux_size; |
| } else if (di_buf->local_meta && provider_name) { |
| pr_info("DI:get meta data error aux_buf:%p\n", |
| req.aux_buf); |
| pr_info("DI:get meta data errorsize:%d (%d)\n", |
| req.aux_size, |
| di_buf->local_meta_total_size); |
| } |
| } |
| 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)) { |
| 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; |
| di_pre_stru.cur_sig_fmt = di_buf->vframe->sig_fmt; |
| 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 |
| |
| /*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)) { |
| if (IS_COMP_MODE(di_buf->vframe->type) && |
| (cur_dw_width != 0xffff) && |
| (cur_dw_height != 0xffff)) { |
| di_buf->vframe->width = cur_dw_width; |
| di_buf->vframe->height = cur_dw_height; |
| } |
| /* 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 ( |
| (bypass_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; |
| #ifdef DI_KEEP_DEC_VF |
| flg_2nd = true; |
| #endif |
| 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; |
| /* 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 (di_buf->local_meta && |
| di_pre_stru.di_inp_buf->local_meta && |
| di_pre_stru.di_inp_buf->local_meta_used_size) { |
| memcpy(di_buf->local_meta, |
| di_pre_stru.di_inp_buf->local_meta, |
| di_pre_stru.di_inp_buf->local_meta_used_size * |
| sizeof(u8)); |
| di_buf->local_meta_used_size = |
| di_pre_stru.di_inp_buf->local_meta_used_size; |
| } else { |
| di_buf->local_meta_used_size = 0; |
| } |
| 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_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; |
| } |
| #ifdef DI_KEEP_DEC_VF |
| if (!flg_2nd) |
| di_pre_stru.di_inp_buf->dec_vf_state = 1; /*dec vf keep*/ |
| #endif /* DI_KEEP_DEC_VF */ |
| 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)); |
| di_print("dec vf back[%d]\n", |
| vframe_in[di_buf->index]->index_disp); |
| vframe_in[di_buf->index] = NULL; |
| } |
| di_buf->invert_top_bot_flag = 0; |
| #ifdef DI_KEEP_DEC_VF |
| di_buf->dec_vf_state = 0; /*dec vf keep*/ |
| #endif |
| 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 unsigned int det3d_frame_cnt = 50; |
| module_param_named(det3d_frame_cnt, det3d_frame_cnt, uint, 0644); |
| 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 |
| |
| static bool calc_mcinfo_en = 1; |
| module_param(calc_mcinfo_en, bool, 0664); |
| MODULE_PARM_DESC(calc_mcinfo_en, "/n get mcinfo for post /n"); |
| |
| static unsigned int colcfd_thr = 128; |
| module_param(colcfd_thr, uint, 0664); |
| MODULE_PARM_DESC(colcfd_thr, "/n threshold for cfd/n"); |
| |
| 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 inetrrupr 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_hpre_gl_sw(false); |
| DI_Wr(DI_INTR_CTRL, (data32&0xfffffffb)|(intr_mode<<30)); |
| } |
| #endif |
| |
| if (di_pre_stru.pre_de_busy == 0) { |
| if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXM)) { |
| /* gxl ? */ |
| 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]); |
| di_tr_ops.pre(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(); |
| if ((is_meson_gxlx_cpu() && |
| di_pre_stru.field_count_for_cont >= 4) || |
| is_meson_txhd_cpu()) |
| mc_pre_mv_irq(); |
| calc_lmv_base_mcinfo((di_pre_stru.cur_height>>1), |
| di_pre_stru.di_wr_buf->mcinfo_vaddr); |
| } |
| 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); |
| di_tr_ops.post(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 sreay 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_diffver_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) |
| |
| static unsigned int pldn_dly = 1; |
| |
| static unsigned int post_blend; |
| module_param(post_blend, uint, 0664); |
| MODULE_PARM_DESC(post_blend, "/n show blend mode/n"); |
| static unsigned int post_ei; |
| module_param(post_ei, uint, 0664); |
| MODULE_PARM_DESC(post_ei, "/n show blend mode/n"); |
| |
| static unsigned int post_cnt; |
| module_param(post_cnt, uint, 0664); |
| MODULE_PARM_DESC(post_cnt, "/n show blend mode/n"); |
| static bool post_refresh; |
| module_param_named(post_refresh, post_refresh, bool, 0644); |
| 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; |
| unsigned char tmp_idx = 0; |
| |
| if (!active_flag) |
| return 0; |
| 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_buf->vframe) |
| di_tr_ops.post_set(di_buf->vframe->omx_index); |
| else |
| 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 > 3) && 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; |
| |
| 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; |
| } |
| |
| 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); |
| 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; |
| } |
| 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; |
| } |
| if (is_meson_txl_cpu() && overturn) |
| mc_pre_flag = 1; |
| |
| 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; |
| if (is_meson_txl_cpu() && overturn) { |
| di_post_stru.di_buf1_mif.canvas0_addr0 = |
| di_post_stru.di_buf2_mif.canvas0_addr0; |
| } |
| 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; |
| } |
| |
| #ifdef DI_KEEP_DEC_VF |
| /*dec vf keep*/ |
| if (di_buf->in_buf) { |
| di_print("di:%s:type[%d]:b:p[%d],i[%d]\n", __func__, |
| di_buf->type, |
| di_buf->index, di_buf->in_buf->index); |
| di_print("di:dec vf[%d]\n", |
| di_buf->in_buf->vframe->index_disp); |
| queue_in(di_buf->in_buf, QUEUE_RECYCLE); |
| di_buf->in_buf = NULL; |
| } |
| #endif |
| |
| 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 int debug_blend_mode = -1; |
| static unsigned int pldn_dly1 = 1; |
| 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; |
| #ifdef DI_KEEP_DEC_VF |
| struct vframe_s *vf = NULL; |
| #endif |
| di_lock_irqfiq_save(irq_flag2); |
| if ((frame_count == 0) && check_drop) { |
| di_post_stru.start_pts = di_buf->vframe->pts; |
| di_post_stru.start_pts64 = di_buf->vframe->pts_us64; |
| } |
| 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_buf->vframe->pts_us64 = |
| di_post_stru.start_pts64; |
| } |
| 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) { |
| #ifdef DI_KEEP_DEC_VF |
| /*dec vf keep*/ |
| if (di_buf->in_buf) { |
| queue_in(di_buf->in_buf, QUEUE_RECYCLE); |
| di_buf->in_buf = NULL; |
| } |
| #endif |
| 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 { |
| #ifdef DI_KEEP_DEC_VF |
| /*dec vf keep*/ |
| if (di_buf->in_buf) { |
| vf = vframe_in[di_buf->in_buf->index]; |
| di_buf->vframe->vf_ext = vf; |
| if (vf) { /*debug*/ |
| di_print("di:dec vf:pb:b[%d],in[%d],v[%p]\n", |
| di_buf->index, di_buf->in_buf->index, |
| vf); |
| di_print("di:dec vf:omx[%d]\n", |
| vf->index_disp); |
| } |
| } |
| #endif /*DI_KEEP_DEC_VF*/ |
| |
| if (post_wr_en && post_wr_support) |
| queue_in(di_buf, QUEUE_POST_DOING); |
| else { |
| queue_in(di_buf, QUEUE_POST_READY); |
| di_tr_ops.post_ready(di_buf->vframe->omx_index); |
| } |
| 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; |
| #ifdef DI_KEEP_DEC_VF |
| struct di_buf_s *di_tmp; |
| struct vframe_s *vf; |
| #endif |
| 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->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)); |
| if (di_buf->local_meta && |
| di_buf->di_buf_dup_p[1]->local_meta && |
| di_buf->di_buf_dup_p[1]->local_meta_used_size) { |
| memset(di_buf->local_meta, 0, |
| di_buf->local_meta_total_size); |
| memcpy(di_buf->local_meta, |
| di_buf->di_buf_dup_p[1]->local_meta, |
| di_buf->di_buf_dup_p[1]->local_meta_used_size * sizeof(u8)); |
| di_buf->local_meta_used_size = |
| di_buf->di_buf_dup_p[1]->local_meta_used_size; |
| } else { |
| di_buf->local_meta_used_size = 0; |
| } |
| 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; |
| |
| 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; |
| |
| 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]); |
| #ifdef DI_KEEP_DEC_VF |
| /* dec vf keep */ |
| di_tmp = di_buf->di_buf[0]; |
| if (di_tmp->type == VFRAME_TYPE_LOCAL && |
| di_tmp->in_buf) { |
| di_buf->in_buf = di_tmp->in_buf; |
| di_buf->vframe->di_instance_id = |
| de_devp->instance_id; |
| di_buf->vframe->flag |= |
| VFRAME_FLAG_DOUBLE_FRAM; |
| di_tmp->in_buf = NULL; |
| vf = di_buf->in_buf->vframe; |
| di_print("di:dec:pa:i:[%d]\n", |
| vf->index_disp); |
| } |
| #endif |
| 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)); |
| if (di_buf->local_meta && |
| di_buf_i->local_meta && |
| di_buf_i->local_meta_used_size) { |
| memset(di_buf->local_meta, 0, |
| di_buf->local_meta_total_size); |
| memcpy(di_buf->local_meta, |
| di_buf_i->local_meta, |
| di_buf_i->local_meta_used_size * |
| sizeof(u8)); |
| di_buf->local_meta_used_size = |
| di_buf_i->local_meta_used_size; |
| } else { |
| di_buf->local_meta_used_size = 0; |
| } |
| if (IS_COMP_MODE(di_buf_i->vframe->type) && |
| (di_buf_i->dw_width_bk != 0xffff)) |
| di_buf->vframe->width = |
| di_buf_i->dw_width_bk; |
| else |
| 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); |
| |
| 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 |
| |
| #ifdef DI_KEEP_DEC_VF |
| /* dec vf */ |
| di_tmp = di_buf->di_buf[0]; |
| if (di_tmp && |
| di_tmp->type == VFRAME_TYPE_LOCAL && |
| di_tmp->in_buf) { |
| di_buf->in_buf = di_tmp->in_buf; |
| di_buf->vframe->di_instance_id = |
| de_devp->instance_id; |
| di_buf->vframe->flag |= |
| VFRAME_FLAG_DOUBLE_FRAM; |
| di_tmp->in_buf = NULL; |
| vf = di_buf->in_buf->vframe; |
| di_print("di:dec:pa:pp:[%d]\n", |
| vf->index_disp); |
| } |
| #endif /*DI_KEEP_DEC_VF*/ |
| 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)); |
| if (di_buf->local_meta && |
| di_buf->di_buf_dup_p[0]->local_meta && |
| di_buf->di_buf_dup_p[0]->local_meta_used_size) { |
| memset(di_buf->local_meta, 0, |
| di_buf->local_meta_total_size); |
| memcpy(di_buf->local_meta, |
| di_buf->di_buf_dup_p[0]->local_meta, |
| di_buf->di_buf_dup_p[0]->local_meta_used_size * sizeof(u8)); |
| di_buf->local_meta_used_size = |
| di_buf->di_buf_dup_p[0]->local_meta_used_size; |
| } else { |
| di_buf->local_meta_used_size = 0; |
| } |
| 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_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_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; |
| |
| 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]); |
| #ifdef DI_KEEP_DEC_VF |
| /* dec vf */ |
| di_tmp = di_buf->di_buf[1]; |
| if (di_tmp && |
| di_tmp->type == VFRAME_TYPE_LOCAL && |
| di_tmp->in_buf) { |
| di_buf->in_buf = di_tmp->in_buf; |
| di_buf->vframe->di_instance_id = |
| de_devp->instance_id; |
| di_buf->vframe->flag |= |
| VFRAME_FLAG_DOUBLE_FRAM; |
| di_tmp->in_buf = NULL; |
| vf = di_buf->in_buf->vframe; |
| di_print("di:dec:pa:pi:[%d]\n", |
| vf->index_disp); |
| } |
| #endif /*DI_KEEP_DEC_VF*/ |
| 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; |
| } |
| |
| /* |
| * di task |
| */ |
| static void di_unreg_process(void) |
| { |
| unsigned long start_jiffes = 0; |
| struct di_dev_s *de_devp;//get_di_de_devp |
| if (reg_flag) { |
| pr_dbg("%s unreg start %d.\n", __func__, reg_flag); |
| start_jiffes = jiffies_64; |
| vf_unreg_provider(&di_vf_prov); |
| /******************************/ |
| de_devp = get_di_de_devp(); |
| if (de_devp) |
| de_devp->instance_id++; |
| /* for s805 */ |
| #ifdef DI_UNREG_RELEAS_ALL_BUF |
| di_unreg_notify(); |
| #endif |
| /******************************/ |
| |
| 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; |
| #ifdef DI_UNREG_RELEAS_ALL_BUF |
| mirror_disable = 1; |
| #else |
| mirror_disable = get_blackout_policy(); |
| #endif |
| 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 |
| if (di_afds()) |
| di_afds()->reg_sw(false); |
| 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); |
| 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); |
| } else |
| DI_Wr(DI_CLKG_CTRL, 0xf60000); |
| /* 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()) |
| switch_vpu_clk_gate_vmod(VPU_VPU_CLKB, |
| VPU_CLK_GATE_OFF); |
| 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; |
| atomic_set(&di_pre_stru.cma_release_req, 1); |
| up(&di_sema); |
| di_pr_info("rel\n"); |
| } |
| #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; |
| |
| nr_all_config(width, height, vf_type); |
| #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(); |
| #ifdef OLD_PRE_GL |
| if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A)) |
| RDMA_WR(DI_PRE_GL_CTRL, 0x80000005); |
| #endif |
| 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); |
| } |
| |
| static bool need_bypass(struct vframe_s *vf) |
| { |
| needbypass_flag = true; |
| if ((is_meson_gxl_package_805X() || is_meson_gxl_package_805Y()) && |
| is_progressive(vf)) |
| return true; |
| |
| if (vf->type & VIDTYPE_MVC) |
| return true; |
| |
| if (vf->source_type == VFRAME_SOURCE_TYPE_PPMGR) |
| return true; |
| |
| if ((vf->type & VIDTYPE_VIU_444) || (vf->type & VIDTYPE_RGB_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 (di_afds() && !di_afds()->is_supported()) |
| return true; |
| if ((vf->compHeight > (default_height + 8)) |
| || (vf->compWidth > default_width)) |
| return true; |
| } |
| #endif |
| if ((vf->width > default_width) || |
| (vf->height > (default_height + 8))) |
| return true; |
| |
| /*true bypass for 720p above*/ |
| if ((vf->flag & VFRAME_FLAG_GAME_MODE) && |
| (vf->width > 720)) |
| return true; |
| |
| needbypass_flag = false; |
| return false; |
| } |
| |
| static bool nrds_en; |
| module_param_named(nrds_en, nrds_en, bool, 0644); |
| |
| 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 (di_afds()) |
| di_afds()->reg_val(); |
| |
| if (need_bypass(vframe) || ((di_debug_flag>>20) & 0x1)) { |
| if (!di_pre_stru.bypass_flag) { |
| pr_info("DI bypass all %ux%u-0x%x.\n", |
| 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; |
| } |
| di_tr_ops.pre_get(vframe->omx_index); |
| /* 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; |
| switch_vpu_clk_gate_vmod(VPU_VPU_CLKB, VPU_CLK_GATE_ON); |
| 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); |
| 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 */ |
| } |
| |
| if (di_afds()) |
| di_afds()->reg_sw(true); |
| 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); |
| |
| di_pre_stru.mtn_status = |
| adpative_combing_config(vframe->width, |
| (vframe->height>>1), |
| (vframe->source_type), |
| is_progressive(vframe), |
| vframe->sig_fmt); |
| |
| di_patch_post_update_mc_sw(DI_MC_SW_REG, true); |
| 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 unsigned int nr_done_check_cnt = 5; |
| 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); |
| di_hpre_gl_sw(false); |
| 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 (atomic_read(&di_pre_stru.cma_release_req) && |
| (!atomic_read(&di_clear_unreg))) { |
| atomic_set(&devp->mem_flag, 0); |
| di_cma_release(devp); |
| //di_pre_stru.cma_release_req = 0; |
| atomic_set(&di_pre_stru.cma_release_req, 0); |
| di_pre_stru.cma_alloc_done = 0; |
| } |
| if (di_pre_stru.cma_alloc_req) { |
| di_pr_info("all=%d\n", |
| atomic_read(&di_pre_stru.cma_release_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()) { |
| usleep_range(40000, 40001); |
| 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 probablity |
| * 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_requeset_afbc(false);*/ |
| trigger_pre_di_process(TRIGGER_PRE_BY_PROVERDER_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"); |
| } |
| |
| 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); |
| |
| atomic_set(&di_flag_unreg, 0); //ary |
| bypass_state = 0; |
| di_pre_stru.reg_req_flag = 1; |
| trigger_pre_di_process(TRIGGER_PRE_BY_PROVERDER_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("vpu_clkb = %ld.\n", clk_get_rate(de_devp->vpu_clkb)); |
| 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) { |
| di_tr_ops.post_peek(0); |
| return vf_peek(VFM_NAME); |
| } |
| if ((init_flag == 0) || recovery_flag || |
| di_blocking || di_pre_stru.unreg_req_flag || dump_state_flag) { |
| di_tr_ops.post_peek(1); |
| return NULL; |
| } |
| if ((run_flag == DI_RUN_FLAG_PAUSE) || |
| (run_flag == DI_RUN_FLAG_STEP_DONE)) { |
| di_tr_ops.post_peek(2); |
| return NULL; |
| } |
| /**************************/ |
| if (list_count(QUEUE_DISPLAY) > 4) { |
| di_tr_ops.post_peek(3); |
| 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 |
| if (vframe_ret) |
| di_tr_ops.post_peek(9); |
| else |
| di_tr_ops.post_peek(4); |
| |
| 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) { |
| di_tr_ops.post_get2(1); |
| return NULL; |
| } |
| |
| if ((run_flag == DI_RUN_FLAG_PAUSE) || |
| (run_flag == DI_RUN_FLAG_STEP_DONE)) { |
| di_tr_ops.post_get2(2); |
| 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]; |
| |
| clear_vframe_src_fmt(vframe_ret); |
| if (di_buf->local_meta && |
| di_buf->local_meta_used_size) |
| update_vframe_src_fmt( |
| vframe_ret, di_buf->local_meta, |
| di_buf->local_meta_used_size, |
| false, NULL, NULL); |
| |
| 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)); |
| di_tr_ops.post_get(vframe_ret->omx_index); |
| di_tr_ops.pos_cnt0(vframe_ret->omx_index); |
| di_tr_ops.pos_cnt1(vframe_ret->omx_index); |
| } else { |
| di_tr_ops.post_get2(3); |
| } |
| |
| 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; |
| switch (cmd) { |
| case AMDI_IOC_SET_PQ_PARM: |
| mm_size = sizeof(struct am_pq_parm_s); |
| 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; |
| if (!of_get_flat_dt_prop(rmem->fdt_node, "no-map", NULL)) |
| di_devp->flags |= DI_MAP_FLAG; |
| pr_dbg("di reveser memory 0x%lx, size %uMB.\n", |
| di_devp->mem_start, (di_devp->mem_size >> 20)); |
| return 0; |
| } |
| /* pr_dbg("di reveser 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) |
| { |
| struct di_dev_s *de_devp = get_di_de_devp(); |
| |
| 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; |
| } |
| |
| if (limit_is_s805x()) |
| di_limit_local = 6; |
| |
| mtn_int_combing_glbmot(); |
| if (!de_devp) |
| return; |
| |
| if (is_meson_tm2b()) |
| de_devp->ic_id = DI_IC_ID_TM2B; |
| else if (cpu_after_eq(MESON_CPU_MAJOR_ID_TM2)) |
| de_devp->ic_id = DI_IC_ID_TM2; |
| else if (cpu_after_eq(MESON_CPU_MAJOR_ID_TL1)) |
| de_devp->ic_id = DI_IC_ID_TL1; |
| else if (cpu_after_eq(MESON_CPU_MAJOR_ID_SM1)) |
| de_devp->ic_id = DI_IC_ID_SM1; |
| else if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12B)) |
| de_devp->ic_id = DI_IC_ID_G12B; |
| else if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A)) |
| de_devp->ic_id = DI_IC_ID_G12A; |
| else if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXHD)) |
| de_devp->ic_id = DI_IC_ID_TXHD; |
| else if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXLX)) |
| de_devp->ic_id = DI_IC_ID_GXLX; |
| else if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXLX)) |
| de_devp->ic_id = DI_IC_ID_TXLX; |
| else if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXL)) |
| de_devp->ic_id = DI_IC_ID_TXL; |
| else if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXL)) |
| de_devp->ic_id = DI_IC_ID_GXL; |
| else |
| de_devp->ic_id = DI_IC_ID_GXL; |
| di_pr_info("ic_id:0x%x [b]%d\n", de_devp->ic_id, is_meson_rev_b()); |
| } |
| |
| #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; |
| |
| 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_composite"); |
| |
| if (IS_ERR(pdev->vpu_clkb)) |
| pr_err("%s: get vpu clkb gate error.\n", __func__); |
| #endif |
| } |
| |
| static struct div1_meson_data deinterlace = { |
| //.cpu_type = MESON_CPU_MAJOR_ID_DEINTERLACE, |
| .name = "di_deinterlace", |
| .ic_id = DI_IC_ID_DEINTERLACE, |
| }; |
| |
| static struct div1_meson_data deinterlace_tm2_revb = { |
| //.cpu_type = MESON_CPU_MAJOR_ID_TM2_REVB, |
| .name = "di_tm2_vb", |
| .ic_id = DI_IC_ID_TM2B, |
| }; |
| |
| static const struct of_device_id amlogic_deinterlace_dt_match[] = { |
| { |
| .compatible = "amlogic, deinterlace", |
| .data = &deinterlace, |
| }, |
| { |
| .compatible = "amlogic, deinterlace_di_tm2b", |
| .data = &deinterlace_tm2_revb, |
| }, |
| {} |
| }; |
| |
| bool is_meson_tm2b(void) |
| { |
| if (getv1_datal()->mdata->ic_id == DI_IC_ID_TM2B) |
| return true; |
| else |
| return false; |
| } |
| |
| static int di_probe(struct platform_device *pdev) |
| { |
| int ret = 0; |
| struct di_dev_s *di_devp = NULL; |
| |
| const struct of_device_id *match; |
| struct div1_data_l_s *pdata; |
| //struct di_device_data_s *di_meson; |
| |
| 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(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 |
| |
| 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->data_l = NULL; |
| di_devp->data_l = kzalloc(sizeof(struct div1_data_l_s), GFP_KERNEL); |
| if (!di_devp->data_l) { |
| pr_error("%s fail to allocate data l.\n", __func__); |
| goto fail_kmalloc_datal; |
| } |
| |
| 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); |
| |
| match = of_match_device(amlogic_deinterlace_dt_match, |
| &pdev->dev); |
| if (!match) { |
| pr_error("%s,no matched table\n", __func__); |
| goto fail_cdev_add; |
| } else { |
| pdata = (struct div1_data_l_s *)di_devp->data_l; |
| pdata->mdata = match->data; |
| pr_info("match name: %s:id[%d]\n", pdata->mdata->name, |
| pdata->mdata->ic_id); |
| } |
| 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 = 0x3800000; |
| //(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 |
| de_devp->local_meta_size = |
| LOCAL_META_BUFF_SIZE * |
| (MAX_IN_BUF_NUM + MAX_POST_BUF_NUM + |
| (MAX_LOCAL_BUF_NUM * 2)) * sizeof(u8); |
| de_devp->local_meta_addr = vmalloc(de_devp->local_meta_size); |
| if (!de_devp->local_meta_addr) { |
| pr_info("DI: allocate local meta buffer fail, disable this function!\n"); |
| de_devp->local_meta_size = 0; |
| } |
| 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); |
| nr_drv_init(di_devp->dev); |
| mutex_init(&di_event_mutex); |
| |
| 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); |
| atomic_set(&di_clear_unreg, 0); |
| /* Disable MCDI when code does not surpport 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(); |
| di_attach_ops_afd(&di_devp->afds); |
| if (di_afds()) |
| di_afds()->prob(di_devp->ic_id); |
| dil_set_cpuver_flag(getv1_datal()->mdata->ic_id); |
| |
| dil_set_diffver_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_datal: |
| pr_info("%s:fail_kmalloc datal\n", __func__); |
| 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 int 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); |
| 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 |
| vfree(di_devp->local_meta_addr); |
| kfree(di_devp); |
| /* free drvdata */ |
| dev_set_drvdata(&pdev->dev, NULL); |
| platform_set_drvdata(pdev, NULL); |
| |
| di_pr_info("%s:ok\n", __func__); |
| return 0; |
| } |
| |
| 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 canel %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()) |
| switch_vpu_clk_gate_vmod(VPU_VPU_CLKB, |
| VPU_CLK_GATE_OFF); |
| 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__); |
| |
| atomic_set(&di_flag_unreg, 1); |
| atomic_set(&di_clear_unreg, 1); |
| di_unreg_process();/*have flag*/ |
| if (di_pre_stru.unreg_req_flag_irq) |
| di_unreg_process_irq(); |
| |
| #ifdef CONFIG_CMA |
| if (atomic_read(&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; |
| atomic_set(&di_pre_stru.cma_release_req, 0); |
| di_pre_stru.cma_alloc_done = 0; |
| } |
| #endif |
| atomic_set(&di_clear_unreg, 0); |
| #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()) |
| switch_vpu_clk_gate_vmod(VPU_VPU_CLKB, |
| VPU_CLK_GATE_OFF); |
| 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 */ |
| #ifdef MARK_HIS |
| static const struct of_device_id amlogic_deinterlace_dt_match[] = { |
| { .compatible = "amlogic, deinterlace", }, |
| {}, |
| }; |
| #endif |
| /* #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 |
| } |
| }; |
| |
| static int __init di_module_init(void) |
| { |
| int ret = 0; |
| |
| di_pr_info("%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 |
| } |
| |
| static 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_init(di_module_init); |
| module_exit(di_module_exit); |
| |
| module_param_named(bypass_all, bypass_all, int, 0664); |
| module_param_named(bypass_3d, bypass_3d, int, 0664); |
| module_param_named(bypass_trick_mode, bypass_trick_mode, int, 0664); |
| module_param_named(invert_top_bot, invert_top_bot, int, 0664); |
| module_param_named(skip_top_bot, skip_top_bot, int, 0664); |
| module_param_named(force_width, force_width, int, 0664); |
| module_param_named(force_height, force_height, int, 0664); |
| module_param_named(prog_proc_config, prog_proc_config, int, 0664); |
| module_param_named(start_frame_drop_count, start_frame_drop_count, int, 0664); |
| #ifdef SUPPORT_START_FRAME_HOLD |
| module_param_named(start_frame_hold_count, start_frame_hold_count, int, 0664); |
| #endif |
| module_param_named(same_field_top_count, same_field_top_count, |
| long, 0664); |
| module_param_named(same_field_bot_count, same_field_bot_count, |
| long, 0664); |
| MODULE_PARM_DESC(di_log_flag, "\n di log flag\n"); |
| module_param(di_log_flag, int, 0664); |
| |
| MODULE_PARM_DESC(di_debug_flag, "\n di debug flag\n"); |
| module_param(di_debug_flag, int, 0664); |
| |
| MODULE_PARM_DESC(buf_state_log_threshold, "\n buf_state_log_threshold\n"); |
| module_param(buf_state_log_threshold, int, 0664); |
| |
| MODULE_PARM_DESC(bypass_state, "\n bypass_state\n"); |
| module_param(bypass_state, uint, 0664); |
| |
| MODULE_PARM_DESC(di_vscale_skip_enable, "\n di_vscale_skip_enable\n"); |
| module_param(di_vscale_skip_enable, uint, 0664); |
| |
| MODULE_PARM_DESC(di_vscale_skip_count, "\n di_vscale_skip_count\n"); |
| module_param(di_vscale_skip_count, int, 0664); |
| |
| MODULE_PARM_DESC(di_vscale_skip_count_real, "\n di_vscale_skip_count_real\n"); |
| module_param(di_vscale_skip_count_real, int, 0664); |
| |
| module_param_named(vpp_3d_mode, vpp_3d_mode, int, 0664); |
| #ifdef DET3D |
| MODULE_PARM_DESC(det3d_en, "\n det3d_enable\n"); |
| module_param(det3d_en, bool, 0664); |
| MODULE_PARM_DESC(det3d_mode, "\n det3d_mode\n"); |
| module_param(det3d_mode, uint, 0664); |
| #endif |
| |
| MODULE_PARM_DESC(post_hold_line, "\n post_hold_line\n"); |
| module_param(post_hold_line, uint, 0664); |
| |
| MODULE_PARM_DESC(post_urgent, "\n post_urgent\n"); |
| module_param(post_urgent, uint, 0664); |
| |
| MODULE_PARM_DESC(di_printk_flag, "\n di_printk_flag\n"); |
| module_param(di_printk_flag, uint, 0664); |
| |
| MODULE_PARM_DESC(force_recovery, "\n force_recovery\n"); |
| module_param(force_recovery, uint, 0664); |
| |
| module_param_named(force_recovery_count, force_recovery_count, uint, 0664); |
| module_param_named(pre_process_time, pre_process_time, uint, 0664); |
| module_param_named(bypass_post, bypass_post, uint, 0664); |
| module_param_named(post_wr_en, post_wr_en, bool, 0664); |
| module_param_named(post_wr_support, post_wr_support, uint, 0664); |
| module_param_named(bypass_post_state, bypass_post_state, uint, 0664); |
| /* n debug for progress interlace mixed source */ |
| module_param_named(use_2_interlace_buff, use_2_interlace_buff, int, 0664); |
| module_param_named(debug_blend_mode, debug_blend_mode, int, 0664); |
| MODULE_PARM_DESC(debug_blend_mode, "\n force post blend mode\n"); |
| module_param_named(nr10bit_support, nr10bit_support, uint, 0664); |
| module_param_named(di_stop_reg_flag, di_stop_reg_flag, uint, 0664); |
| module_param(di_dbg_mask, uint, 0664); |
| MODULE_PARM_DESC(di_dbg_mask, "\n di_dbg_mask\n"); |
| module_param(nr_done_check_cnt, uint, 0664); |
| MODULE_PARM_DESC(nr_done_check_cnt, "\n nr_done_check_cnt\n"); |
| module_param_array(di_stop_reg_addr, uint, &num_di_stop_reg_addr, |
| 0664); |
| module_param_named(mcpre_en, mcpre_en, bool, 0664); |
| module_param_named(check_start_drop_prog, check_start_drop_prog, bool, 0664); |
| module_param_named(overturn, overturn, bool, 0664); |
| module_param_named(queue_print_flag, queue_print_flag, int, 0664); |
| module_param_named(full_422_pack, full_422_pack, bool, 0644); |
| module_param_named(cma_print, cma_print, bool, 0644); |
| module_param_named(pulldown_enable, pulldown_enable, bool, 0644); |
| #ifdef DEBUG_SUPPORT |
| #ifdef RUN_DI_PROCESS_IN_IRQ |
| module_param_named(input2pre, input2pre, uint, 0664); |
| module_param_named(input2pre_buf_miss_count, input2pre_buf_miss_count, |
| uint, 0664); |
| module_param_named(input2pre_proc_miss_count, input2pre_proc_miss_count, |
| uint, 0664); |
| module_param_named(input2pre_miss_policy, input2pre_miss_policy, uint, 0664); |
| module_param_named(input2pre_throw_count, input2pre_throw_count, uint, 0664); |
| #endif |
| #ifdef SUPPORT_MPEG_TO_VDIN |
| module_param_named(mpeg2vdin_en, mpeg2vdin_en, int, 0664); |
| module_param_named(mpeg2vdin_flag, mpeg2vdin_flag, int, 0664); |
| #endif |
| module_param_named(di_pre_rdma_enable, di_pre_rdma_enable, uint, 0664); |
| module_param_named(pldn_dly, pldn_dly, uint, 0644); |
| module_param_named(pldn_dly1, pldn_dly1, uint, 0644); |
| module_param_named(di_reg_unreg_cnt, di_reg_unreg_cnt, int, 0664); |
| module_param_named(bypass_pre, bypass_pre, int, 0664); |
| module_param_named(frame_count, frame_count, int, 0664); |
| #endif |
| MODULE_DESCRIPTION("AMLOGIC DEINTERLACE driver"); |
| MODULE_LICENSE("GPL"); |
| MODULE_VERSION("4.0.0"); |