deinterlace: add di-multi folder v2 [2/3]

PD#SWPL-10064

Problem:
add di-multi folder

Solution:
1. add di_multi folder;
2. it can be enable by dts;
3. only one of di can be enabled at the same time;
4. no di-pq filse;

Verify:
U212

Change-Id: I8726d2430cf1beb58d0cd37c0358b7ea8e06c414
Signed-off-by: Jihong Sui <jihong.sui@amlogic.com>
This commit is contained in:
Jihong Sui
2019-08-05 14:17:07 +08:00
committed by Tao Zeng
parent 433ca76390
commit b391eea3db
41 changed files with 30416 additions and 0 deletions

View File

@@ -15104,3 +15104,7 @@ AMLOGIC DEINTERLACE DRIVER
M: Jihong Sui <jihong.sui@amlogic.com>
F: drivers/amlogic/media/deinterlace/di_pqa.h
F: drivers/amlogic/media/di_local/*
AMLOGIC ADD DI_MULTI DRIVER
M: Jihong Sui <jihong.sui@amlogic.com>
F: drivers/amlogic/media/di_multi/*

View File

@@ -89,6 +89,7 @@ source "drivers/amlogic/media/vout/Kconfig"
source "drivers/amlogic/media/osd/Kconfig"
source "drivers/amlogic/media/osd_ext/Kconfig"
source "drivers/amlogic/media/deinterlace/Kconfig"
source "drivers/amlogic/media/di_multi/Kconfig"
source "drivers/amlogic/media/di_local/Kconfig"
source "drivers/amlogic/media/vin/Kconfig"
source "drivers/amlogic/media/video_processor/Kconfig"

View File

@@ -5,6 +5,7 @@ obj-$(CONFIG_AMLOGIC_MEDIA_FB) += osd/
obj-$(CONFIG_AMLOGIC_MEDIA_FB_EXT) += osd_ext/
obj-$(CONFIG_AMLOGIC_VOUT) += vout/
obj-$(CONFIG_AMLOGIC_MEDIA_DEINTERLACE) += deinterlace/
obj-$(CONFIG_AMLOGIC_MEDIA_DEINTERLACE) += di_multi/
obj-$(CONFIG_AMLOGIC_MEDIA_DEINTERLACE) += di_local/
obj-$(CONFIG_AMLOGIC_MEDIA_VIN) += vin/
obj-$(CONFIG_AMLOGIC_MEDIA_VIDEO_PROCESSOR) += video_processor/

View File

@@ -0,0 +1,15 @@
#
# Deinterlace driver configuration
#
menu "DI_MULTI driver"
config AMLOGIC_MEDIA_DEINTERLACE
tristate "DI_MULTI driver"
default n
help
Select to enable AMLOGIC DEINTERLACE driver
process interlace source need three continueed fields,
wave progressive source with two interlace fields from
one progreesive fields
endmenu

View File

@@ -0,0 +1,34 @@
# # Makefile for the Post Process Manager device #
ifeq ($(TARGET_BUILD_VARIANT),userdebug)
ccflags-y := -D DEBUG_SUPPORT
ccflags-y := -DDEBUG
else
ccflags-y := -DDEBUG
endif
ccflags-y += -I.
CFLAGS_dim.o := -I$(src)
obj-$(CONFIG_AMLOGIC_MEDIA_DEINTERLACE) += dim.o
dim-objs += deinterlace.o
dim-objs += deinterlace_hw.o
#dim-objs += deinterlace_mtn.o
dim-objs += deinterlace_dbg.o
#dim-objs += nr_drv.o
#dim-objs += pulldown_drv.o
#dim-objs += detect3d.o
dim-objs += nr_downscale.o
dim-objs += di_pps.o
dim-objs += di_vframe.o
dim-objs += di_prc.o
dim-objs += di_pre.o
dim-objs += di_post.o
dim-objs += di_reg_tab.o
dim-objs += di_dbg.o
dim-objs += di_que.o
dim-objs += di_sys.o
dim-objs += di_task.o
dim-objs += di_api.o
#dim-objs += film_mode_fmw/vof_soft_top.o
#dim-objs += film_mode_fmw/flm_mod_xx.o
#dim-objs += film_mode_fmw/film_fw1.o
ccflags-y += -Idrivers/amlogic/media/common/rdma/
ccflags-y += -I$(src)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,656 @@
/*
* drivers/amlogic/media/di_multi/deinterlace.h
*
* 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.
*
*/
#ifndef _DI_H
#define _DI_H
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/amlogic/media/vfm/vframe.h>
#include <linux/amlogic/media/vfm/vframe_provider.h>
#include "../di_local/di_local.h"
#include <linux/clk.h>
#include <linux/atomic.h>
#include "deinterlace_hw.h"
#include "../deinterlace/di_pqa.h"
/*trigger_pre_di_process param*/
#define TRIGGER_PRE_BY_PUT 'p'
#define TRIGGER_PRE_BY_DE_IRQ 'i'
#define TRIGGER_PRE_BY_UNREG 'u'
/*di_timer_handle*/
#define TRIGGER_PRE_BY_TIMER 't'
#define TRIGGER_PRE_BY_FORCE_UNREG 'f'
#define TRIGGER_PRE_BY_VFRAME_READY 'r'
#define TRIGGER_PRE_BY_PROVERDER_UNREG 'n'
#define TRIGGER_PRE_BY_DEBUG_DISABLE 'd'
#define TRIGGER_PRE_BY_PROVERDER_REG 'R'
#define DI_RUN_FLAG_RUN 0
#define DI_RUN_FLAG_PAUSE 1
#define DI_RUN_FLAG_STEP 2
#define DI_RUN_FLAG_STEP_DONE 3
#define USED_LOCAL_BUF_MAX 3
#define BYPASS_GET_MAX_BUF_NUM 4
/* buffer management related */
#define MAX_IN_BUF_NUM (4)
#define MAX_LOCAL_BUF_NUM (7)
#define MAX_POST_BUF_NUM (7) /*(5)*/ /* 16 */
#define VFRAME_TYPE_IN 1
#define VFRAME_TYPE_LOCAL 2
#define VFRAME_TYPE_POST 3
#define VFRAME_TYPE_NUM 3
#define DI_POST_GET_LIMIT 4
#define DI_PRE_READY_LIMIT 4
/*vframe define*/
#define vframe_t struct vframe_s
#define is_from_vdin(vframe) ((vframe)->type & VIDTYPE_VIU_422)
/* canvas defination */
#define DI_USE_FIXED_CANVAS_IDX
/*#define DET3D */
#undef SUPPORT_MPEG_TO_VDIN
#define CLK_TREE_SUPPORT
#ifndef CONFIG_AMLOGIC_MEDIA_RDMA
#ifndef VSYNC_WR_MPEG_REG
#define VSYNC_WR_MPEG_REG(adr, val) aml_write_vcbus(adr, val)
#define VSYNC_WR_MPEG_REG_BITS(adr, val, start, len) \
aml_vcbus_update_bits((adr), \
((1 << (len)) - 1) << (start), (val) << (start))
#define VSYNC_RD_MPEG_REG(adr) aml_read_vcbus(adr)
#endif
#endif
#define IS_VDIN_SRC(src) ( \
((src) == VFRAME_SOURCE_TYPE_TUNER) || \
((src) == VFRAME_SOURCE_TYPE_CVBS) || \
((src) == VFRAME_SOURCE_TYPE_COMP) || \
((src) == VFRAME_SOURCE_TYPE_HDMI))
#define IS_I_SRC(vftype) ((vftype) & VIDTYPE_INTERLACE_BOTTOM)
#define IS_COMP_MODE(vftype) ((vftype) & VIDTYPE_COMPRESS)
enum process_fun_index_e {
PROCESS_FUN_NULL = 0,
PROCESS_FUN_DI,
PROCESS_FUN_PD,
PROCESS_FUN_PROG,
PROCESS_FUN_BOB
};
#define process_fun_index_t enum process_fun_index_e
enum canvas_idx_e {
NR_CANVAS,
MTN_CANVAS,
MV_CANVAS,
};
#define pulldown_mode_t enum pulldown_mode_e
struct di_buf_s {
struct vframe_s *vframe;
int index; /* index in vframe_in_dup[] or vframe_in[],
* only for type of VFRAME_TYPE_IN
*/
int post_proc_flag; /* 0,no post di; 1, normal post di;
* 2, edge only; 3, dummy
*/
int new_format_flag;
int type;
int throw_flag;
int invert_top_bot_flag;
int seq;
int pre_ref_count; /* none zero, is used by mem_mif,
* chan2_mif, or wr_buf
*/
int post_ref_count; /* none zero, is used by post process */
int queue_index;
/*below for type of VFRAME_TYPE_LOCAL */
unsigned long nr_adr;
int nr_canvas_idx;
unsigned long mtn_adr;
int mtn_canvas_idx;
unsigned long cnt_adr;
int cnt_canvas_idx;
unsigned long mcinfo_adr;
int mcinfo_canvas_idx;
unsigned long mcvec_adr;
int mcvec_canvas_idx;
struct mcinfo_pre_s {
unsigned int highvertfrqflg;
unsigned int motionparadoxflg;
unsigned int regs[26];/* reg 0x2fb0~0x2fc9 */
} curr_field_mcinfo;
/* blend window */
struct pulldown_detected_s
pd_config;
/* tff bff check result bit[1:0]*/
unsigned int privated;
unsigned int canvas_config_flag;
/* 0,configed; 1,config type 1 (prog);
* 2, config type 2 (interlace)
*/
unsigned int canvas_height;
unsigned int canvas_height_mc; /*ary add for mc h is diff*/
unsigned int canvas_width[3];/* nr/mtn/mv */
process_fun_index_t process_fun_index;
int early_process_fun_index;
int left_right;/*1,left eye; 0,right eye in field alternative*/
/*below for type of VFRAME_TYPE_POST*/
struct di_buf_s *di_buf[2];
struct di_buf_s *di_buf_dup_p[5];
/* 0~4: n-2, n-1, n, n+1, n+2; n is the field to display*/
/*0: n-2*/
/*1: n-1*/
/*2: n*/
/*3: n+1*/
/*4: n+2*/
struct di_buf_s *di_wr_linked_buf;
/* debug for di-vf-get/put
* 1: after get
* 0: after put
*/
atomic_t di_cnt;
struct page *pages;
/*ary add */
unsigned int channel;
unsigned int width_bk; /*move from ppre*/
};
#define RDMA_DET3D_IRQ 0x20
/* vdin0 rdma irq */
#define RDMA_DEINT_IRQ 0x2
#define RDMA_TABLE_SIZE ((PAGE_SIZE) << 1)
#define MAX_CANVAS_WIDTH 1920
#define MAX_CANVAS_HEIGHT 1088
/* #define DI_BUFFER_DEBUG */
#define DI_LOG_MTNINFO 0x02
#define DI_LOG_PULLDOWN 0x10
#define DI_LOG_BUFFER_STATE 0x20
#define DI_LOG_TIMESTAMP 0x100
#define DI_LOG_PRECISE_TIMESTAMP 0x200
#define DI_LOG_QUEUE 0x40
#define DI_LOG_VFRAME 0x80
#if 0
#define QUEUE_LOCAL_FREE 0
#define QUEUE_IN_FREE 1
#define QUEUE_PRE_READY 2
#define QUEUE_POST_FREE 3
#define QUEUE_POST_READY 4
#define QUEUE_RECYCLE 5
#define QUEUE_DISPLAY 6
#define QUEUE_TMP 7
#define QUEUE_POST_DOING 8
#define QUEUE_NUM 9
#else
#define QUEUE_LOCAL_FREE 0
#define QUEUE_RECYCLE 1 /* 5 */
#define QUEUE_DISPLAY 2 /* 6 */
#define QUEUE_TMP 3 /* 7 */
#define QUEUE_POST_DOING 4 /* 8 */
#define QUEUE_IN_FREE 5 /* 1 */
#define QUEUE_PRE_READY 6 /* 2 */
#define QUEUE_POST_FREE 7 /* 3 */
#define QUEUE_POST_READY 8 /* 4 QUE_POST_READY */
/*new use this for put back control*/
#define QUEUE_POST_PUT_BACK (9)
#define QUEUE_NUM 5 /* 9 */
#define QUEUE_NEW_THD_MIN (QUEUE_IN_FREE - 1)
#define QUEUE_NEW_THD_MAX (QUEUE_POST_READY + 1)
#endif
#define queue_t struct queue_s
#define VFM_NAME "deinterlace"
#ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA
void enable_rdma(int enable_flag);
int VSYNC_WR_MPEG_REG(u32 adr, u32 val);
int VSYNC_WR_MPEG_REG_BITS(u32 adr, u32 val, u32 start, u32 len);
u32 VSYNC_RD_MPEG_REG(u32 adr);
bool is_vsync_rdma_enable(void);
#else
#ifndef VSYNC_WR_MPEG_REG
#define VSYNC_WR_MPEG_REG(adr, val) aml_write_vcbus(adr, val)
#define VSYNC_WR_MPEG_REG_BITS(adr, val, start, len) \
aml_vcbus_update_bits((adr), \
((1 << (len)) - 1) << (start), (val) << (start))
#define VSYNC_RD_MPEG_REG(adr) aml_read_vcbus(adr)
#endif
#endif
#define DI_COUNT 1
#define DI_MAP_FLAG 0x1
#define DI_SUSPEND_FLAG 0x2
#define DI_LOAD_REG_FLAG 0x4
#define DI_VPU_CLKB_SET 0x8
struct di_dev_s {
dev_t devt;
struct cdev cdev; /* The cdev structure */
struct device *dev;
struct platform_device *pdev;
dev_t devno;
struct class *pclss;
bool sema_flg; /*di_sema_init_flag*/
struct task_struct *task;
struct clk *vpu_clkb;
unsigned long clkb_max_rate;
unsigned long clkb_min_rate;
struct list_head pq_table_list;
atomic_t pq_flag;
unsigned char di_event;
unsigned int pre_irq;
unsigned int post_irq;
unsigned int flags;
unsigned long jiffy;
unsigned long mem_start;
unsigned int mem_size;
bool mem_flg; /*ary add for make sure mem is ok*/
unsigned int buffer_size;
unsigned int post_buffer_size;
unsigned int buf_num_avail;
int rdma_handle;
/* is support nr10bit */
unsigned int nr10bit_support;
/* is DI support post wr to mem for OMX */
unsigned int post_wr_support;
unsigned int nrds_enable;
unsigned int pps_enable;
unsigned int h_sc_down_en;/*sm1, tm2 ...*/
/*struct mutex cma_mutex;*/
unsigned int flag_cma;
struct page *total_pages;
struct dentry *dbg_root; /*dbg_fs*/
/***************************/
/*struct di_data_l_s data_l;*/
void *data_l;
};
struct di_pre_stru_s {
/* pre input */
struct DI_MIF_s di_inp_mif;
struct DI_MIF_s di_mem_mif;
struct DI_MIF_s di_chan2_mif;
struct di_buf_s *di_inp_buf;
struct di_buf_s *di_post_inp_buf;
struct di_buf_s *di_inp_buf_next;
/* p_asi_next: ary:add for p */
struct di_buf_s *p_asi_next;
struct di_buf_s *di_mem_buf_dup_p;
struct di_buf_s *di_chan2_buf_dup_p;
/* pre output */
struct DI_SIM_MIF_s di_nrwr_mif;
struct DI_SIM_MIF_s di_mtnwr_mif;
struct di_buf_s *di_wr_buf;
struct di_buf_s *di_post_wr_buf;
struct DI_SIM_MIF_s di_contp2rd_mif;
struct DI_SIM_MIF_s di_contprd_mif;
struct DI_SIM_MIF_s di_contwr_mif;
int field_count_for_cont;
/*
* 0 (f0,null,f0)->nr0,
* 1 (f1,nr0,f1)->nr1_cnt,
* 2 (f2,nr1_cnt,nr0)->nr2_cnt
* 3 (f3,nr2_cnt,nr1_cnt)->nr3_cnt
*/
struct DI_MC_MIF_s di_mcinford_mif;
struct DI_MC_MIF_s di_mcvecwr_mif;
struct DI_MC_MIF_s di_mcinfowr_mif;
/* pre state */
int in_seq;
int recycle_seq;
int pre_ready_seq;
int pre_de_busy; /* 1 if pre_de is not done */
int pre_de_process_flag; /* flag when dim_pre_de_process done */
int pre_de_clear_flag;
/* flag is set when VFRAME_EVENT_PROVIDER_UNREG*/
int unreg_req_flag_cnt;
int reg_req_flag_cnt;
int force_unreg_req_flag;
int disable_req_flag;
/* current source info */
int cur_width;
int cur_height;
int cur_inp_type;
int cur_source_type;
int cur_sig_fmt;
unsigned int orientation;
int cur_prog_flag; /* 1 for progressive source */
/* valid only when prog_proc_type is 0, for
* progressive source: top field 1, bot field 0
*/
int source_change_flag;
/* input size change flag, 1: need reconfig pre/nr/dnr size */
/* 0: not need config pre/nr/dnr size*/
bool input_size_change_flag;
/* true: bypass di all logic, false: not bypass */
bool bypass_flag;
unsigned char prog_proc_type;
/* set by prog_proc_config when source is vdin,0:use 2 i
* serial buffer,1:use 1 p buffer,3:use 2 i paralleling buffer
*/
/* ary: loacal play p mode is 0
* local play i mode is 0
*/
unsigned char buf_alloc_mode;
/* alloc di buf as p or i;0: alloc buf as i;
* 1: alloc buf as p;
*/
unsigned char madi_enable;
unsigned char mcdi_enable;
unsigned int pps_dstw; /*no use ?*/
unsigned int pps_dsth; /*no use ?*/
int left_right;/*1,left eye; 0,right eye in field alternative*/
/*input2pre*/
int bypass_start_count;
/* need discard some vframe when input2pre => bypass */
unsigned char vdin2nr;
enum tvin_trans_fmt source_trans_fmt;
enum tvin_trans_fmt det3d_trans_fmt;
unsigned int det_lr;
unsigned int det_tp;
unsigned int det_la;
unsigned int det_null;
unsigned int width_bk;
#ifdef DET3D
int vframe_interleave_flag;
#endif
/**/
int pre_de_irq_timeout_count;
int pre_throw_flag;
int bad_frame_throw_count;
/*for static pic*/
int static_frame_count;
bool force_interlace;
bool bypass_pre;
bool invert_flag;
bool vdin_source;
int nr_size;
int count_size;
int mcinfo_size;
int mv_size;
int mtn_size;
int cma_release_req;
/* for performance debug */
unsigned long irq_time[2];
/* combing adaptive */
struct combing_status_s *mtn_status;
};
struct di_post_stru_s {
struct DI_MIF_s di_buf0_mif;
struct DI_MIF_s di_buf1_mif;
struct DI_MIF_s di_buf2_mif;
struct DI_SIM_MIF_s di_diwr_mif;
struct DI_SIM_MIF_s di_mtnprd_mif;
struct DI_MC_MIF_s di_mcvecrd_mif;
/*post doing buf and write buf to post ready*/
struct di_buf_s *cur_post_buf;
struct di_buf_s *keep_buf;
struct di_buf_s *keep_buf_post; /*ary add for keep post buf*/
int update_post_reg_flag;
int run_early_proc_fun_flag;
int cur_disp_index;
int canvas_id;
int next_canvas_id;
bool toggle_flag;
bool vscale_skip_flag;
uint start_pts;
int buf_type;
int de_post_process_done;
int post_de_busy;
int di_post_num;
unsigned int post_peek_underflow;
unsigned int di_post_process_cnt;
unsigned int check_recycle_buf_cnt;/*cp to di_hpre_s*/
/* performance debug */
unsigned int post_wr_cnt;
unsigned long irq_time;
/*frame cnt*/
unsigned int frame_cnt; /*cnt for post process*/
};
#define MAX_QUEUE_POOL_SIZE 256
struct queue_s {
unsigned int num;
unsigned int in_idx;
unsigned int out_idx;
unsigned int type;
/* 0, first in first out;
* 1, general;2, fix position for di buf
*/
unsigned int pool[MAX_QUEUE_POOL_SIZE];
};
struct di_buf_pool_s {
struct di_buf_s *di_buf_ptr;
unsigned int size;
};
struct dim_mm_s {
struct page *ppage;
unsigned long addr;
};
bool dim_mm_alloc(int cma_mode, size_t count, struct dim_mm_s *o);
bool dim_mm_release(int cma_mode,
struct page *pages,
int count,
unsigned long addr);
unsigned char dim_is_bypass(vframe_t *vf_in, unsigned int channel);
bool dim_bypass_first_frame(unsigned int ch);
int di_cnt_buf(int width, int height, int prog_flag, int mc_mm,
int bit10_support, int pack422);
/*---get di state parameter---*/
struct di_dev_s *get_dim_de_devp(void);
const char *dim_get_version_s(void);
int dim_get_dump_state_flag(void);
int dim_get_blocking(void);
struct di_buf_s *dim_get_recovery_log_di_buf(void);
unsigned long dim_get_reg_unreg_timeout_cnt(void);
struct vframe_s **dim_get_vframe_in(unsigned int ch);
int dim_check_recycle_buf(unsigned int channel);
int dim_seq_file_module_para_di(struct seq_file *seq);
int dim_seq_file_module_para_hw(struct seq_file *seq);
int dim_seq_file_module_para_film_fw1(struct seq_file *seq);
int dim_seq_file_module_para_mtn(struct seq_file *seq);
int dim_seq_file_module_para_pps(struct seq_file *seq);
int dim_seq_file_module_para_(struct seq_file *seq);
/***********************/
unsigned int di_get_dts_nrds_en(void);
int di_get_disp_cnt(void);
/*---------------------*/
long dim_pq_load_io(unsigned long arg);
int dim_get_canvas(void);
unsigned int dim_cma_alloc_total(struct di_dev_s *de_devp);
irqreturn_t dim_irq(int irq, void *dev_instance);
irqreturn_t dim_post_irq(int irq, void *dev_instance);
void dim_rdma_init(void);
void dim_rdma_exit(void);
void dim_set_di_flag(void);
void dim_get_vpu_clkb(struct device *dev, struct di_dev_s *pdev);
void dim_log_buffer_state(unsigned char *tag, unsigned int channel);
unsigned char dim_pre_de_buf_config(unsigned int channel);
void dim_pre_de_process(unsigned int channel);
void dim_pre_de_done_buf_config(unsigned int channel, bool flg_timeout);
void dim_pre_de_done_buf_clear(unsigned int channel);
void di_reg_setting(unsigned int channel, struct vframe_s *vframe);
void di_reg_variable(unsigned int channel, struct vframe_s *vframe);
void dim_unreg_process_irq(unsigned int channel);
void di_unreg_variable(unsigned int channel);
void di_unreg_setting(void);
void dim_uninit_buf(unsigned int disable_mirror, unsigned int channel);
void dim_unreg_process(unsigned int channel);
int dim_process_post_vframe(unsigned int channel);
unsigned char dim_check_di_buf(struct di_buf_s *di_buf, int reason,
unsigned int channel);
int dim_do_post_wr_fun(void *arg, vframe_t *disp_vf);
int dim_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);
void dim_post_de_done_buf_config(unsigned int channel);
void dim_recycle_post_back(unsigned int channel);
void recycle_post_ready_local(struct di_buf_s *di_buf,
unsigned int channel);
/*--------------------------*/
unsigned char dim_vcry_get_flg(void);
void dim_vcry_flg_inc(void);
void dim_vcry_set_flg(unsigned char val);
/*--------------------------*/
unsigned int dim_vcry_get_log_reason(void);
void dim_vcry_set_log_reason(unsigned int val);
/*--------------------------*/
unsigned char dim_vcry_get_log_q_idx(void);
void dim_vcry_set_log_q_idx(unsigned int val);
/*--------------------------*/
struct di_buf_s **dim_vcry_get_log_di_buf(void);
void dim_vcry_set_log_di_buf(struct di_buf_s *di_bufp);
void dim_vcry_set(unsigned int reason, unsigned int idx,
struct di_buf_s *di_bufp);
const char *dim_get_vfm_type_name(unsigned int nub);
bool dim_cma_top_alloc(unsigned int ch);
bool dim_cma_top_release(unsigned int ch);
int dim_get_reg_unreg_cnt(void);
void dim_reg_timeout_inc(void);
void dim_reg_process(unsigned int channel);
bool is_bypass2(struct vframe_s *vf_in, unsigned int ch);
/*--------------------------*/
int di_ori_event_unreg(unsigned int channel);
int di_ori_event_reg(void *data, unsigned int channel);
int di_ori_event_qurey_vdin2nr(unsigned int channel);
int di_ori_event_reset(unsigned int channel);
int di_ori_event_light_unreg(unsigned int channel);
int di_ori_event_light_unreg_revframe(unsigned int channel);
int di_ori_event_ready(unsigned int channel);
int di_ori_event_qurey_state(unsigned int channel);
void di_ori_event_set_3D(int type, void *data, unsigned int channel);
/*--------------------------*/
extern int pre_run_flag;
extern unsigned int dbg_first_cnt_pre;
extern spinlock_t plist_lock;
void dim_dbg_pre_cnt(unsigned int channel, char *item);
void diext_clk_b_sw(bool on);
int di_vf_l_states(struct vframe_states *states, unsigned int channel);
struct vframe_s *di_vf_l_peek(unsigned int channel);
void di_vf_l_put(struct vframe_s *vf, unsigned char channel);
struct vframe_s *di_vf_l_get(unsigned int channel);
unsigned char pre_p_asi_de_buf_config(unsigned int ch);
/*---------------------*/
ssize_t
store_config(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
ssize_t
store_dbg(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
ssize_t
store_dump_mem(struct device *dev, struct device_attribute *attr,
const char *buf, size_t len);
ssize_t
store_log(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
ssize_t
show_vframe_status(struct device *dev,
struct device_attribute *attr,
char *buf);
ssize_t dim_read_log(char *buf);
/*---------------------*/
struct di_buf_s *dim_get_buf(unsigned int channel,
int queue_idx, int *start_pos);
#define queue_for_each_entry(di_buf, channel, queue_idx, list) \
for (itmp = 0; \
((di_buf = dim_get_buf(channel, queue_idx, &itmp)) != NULL);)
#define di_dev_t struct di_dev_s
#define di_pr_info(fmt, args ...) pr_info("DI: " fmt, ## args)
#define pr_dbg(fmt, args ...) pr_debug("DI: " fmt, ## args)
#define pr_error(fmt, args ...) pr_err("DI: " fmt, ## args)
/*this is debug for buf*/
/*#define DI_DEBUG_POST_BUF_FLOW (1)*/
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,43 @@
/*
* drivers/amlogic/media/di_multi/deinterlace_dbg.h
*
* 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.
*
*/
#ifndef _DI_DBG_H
#define _DI_DBG_H
#include "deinterlace.h"
void dim_parse_cmd_params(char *buf_orig, char **parm);
void dim_dump_pre_stru(struct di_pre_stru_s *ppre);
void dim_dump_post_stru(struct di_post_stru_s *di_post_stru_p);
void dim_dump_di_buf(struct di_buf_s *di_buf);
void dim_dump_pool(struct queue_s *q);
void dim_dump_vframe(vframe_t *vf);
void dim_print_di_buf(struct di_buf_s *di_buf, int format);
void dim_dump_pre_mif_state(void);
void dim_dump_post_mif_reg(void);
void dim_dump_buf_addr(struct di_buf_s *di_buf, unsigned int num);
void dim_dump_mif_size_state(struct di_pre_stru_s *pre,
struct di_post_stru_s *post);
void debug_device_files_add(struct device *dev);
void debug_device_files_del(struct device *dev);
void dim_debugfs_init(void);
void dim_debugfs_exit(void);
int dim_state_show(struct seq_file *seq, void *v,
unsigned int channel);
int dim_dump_mif_size_state_show(struct seq_file *seq, void *v,
unsigned int channel);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,277 @@
/*
* drivers/amlogic/media/di_multi/deinterlace_hw.h
*
* 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.
*
*/
#ifndef _DI_HW_H
#define _DI_HW_H
#include <linux/amlogic/media/amvecm/amvecm.h>
#include "../deinterlace/di_pqa.h"
/* if post size < 80, filter of ei can't work */
#define MIN_POST_WIDTH 80
#define MIN_BLEND_WIDTH 27
#define SKIP_CTRE_NUM 13
/*move from deinterlace.c*/
enum eAFBC_REG {
eAFBC_ENABLE,
eAFBC_MODE,
eAFBC_SIZE_IN,
eAFBC_DEC_DEF_COLOR,
eAFBC_CONV_CTRL,
eAFBC_LBUF_DEPTH,
eAFBC_HEAD_BADDR,
eAFBC_BODY_BADDR,
eAFBC_SIZE_OUT,
eAFBC_OUT_YSCOPE,
eAFBC_STAT,
eAFBC_VD_CFMT_CTRL,
eAFBC_VD_CFMT_W,
eAFBC_MIF_HOR_SCOPE,
eAFBC_MIF_VER_SCOPE,
eAFBC_PIXEL_HOR_SCOPE,
eAFBC_PIXEL_VER_SCOPE,
eAFBC_VD_CFMT_H,
};
enum eAFBC_DEC {
eAFBC_DEC0,
eAFBC_DEC1,
};
#define AFBC_REG_INDEX_NUB (18)
#define AFBC_DEC_NUB (2)
struct DI_MIF_s {
unsigned short luma_x_start0;
unsigned short luma_x_end0;
unsigned short luma_y_start0;
unsigned short luma_y_end0;
unsigned short chroma_x_start0;
unsigned short chroma_x_end0;
unsigned short chroma_y_start0;
unsigned short chroma_y_end0;
unsigned int nocompress;
unsigned set_separate_en:2;
unsigned src_field_mode:1;
unsigned src_prog:1;
unsigned video_mode:1;
unsigned output_field_num:1;
unsigned bit_mode:2;
/*
* unsigned burst_size_y:2; set 3 as default
* unsigned burst_size_cb:2;set 1 as default
* unsigned burst_size_cr:2;set 1 as default
*/
unsigned canvas0_addr0:8;
unsigned canvas0_addr1:8;
unsigned canvas0_addr2:8;
};
struct DI_SIM_MIF_s {
unsigned short start_x;
unsigned short end_x;
unsigned short start_y;
unsigned short end_y;
unsigned short canvas_num;
unsigned short bit_mode;
};
struct DI_MC_MIF_s {
unsigned short start_x;
unsigned short start_y;
unsigned short end_y;
unsigned short size_x;
unsigned short size_y;
unsigned short canvas_num;
unsigned short blend_en;
unsigned short vecrd_offset;
};
enum gate_mode_e {
GATE_AUTO,
GATE_ON,
GATE_OFF,
};
struct mcinfo_lmv_s {
unsigned char lock_flag;
char lmv;
unsigned short lock_cnt;
};
struct di_pq_parm_s {
struct am_pq_parm_s pq_parm;
struct am_reg_s *regs;
struct list_head list;
};
void dim_read_pulldown_info(unsigned int *glb_frm_mot_num,
unsigned int *glb_fid_mot_num);
#if 0
void read_new_pulldown_info(struct FlmModReg_t *pFMRegp);
#endif
void dim_pulldown_info_clear_g12a(void);
void dimh_combing_pd22_window_config(unsigned int width, unsigned int height);
void dimh_hw_init(bool pulldown_en, bool mc_enable);
void dimh_hw_uninit(void);
void dimh_enable_di_pre_aml(struct DI_MIF_s *di_inp_mif,
struct DI_MIF_s *di_mem_mif,
struct DI_MIF_s *di_chan2_mif,
struct DI_SIM_MIF_s *di_nrwr_mif,
struct DI_SIM_MIF_s *di_mtnwr_mif,
struct DI_SIM_MIF_s *di_contp2rd_mif,
struct DI_SIM_MIF_s *di_contprd_mif,
struct DI_SIM_MIF_s *di_contwr_mif,
unsigned char madi_en,
unsigned char pre_field_num,
unsigned char pre_vdin_link);
void dimh_enable_afbc_input(struct vframe_s *vf);
void dimh_mc_pre_mv_irq(void);
void dimh_enable_mc_di_pre(struct DI_MC_MIF_s *di_mcinford_mif,
struct DI_MC_MIF_s *di_mcinfowr_mif,
struct DI_MC_MIF_s *di_mcvecwr_mif,
unsigned char mcdi_en);
void dimh_enable_mc_di_pre_g12(struct DI_MC_MIF_s *di_mcinford_mif,
struct DI_MC_MIF_s *di_mcinfowr_mif,
struct DI_MC_MIF_s *di_mcvecwr_mif,
unsigned char mcdi_en);
void dimh_enable_mc_di_post(struct DI_MC_MIF_s *di_mcvecrd_mif,
int urgent, bool reverse, int invert_mv);
void dimh_enable_mc_di_post_g12(struct DI_MC_MIF_s *di_mcvecrd_mif,
int urgent, bool reverse, int invert_mv);
void dimh_disable_post_deinterlace_2(void);
void dimh_initial_di_post_2(int hsize_post, int vsize_post,
int hold_line, bool write_en);
void dimh_enable_di_post_2(
struct DI_MIF_s *di_buf0_mif,
struct DI_MIF_s *di_buf1_mif,
struct DI_MIF_s *di_buf2_mif,
struct DI_SIM_MIF_s *di_diwr_mif,
struct DI_SIM_MIF_s *di_mtnprd_mif,
int ei_en, int blend_en, int blend_mtn_en, int blend_mode,
int di_vpp_en, int di_ddr_en,
int post_field_num, int hold_line, int urgent,
int invert_mv, int vskip_cnt
);
void dimh_post_switch_buffer(
struct DI_MIF_s *di_buf0_mif,
struct DI_MIF_s *di_buf1_mif,
struct DI_MIF_s *di_buf2_mif,
struct DI_SIM_MIF_s *di_diwr_mif,
struct DI_SIM_MIF_s *di_mtnprd_mif,
struct DI_MC_MIF_s *di_mcvecrd_mif,
int ei_en, int blend_en, int blend_mtn_en, int blend_mode,
int di_vpp_en, int di_ddr_en,
int post_field_num, int hold_line, int urgent,
int invert_mv, bool pd_en, bool mc_enable,
int vskip_cnt
);
void dim_post_read_reverse_irq(bool reverse,
unsigned char mc_pre_flag, bool mc_enable);
void dim_top_gate_control(bool top_en, bool mc_en);
void dim_pre_gate_control(bool enable, bool mc_enable);
void dim_post_gate_control(bool gate);
void dim_set_power_control(unsigned char enable);
void dim_hw_disable(bool mc_enable);
void dimh_enable_di_pre_mif(bool enable, bool mc_enable);
void dimh_enable_di_post_mif(enum gate_mode_e mode);
void dimh_combing_pd22_window_config(unsigned int width, unsigned int height);
void dimh_calc_lmv_init(void);
void dimh_calc_lmv_base_mcinfo(unsigned int vf_height,
unsigned long mcinfo_adr,
unsigned int mcinfo_size);
void dimh_init_field_mode(unsigned short height);
void dim_film_mode_win_config(unsigned int width, unsigned int height);
void dimh_pulldown_vof_win_config(struct pulldown_detected_s *wins);
void dimh_load_regs(struct di_pq_parm_s *di_pq_ptr);
void dim_pre_frame_reset_g12(unsigned char madi_en, unsigned char mcdi_en);
void dim_pre_frame_reset(void);
void dimh_interrupt_ctrl(unsigned char ma_en,
unsigned char det3d_en, unsigned char nrds_en,
unsigned char post_wr, unsigned char mc_en);
void dimh_txl_patch_prog(int prog_flg, unsigned int cnt, bool mc_en);
bool dimh_afbc_is_supported(void);
void dimh_afbc_reg_sw(bool on);
void dump_vd2_afbc(void);
u8 *dim_vmap(ulong addr, u32 size, bool *bflg);
void dim_unmap_phyaddr(u8 *vaddr);
int dim_print(const char *fmt, ...);
#define DI_MC_SW_OTHER (1 << 0)
#define DI_MC_SW_REG (1 << 1)
/*#define DI_MC_SW_POST (1 << 2)*/
#define DI_MC_SW_IC (1 << 2)
#define DI_MC_SW_ON_MASK (DI_MC_SW_REG | DI_MC_SW_OTHER | DI_MC_SW_IC)
void dimh_patch_post_update_mc(void);
void dimh_patch_post_update_mc_sw(unsigned int cmd, bool on);
void dim_rst_protect(bool on);
void dim_pre_nr_wr_done_sel(bool on);
void dim_arb_sw(bool on);
void dbg_set_DI_PRE_CTRL(void);
void di_async_reset2(void); /*2019-04-05 add for debug*/
enum DI_HW_POST_CTRL {
DI_HW_POST_CTRL_INIT,
DI_HW_POST_CTRL_RESET,
};
void dimh_post_ctrl(enum DI_HW_POST_CTRL contr,
unsigned int post_write_en);
void dimh_int_ctr(unsigned int set_mod, unsigned char ma_en,
unsigned char det3d_en, unsigned char nrds_en,
unsigned char post_wr, unsigned char mc_en);
void h_dbg_reg_set(unsigned int val);
enum eDI_POST_FLOW {
eDI_POST_FLOW_STEP1_STOP,
eDI_POST_FLOW_STEP2_START,
/* eDI_POST_FLOW_STEP3_RESET_INT,*/
};
void di_post_set_flow(unsigned int post_wr_en, enum eDI_POST_FLOW step);
void post_mif_sw(bool on);
void post_dbg_contr(void);
void post_close_new(void);
void di_post_reset(void);
void dimh_pst_trig_resize(void);
void hpst_power_ctr(bool on);
void hpst_dbg_power_ctr_trig(unsigned int cmd);
void hpst_dbg_mem_pd_trig(unsigned int cmd);
void hpst_dbg_trig_gate(unsigned int cmd);
void hpst_dbg_trig_mif(unsigned int cmd);
void hpst_mem_pd_sw(unsigned int on);
void hpst_vd1_sw(unsigned int on);
void dim_init_setting_once(void);
void dim_hw_init_reg(void);
#endif

View File

@@ -0,0 +1,106 @@
/*
* drivers/amlogic/media/di_multi/di_api.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/types.h>
#include <linux/slab.h>
#include <linux/amlogic/media/vpu/vpu.h>
#include "di_api.h"
/**********************************
* DI api is used for other module
*********************************/
static const struct di_ext_ops di_ext = {
.di_post_reg_rd = l_DI_POST_REG_RD,
.di_post_wr_reg_bits = l_DI_POST_WR_REG_BITS,
};
void dim_attach_to_local(void)
{
dil_attach_ext_api(&di_ext);
}
bool dim_attach_ext_api(struct di_ext_ops *di_api)
{
#if 1
if (!di_api)
return false;
memcpy(di_api, &di_ext, sizeof(struct di_ext_ops));
#else
di_api = &di_ext;
#endif
return true;
}
/*EXPORT_SYMBOL(dim_attach_ext_api);*/
/**********************************
* ext_api used by DI
********************************/
#define ARY_TEMP2
#ifdef ARY_TEMP2
void ext_switch_vpu_mem_pd_vmod(unsigned int vmod, bool on)
{
switch_vpu_mem_pd_vmod(vmod,
on ? VPU_MEM_POWER_ON : VPU_MEM_POWER_DOWN);
}
const struct ext_ops_s ext_ops = {
.switch_vpu_mem_pd_vmod = ext_switch_vpu_mem_pd_vmod,
/*no use ?*/
/* .vf_get_receiver_name = vf_get_receiver_name,*/
.switch_vpu_clk_gate_vmod = switch_vpu_clk_gate_vmod,
.get_current_vscale_skip_count = get_current_vscale_skip_count,
.canvas_pool_alloc_canvas_table = canvas_pool_alloc_canvas_table,
};
#else
void n_switch_vpu_mem_pd_vmod(unsigned int vmod, bool on)
{
}
char *n_vf_get_receiver_name(const char *provider_name)
{
return "";
}
void n_switch_vpu_clk_gate_vmod(unsigned int vmod, int flag)
{
}
int n_get_current_vscale_skip_count(struct vframe_s *vf)
{
return 0;
}
u32 n_canvas_pool_alloc_canvas_table(const char *owner, u32 *tab,
int size,
enum canvas_map_type_e type)
{
return 0;
}
const struct ext_ops_s ext_ops = {
.switch_vpu_mem_pd_vmod = n_switch_vpu_mem_pd_vmod,
.vf_get_receiver_name = n_vf_get_receiver_name,
.switch_vpu_clk_gate_vmod = n_switch_vpu_clk_gate_vmod,
.get_current_vscale_skip_count = n_get_current_vscale_skip_count,
.canvas_pool_alloc_canvas_table = n_canvas_pool_alloc_canvas_table,
};
#endif

View File

@@ -0,0 +1,55 @@
/*
* drivers/amlogic/media/di_multi/di_api.h
*
* 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.
*
*/
#ifndef __DI_API_H__
#define __DI_API_H__
#include <linux/amlogic/media/canvas/canvas_mgr.h>
#include <linux/amlogic/media/vfm/vframe.h>
#include "../di_local/di_local.h"
/*--------------------------*/
unsigned int l_DI_POST_REG_RD(unsigned int addr);
int l_DI_POST_WR_REG_BITS(u32 adr, u32 val, u32 start, u32 len);
/*--------------------------*/
bool di_attach_ext_api(struct di_ext_ops *di_api);
/*attach di_ops to di_local*/
bool dil_attach_ext_api(const struct di_ext_ops *di_api);
void dim_attach_to_local(void);
/*--------------------------*/
int get_current_vscale_skip_count(struct vframe_s *vf);
struct ext_ops_s {
void (*switch_vpu_mem_pd_vmod)(unsigned int vmod, bool on);
/* char *(*vf_get_receiver_name)(const char *provider_name);*/
void (*switch_vpu_clk_gate_vmod)(unsigned int vmod, int flag);
int (*get_current_vscale_skip_count)(struct vframe_s *vf);
u32 (*canvas_pool_alloc_canvas_table)(const char *owner, u32 *tab,
int size,
enum canvas_map_type_e type);
};
extern const struct ext_ops_s ext_ops;
/*--------------------------*/
void dil_get_rev_mem(unsigned long *mstart, unsigned int *msize);
void dil_get_flg(unsigned int *flg);
#endif /*__DI_API_H__*/

View File

@@ -0,0 +1,21 @@
/*
* drivers/amlogic/media/di_multi/di_data.h
*
* 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.
*
*/
#ifndef __DI_DATA_H__
#define __DI_DATA_H__
#endif /*__DI_DATA_H__*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,69 @@
/*
* drivers/amlogic/media/di_multi/di_dbg.h
*
* 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.
*
*/
#ifndef __DI_DBG_H__
#define __DI_DBG_H__
#include <linux/amlogic/media/vfm/vframe.h>
#include <linux/amlogic/media/vfm/vframe_provider.h>
#include <linux/amlogic/media/vfm/vframe_receiver.h>
void didbg_fs_init(void);
void didbg_fs_exit(void);
void di_cfgx_init_val(void);
void didbg_vframe_in_copy(unsigned int ch, struct vframe_s *pvfm);
void didbg_vframe_out_save(struct vframe_s *pvfm);
/********************************
*debug register:
*******************************/
void ddbg_reg_save(unsigned int addr, unsigned int val,
unsigned int st, unsigned int bw);
void dim_ddbg_mod_save(unsigned int mod,
unsigned int ch,
unsigned int cnt);
void ddbg_sw(unsigned int mode, bool on);
/********************************
*time:
*******************************/
u64 cur_to_msecs(void);
u64 cur_to_usecs(void); /*2019*/
/********************************
*trace:
*******************************/
struct dim_tr_ops_s {
void (*pre)(unsigned int index, unsigned long ctime);
void (*post)(unsigned int index, unsigned long ctime);
void (*pre_get)(unsigned int index);
void (*pre_set)(unsigned int index);
void (*pre_ready)(unsigned int index);
void (*post_ready)(unsigned int index);
void (*post_get)(unsigned int index);
void (*post_get2)(unsigned int index);
void (*post_set)(unsigned int index);
void (*post_ir)(unsigned int index);
void (*post_do)(unsigned int index);
void (*post_peek)(unsigned int index);
};
extern const struct dim_tr_ops_s dim_tr_ops;
#endif /*__DI_DBG_H__*/

View File

@@ -0,0 +1,389 @@
/*
* drivers/amlogic/media/di_multi/di_post.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/kernel.h>
#include <linux/err.h>
#include <linux/seq_file.h>
#include <linux/amlogic/media/vfm/vframe.h>
#include "deinterlace.h"
#include "deinterlace_dbg.h"
#include "di_data_l.h"
#include "di_data.h"
#include "di_dbg.h"
#include "di_vframe.h"
#include "di_que.h"
#include "di_task.h"
#include "di_prc.h"
#include "di_post.h"
#include "nr_downscale.h"
#include "register.h"
void dpost_clear(void)/*not been called*/
{
struct di_hpst_s *pst = get_hw_pst();
memset(pst, 0, sizeof(struct di_hpst_s));
}
void dpost_init(void)
{/*reg:*/
struct di_hpst_s *pst = get_hw_pst();
pst->state = eDI_PST_ST_IDLE;
/*timer out*/
di_tout_int(&pst->tout, 40); /*ms*/
}
void pw_use_hw_post(enum eDI_SUB_ID channel, bool on)
{
struct di_hpst_s *post = get_hw_pst();
post->hw_flg_busy_post = on;
if (on)
post->curr_ch = channel;
}
static bool pw_try_sw_ch_next_post(enum eDI_SUB_ID channel)
{
bool ret = false;
struct di_hpst_s *post = get_hw_pst();
enum eDI_SUB_ID lst_ch, nch;
lst_ch = channel;
nch = pw_ch_next_count(lst_ch);
if (!get_reg_flag(nch) || get_flag_trig_unreg(nch))
return false;
if (nch != channel)
dim_ddbg_mod_save(eDI_DBG_MOD_POST_CH_CHG, nch, 0);/*dbg*/
post->curr_ch = nch;
post->hw_flg_busy_post = true;
ret = true;
/*dim_print("%s:%d->%d:%d\n", __func__, lst_ch, nch, ret);*/
return ret;
}
/*****************************/
/* debug */
/*****************************/
/*****************************/
/* STEP */
/*****************************/
bool dpst_step_idle(void)
{
struct di_hpst_s *pst = get_hw_pst();
bool reflesh = false;
if (!pw_try_sw_ch_next_post(pst->curr_ch))
return false;
pst->pres = get_pre_stru(pst->curr_ch);
pst->psts = get_post_stru(pst->curr_ch);
pst->state++;/*tmp*/
reflesh = true;
return reflesh;
}
bool dpst_step_check(void)
{
struct di_hpst_s *pst = get_hw_pst();
unsigned int ch;
struct di_post_stru_s *ppost;
bool reflesh = false;
ch = pst->curr_ch;
ppost = get_post_stru(ch);
if (queue_empty(ch, QUEUE_POST_DOING)) {
ppost->post_peek_underflow++;
pst->state--;
return reflesh;
}
pst->state++;
reflesh = true;
return reflesh;
}
bool dpst_step_set(void)
{
struct di_buf_s *di_buf = NULL;
vframe_t *vf_p = NULL;
struct di_post_stru_s *ppost;
struct di_hpst_s *pst = get_hw_pst();
unsigned int ch;
bool reflesh = false;
ulong flags = 0;
ch = pst->curr_ch;
ppost = get_post_stru(ch);
di_buf = get_di_buf_head(ch, QUEUE_POST_DOING);
if (dim_check_di_buf(di_buf, 20, ch)) {
PR_ERR("%s:err1\n", __func__);
return reflesh;
}
vf_p = di_buf->vframe;
if (ppost->run_early_proc_fun_flag) {
if (vf_p->early_process_fun)
vf_p->early_process_fun = dim_do_post_wr_fun;
}
dim_print("%s:pr_index=%d\n", __func__, di_buf->process_fun_index);
if (di_buf->process_fun_index) { /*not bypass?*/
ppost->post_wr_cnt++;
spin_lock_irqsave(&plist_lock, flags);
dim_post_process(di_buf, 0, vf_p->width - 1,
0, vf_p->height - 1, vf_p);
spin_unlock_irqrestore(&plist_lock, flags);
/*begin to count timer*/
di_tout_contr(eDI_TOUT_CONTR_EN, &pst->tout);
ppost->post_de_busy = 1;
ppost->irq_time = cur_to_msecs();
/*state*/
pst->state++;
/*reflesh = true;*/
} else {
ppost->de_post_process_done = 1; /*trig done*/
pst->flg_int_done = 1;
/*state*/
pst->state++;/*pst->state = eDI_PST_ST_DONE;*/
reflesh = true;
}
ppost->cur_post_buf = di_buf;
return reflesh;
}
bool dpst_step_wait_int(void)
{
struct di_hpst_s *pst = get_hw_pst();
unsigned int ch;
struct di_post_stru_s *ppost;
bool reflesh = false;
ulong flags = 0;
ch = pst->curr_ch;
dim_print("%s:ch[%d],done_flg[%d]\n", __func__,
pst->curr_ch, pst->flg_int_done);
if (pst->flg_int_done) {
/*finish to count timer*/
di_tout_contr(eDI_TOUT_CONTR_FINISH, &pst->tout);
spin_lock_irqsave(&plist_lock, flags);
dim_post_de_done_buf_config(ch);
spin_unlock_irqrestore(&plist_lock, flags);
pst->flg_int_done = false;
/*state*/
pst->state = eDI_PST_ST_IDLE;
reflesh = true;
} else {
/*check if timeout:*/
if (di_tout_contr(eDI_TOUT_CONTR_CHECK, &pst->tout)) {
ppost = get_post_stru(ch);
PR_WARN("ch[%d]:post timeout[%d]\n", ch,
ppost->cur_post_buf->seq);
dim_ddbg_mod_save(eDI_DBG_MOD_POST_TIMEOUT, ch, 0);
/*state*/
pst->state = eDI_PST_ST_TIMEOUT;
reflesh = true;
}
}
return reflesh;
}
void dpst_timeout(unsigned int ch)
{
hpst_dbg_mem_pd_trig(0);
post_close_new();
#if 0
di_post_set_flow(1, eDI_POST_FLOW_STEP1_STOP);
di_post_reset();
#endif
dimh_pst_trig_resize();
}
bool dpst_step_timeout(void)
{
struct di_hpst_s *pst = get_hw_pst();
unsigned int ch;
bool reflesh = false;
ulong flags = 0;
ch = pst->curr_ch;
dpst_timeout(ch);
spin_lock_irqsave(&plist_lock, flags);
dim_post_de_done_buf_config(ch);
spin_unlock_irqrestore(&plist_lock, flags);
pst->flg_int_done = false;
/*state*/
pst->state = eDI_PST_ST_IDLE;
reflesh = true;
return reflesh;
}
bool dpst_step_done(void)/*this step no use ?*/
{
struct di_hpst_s *pst = get_hw_pst();
unsigned int ch;
bool reflesh = false;
ch = pst->curr_ch;
/* dim_post_de_done_buf_config(ch);*/
/*state*/
pst->state = eDI_PST_ST_IDLE;
reflesh = true;
return reflesh;
}
const struct di_func_tab_s di_pst_func_tab[] = {
{eDI_PST_ST_EXIT, NULL},
{eDI_PST_ST_IDLE, dpst_step_idle},
{eDI_PST_ST_CHECK, dpst_step_check},
{eDI_PST_ST_SET, dpst_step_set},
{eDI_PST_ST_WAIT_INT, dpst_step_wait_int},
{eDI_PST_ST_TIMEOUT, dpst_step_timeout},
{eDI_PST_ST_DONE, dpst_step_done},
};
const char * const dpst_state_name[] = {
"EXIT",
"IDLE", /*swith to next channel?*/
"CHECK",
"SET",
"WAIT_INT",
"TIMEOUT",
"DONE",
};
const char *dpst_state_name_get(enum eDI_PST_ST state)
{
if (state > eDI_PST_ST_DONE)
return "nothing";
return dpst_state_name[state];
}
bool dpst_can_exit(unsigned int ch)
{
struct di_hpst_s *pst = get_hw_pst();
bool ret = false;
if (ch != pst->curr_ch) {
ret = true;
} else {
if (pst->state <= eDI_PST_ST_IDLE)
ret = true;
}
pr_info("%s:ch[%d]:curr[%d]:stat[%s] ret[%d]\n",
__func__,
ch, pst->curr_ch,
dpst_state_name_get(pst->state),
ret);
return ret;
}
static bool dpst_process_step2(void)
{
struct di_hpst_s *pst = get_hw_pst();
enum eDI_PST_ST pst_st = pst->state;
unsigned int ch;
ch = pst->curr_ch;
if (pst_st > eDI_PST_ST_EXIT)
dim_recycle_post_back(ch);
if ((pst_st <= eDI_PST_ST_DONE) &&
di_pst_func_tab[pst_st].func)
return di_pst_func_tab[pst_st].func();
else
return false;
}
void dpst_dbg_f_trig(unsigned int cmd)
{
struct di_task *tsk = get_task();
struct di_hpst_s *pst = get_hw_pst();
if (down_interruptible(&tsk->sem)) {
PR_ERR("%s:can't get sem\n", __func__);
return;
}
/*set on/off and trig*/
if (cmd & 0x10) {
pst->dbg_f_en = 1;
pst->dbg_f_cnt = cmd & 0xf;
pst->dbg_f_lstate = pst->state;
} else {
pst->dbg_f_en = 0;
}
up(&tsk->sem);
}
void dpst_process(void)
{
bool reflesh;
struct di_hpst_s *pst = get_hw_pst();
if (pst->dbg_f_en) {
if (pst->dbg_f_cnt) {
dpst_process_step2();
pst->dbg_f_cnt--;
}
if (pst->dbg_f_lstate != pst->state) {
pr_info("ch[%d]:state:%s->%s\n",
pst->curr_ch,
dpst_state_name_get(pst->dbg_f_lstate),
dpst_state_name_get(pst->state));
pst->dbg_f_lstate = pst->state;
}
return;
}
reflesh = true;
while (reflesh)
reflesh = dpst_process_step2();
}

View File

@@ -0,0 +1,27 @@
/*
* drivers/amlogic/media/di_multi/di_post.h
*
* 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.
*
*/
#ifndef __DI_POST_H__
#define __DI_POST_H__
void dpost_init(void);
void dpst_process(void);
const char *dpst_state_name_get(enum eDI_PST_ST state);
void dpst_dbg_f_trig(unsigned int cmd);
bool dpst_can_exit(unsigned int ch);
#endif /*__DI_POST_H__*/

View File

@@ -0,0 +1,628 @@
/*
* drivers/amlogic/media/di_multi/di_pps.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/kernel.h>
#include <linux/err.h>
#include <linux/amlogic/media/registers/regs/di_regs.h>
#include <linux/amlogic/media/vfm/vframe.h>
#include "di_pps.h"
#include "register.h"
#include <linux/seq_file.h>
#if 0
/* pps filter coefficients */
#define COEF_BICUBIC 0
#define COEF_3POINT_TRIANGLE 1
#define COEF_4POINT_TRIANGLE 2
#define COEF_BILINEAR 3
#define COEF_2POINT_BILINEAR 4
#define COEF_BICUBIC_SHARP 5
#define COEF_3POINT_TRIANGLE_SHARP 6
#define COEF_3POINT_BSPLINE 7
#define COEF_4POINT_BSPLINE 8
#define COEF_3D_FILTER 9
#define COEF_NULL 0xff
#define TOTAL_FILTERS 10
#define MAX_NONLINEAR_FACTOR 0x40
const u32 vpp_filter_coefs_bicubic_sharp[] = {
3,
33 | 0x8000,
/* 0x01f80090, 0x01f80100, 0xff7f0200, 0xfe7f0300, */
0x01fa008c, 0x01fa0100, 0xff7f0200, 0xfe7f0300,
0xfd7e0500, 0xfc7e0600, 0xfb7d0800, 0xfb7c0900,
0xfa7b0b00, 0xfa7a0dff, 0xf9790fff, 0xf97711ff,
0xf87613ff, 0xf87416fe, 0xf87218fe, 0xf8701afe,
0xf76f1dfd, 0xf76d1ffd, 0xf76b21fd, 0xf76824fd,
0xf76627fc, 0xf76429fc, 0xf7612cfc, 0xf75f2ffb,
0xf75d31fb, 0xf75a34fb, 0xf75837fa, 0xf7553afa,
0xf8523cfa, 0xf8503ff9, 0xf84d42f9, 0xf84a45f9,
0xf84848f8
};
const u32 vpp_filter_coefs_bicubic[] = {
4,
33,
0x00800000, 0x007f0100, 0xff7f0200, 0xfe7f0300,
0xfd7e0500, 0xfc7e0600, 0xfb7d0800, 0xfb7c0900,
0xfa7b0b00, 0xfa7a0dff, 0xf9790fff, 0xf97711ff,
0xf87613ff, 0xf87416fe, 0xf87218fe, 0xf8701afe,
0xf76f1dfd, 0xf76d1ffd, 0xf76b21fd, 0xf76824fd,
0xf76627fc, 0xf76429fc, 0xf7612cfc, 0xf75f2ffb,
0xf75d31fb, 0xf75a34fb, 0xf75837fa, 0xf7553afa,
0xf8523cfa, 0xf8503ff9, 0xf84d42f9, 0xf84a45f9,
0xf84848f8
};
const u32 vpp_filter_coefs_bilinear[] = {
4,
33,
0x00800000, 0x007e0200, 0x007c0400, 0x007a0600,
0x00780800, 0x00760a00, 0x00740c00, 0x00720e00,
0x00701000, 0x006e1200, 0x006c1400, 0x006a1600,
0x00681800, 0x00661a00, 0x00641c00, 0x00621e00,
0x00602000, 0x005e2200, 0x005c2400, 0x005a2600,
0x00582800, 0x00562a00, 0x00542c00, 0x00522e00,
0x00503000, 0x004e3200, 0x004c3400, 0x004a3600,
0x00483800, 0x00463a00, 0x00443c00, 0x00423e00,
0x00404000
};
const u32 vpp_3d_filter_coefs_bilinear[] = {
2,
33,
0x80000000, 0x7e020000, 0x7c040000, 0x7a060000,
0x78080000, 0x760a0000, 0x740c0000, 0x720e0000,
0x70100000, 0x6e120000, 0x6c140000, 0x6a160000,
0x68180000, 0x661a0000, 0x641c0000, 0x621e0000,
0x60200000, 0x5e220000, 0x5c240000, 0x5a260000,
0x58280000, 0x562a0000, 0x542c0000, 0x522e0000,
0x50300000, 0x4e320000, 0x4c340000, 0x4a360000,
0x48380000, 0x463a0000, 0x443c0000, 0x423e0000,
0x40400000
};
const u32 vpp_filter_coefs_3point_triangle[] = {
3,
33,
0x40400000, 0x3f400100, 0x3d410200, 0x3c410300,
0x3a420400, 0x39420500, 0x37430600, 0x36430700,
0x35430800, 0x33450800, 0x32450900, 0x31450a00,
0x30450b00, 0x2e460c00, 0x2d460d00, 0x2c470d00,
0x2b470e00, 0x29480f00, 0x28481000, 0x27481100,
0x26491100, 0x25491200, 0x24491300, 0x234a1300,
0x224a1400, 0x214a1500, 0x204a1600, 0x1f4b1600,
0x1e4b1700, 0x1d4b1800, 0x1c4c1800, 0x1b4c1900,
0x1a4c1a00
};
/* point_num =4, filt_len =4, group_num = 64, [1 2 1] */
const u32 vpp_filter_coefs_4point_triangle[] = {
4,
33,
0x20402000, 0x20402000, 0x1f3f2101, 0x1f3f2101,
0x1e3e2202, 0x1e3e2202, 0x1d3d2303, 0x1d3d2303,
0x1c3c2404, 0x1c3c2404, 0x1b3b2505, 0x1b3b2505,
0x1a3a2606, 0x1a3a2606, 0x19392707, 0x19392707,
0x18382808, 0x18382808, 0x17372909, 0x17372909,
0x16362a0a, 0x16362a0a, 0x15352b0b, 0x15352b0b,
0x14342c0c, 0x14342c0c, 0x13332d0d, 0x13332d0d,
0x12322e0e, 0x12322e0e, 0x11312f0f, 0x11312f0f,
0x10303010
};
/*
*4th order (cubic) b-spline
*filt_cubic point_num =4, filt_len =4, group_num = 64, [1 5 1]
*/
const u32 vpp_filter_coefs_4point_bspline[] = {
4,
33,
0x15561500, 0x14561600, 0x13561700, 0x12561800,
0x11551a00, 0x11541b00, 0x10541c00, 0x0f541d00,
0x0f531e00, 0x0e531f00, 0x0d522100, 0x0c522200,
0x0b522300, 0x0b512400, 0x0a502600, 0x0a4f2700,
0x094e2900, 0x084e2a00, 0x084d2b00, 0x074c2c01,
0x074b2d01, 0x064a2f01, 0x06493001, 0x05483201,
0x05473301, 0x05463401, 0x04453601, 0x04433702,
0x04423802, 0x03413a02, 0x03403b02, 0x033f3c02,
0x033d3d03
};
/*3rd order (quadratic) b-spline*/
/*filt_quadratic, point_num =3, filt_len =3, group_num = 64, [1 6 1] */
const u32 vpp_filter_coefs_3point_bspline[] = {
3,
33,
0x40400000, 0x3e420000, 0x3c440000, 0x3a460000,
0x38480000, 0x364a0000, 0x344b0100, 0x334c0100,
0x314e0100, 0x304f0100, 0x2e500200, 0x2c520200,
0x2a540200, 0x29540300, 0x27560300, 0x26570300,
0x24580400, 0x23590400, 0x215a0500, 0x205b0500,
0x1e5c0600, 0x1d5c0700, 0x1c5d0700, 0x1a5e0800,
0x195e0900, 0x185e0a00, 0x175f0a00, 0x15600b00,
0x14600c00, 0x13600d00, 0x12600e00, 0x11600f00,
0x10601000
};
/*filt_triangle, point_num =3, filt_len =2.6, group_num = 64, [1 7 1] */
const u32 vpp_filter_coefs_3point_triangle_sharp[] = {
3,
33,
0x40400000, 0x3e420000, 0x3d430000, 0x3b450000,
0x3a460000, 0x38480000, 0x37490000, 0x354b0000,
0x344c0000, 0x324e0000, 0x314f0000, 0x2f510000,
0x2e520000, 0x2c540000, 0x2b550000, 0x29570000,
0x28580000, 0x265a0000, 0x245c0000, 0x235d0000,
0x215f0000, 0x20600000, 0x1e620000, 0x1d620100,
0x1b620300, 0x19630400, 0x17630600, 0x15640700,
0x14640800, 0x12640a00, 0x11640b00, 0x0f650c00,
0x0d660d00
};
const u32 vpp_filter_coefs_2point_binilear[] = {
2,
33,
0x80000000, 0x7e020000, 0x7c040000, 0x7a060000,
0x78080000, 0x760a0000, 0x740c0000, 0x720e0000,
0x70100000, 0x6e120000, 0x6c140000, 0x6a160000,
0x68180000, 0x661a0000, 0x641c0000, 0x621e0000,
0x60200000, 0x5e220000, 0x5c240000, 0x5a260000,
0x58280000, 0x562a0000, 0x542c0000, 0x522e0000,
0x50300000, 0x4e320000, 0x4c340000, 0x4a360000,
0x48380000, 0x463a0000, 0x443c0000, 0x423e0000,
0x40400000
};
static const u32 *filter_table[] = {
vpp_filter_coefs_bicubic,
vpp_filter_coefs_3point_triangle,
vpp_filter_coefs_4point_triangle,
vpp_filter_coefs_bilinear,
vpp_filter_coefs_2point_binilear,
vpp_filter_coefs_bicubic_sharp,
vpp_filter_coefs_3point_triangle_sharp,
vpp_filter_coefs_3point_bspline,
vpp_filter_coefs_4point_bspline,
vpp_3d_filter_coefs_bilinear
};
static int chroma_filter_table[] = {
COEF_BICUBIC, /* bicubic */
COEF_3POINT_TRIANGLE,
COEF_4POINT_TRIANGLE,
COEF_4POINT_TRIANGLE, /* bilinear */
COEF_2POINT_BILINEAR,
COEF_3POINT_TRIANGLE, /* bicubic_sharp */
COEF_3POINT_TRIANGLE, /* 3point_triangle_sharp */
COEF_3POINT_TRIANGLE, /* 3point_bspline */
COEF_4POINT_TRIANGLE, /* 4point_bspline */
COEF_3D_FILTER /* can not change */
};
static unsigned int vert_scaler_filter = 0xff;
module_param(vert_scaler_filter, uint, 0664);
MODULE_PARM_DESC(vert_scaler_filter, "vert_scaler_filter");
static unsigned int vert_chroma_scaler_filter = 0xff;
module_param(vert_chroma_scaler_filter, uint, 0664);
MODULE_PARM_DESC(vert_chroma_scaler_filter, "vert_chroma_scaler_filter");
static unsigned int horz_scaler_filter = 0xff;
module_param(horz_scaler_filter, uint, 0664);
MODULE_PARM_DESC(horz_scaler_filter, "horz_scaler_filter");
bool pre_scaler_en = true;
module_param(pre_scaler_en, bool, 0664);
MODULE_PARM_DESC(pre_scaler_en, "pre_scaler_en");
#endif
/*bicubic*/
static const unsigned int di_filt_coef0[] = {
0x00800000,
0x007f0100,
0xff7f0200,
0xfe7f0300,
0xfd7e0500,
0xfc7e0600,
0xfb7d0800,
0xfb7c0900,
0xfa7b0b00,
0xfa7a0dff,
0xf9790fff,
0xf97711ff,
0xf87613ff,
0xf87416fe,
0xf87218fe,
0xf8701afe,
0xf76f1dfd,
0xf76d1ffd,
0xf76b21fd,
0xf76824fd,
0xf76627fc,
0xf76429fc,
0xf7612cfc,
0xf75f2ffb,
0xf75d31fb,
0xf75a34fb,
0xf75837fa,
0xf7553afa,
0xf8523cfa,
0xf8503ff9,
0xf84d42f9,
0xf84a45f9,
0xf84848f8
};
/* 2 point bilinear */
static const unsigned int di_filt_coef1[] = {
0x00800000,
0x007e0200,
0x007c0400,
0x007a0600,
0x00780800,
0x00760a00,
0x00740c00,
0x00720e00,
0x00701000,
0x006e1200,
0x006c1400,
0x006a1600,
0x00681800,
0x00661a00,
0x00641c00,
0x00621e00,
0x00602000,
0x005e2200,
0x005c2400,
0x005a2600,
0x00582800,
0x00562a00,
0x00542c00,
0x00522e00,
0x00503000,
0x004e3200,
0x004c3400,
0x004a3600,
0x00483800,
0x00463a00,
0x00443c00,
0x00423e00,
0x00404000
};
/* 2 point bilinear, bank_length == 2*/
static const unsigned int di_filt_coef2[] = {
0x80000000,
0x7e020000,
0x7c040000,
0x7a060000,
0x78080000,
0x760a0000,
0x740c0000,
0x720e0000,
0x70100000,
0x6e120000,
0x6c140000,
0x6a160000,
0x68180000,
0x661a0000,
0x641c0000,
0x621e0000,
0x60200000,
0x5e220000,
0x5c240000,
0x5a260000,
0x58280000,
0x562a0000,
0x542c0000,
0x522e0000,
0x50300000,
0x4e320000,
0x4c340000,
0x4a360000,
0x48380000,
0x463a0000,
0x443c0000,
0x423e0000,
0x40400000
};
#define ZOOM_BITS 20
#define PHASE_BITS 16
static enum f2v_vphase_type_e top_conv_type = F2V_P2P;
static enum f2v_vphase_type_e bot_conv_type = F2V_P2P;
static unsigned int prehsc_en;
static unsigned int prevsc_en;
static const unsigned char f2v_420_in_pos_luma[F2V_TYPE_MAX] = {
0, 2, 0, 2, 0, 0, 0, 2, 0};
#if 0
static const unsigned char f2v_420_in_pos_chroma[F2V_TYPE_MAX] = {
1, 5, 1, 5, 2, 2, 1, 5, 2};
#endif
static const unsigned char f2v_420_out_pos[F2V_TYPE_MAX] = {
0, 2, 2, 0, 0, 2, 0, 0, 0};
static void f2v_get_vertical_phase(unsigned int zoom_ratio,
enum f2v_vphase_type_e type,
unsigned char bank_length,
struct pps_f2v_vphase_s *vphase)
{
int offset_in, offset_out;
/* luma */
offset_in = f2v_420_in_pos_luma[type] << PHASE_BITS;
offset_out = (f2v_420_out_pos[type] * zoom_ratio)
>> (ZOOM_BITS - PHASE_BITS);
vphase->rcv_num = bank_length;
if (bank_length == 4 || bank_length == 3)
vphase->rpt_num = 1;
else
vphase->rpt_num = 0;
if (offset_in > offset_out) {
vphase->rpt_num = vphase->rpt_num + 1;
vphase->phase =
((4 << PHASE_BITS) + offset_out - offset_in) >> 2;
} else {
while ((offset_in + (4 << PHASE_BITS)) <= offset_out) {
if (vphase->rpt_num == 1)
vphase->rpt_num = 0;
else
vphase->rcv_num++;
offset_in += 4 << PHASE_BITS;
}
vphase->phase = (offset_out - offset_in) >> 2;
}
}
/*
* patch 1: inp scaler 0: di wr scaler
* support: TM2
* not support: SM1
*/
void dim_pps_config(unsigned char path, int src_w, int src_h,
int dst_w, int dst_h)
{
struct pps_f2v_vphase_s vphase;
int i;
int hsc_en = 0, vsc_en = 0;
int vsc_double_line_mode;
unsigned int p_src_w, p_src_h;
unsigned int vert_phase_step, horz_phase_step;
unsigned char top_rcv_num, bot_rcv_num;
unsigned char top_rpt_num, bot_rpt_num;
unsigned short top_vphase, bot_vphase;
unsigned char is_frame;
int vert_bank_length = 4;
const unsigned int *filt_coef0 = di_filt_coef0;
/*unsigned int *filt_coef1 = di_filt_coef1;*/
const unsigned int *filt_coef2 = di_filt_coef2;
vsc_double_line_mode = 0;
if (src_h != dst_h)
vsc_en = 1;
if (src_w != dst_w)
hsc_en = 1;
/* config hdr size */
Wr_reg_bits(DI_HDR_IN_HSIZE, dst_w, 0, 13);
Wr_reg_bits(DI_HDR_IN_VSIZE, dst_h, 0, 13);
p_src_w = (prehsc_en ? ((src_w + 1) >> 1) : src_w);
p_src_h = prevsc_en ? ((src_h + 1) >> 1) : src_h;
Wr(DI_SC_HOLD_LINE, 0x10);
if (p_src_w > 2048) {
/*force vert bank length = 2*/
vert_bank_length = 2;
vsc_double_line_mode = 1;
}
/*write vert filter coefs*/
Wr(DI_SC_COEF_IDX, 0x0000);
for (i = 0; i < 33; i++) {
if (vert_bank_length == 2)
Wr(DI_SC_COEF, filt_coef2[i]); /*bilinear*/
else
Wr(DI_SC_COEF, filt_coef0[i]); /*bicubic*/
}
/*write horz filter coefs*/
Wr(DI_SC_COEF_IDX, 0x0100);
for (i = 0; i < 33; i++)
Wr(DI_SC_COEF, filt_coef0[i]); /*bicubic*/
if (p_src_h > 2048)
vert_phase_step = ((p_src_h << 18) / dst_h) << 2;
else
vert_phase_step = (p_src_h << 20) / dst_h;
if (p_src_w > 2048)
horz_phase_step = ((p_src_w << 18) / dst_w) << 2;
else
horz_phase_step = (p_src_w << 20) / dst_w;
is_frame = ((top_conv_type == F2V_IT2P) ||
(top_conv_type == F2V_IB2P) ||
(top_conv_type == F2V_P2P));
if (is_frame) {
f2v_get_vertical_phase(vert_phase_step, top_conv_type,
vert_bank_length, &vphase);
top_rcv_num = vphase.rcv_num;
top_rpt_num = vphase.rpt_num;
top_vphase = vphase.phase;
bot_rcv_num = 0;
bot_rpt_num = 0;
bot_vphase = 0;
} else {
f2v_get_vertical_phase(vert_phase_step, top_conv_type,
vert_bank_length, &vphase);
top_rcv_num = vphase.rcv_num;
top_rpt_num = vphase.rpt_num;
top_vphase = vphase.phase;
f2v_get_vertical_phase(vert_phase_step, bot_conv_type,
vert_bank_length, &vphase);
bot_rcv_num = vphase.rcv_num;
bot_rpt_num = vphase.rpt_num;
bot_vphase = vphase.phase;
}
vert_phase_step = (vert_phase_step << 4);
horz_phase_step = (horz_phase_step << 4);
Wr(DI_SC_LINE_IN_LENGTH, src_w);
Wr(DI_SC_PIC_IN_HEIGHT, src_h);
Wr(DI_VSC_REGION12_STARTP, 0);
Wr(DI_VSC_REGION34_STARTP, ((dst_h << 16) | dst_h));
Wr(DI_VSC_REGION4_ENDP, (dst_h - 1));
Wr(DI_VSC_START_PHASE_STEP, vert_phase_step);
Wr(DI_VSC_REGION0_PHASE_SLOPE, 0);
Wr(DI_VSC_REGION1_PHASE_SLOPE, 0);
Wr(DI_VSC_REGION3_PHASE_SLOPE, 0);
Wr(DI_VSC_REGION4_PHASE_SLOPE, 0);
Wr(DI_VSC_PHASE_CTRL,
((vsc_double_line_mode << 17) |
(!is_frame) << 16) |
(0 << 15) |
(bot_rpt_num << 13) |
(bot_rcv_num << 8) |
(0 << 7) |
(top_rpt_num << 5) |
(top_rcv_num));
Wr(DI_VSC_INI_PHASE, (bot_vphase << 16) | top_vphase);
Wr(DI_HSC_REGION12_STARTP, 0);
Wr(DI_HSC_REGION34_STARTP, (dst_w << 16) | dst_w);
Wr(DI_HSC_REGION4_ENDP, dst_w - 1);
Wr(DI_HSC_START_PHASE_STEP, horz_phase_step);
Wr(DI_HSC_REGION0_PHASE_SLOPE, 0);
Wr(DI_HSC_REGION1_PHASE_SLOPE, 0);
Wr(DI_HSC_REGION3_PHASE_SLOPE, 0);
Wr(DI_HSC_REGION4_PHASE_SLOPE, 0);
Wr(DI_HSC_PHASE_CTRL, (1 << 21) | (4 << 16) | 0);
Wr_reg_bits(DI_SC_TOP_CTRL, (path ? 3 : 0), 29, 2);
Wr(DI_SC_MISC,
(prevsc_en << 21) |
(prehsc_en << 20) | /* prehsc_en */
(prevsc_en << 19) | /* prevsc_en */
(vsc_en << 18) | /* vsc_en */
(hsc_en << 17) | /* hsc_en */
((vsc_en | hsc_en) << 16) | /* sc_top_en */
(1 << 15) | /* vd1 sc out enable */
(0 << 12) | /* horz nonlinear 4region enable */
(4 << 8) | /* horz scaler bank length */
(0 << 5) | /* vert scaler phase field enable */
(0 << 4) | /* vert nonlinear 4region enable */
(vert_bank_length << 0) /* vert scaler bank length */
);
pr_info("[pps] %s input %d %d output %d %d.\n",
path ? "pre" : "post", src_w, src_h, dst_w, dst_h);
}
/*
* 0x374e ~ 0x376d, 20 regs
*/
void dim_dump_pps_reg(unsigned int base_addr)
{
unsigned int i = 0x374e;
pr_info("-----dump pps start-----\n");
for (i = 0x374e; i < 0x376e; i++) {
pr_info("[0x%x][0x%x]=0x%x\n",
base_addr + (i << 2),
i, dim_RDMA_RD(i));
}
pr_info("-----dump pps end-----\n");
}
/*
* di pre h scaling down function
* only have h scaling down
* support: sm1 tm2 ...
* 0x37b0 ~ 0x37b5
*/
void dim_inp_hsc_setting(u32 src_w, u32 dst_w)
{
u32 i;
u32 hsc_en;
u32 horz_phase_step;
const int *filt_coef0 = di_filt_coef0;
/*int *filt_coef1 = di_filt_coef1;*/
/*int *filt_coef2 = di_filt_coef2;*/
if (src_w == dst_w) {
hsc_en = 0;
} else {
hsc_en = 1;
/*write horz filter coefs*/
dim_RDMA_WR(DI_VIU_HSC_COEF_IDX, 0x0100);
for (i = 0; i < 33; i++) /*bicubic*/
dim_RDMA_WR(DI_VIU_HSC_COEF, filt_coef0[i]);
horz_phase_step = (src_w << 20) / dst_w;
horz_phase_step = (horz_phase_step << 4);
dim_RDMA_WR(DI_VIU_HSC_WIDTHM1,
(src_w - 1) << 16 | (dst_w - 1));
dim_RDMA_WR(DI_VIU_HSC_PHASE_STEP, horz_phase_step);
dim_RDMA_WR(DI_VIU_HSC_PHASE_CTRL, 0);
}
dim_RDMA_WR(DI_VIU_HSC_CTRL,
(4 << 20) | /* initial receive number*/
(0 << 12) | /* initial pixel ptr*/
(1 << 10) | /* repeat first pixel number*/
(0 << 8) | /* sp422 mode*/
(4 << 4) | /* horz scaler bank length*/
(0 << 2) | /* phase0 always en*/
(0 << 1) | /* nearest_en*/
(hsc_en << 0)); /* hsc_en*/
}
/*
* 0x37b0 ~ 0x37b5
*/
void dim_dump_hdownscler_reg(unsigned int base_addr)
{
unsigned int i = 0x374e;
pr_info("-----dump hdownscler start-----\n");
for (i = 0x37b0; i < 0x37b5; i++) {
pr_info("[0x%x][0x%x]=0x%x\n",
base_addr + (i << 2),
i, dim_RDMA_RD(i));
}
pr_info("-----dump hdownscler end-----\n");
}
int dim_seq_file_module_para_pps(struct seq_file *seq)
{
seq_puts(seq, "pps---------------\n");
return 0;
}

View File

@@ -0,0 +1,112 @@
/*
* drivers/amlogic/media/di_multi/di_pps.h
*
* 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.
*
*/
#ifndef DI_PPS_H
#define DI_PPS_H
#include <linux/amlogic/media/video_sink/video.h>
#include <linux/amlogic/media/video_sink/vpp.h>
#if 0
#define VPP_FLAG_WIDEMODE_MASK 0x0000000F
#define VPP_FLAG_INTERLACE_OUT 0x00000010
#define VPP_FLAG_INTERLACE_IN 0x00000020
#define VPP_FLAG_CBCR_SEPARATE 0x00000040
#define VPP_FLAG_ZOOM_SHORTSIDE 0x00000080
#define VPP_FLAG_AR_MASK 0x0003ff00
#define VPP_FLAG_AR_BITS 8
#define VPP_FLAG_PORTRAIT_MODE 0x00040000
#define VPP_FLAG_VSCALE_DISABLE 0x00080000
#define IDX_H (2 << 8)
#define IDX_V_Y (1 << 13)
#define IDX_V_CBCR ((1 << 13) | (1 << 8))
#define ASPECT_4_3 ((3 << 8) / 4)
#define ASPECT_16_9 ((9 << 8) / 16)
#define SPEED_CHECK_DONE 0
#define SPEED_CHECK_HSKIP 1
#define SPEED_CHECK_VSKIP 2
enum f2v_vphase_type_e {
F2V_IT2IT = 0,
F2V_IB2IB,
F2V_IT2IB,
F2V_IB2IT,
F2V_P2IT,
F2V_P2IB,
F2V_IT2P,
F2V_IB2P,
F2V_P2P,
F2V_TYPE_MAX
}; /* frame to video conversion type */
#endif
enum hdr2_scaler_e {
hdr2_scaler_postdi = 0,
hdr2_scaler_predi = 1,
};
struct pps_f2v_vphase_s {
unsigned char rcv_num;
unsigned char rpt_num;
unsigned short phase;
};
struct ppsfilter_mode_s {
u32 pps_hf_start_phase_step;
u32 pps_hf_start_phase_slope;
u32 pps_hf_end_phase_slope;
const u32 *pps_vert_coeff;
const u32 *pps_horz_coeff;
u32 pps_sc_misc_;
u32 pps_vsc_start_phase_step;
u32 pps_hsc_start_phase_step;
bool pps_pre_vsc_en;
bool pps_pre_hsc_en;
u32 pps_vert_filter;
u32 pps_horz_filter;
const u32 *pps_chroma_coeff;
u32 pps_chroma_filter_en;
};
struct pps_frame_par_s {
u32 pps_vsc_startp;
u32 pps_vsc_endp;
u32 pps_hsc_startp;
u32 pps_hsc_linear_startp;
u32 pps_hsc_linear_endp;
u32 pps_hsc_endp;
u32 VPP_hf_ini_phase_;
struct f2v_vphase_s VPP_vf_ini_phase_[9];
u32 pps_pic_in_height_;
u32 pps_line_in_length_;
struct ppsfilter_mode_s pps_filter;
u32 pps_3d_mode;
u32 trans_fmt;
/* bit[1:0] 0: 1 pic,1:two pic one buf,2:tow pic two buf */
/* bit[2]0:select pic0,1:select pic1 */
/* bit[3]0:pic0 first,1:pic1 first */
bool pps_3d_scale;
};
void dim_pps_config(unsigned char path, int src_w, int src_h,
int dst_w, int dst_h);
void dim_dump_pps_reg(unsigned int base_addr);
void dim_inp_hsc_setting(u32 src_w, u32 dst_w);
void dim_dump_hdownscler_reg(unsigned int base_addr);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,131 @@
/*
* drivers/amlogic/media/di_multi/di_prc.h
*
* 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.
*
*/
#ifndef __DI_PRC_H__
#define __DI_PRC_H__
bool dip_prob(void);
void dip_exit(void);
void dip_even_reg_init_val(unsigned int ch);
void dip_even_unreg_val(unsigned int ch);
/************************/
/* CMA */
/************************/
void dip_wq_cma_run(unsigned char ch, bool reg_cmd);
bool dip_cma_st_is_ready(unsigned int ch);
bool dip_cma_st_is_idle(unsigned int ch);
bool dip_cma_st_is_idl_all(void);
enum eDI_CMA_ST dip_cma_get_st(unsigned int ch);
void dip_cma_st_set_ready_all(void);
void dip_cma_close(void);
const char *di_cma_dbg_get_st_name(unsigned int ch);
/*************************/
/* STATE*/
/*************************/
bool dip_event_reg_chst(unsigned int ch);
bool dip_event_unreg_chst(unsigned int ch);
void dip_chst_process_reg(unsigned int ch);
void dip_hw_process(void);
void dip_chst_process_ch(void);
bool dip_chst_change_2unreg(void);
enum eDI_TOP_STATE dip_chst_get(unsigned int ch);
const char *dip_chst_get_name_curr(unsigned int ch);
const char *dip_chst_get_name(enum eDI_TOP_STATE chst);
/**************************************
*
* summmary variable
*
**************************************/
void di_sum_reg_init(unsigned int ch);
void di_sum_set(unsigned int ch, enum eDI_SUM id, unsigned int val);
unsigned int di_sum_inc(unsigned int ch, enum eDI_SUM id);
unsigned int di_sum_get(unsigned int ch, enum eDI_SUM id);
void di_sum_get_info(unsigned int ch, enum eDI_SUM id, char **name,
unsigned int *pval);
unsigned int di_sum_get_tab_size(void);
bool di_sum_check(unsigned int ch, enum eDI_SUM id);
/**************************************
*
* cfg ctr top
* bool
**************************************/
char *di_cfg_top_get_name(enum eDI_CFG_TOP_IDX idx);
void di_cfg_top_get_info(unsigned int idx, char **name);
void di_cfg_top_init_val(void);
bool di_cfg_top_get(enum eDI_CFG_TOP_IDX id);
void di_cfg_top_set(enum eDI_CFG_TOP_IDX id, bool en);
/**************************************
*
* cfg ctr x
* bool
**************************************/
char *di_cfgx_get_name(enum eDI_CFGX_IDX idx);
void di_cfgx_get_info(enum eDI_CFGX_IDX idx, char **name);
void di_cfgx_init_val(void);
bool di_cfgx_get(unsigned int ch, enum eDI_CFGX_IDX idx);
void di_cfgx_set(unsigned int ch, enum eDI_CFGX_IDX idx, bool en);
/**************************************
*
* module para top
* int
**************************************/
char *di_mp_uit_get_name(enum eDI_MP_UI_T idx);
void di_mp_uit_init_val(void);
int di_mp_uit_get(enum eDI_MP_UI_T idx);
void di_mp_uit_set(enum eDI_MP_UI_T idx, int val);
/**************************************
*
* module para x
* unsigned int
**************************************/
char *di_mp_uix_get_name(enum eDI_MP_UIX_T idx);
void di_mp_uix_init_val(void);
unsigned int di_mp_uix_get(unsigned int ch, enum eDI_MP_UIX_T idx);
void di_mp_uix_set(unsigned int ch, enum eDI_MP_UIX_T idx,
unsigned int val);
/****************************************/
/* do_table */
/****************************************/
void do_table_init(struct do_table_s *pdo,
const struct do_table_ops_s *ptable,
unsigned int size_tab);
/* now only call in same thread */
void do_talbe_cmd(struct do_table_s *pdo, enum eDO_TABLE_CMD cmd);
void do_table_working(struct do_table_s *pdo);
bool do_table_is_crr(struct do_table_s *pdo, unsigned int state);
enum eDI_SUB_ID pw_ch_next_count(enum eDI_SUB_ID channel);
void dip_init_value_reg(unsigned int ch);
bool di_is_pause(unsigned int ch);
void di_pause_step_done(unsigned int ch);
void di_pause(unsigned int ch, bool on);
#endif /*__DI_PRC_H__*/

View File

@@ -0,0 +1,985 @@
/*
* drivers/amlogic/media/di_multi/di_pre.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/kernel.h>
#include <linux/err.h>
#include <linux/seq_file.h>
#include <linux/amlogic/media/vfm/vframe.h>
#include "deinterlace.h"
#include "deinterlace_dbg.h"
#include "di_data_l.h"
#include "di_data.h"
#include "di_dbg.h"
#include "di_vframe.h"
#include "di_que.h"
#include "di_task.h"
#include "di_prc.h"
#include "di_pre.h"
#include "nr_downscale.h"
#include "register.h"
/****************************************
* 1. copy curr to last
* 2. set curr
****************************************/
void pre_vinfo_set(unsigned int ch,
struct vframe_s *ori_vframe)
{
struct di_hpre_s *pre = get_hw_pre();
struct di_vinfo_s *vc = &pre->vinf_curr;
struct di_vinfo_s *vl = &pre->vinf_lst;
memcpy(vl, vc, sizeof(struct di_vinfo_s));
vc->ch = ch;
vc->vtype = ori_vframe->type;
vc->src_type = ori_vframe->source_type;
vc->trans_fmt = ori_vframe->trans_fmt;
if (COM_ME(ori_vframe->type, VIDTYPE_COMPRESS)) {
vc->h = ori_vframe->compWidth;
vc->v = ori_vframe->compHeight;
} else {
vc->h = ori_vframe->width;
vc->v = ori_vframe->height;
}
}
/****************************************
* compare current vframe info with last
* return
* 0. no change
* 1. video format channge
* 2. scan mode channge?
****************************************/
unsigned int is_vinfo_change(unsigned int ch)
{
struct di_hpre_s *pre = get_hw_pre();
struct di_vinfo_s *vc = &pre->vinf_curr;
struct di_vinfo_s *vl = &pre->vinf_lst;
struct di_pre_stru_s *ppre = get_pre_stru(ch);
unsigned int ret = 0;
if (vc->src_type != vl->src_type ||
!COM_M(DI_VFM_T_MASK_CHANGE, vc->vtype, vl->vtype) ||
vc->v != vl->v ||
vc->h != vl->h ||
vc->trans_fmt != vl->trans_fmt) {
/* video format changed */
ret = 1;
} else if (!COM_M(VIDTYPE_VIU_FIELD, vc->vtype, vl->vtype))
/* just scan mode changed */
ret = 2;
if (ret) {
dim_print(
"%s:ch[%d]: %dth source change 2: 0x%x/%d/%d/%d=>0x%x/%d/%d/%d\n",
__func__,
ch,
/*jiffies_to_msecs(jiffies_64),*/
ppre->in_seq,
vl->vtype,
vl->h,
vl->v,
vl->src_type,
vc->vtype,
vc->h,
vc->v,
vc->src_type);
}
return ret;
}
bool dim_bypass_detect(unsigned int ch, struct vframe_s *vfm)
{
bool ret = false;
if (!vfm)
return ret;
pre_vinfo_set(ch, vfm);
if (is_vinfo_change(ch)) {
if (!is_bypass2(vfm, ch)) {
set_bypass2_complete(ch, false);
PR_INF("%s:\n", __func__);
/*task_send_ready();*/
task_send_cmd(LCMD1(eCMD_CHG, ch));
ret = true;
}
}
return ret;
}
unsigned int di_get_other_ch(unsigned int curr)
{
return curr ? 0 : 1;
}
bool is_bypass_i_p(void)
{
bool ret = false;
struct di_hpre_s *pre = get_hw_pre();
struct di_vinfo_s *vc = &pre->vinf_curr;
#if 0
struct di_vinfo_s *vl = &pre->vinf_lst;
if (vl->ch != vc->ch &&
vf_type_is_interlace(vl->vtype) &&
vf_type_is_prog(vc->vtype)) {
ret = true;
}
#else
unsigned int ch_c, ch_l;
struct di_pre_stru_s *ppre_c, *ppre_l;
if (!get_reg_flag(0) ||
!get_reg_flag(1))
return ret;
ch_c = vc->ch;
ch_l = (ch_c ? 0 : 1);
ppre_c = get_pre_stru(ch_c);
ppre_l = get_pre_stru(ch_l);
if (vf_type_is_interlace(ppre_l->cur_inp_type) &&
vf_type_is_prog(ppre_c->cur_inp_type)) {
ret = true;
dim_print("ch[%d]:bypass p\n", ch_c);
}
#endif
return ret;
}
void dpre_clear(void)
{
struct di_hpre_s *pre = get_hw_pre();
memset(pre, 0, sizeof(struct di_hpre_s));
}
void dpre_init(void)
{/*reg:*/
struct di_hpre_s *pre = get_hw_pre();
pre->pre_st = eDI_PRE_ST_IDLE;
/*timer out*/
di_tout_int(&pre->tout, 40); /*ms*/
}
void pw_use_hw_pre(enum eDI_SUB_ID channel, bool on)
{
struct di_hpre_s *pre = get_hw_pre();
pre->hw_flg_busy_pre = on;
if (on)
pre->curr_ch = channel;
}
enum eDI_SUB_ID pw_ch_next_count(enum eDI_SUB_ID channel)
{
int i;
unsigned int lch, nch;
nch = channel;
for (i = 0; i < DI_CHANNEL_NUB; i++) {
lch = channel + i + 1;
if (lch >= DI_CHANNEL_NUB)
lch -= DI_CHANNEL_NUB;
#if 0
if (pbm->sub_act_flg[lch]) {
nch = lch;
break;
}
#else
if (get_reg_flag(lch) &&
!get_flag_trig_unreg(lch) &&
!is_bypss2_complete(lch)) {
nch = lch;
break;
}
#endif
}
return nch;
}
/****************************************/
static bool pw_try_sw_ch_next_pre(enum eDI_SUB_ID channel)
{
bool ret = false;
struct di_hpre_s *pre = get_hw_pre();
enum eDI_SUB_ID lst_ch, nch;
lst_ch = channel;
nch = pw_ch_next_count(lst_ch);
if (!get_reg_flag(nch) ||
get_flag_trig_unreg(nch) ||
is_bypss2_complete(nch))
return false;
pre->curr_ch = nch;
pre->hw_flg_busy_pre = true;
ret = true;
/*dim_print("%s:%d->%d:%d\n", __func__, lst_ch, nch, ret);*/
return ret;
}
/*****************************/
/* debug */
/*****************************/
unsigned int di_dbg_pre_cnt;
void dbg_cnt_begin(void)
{
di_dbg_pre_cnt = 0x10;
}
void dbg_cnt_print(void)
{
if (di_dbg_pre_cnt < 0xf)
return;
if (di_dbg_pre_cnt > 0x10) {
di_dbg_pre_cnt++;
pr_info("di:[%d]\n", di_dbg_pre_cnt);
}
if (di_dbg_pre_cnt > 0x15)
di_dbg_pre_cnt = 0;
}
/*****************************/
/* STEP */
/*****************************/
void dpre_recyc(unsigned int ch)
{
struct di_hpre_s *pre = get_hw_pre();
pre->check_recycle_buf_cnt = 0;
while (dim_check_recycle_buf(ch) & 1) {
if (pre->check_recycle_buf_cnt++ > MAX_IN_BUF_NUM) {
di_pr_info("%s: dim_check_recycle_buf time out!!\n",
__func__);
break;
}
}
}
void dpre_vdoing(unsigned int ch)
{
struct di_post_stru_s *ppost = get_post_stru(ch);
ppost->di_post_process_cnt = 0;
while (dim_process_post_vframe(ch)) {
if (ppost->di_post_process_cnt++ >
MAX_POST_BUF_NUM) {
di_pr_info("%s: dim_process_post_vframe time out!!\n",
__func__);
break;
}
}
}
bool dpre_can_exit(unsigned int ch)
{
struct di_hpre_s *pre = get_hw_pre();
bool ret = false;
if (ch != pre->curr_ch) {
ret = true;
} else {
if (pre->pre_st <= eDI_PRE_ST4_IDLE)
ret = true;
}
pr_info("%s:ch[%d]:curr[%d]:stat[%s] ret[%d]\n",
__func__,
ch, pre->curr_ch,
dpre_state4_name_get(pre->pre_st),
ret);
return ret;
}
void dpre_dbg_f_trig(unsigned int cmd)
{
struct di_task *tsk = get_task();
struct di_hpre_s *pre = get_hw_pre();
if (down_interruptible(&tsk->sem)) {
PR_ERR("%s:can't get sem\n", __func__);
return;
}
/*set on/off and trig*/
if (cmd & 0x10) {
pre->dbg_f_en = 1;
pre->dbg_f_cnt = cmd & 0xf;
pre->dbg_f_lstate = pre->pre_st;
} else {
pre->dbg_f_en = 0;
}
up(&tsk->sem);
}
void dpre_process(void)
{
bool reflesh;
struct di_hpre_s *pre = get_hw_pre();
if (pre->dbg_f_en) {
if (pre->dbg_f_cnt) {
dpre_process_step4();
pre->dbg_f_cnt--;
}
if (pre->dbg_f_lstate != pre->pre_st) {
pr_info("ch[%d]:state:%s->%s\n",
pre->curr_ch,
dpre_state4_name_get(pre->dbg_f_lstate),
dpre_state4_name_get(pre->pre_st));
pre->dbg_f_lstate = pre->pre_st;
}
return;
}
reflesh = true;
while (reflesh) {
reflesh = dpre_process_step4();
#if 0 /*debug only*/
dbg_tsk("ch[%d]:st[%s]r[%d]\n", pre->curr_ch,
dpre_state4_name_get(pre->pre_st), reflesh);
#endif
}
}
enum eDI_PRE_MT {
eDI_PRE_MT_CHECK = K_DO_TABLE_ID_START,
eDI_PRE_MT_SET,
eDI_PRE_MT_WAIT_INT,
eDI_PRE_MT_TIME_OUT,
};
/*use do_table:*/
unsigned int dpre_mtotal_check(void *data)
{
struct di_hpre_s *pre = get_hw_pre();
unsigned int ret = K_DO_R_NOT_FINISH;
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;
/*dim_print("%s:\n", __func__);*/
if (dim_pre_de_buf_config(pre->curr_ch))
ret = K_DO_R_FINISH;
else
ret = K_DO_R_JUMP(K_DO_TABLE_ID_STOP);
dim_dbg_pre_cnt(pre->curr_ch, "x");
}
return ret;
}
unsigned int dpre_mtotal_set(void *data)
{
struct di_hpre_s *pre = get_hw_pre();
ulong flags = 0;
/*dim_print("%s:\n", __func__);*/
spin_lock_irqsave(&plist_lock, flags);
dim_pre_de_process(pre->curr_ch);
spin_unlock_irqrestore(&plist_lock, flags);
/*begin to count timer*/
di_tout_contr(eDI_TOUT_CONTR_EN, &pre->tout);
return K_DO_R_FINISH;
}
enum eDI_WAIT_INT {
eDI_WAIT_INT_NEED_WAIT,
eDI_WAIT_INT_HAVE_INT,
eDI_WAIT_INT_TIME_OUT,
};
/*
*return: enum eDI_WAIT_INT
*
*/
enum eDI_WAIT_INT di_pre_wait_int(void *data)
{
struct di_hpre_s *pre = get_hw_pre();
ulong flags = 0;
struct di_pre_stru_s *ppre;
enum eDI_WAIT_INT ret = eDI_WAIT_INT_NEED_WAIT;
if (pre->flg_int_done) {
/*have INT done flg*/
/*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 0
data32 = Rd(DI_INTR_CTRL);
if (((data32 & 0x1) &&
((ppre->enable_mtnwr == 0) || (data32 & 0x2))) ||
(ppre->pre_de_clear_flag == 2)) {
dim_RDMA_WR(DI_INTR_CTRL, data32);
}
#endif
di_pre_wait_irq_set(false);
/*finish to count timer*/
di_tout_contr(eDI_TOUT_CONTR_FINISH, &pre->tout);
spin_lock_irqsave(&plist_lock, flags);
dim_pre_de_done_buf_config(pre->curr_ch, false);
pre->flg_int_done = 0;
dpre_recyc(pre->curr_ch);
dpre_vdoing(pre->curr_ch);
spin_unlock_irqrestore(&plist_lock, flags);
ppre = get_pre_stru(pre->curr_ch);
#if 0
if (ppre->field_count_for_cont == 1) {
usleep_range(2000, 2001);
pr_info("delay 1ms\n");
}
#endif
ret = eDI_WAIT_INT_HAVE_INT;
} else {
/*check if timeout:*/
if (di_tout_contr(eDI_TOUT_CONTR_CHECK, &pre->tout)) {
di_pre_wait_irq_set(false);
/*return K_DO_R_FINISH;*/
ret = eDI_WAIT_INT_TIME_OUT;
}
}
/*debug:*/
if (dbg_first_cnt_pre)
dbg_first_frame("ch[%d],w_int[%d]\n", pre->curr_ch, ret);
return ret;
}
unsigned int dpre_mtotal_wait_int(void *data)
{
enum eDI_WAIT_INT wret;
unsigned int ret = K_DO_R_NOT_FINISH;
wret = di_pre_wait_int(NULL);
switch (wret) {
case eDI_WAIT_INT_NEED_WAIT:
ret = K_DO_R_NOT_FINISH;
break;
case eDI_WAIT_INT_HAVE_INT:
ret = K_DO_R_JUMP(K_DO_TABLE_ID_STOP);
break;
case eDI_WAIT_INT_TIME_OUT:
ret = K_DO_R_FINISH;
break;
}
return ret;
}
void dpre_mtotal_timeout_contr(void)
{
struct di_hpre_s *pre = get_hw_pre();
/*move from di_pre_trigger_work*/
if (dimp_get(eDI_MP_di_dbg_mask) & 4)
dim_dump_mif_size_state(pre->pres, pre->psts);
dimh_enable_di_pre_mif(false, dimp_get(eDI_MP_mcpre_en));
if (di_get_dts_nrds_en())
dim_nr_ds_hw_ctrl(false);
pre->pres->pre_de_irq_timeout_count++;
pre->pres->pre_de_busy = 0;
pre->pres->pre_de_clear_flag = 2;
if ((dimp_get(eDI_MP_di_dbg_mask) & 0x2)) {
pr_info("DI:ch[%d]*****wait %d timeout 0x%x(%d ms)*****\n",
pre->curr_ch,
pre->pres->field_count_for_cont,
Rd(DI_INTR_CTRL),
(unsigned int)(cur_to_msecs() -
pre->pres->irq_time[1]));
}
/*******************************/
dim_pre_de_done_buf_config(pre->curr_ch, true);
dpre_recyc(pre->curr_ch);
dpre_vdoing(pre->curr_ch);
/*******************************/
/*dpre_recyc(pre->curr_ch);*/
}
unsigned int dpre_mtotal_timeout(void *data)
{
ulong flags = 0;
spin_lock_irqsave(&plist_lock, flags);
dpre_mtotal_timeout_contr();
spin_unlock_irqrestore(&plist_lock, flags);
return K_DO_R_JUMP(K_DO_TABLE_ID_STOP);
}
const struct do_table_ops_s pr_mode_total[] = {
/*fix*/
[K_DO_TABLE_ID_PAUSE] = {
.id = K_DO_TABLE_ID_PAUSE,
.mark = 0,
.con = NULL,
.do_op = NULL,
.do_stop_op = NULL,
.name = "pause",
},
[K_DO_TABLE_ID_STOP] = {
.id = K_DO_TABLE_ID_STOP,
.mark = 0,
.con = NULL,
.do_op = NULL,
.do_stop_op = NULL,
.name = "stop",
},
/******************/
[K_DO_TABLE_ID_START] = { /*eDI_PRE_MT_CHECK*/
.id = K_DO_TABLE_ID_START,
.mark = 0,
.con = NULL,
.do_op = dpre_mtotal_check,
.do_stop_op = NULL,
.name = "start-check",
},
[eDI_PRE_MT_SET] = {
.id = eDI_PRE_MT_SET,
.mark = 0,
.con = NULL,
.do_op = dpre_mtotal_set,
.do_stop_op = NULL,
.name = "set",
},
[eDI_PRE_MT_WAIT_INT] = {
.id = eDI_PRE_MT_WAIT_INT,
.mark = 0,
.con = NULL,
.do_op = dpre_mtotal_wait_int,
.do_stop_op = NULL,
.name = "wait_int",
},
[eDI_PRE_MT_TIME_OUT] = {
.id = eDI_PRE_MT_TIME_OUT,
.mark = 0,
.con = NULL,
.do_op = dpre_mtotal_timeout,
.do_stop_op = NULL,
.name = "timeout",
},
};
/****************************
*
* mode for p
*
****************************/
enum eDI_PRE_MP {
eDI_PRE_MP_CHECK = K_DO_TABLE_ID_START,
eDI_PRE_MP_SET,
eDI_PRE_MP_WAIT_INT,
eDI_PRE_MP_TIME_OUT,
eDI_PRE_MP_CHECK2,
eDI_PRE_MP_SET2,
eDI_PRE_MP_WAIT_INT2,
eDI_PRE_MP_TIME_OUT2,
};
unsigned int dpre_mp_check(void *data)
{
struct di_hpre_s *pre = get_hw_pre();
unsigned int ret = K_DO_R_NOT_FINISH;
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;
/*dim_print("%s:\n", __func__);*/
if (dim_pre_de_buf_config(pre->curr_ch)) {
/*pre->flg_wait_int = false;*/
/*pre_p_asi_set_next(pre->curr_ch);*/
ret = K_DO_R_FINISH;
} else {
/*pre->flg_wait_int = false;*/
ret = K_DO_R_JUMP(K_DO_TABLE_ID_STOP);
}
dim_dbg_pre_cnt(pre->curr_ch, "x");
}
return ret;
}
unsigned int dpre_mp_check2(void *data)
{
struct di_hpre_s *pre = get_hw_pre();
unsigned int ret = K_DO_R_NOT_FINISH;
if (dim_pre_de_buf_config(pre->curr_ch)) {
/*pre->flg_wait_int = false;*/
ret = K_DO_R_FINISH;
}
#if 0
else {
PR_ERR("%s:not second?ch[%d]\n", __func__, pre->curr_ch);
ret = K_DO_R_JUMP(K_DO_TABLE_ID_STOP);
}
#endif
return ret;
}
unsigned int dpre_mp_wait_int(void *data)
{
enum eDI_WAIT_INT wret;
unsigned int ret = K_DO_R_NOT_FINISH;
wret = di_pre_wait_int(NULL);
switch (wret) {
case eDI_WAIT_INT_NEED_WAIT:
ret = K_DO_R_NOT_FINISH;
break;
case eDI_WAIT_INT_HAVE_INT:
ret = K_DO_R_JUMP(eDI_PRE_MP_CHECK2);
break;
case eDI_WAIT_INT_TIME_OUT:
ret = K_DO_R_FINISH;
break;
}
return ret;
}
unsigned int dpre_mp_wait_int2(void *data)
{
enum eDI_WAIT_INT wret;
unsigned int ret = K_DO_R_NOT_FINISH;
wret = di_pre_wait_int(NULL);
switch (wret) {
case eDI_WAIT_INT_NEED_WAIT:
ret = K_DO_R_NOT_FINISH;
break;
case eDI_WAIT_INT_HAVE_INT:
ret = K_DO_R_JUMP(K_DO_TABLE_ID_STOP);
break;
case eDI_WAIT_INT_TIME_OUT:
ret = K_DO_R_FINISH;
break;
}
return ret;
}
unsigned int dpre_mp_timeout(void *data)
{
dpre_mtotal_timeout_contr();
return K_DO_R_FINISH;
}
unsigned int dpre_mp_timeout2(void *data)
{
dpre_mtotal_timeout_contr();
return K_DO_R_JUMP(K_DO_TABLE_ID_STOP);
}
const struct do_table_ops_s pre_mode_proc[] = {
/*fix*/
[K_DO_TABLE_ID_PAUSE] = {
.id = K_DO_TABLE_ID_PAUSE,
.mark = 0,
.con = NULL,
.do_op = NULL,
.do_stop_op = NULL,
.name = "pause",
},
[K_DO_TABLE_ID_STOP] = {
.id = K_DO_TABLE_ID_STOP,
.mark = 0, /*stop / pause*/
.con = NULL,
.do_op = NULL,
.do_stop_op = NULL,
.name = "stop",
},
/******************/
[K_DO_TABLE_ID_START] = { /*eDI_PRE_MP_CHECK*/
.id = K_DO_TABLE_ID_START,
.mark = 0, /*stop / pause*/
.con = NULL,
.do_op = dpre_mp_check,
.do_stop_op = NULL,
.name = "start-check",
},
[eDI_PRE_MP_SET] = {
.id = eDI_PRE_MP_SET,
.mark = 0, /*stop / pause*/
.con = NULL, /*condition*/
.do_op = dpre_mtotal_set,
.do_stop_op = NULL,
.name = "pset",
},
[eDI_PRE_MP_WAIT_INT] = {
.id = eDI_PRE_MP_WAIT_INT,
.mark = 0, /*stop / pause*/
.con = NULL, /*condition*/
.do_op = dpre_mp_wait_int,
.do_stop_op = NULL,
.name = "pwait_int",
},
[eDI_PRE_MP_TIME_OUT] = {
.id = eDI_PRE_MP_TIME_OUT,
.mark = 0, /*stop / pause*/
.con = NULL, /*condition*/
.do_op = dpre_mp_timeout,
.do_stop_op = NULL,
.name = "ptimeout",
},
/******/
[eDI_PRE_MP_CHECK2] = { /*eDI_PRE_MP_CHECK2*/
.id = eDI_PRE_MP_CHECK2,
.mark = 0, /*stop / pause*/
.con = NULL, /*condition*/
.do_op = dpre_mp_check2,
.do_stop_op = NULL,
.name = "start-check",
},
[eDI_PRE_MP_SET2] = {
.id = eDI_PRE_MP_SET2,
.mark = 0, /*stop / pause*/
.con = NULL, /*condition*/
.do_op = dpre_mtotal_set,
.do_stop_op = NULL,
.name = "psetp2",
},
[eDI_PRE_MP_WAIT_INT2] = {
.id = eDI_PRE_MP_WAIT_INT2,
.mark = 0, /*stop / pause*/
.con = NULL, /*condition*/
.do_op = dpre_mp_wait_int2,
.do_stop_op = NULL,
.name = "pwait_int2",
},
[eDI_PRE_MP_TIME_OUT2] = {
.id = eDI_PRE_MP_TIME_OUT2,
.mark = 0, /*stop / pause*/
.con = NULL, /*condition*/
.do_op = dpre_mp_timeout2,
.do_stop_op = NULL,
.name = "ptimeout2",
},
};
void pre_mode_setting(void)
{
struct di_hpre_s *pre = get_hw_pre();
if (pre->pre_st != eDI_PRE_ST4_DO_TABLE)
return;
do_table_working(&pre->sdt_mode);
}
/*--------------------------*/
enum eDI_WORK_MODE pre_cfg_count_mode(unsigned int ch, struct vframe_s *vframe)
{
enum eDI_WORK_MODE pmode;
if (is_bypass2(vframe, ch)) {
pmode = eDI_WORK_MODE_bypass_all;
return pmode;
}
if (COM_ME(vframe->type, VIDTYPE_INTERLACE)) {
/*interlace:*/
pmode = eDI_WORK_MODE_i;
return pmode;
}
if (dimp_get(eDI_MP_prog_proc_config) & 0x10)
pmode = eDI_WORK_MODE_p_as_p;
else if (is_from_vdin(vframe))
pmode = eDI_WORK_MODE_p_use_ibuf;
else
pmode = eDI_WORK_MODE_p_as_i;
return pmode;
}
unsigned int dpre_check_mode(unsigned int ch)
{
struct vframe_s *vframe;
unsigned int mode;
vframe = pw_vf_peek(ch);
if (!vframe)
return eDI_WORK_MODE_NONE;
mode = pre_cfg_count_mode(ch, vframe);/*eDI_WORK_MODE_all;*/
return mode;
}
/*--------------------------*/
bool dpre_step4_idle(void)
{
struct di_hpre_s *pre = get_hw_pre();
bool reflesh = false;
unsigned int ch;
ch = pre->curr_ch;
if (!pw_try_sw_ch_next_pre(ch))
return false;
if (pre->idle_cnt >= DI_CHANNEL_NUB) {
pre->idle_cnt = 0;
return false;
}
pre->pres = get_pre_stru(pre->curr_ch);
pre->psts = get_post_stru(pre->curr_ch);
/*state*/
pre->pre_st++;/*tmp*/
reflesh = true;
return reflesh;
}
bool dpre_step4_check(void)
{
struct di_hpre_s *pre = get_hw_pre();
bool reflesh = false;
unsigned int mode;
/*get vframe and select mode
* now: fix use total table
*/
mode = dpre_check_mode(pre->curr_ch);
if (mode == eDI_WORK_MODE_NONE) {
pre->pre_st--;
pre->idle_cnt++;
return true;
}
pre->idle_cnt = 0;
if (mode == eDI_WORK_MODE_p_as_i) {
do_table_init(&pre->sdt_mode,
&pre_mode_proc[0],
ARRAY_SIZE(pre_mode_proc));
} else {
do_table_init(&pre->sdt_mode,
&pr_mode_total[0],
ARRAY_SIZE(pr_mode_total));
}
do_talbe_cmd(&pre->sdt_mode, eDO_TABLE_CMD_START);
/*state*/
pre->pre_st++;
reflesh = true;
return reflesh;
}
bool dpre_step4_do_table(void)
{
struct di_hpre_s *pre = get_hw_pre();
bool reflesh = false;
if (do_table_is_crr(&pre->sdt_mode, K_DO_TABLE_ID_STOP)) {
pre->pre_st = eDI_PRE_ST4_IDLE;
reflesh = true;
}
return reflesh;
}
const struct di_func_tab_s di_pre_func_tab4[] = {
{eDI_PRE_ST4_EXIT, NULL},
{eDI_PRE_ST4_IDLE, dpre_step4_idle},
{eDI_PRE_ST4_CHECK, dpre_step4_check},
{eDI_PRE_ST4_DO_TABLE, dpre_step4_do_table},
};
const char * const dpre_state_name4[] = {
"EXIT",
"IDLE", /*swith to next channel?*/
"CHECK",
"DO_TABLE",
};
const char *dpre_state4_name_get(enum eDI_PRE_ST4 state)
{
if (state > eDI_PRE_ST4_DO_TABLE)
return "nothing";
return dpre_state_name4[state];
}
bool dpre_process_step4(void)
{
struct di_hpre_s *pre = get_hw_pre();
enum eDI_PRE_ST4 pre_st = pre->pre_st;
ulong flags = 0;
if (pre_st > eDI_PRE_ST4_EXIT) {
spin_lock_irqsave(&plist_lock, flags);
dim_recycle_post_back(pre->curr_ch);
dpre_recyc(pre->curr_ch);
dpre_vdoing(pre->curr_ch);
spin_unlock_irqrestore(&plist_lock, flags);
}
if ((pre_st <= eDI_PRE_ST4_DO_TABLE) &&
di_pre_func_tab4[pre_st].func) {
return di_pre_func_tab4[pre_st].func();
}
return false;
}

View File

@@ -0,0 +1,38 @@
/*
* drivers/amlogic/media/di_multi/di_pre.h
*
* 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.
*
*/
#ifndef __DI_PRE_H__
#define __DI_PRE_H__
void dpre_process(void);
void dpre_init(void);
const char *dpre_state_name_get(enum eDI_PRE_ST state);
void dpre_dbg_f_trig(unsigned int cmd);
void pre_vinfo_set(unsigned int ch,
struct vframe_s *ori_vframe);
unsigned int is_vinfo_change(unsigned int ch);
bool dpre_can_exit(unsigned int ch);
bool is_bypass_i_p(void);
bool dim_bypass_detect(unsigned int ch, struct vframe_s *vfm);
void pre_mode_setting(void);
bool dpre_process_step4(void);
const char *dpre_state4_name_get(enum eDI_PRE_ST4 state);
#endif /*__DI_PRE_H__*/

View File

@@ -0,0 +1,995 @@
/*
* drivers/amlogic/media/di_multi/di_que.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/kernel.h>
#include <linux/err.h>
#include <linux/seq_file.h>
#include <linux/kfifo.h>
#include <linux/amlogic/media/vfm/vframe.h>
#include "deinterlace.h"
#include "di_data_l.h"
#include "di_que.h"
#include "di_vframe.h"
#include "di_prc.h"
const char * const di_name_new_que[QUE_NUB] = {
"QUE_IN_FREE", /*0*/
"QUE_PRE_READY", /*1*/
"QUE_POST_FREE", /*2*/
"QUE_POST_READY", /*3*/
"QUE_POST_BACK", /*4*/
"QUE_DBG",
/* "QUE_NUB",*/
};
#define que_dbg dim_print
static void pw_queue_clear(unsigned int ch, enum QUE_TYPE qtype)
{
struct di_ch_s *pch = get_chdata(ch);
#if 0
if (qtype >= QUE_NUB)
return;
#endif
kfifo_reset(&pch->fifo[qtype]);
}
bool pw_queue_in(unsigned int ch, enum QUE_TYPE qtype, unsigned int buf_index)
{
struct di_ch_s *pch = get_chdata(ch);
#if 0
if (qtype >= QUE_NUB)
return false;
#endif
if (kfifo_in(&pch->fifo[qtype], &buf_index, sizeof(unsigned int))
!= sizeof(unsigned int))
return false;
#if 0
/*below for debug: save in que*/
if (qtype <= QUE_POST_RECYC) {
if (buf_index >= MAX_POST_BUF_NUM) {
pr_err("%s:err:overflow?[%d]\n", __func__, buf_index);
} else {
ppw = &pch->lpost_buf[buf_index];
ppw->in_qtype = qtype;
}
}
#endif
return true;
}
bool pw_queue_out(unsigned int ch, enum QUE_TYPE qtype,
unsigned int *buf_index)
{
struct di_ch_s *pch = get_chdata(ch);
unsigned int index;
#if 0
if (qtype >= QUE_NUB)
return false;
#endif
if (kfifo_out(&pch->fifo[qtype], &index, sizeof(unsigned int))
!= sizeof(unsigned int))
return false;
*buf_index = index;
return true;
}
static bool pw_queue_peek(unsigned int ch, enum QUE_TYPE qtype,
unsigned int *buf_index)
{
struct di_ch_s *pch = get_chdata(ch);
unsigned int index;
#if 0
if (qtype >= QUE_NUB)
return false;
#endif
if (kfifo_out_peek(&pch->fifo[qtype], &index, sizeof(unsigned int))
!= sizeof(unsigned int))
return false;
*buf_index = index;
return true;
}
bool pw_queue_move(unsigned int ch, enum QUE_TYPE qtypef, enum QUE_TYPE qtypet,
unsigned int *oindex)
{
struct di_ch_s *pch = get_chdata(ch);
unsigned int index;
/*struct di_post_buf_s *ppw;*/ /*debug only*/
#if 0
if (qtypef >= QUE_NUB || qtypet >= QUE_NUB)
return false;
#endif
if (kfifo_out(&pch->fifo[qtypef], &index, sizeof(unsigned int))
!= sizeof(unsigned int)) {
PR_ERR("qtypef[%d] is empty\n", qtypef);
return false;
}
if (kfifo_in(&pch->fifo[qtypet], &index, sizeof(unsigned int))
!= sizeof(unsigned int)) {
PR_ERR("qtypet[%d] is full\n", qtypet);
return false;
}
*oindex = index;
#if 0
if (qtypet <= QUE_POST_RECYC) {
/*below for debug: save in que*/
if (index >= MAX_POST_BUF_NUM) {
pr_err("%s:err:overflow?[%d]\n", __func__, index);
} else {
ppw = &pch->lpost_buf[index];
ppw->in_qtype = qtypet;
}
}
#endif
return true;
}
bool pw_queue_empty(unsigned int ch, enum QUE_TYPE qtype)
{
struct di_ch_s *pch = get_chdata(ch);
if (kfifo_is_empty(&pch->fifo[qtype]))
return true;
return false;
}
int di_que_list_count(unsigned int ch, enum QUE_TYPE qtype)
{
struct di_ch_s *pch = get_chdata(ch);
unsigned int length;
#if 0
if (qtype >= QUE_NUB)
return -1;
#endif
length = kfifo_len(&pch->fifo[qtype]);
length = length / sizeof(unsigned int);
return length;
}
/***************************************/
/*outbuf : array size MAX_FIFO_SIZE*/
/***************************************/
bool di_que_list(unsigned int ch, enum QUE_TYPE qtype, unsigned int *outbuf,
unsigned int *rsize)
{
struct di_ch_s *pch = get_chdata(ch);
/* unsigned int tmp[MAX_FIFO_SIZE + 1];*/
int i;
unsigned int index;
bool ret = false;
/*que_dbg("%s:begin\n", __func__);*/
for (i = 0; i < MAX_FIFO_SIZE; i++)
outbuf[i] = 0xff;
if (kfifo_is_empty(&pch->fifo[qtype])) {
que_dbg("\t%d:empty\n", qtype);
*rsize = 0;
return true;
}
ret = true;
memcpy(&pch->fifo[QUE_DBG], &pch->fifo[qtype],
sizeof(pch->fifo[qtype]));
#if 0
if (kfifo_is_empty(&pbm->fifo[QUE_DBG]))
pr_err("%s:err, kfifo can not copy?\n", __func__);
#endif
i = 0;
*rsize = 0;
while (kfifo_out(&pch->fifo[QUE_DBG], &index, sizeof(unsigned int))
== sizeof(unsigned int)) {
outbuf[i] = index;
/*pr_info("%d->%d\n",i,index);*/
i++;
}
*rsize = di_que_list_count(ch, qtype);
#if 0 /*debug only*/
que_dbg("%s: size[%d]\n", di_name_new_que[qtype], *rsize);
for (i = 0; i < *rsize; i++)
que_dbg("%d,", outbuf[i]);
que_dbg("\n");
#endif
/*que_dbg("finish\n");*/
return ret;
}
int di_que_is_empty(unsigned int ch, enum QUE_TYPE qtype)
{
struct di_ch_s *pch = get_chdata(ch);
#if 0
if (qtype >= QUE_NUB)
return -1;
#endif
return kfifo_is_empty(&pch->fifo[qtype]);
}
void di_que_init(unsigned int ch)
{
int i;
for (i = 0; i < QUE_NUB; i++)
pw_queue_clear(ch, i);
}
bool di_que_alloc(unsigned int ch)
{
int i;
int ret;
bool flg_err;
struct di_ch_s *pch = get_chdata(ch);
/*kfifo----------------------------*/
flg_err = 0;
for (i = 0; i < QUE_NUB; i++) {
ret = kfifo_alloc(&pch->fifo[i],
sizeof(unsigned int) * MAX_FIFO_SIZE,
GFP_KERNEL);
if (ret < 0) {
flg_err = 1;
PR_ERR("%s:%d:can't get kfifo\n", __func__, i);
break;
}
pch->flg_fifo[i] = 1;
}
#if 0
/*canvas-----------------------------*/
canvas_alloc();
#endif
/* pdp_clear();*/
if (!flg_err) {
/*pbm->flg_fifo = 1;*/
pr_info("%s:ok\n", __func__);
ret = true;
} else {
di_que_release(ch);
ret = false;
}
return ret;
}
void di_que_release(unsigned int ch)
{
struct di_ch_s *pch = get_chdata(ch);
int i;
/* canvas_release();*/
for (i = 0; i < QUE_NUB; i++) {
if (pch->flg_fifo[i]) {
kfifo_free(&pch->fifo[i]);
pch->flg_fifo[i] = 0;
}
}
pr_info("%s:ok\n", __func__);
}
/********************************************
*get di_buf from index that same in que
* (di_buf->type << 8) | (di_buf->index)
********************************************/
struct di_buf_s *pw_qindex_2_buf(unsigned int ch, unsigned int qindex)
{
union uDI_QBUF_INDEX index;
struct di_buf_s *di_buf;
struct di_buf_pool_s *pbuf_pool = get_buf_pool(ch);
index.d32 = qindex;
di_buf = &pbuf_pool[index.b.type - 1].di_buf_ptr[index.b.index];
return di_buf;
}
/********************************************/
/*get di_buf from index that same in que*/
/*(di_buf->type << 8) | (di_buf->index)*/
/********************************************/
static unsigned int pw_buf_2_qindex(unsigned int ch, struct di_buf_s *pdi_buf)
{
union uDI_QBUF_INDEX index;
index.b.index = pdi_buf->index;
index.b.type = pdi_buf->type;
return index.d32;
}
/*di_buf is out*/
struct di_buf_s *di_que_out_to_di_buf(unsigned int ch, enum QUE_TYPE qtype)
{
unsigned int q_index;
struct di_buf_s *pdi_buf = NULL;
if (!pw_queue_peek(ch, qtype, &q_index))
return pdi_buf;
pdi_buf = pw_qindex_2_buf(ch, q_index);
if (!pdi_buf) {
PR_ERR("di:err:%s:buf is null[%d]\n", __func__, q_index);
return NULL;
}
pw_queue_out(ch, qtype, &q_index);
pdi_buf->queue_index = -1;
return pdi_buf;
}
/*di_buf is input*/
bool di_que_out(unsigned int ch, enum QUE_TYPE qtype, struct di_buf_s *di_buf)
{
unsigned int q_index;
unsigned int q_index2;
if (!pw_queue_peek(ch, qtype, &q_index))
return false;
q_index2 = pw_buf_2_qindex(ch, di_buf);
if (q_index2 != q_index) {
PR_ERR("di:%s:not map[%d,%d]\n", __func__, q_index2, q_index);
return false;
}
pw_queue_out(ch, qtype, &q_index);
di_buf->queue_index = -1;
return true;
}
bool di_que_in(unsigned int ch, enum QUE_TYPE qtype, struct di_buf_s *di_buf)
{
unsigned int q_index;
if (!di_buf) {
PR_ERR("di:%s:err:di_buf is NULL,ch[%d],qtype[%d]\n",
__func__, ch, qtype);
return false;
}
if (di_buf->queue_index != -1) {
PR_ERR("di:%s:buf in some que,ch[%d],qt[%d],qi[%d],bi[%d]\n",
__func__,
ch, qtype, di_buf->queue_index, di_buf->index);
return false;
}
q_index = pw_buf_2_qindex(ch, di_buf);
if (!pw_queue_in(ch, qtype, q_index)) {
PR_ERR("di:%s:err:can't que in,ch[%d],qtype[%d],q_index[%d]\n",
__func__,
ch, qtype, q_index);
return false;
}
di_buf->queue_index = qtype + QUEUE_NUM;
if (qtype == QUE_PRE_READY)
dim_print("di:pre_ready in %d\n", di_buf->index);
return true;
}
bool di_que_is_in_que(unsigned int ch, enum QUE_TYPE qtype,
struct di_buf_s *di_buf)
{
unsigned int q_index;
unsigned int arr[MAX_FIFO_SIZE + 1];
unsigned int asize = 0;
bool ret = false;
unsigned int i;
if (!di_buf)
return false;
q_index = pw_buf_2_qindex(ch, di_buf);
di_que_list(ch, qtype, &arr[0], &asize);
if (asize == 0)
return ret;
for (i = 0; i < asize; i++) {
if (arr[i] == q_index) {
ret = true;
break;
}
}
return ret;
}
/*same as get_di_buf_head*/
struct di_buf_s *di_que_peek(unsigned int ch, enum QUE_TYPE qtype)
{
struct di_buf_s *di_buf = NULL;
unsigned int q_index;
if (!pw_queue_peek(ch, qtype, &q_index))
return di_buf;
di_buf = pw_qindex_2_buf(ch, q_index);
return di_buf;
}
bool di_que_type_2_new(unsigned int q_type, enum QUE_TYPE *nqtype)
{
if (!F_IN(q_type, QUEUE_NEW_THD_MIN, QUEUE_NEW_THD_MAX))
return false;
*nqtype = (enum QUE_TYPE)(q_type - QUEUE_NUM);
return true;
}
/**********************************************************/
/**********************************************************/
/*ary add this function for reg ini value, no need wait peek*/
void queue_init2(unsigned int channel)
{
int i, j;
struct queue_s *pqueue = get_queue(channel);
for (i = 0; i < QUEUE_NUM; i++) {
queue_t *q = &pqueue[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 0
if ((i == QUEUE_LOCAL_FREE) && dim_get_use_2_int_buf())
q->type = 2;
#endif
}
}
void queue_init(unsigned int channel, int local_buffer_num)
{
int i, j;
struct di_buf_s *pbuf_local = get_buf_local(channel);
struct di_buf_s *pbuf_in = get_buf_in(channel);
struct di_buf_s *pbuf_post = get_buf_post(channel);
struct queue_s *pqueue = get_queue(channel);
struct di_buf_pool_s *pbuf_pool = get_buf_pool(channel);
for (i = 0; i < QUEUE_NUM; i++) {
queue_t *q = &pqueue[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) &&
dimp_get(eDI_MP_use_2_interlace_buff))
q->type = 2;
}
if (local_buffer_num > 0) {
pbuf_pool[VFRAME_TYPE_IN - 1].di_buf_ptr = &pbuf_in[0];
pbuf_pool[VFRAME_TYPE_IN - 1].size = MAX_IN_BUF_NUM;
pbuf_pool[VFRAME_TYPE_LOCAL - 1].di_buf_ptr = &pbuf_local[0];
pbuf_pool[VFRAME_TYPE_LOCAL - 1].size = local_buffer_num;
pbuf_pool[VFRAME_TYPE_POST - 1].di_buf_ptr = &pbuf_post[0];
pbuf_pool[VFRAME_TYPE_POST - 1].size = MAX_POST_BUF_NUM;
}
}
struct di_buf_s *get_di_buf_head(unsigned int channel, int queue_idx)
{
struct queue_s *pqueue = get_queue(channel);
queue_t *q = &pqueue[queue_idx];
int idx;
unsigned int pool_idx, di_buf_idx;
struct di_buf_s *di_buf = NULL;
struct di_buf_pool_s *pbuf_pool = get_buf_pool(channel);
enum QUE_TYPE nqtype;/*new que*/
if (dimp_get(eDI_MP_di_log_flag) & DI_LOG_QUEUE)
dim_print("%s:<%d:%d,%d,%d>\n", __func__, queue_idx,
q->num, q->in_idx, q->out_idx);
/* ****new que***** */
if (di_que_type_2_new(queue_idx, &nqtype))
return di_que_peek(channel, nqtype);
/* **************** */
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 < pbuf_pool[pool_idx].size)
di_buf = &pbuf_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 (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(2);
dim_vcry_set_log_q_idx(queue_idx);
dim_vcry_set_log_di_buf(di_buf);
}
dim_vcry_flg_inc();
di_buf = NULL;
}
if (dimp_get(eDI_MP_di_log_flag) & DI_LOG_QUEUE) {
if (di_buf)
dim_print("%s: %x(%d,%d)\n", __func__, di_buf,
pool_idx, di_buf_idx);
else
dim_print("%s: %x\n", __func__, di_buf);
}
return di_buf;
}
/*ary: note:*/
/*a. di_buf->queue_index = -1*/
/*b. */
void queue_out(unsigned int channel, struct di_buf_s *di_buf)
{
int i;
queue_t *q;
struct queue_s *pqueue = get_queue(channel);
enum QUE_TYPE nqtype;/*new que*/
if (!di_buf) {
PR_ERR("%s:Error\n", __func__);
if (dim_vcry_get_flg() == 0)
dim_vcry_set_log_reason(3);
dim_vcry_flg_inc();
return;
}
/* ****new que***** */
if (di_que_type_2_new(di_buf->queue_index, &nqtype)) {
di_que_out(channel, nqtype, di_buf); /*?*/
return;
}
/* **************** */
if (di_buf->queue_index >= 0 && di_buf->queue_index < QUEUE_NUM) {
q = &pqueue[di_buf->queue_index];
if (dimp_get(eDI_MP_di_log_flag) & DI_LOG_QUEUE)
dim_print("%s:<%d:%d,%d,%d> %x\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_ERR(
"%s: Error (%d, %x,%x)\n",
__func__,
di_buf->queue_index,
q->pool[q->out_idx],
((di_buf->type << 8) |
(di_buf->index)));
if (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(4);
dim_vcry_set_log_q_idx(di_buf->queue_index);
dim_vcry_set_log_di_buf(di_buf);
}
dim_vcry_flg_inc();
}
} 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_ERR("%s: Error\n", __func__);
if (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(5);
dim_vcry_set_log_q_idx(di_buf->queue_index);
dim_vcry_set_log_di_buf(di_buf);
}
dim_vcry_flg_inc();
}
} 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_ERR("%s: Error\n", __func__);
if (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(5);
dim_vcry_set_log_q_idx(di_buf->queue_index);
dim_vcry_set_log_di_buf(di_buf);
}
dim_vcry_flg_inc();
}
}
}
} else {
PR_ERR("%s: Error, queue_index %d is not right\n",
__func__, di_buf->queue_index);
if (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(6);
dim_vcry_set_log_q_idx(0);
dim_vcry_set_log_di_buf(di_buf);
}
dim_vcry_flg_inc();
}
if (dimp_get(eDI_MP_di_log_flag) & DI_LOG_QUEUE)
dim_print("%s done\n", __func__);
}
void queue_out_dbg(unsigned int channel, struct di_buf_s *di_buf)
{
int i;
queue_t *q;
struct queue_s *pqueue = get_queue(channel);
enum QUE_TYPE nqtype;/*new que*/
if (!di_buf) {
PR_ERR("%s:Error\n", __func__);
if (dim_vcry_get_flg() == 0)
dim_vcry_set_log_reason(3);
dim_vcry_flg_inc();
return;
}
/* ****new que***** */
if (di_que_type_2_new(di_buf->queue_index, &nqtype)) {
di_que_out(channel, nqtype, di_buf); /*?*/
pr_info("dbg1:nqtype=%d\n", nqtype);
return;
}
/* **************** */
if (di_buf->queue_index >= 0 && di_buf->queue_index < QUEUE_NUM) {
q = &pqueue[di_buf->queue_index];
if (dimp_get(eDI_MP_di_log_flag) & DI_LOG_QUEUE)
dim_print("%s:<%d:%d,%d,%d> %x\n", __func__,
di_buf->queue_index, q->num, q->in_idx,
q->out_idx, di_buf);
if (q->num > 0) {
if (q->type == 0) {
pr_info("dbg3\n");
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_ERR(
"%s: Error (%d, %x,%x)\n",
__func__,
di_buf->queue_index,
q->pool[q->out_idx],
((di_buf->type << 8) |
(di_buf->index)));
if (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(4);
dim_vcry_set_log_q_idx(di_buf->queue_index);
dim_vcry_set_log_di_buf(di_buf);
}
dim_vcry_flg_inc();
}
} 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;
}
}
pr_info("dbg2:i=%d,qindex=%d\n", i,
di_buf->queue_index);
if (i == MAX_QUEUE_POOL_SIZE) {
PR_ERR("%s: Error\n", __func__);
if (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(5);
dim_vcry_set_log_q_idx(di_buf->queue_index);
dim_vcry_set_log_di_buf(di_buf);
}
dim_vcry_flg_inc();
}
} else if (q->type == 2) {
int pool_val =
(di_buf->type << 8) | (di_buf->index);
pr_info("dbg4\n");
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_ERR("%s: Error\n", __func__);
if (dim_vcry_get_flg() == 0) {
dim_vcry_set(5,
di_buf->queue_index,
di_buf);
}
dim_vcry_flg_inc();
}
}
}
} else {
PR_ERR("%s: Error, queue_index %d is not right\n",
__func__, di_buf->queue_index);
if (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(6);
dim_vcry_set_log_q_idx(0);
dim_vcry_set_log_di_buf(di_buf);
}
dim_vcry_flg_inc();
}
if (dimp_get(eDI_MP_di_log_flag) & DI_LOG_QUEUE)
dim_print("%s done\n", __func__);
}
/***************************************/
/* set di_buf->queue_index*/
/***************************************/
void queue_in(unsigned int channel, struct di_buf_s *di_buf, int queue_idx)
{
queue_t *q = NULL;
struct queue_s *pqueue = get_queue(channel);
enum QUE_TYPE nqtype;/*new que*/
if (!di_buf) {
PR_ERR("%s:Error\n", __func__);
if (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(7);
dim_vcry_set_log_q_idx(queue_idx);
dim_vcry_set_log_di_buf(di_buf);
}
dim_vcry_flg_inc();
return;
}
/* ****new que***** */
if (di_que_type_2_new(queue_idx, &nqtype)) {
di_que_in(channel, nqtype, di_buf);
return;
}
/* **************** */
if (di_buf->queue_index != -1) {
PR_ERR("%s:%s[%d] queue_index(%d) is not -1, to que[%d]\n",
__func__, dim_get_vfm_type_name(di_buf->type),
di_buf->index, di_buf->queue_index, queue_idx);
if (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(8);
dim_vcry_set_log_q_idx(queue_idx);
dim_vcry_set_log_di_buf(di_buf);
}
dim_vcry_flg_inc();
return;
}
q = &pqueue[queue_idx];
if (dimp_get(eDI_MP_di_log_flag) & DI_LOG_QUEUE)
dim_print("%s:<%d:%d,%d,%d> %x\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 (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(9);
dim_vcry_set_log_q_idx(queue_idx);
}
dim_vcry_flg_inc();
}
} 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 (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(9);
dim_vcry_set_log_q_idx(queue_idx);
}
dim_vcry_flg_inc();
}
}
if (dimp_get(eDI_MP_di_log_flag) & DI_LOG_QUEUE)
dim_print("%s done\n", __func__);
}
int list_count(unsigned int channel, int queue_idx)
{
struct queue_s *pqueue;
enum QUE_TYPE nqtype;/*new que*/
/* ****new que***** */
if (di_que_type_2_new(queue_idx, &nqtype)) {
PR_ERR("%s:err: over flow\n", __func__);
return di_que_list_count(channel, nqtype);
}
/* **************** */
pqueue = get_queue(channel);
return pqueue[queue_idx].num;
}
bool queue_empty(unsigned int channel, int queue_idx)
{
struct queue_s *pqueue;
bool ret;
enum QUE_TYPE nqtype;/*new que*/
/* ****new que***** */
if (di_que_type_2_new(queue_idx, &nqtype)) {
PR_ERR("%s:err: over flow\n", __func__);
return di_que_is_empty(channel, nqtype);
}
/* **************** */
pqueue = get_queue(channel);
ret = (pqueue[queue_idx].num == 0);
return ret;
}
bool is_in_queue(unsigned int channel, struct di_buf_s *di_buf, int queue_idx)
{
bool ret = 0;
struct di_buf_s *p = NULL;
int itmp;
unsigned int overflow_cnt;
enum QUE_TYPE nqtype;/*new que*/
/* ****new que***** */
if (di_que_type_2_new(queue_idx, &nqtype))
return di_que_is_in_que(channel, nqtype, di_buf);
/* **************** */
overflow_cnt = 0;
if (!di_buf || (queue_idx < 0) || (queue_idx >= QUEUE_NUM)) {
ret = 0;
dim_print("%s: not in queue:%d!!!\n", __func__, queue_idx);
return ret;
}
queue_for_each_entry(p, channel, queue_idx, list) {
if (p == di_buf) {
ret = 1;
break;
}
if (overflow_cnt++ > MAX_QUEUE_POOL_SIZE) {
ret = 0;
dim_print("%s: overflow_cnt!!!\n", __func__);
break;
}
}
return ret;
}

View File

@@ -0,0 +1,76 @@
/*
* drivers/amlogic/media/di_multi/di_que.h
*
* 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.
*
*/
#ifndef __DI_QUE_H__
#define __DI_QUE_H__
void queue_init(unsigned int channel, int local_buffer_num);
void queue_out(unsigned int channel, struct di_buf_s *di_buf);
void queue_in(unsigned int channel, struct di_buf_s *di_buf,
int queue_idx);
int list_count(unsigned int channel, int queue_idx);
bool queue_empty(unsigned int channel, int queue_idx);
bool is_in_queue(unsigned int channel, struct di_buf_s *di_buf,
int queue_idx);
struct di_buf_s *get_di_buf_head(unsigned int channel,
int queue_idx);
void queue_init2(unsigned int channel);
/*new buf:*/
bool pw_queue_in(unsigned int ch, enum QUE_TYPE qtype,
unsigned int buf_index);
bool pw_queue_out(unsigned int ch, enum QUE_TYPE qtype,
unsigned int *buf_index);
bool pw_queue_empty(unsigned int ch, enum QUE_TYPE qtype);
/******************************************/
/*new api*/
/******************************************/
union uDI_QBUF_INDEX {
unsigned int d32;
struct {
unsigned int index:8, /*low*/
type:8,
reserved0:16;
} b;
};
void di_que_init(unsigned int ch);
bool di_que_alloc(unsigned int ch);
void di_que_release(unsigned int ch);
int di_que_is_empty(unsigned int ch, enum QUE_TYPE qtype);
bool di_que_out(unsigned int ch, enum QUE_TYPE qtype,
struct di_buf_s *di_buf);
struct di_buf_s *di_que_out_to_di_buf(unsigned int ch,
enum QUE_TYPE qtype);
bool di_que_in(unsigned int ch, enum QUE_TYPE qtype,
struct di_buf_s *di_buf);
bool di_que_is_in_que(unsigned int ch, enum QUE_TYPE qtype,
struct di_buf_s *di_buf);
struct di_buf_s *di_que_peek(unsigned int ch, enum QUE_TYPE qtype);
bool di_que_type_2_new(unsigned int q_type, enum QUE_TYPE *nqtype);
int di_que_list_count(unsigned int ch, enum QUE_TYPE qtype);
bool di_que_list(unsigned int ch, enum QUE_TYPE qtype,
unsigned int *outbuf, unsigned int *rsize);
struct di_buf_s *pw_qindex_2_buf(unsigned int ch, unsigned int qindex);
void queue_out_dbg(unsigned int channel, struct di_buf_s *di_buf);
#endif /*__DI_QUE_H__*/

View File

@@ -0,0 +1,249 @@
/*
* drivers/amlogic/media/di_multi/di_reg_tab.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/kernel.h>
#include <linux/err.h>
#include <linux/seq_file.h>
#include <linux/amlogic/iomap.h>
#include "deinterlace.h"
#include "di_data_l.h"
#include "register.h"
static const struct reg_t rtab_contr[] = {
/*--------------------------*/
{VD1_AFBCD0_MISC_CTRL, 20, 2, 0, "VD1_AFBCD0_MISC_CTRL",
"vd1_go_field_sel",
"0: gofile;1: post;2: pre"},
{VD1_AFBCD0_MISC_CTRL, 9, 1, 0, "",
"afbc0_mux_vpp_mad",
"afbc0 to 0:vpp; 1:di"},
{VD1_AFBCD0_MISC_CTRL, 8, 1, 0, "",
"di_mif0_en",
":mif to 0-vpp;1-di"},
/*--------------------------*/
{DI_POST_CTRL, 12, 1, 0, "DI_POST_CTRL",
"di_post_viu_link",
""},
{DI_POST_CTRL, 8, 1, 0, "",
"di_vpp_out_en",
""},
/*--------------------------*/
{VIU_MISC_CTRL0, 20, 1, 0, "VIU_MISC_CTRL0",
"?",
"?"},
{VIU_MISC_CTRL0, 18, 1, 0, "",
"Vdin0_wr_out_ctrl",
"0: nr_inp to vdin; 1: vdin wr dout"},
{VIU_MISC_CTRL0, 17, 1, 0, "",
"Afbc_inp_sel",
"0: mif to INP; 1: afbc to INP"},
{VIU_MISC_CTRL0, 16, 1, 0, "",
"di_mif0_en",
" vd1(afbc) to di post(if0) enable"},
/*--------------------------*/
{DI_IF1_GEN_REG, 0, 1, 0, "DI_IF1_GEN_REG",
"enable",
""},
/*--------------------------*/
{DI_IF1_GEN_REG3, 8, 2, 0, "DI_IF1_GEN_REG3",
"cntl_bits_mode",
"0:8bit;1:10bit 422;2:10bit 444"},
/*--------------------------*/
{DI_IF2_GEN_REG3, 8, 2, 0, "DI_IF2_GEN_REG3",
"cntl_bits_mode",
"0:8bit;1:10bit 422;2:10bit 444"},
/*--------------------------*/
{DI_IF0_GEN_REG3, 8, 2, 0, "DI_IF0_GEN_REG3",
"cntl_bits_mode",
"0:8bit;1:10bit 422;2:10bit 444"},
/*--------------------------*/
{DI_POST_GL_CTRL, 31, 1, 0, "DI_POST_GL_CTRL",
"post count enable",
""},
{DI_POST_GL_CTRL, 30, 1, 0, "",
"post count reset",
""},
{DI_POST_GL_CTRL, 16, 14, 0, "",
"total line number for post count",
""},
{DI_POST_GL_CTRL, 0, 14, 0, "",
"the line number of post frame reset",
""},
{TABLE_FLG_END, 0, 0, 0, "end", "end", ""},
};
/**********************/
/* debug register */
/**********************/
static unsigned int get_reg_bits(unsigned int val, unsigned int bstart,
unsigned int bw)
{
return((val &
(((1L << bw) - 1) << bstart)) >> (bstart));
}
static void dbg_reg_tab(struct seq_file *s, const struct reg_t *pRegTab)
{
struct reg_t creg;
int i;
unsigned int l_add;
unsigned int val32 = 1, val;
char *bname;
char *info;
i = 0;
l_add = 0;
creg = pRegTab[i];
do {
if (creg.add != l_add) {
val32 = Rd(creg.add); /*RD*/
seq_printf(s, "add:0x%x = 0x%08x, %s\n",
creg.add, val32, creg.name);
l_add = creg.add;
}
val = get_reg_bits(val32, creg.bit, creg.wid); /*RD_B*/
if (creg.bname)
bname = creg.bname;
else
bname = "";
if (creg.info)
info = creg.info;
else
info = "";
seq_printf(s, "\tbit[%d,%d]:\t0x%x[%d]:\t%s:\t%s\n",
creg.bit, creg.wid, val, val, bname, info);
i++;
creg = pRegTab[i];
if (i > TABLE_LEN_MAX) {
pr_info("warn: too long, stop\n");
break;
}
} while (creg.add != TABLE_FLG_END);
}
int reg_con_show(struct seq_file *seq, void *v)
{
dbg_reg_tab(seq, &rtab_contr[0]);
return 0;
}
static const struct reg_t rtab_cue_int[] = {
/*--------------------------*/
{NR2_CUE_CON_DIF0, 0, 32, 0x1400, "NR2_CUE_CON_DIF0",
NULL,
NULL},
{NR2_CUE_CON_DIF1, 0, 32, 0x80064, "NR2_CUE_CON_DIF1",
NULL,
NULL},
{NR2_CUE_CON_DIF2, 0, 32, 0x80064, "NR2_CUE_CON_DIF2",
NULL,
NULL},
{NR2_CUE_CON_DIF3, 0, 32, 0x80a0a, "NR2_CUE_CON_DIF3",
NULL,
NULL},
{NR2_CUE_PRG_DIF, 0, 32, 0x80a0a, "NR2_CUE_PRG_DIF",
NULL,
NULL},
{TABLE_FLG_END, 0, 0, 0, "end", "end", ""},
/*--------------------------*/
};
/************************************************
* register table
************************************************/
static bool di_g_rtab_cue(const struct reg_t **tab, unsigned int *tabsize)
{
*tab = &rtab_cue_int[0];
*tabsize = ARRAY_SIZE(rtab_cue_int);
return true;
}
static unsigned int dim_reg_read(unsigned int addr)
{
return aml_read_vcbus(addr);
}
static const struct reg_acc di_pre_regset = {
.wr = dim_DI_Wr,
.rd = dim_reg_read,
.bwr = dim_RDMA_WR_BITS,
.brd = dim_RDMA_RD_BITS,
};
static bool di_wr_tab(const struct reg_acc *ops,
const struct reg_t *ptab, unsigned int tabsize)
{
int i;
const struct reg_t *pl;
pl = ptab;
if (!ops ||
!tabsize ||
!ptab)
return false;
for (i = 0; i < tabsize; i++) {
if (pl->add == TABLE_FLG_END ||
i > TABLE_LEN_MAX) {
break;
}
if (pl->wid == 32)
ops->wr(pl->add, pl->df_val);
else
ops->bwr(pl->add, pl->df_val, pl->bit, pl->wid);
pl++;
}
return true;
}
bool dim_wr_cue_int(void)
{
const struct reg_t *ptab;
unsigned int tabsize;
di_g_rtab_cue(&ptab, &tabsize);
di_wr_tab(&di_pre_regset,
ptab,
tabsize);
PR_INF("%s:finish\n", __func__);
return true;
}
int dim_reg_cue_int_show(struct seq_file *seq, void *v)
{
dbg_reg_tab(seq, &rtab_cue_int[0]);
return 0;
}

View File

@@ -0,0 +1,26 @@
/*
* drivers/amlogic/media/di_multi/di_reg_tab.h
*
* 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.
*
*/
#ifndef __DI_REG_TABL_H__
#define __DI_REG_TABL_H__
int reg_con_show(struct seq_file *seq, void *v);
bool dim_wr_cue_int(void);
int dim_reg_cue_int_show(struct seq_file *seq, void *v);
#endif /*__DI_REG_TABL_H__*/

View File

@@ -0,0 +1,754 @@
/*
* drivers/amlogic/media/di_multi/di_sys.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/media/vfm/vframe.h>
/*dma_get_cma_size_int_byte*/
#include <linux/amlogic/media/codec_mm/codec_mm.h>
#include "deinterlace_dbg.h"
#include "deinterlace.h"
#include "di_data_l.h"
#include "di_data.h"
#include "di_dbg.h"
#include "di_vframe.h"
#include "di_task.h"
#include "di_prc.h"
#include "di_sys.h"
#include "di_api.h"
#include "register.h"
#include "nr_downscale.h"
static di_dev_t *di_pdev;
struct di_dev_s *get_dim_de_devp(void)
{
return di_pdev;
}
unsigned int di_get_dts_nrds_en(void)
{
return get_dim_de_devp()->nrds_enable;
}
/********************************************
* mem
*******************************************/
/********************************************/
static ssize_t
show_config(struct device *dev,
struct device_attribute *attr, char *buf)
{
int pos = 0;
return pos;
}
static ssize_t show_tvp_region(struct device *dev,
struct device_attribute *attr, char *buff)
{
ssize_t len = 0;
struct di_dev_s *de_devp = get_dim_de_devp();
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
show_log(struct device *dev, struct device_attribute *attr, char *buf)
{
return dim_read_log(buf);
}
static ssize_t
show_frame_format(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret = 0;
unsigned int channel = get_current_channel(); /*debug only*/
struct di_pre_stru_s *ppre = get_pre_stru(channel);
if (get_init_flag(channel))
ret += sprintf(buf + ret, "%s\n",
ppre->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);
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);
/********************************************/
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 long di_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
long ret = 0;
if (_IOC_TYPE(cmd) != _DI_) {
PR_ERR("%s invalid command: %u\n", __func__, cmd);
return -EFAULT;
}
#if 0
dbg_reg("no pq\n");
return 0;
#endif
switch (cmd) {
case AMDI_IOC_SET_PQ_PARM:
ret = dim_pq_load_io(arg);
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 int dim_rev_mem(struct di_dev_s *di_devp)
{
unsigned int ch;
unsigned int o_size;
unsigned long rmstart;
unsigned int rmsize;
unsigned int flg_map;
if (di_devp && !di_devp->flag_cma) {
dil_get_rev_mem(&rmstart, &rmsize);
dil_get_flg(&flg_map);
if (!rmstart) {
PR_ERR("%s:reserved mem start add is 0\n", __func__);
return -1;
}
di_devp->mem_start = rmstart;
di_devp->mem_size = rmsize;
if (!flg_map)
di_devp->flags |= DI_MAP_FLAG;
o_size = rmsize / DI_CHANNEL_NUB;
for (ch = 0; ch < DI_CHANNEL_NUB; ch++) {
di_set_mem_info(ch,
di_devp->mem_start + (o_size * ch),
o_size);
PR_INF("rmem:ch[%d]:start:0x%lx, size:%uB\n",
ch,
(di_devp->mem_start + (o_size * ch)),
o_size);
}
PR_INF("rmem:0x%lx, size %uMB.\n",
di_devp->mem_start, (di_devp->mem_size >> 20));
di_devp->mem_flg = true;
return 0;
}
PR_INF("%s:no dev or no rev mem\n", __func__);
return -1;
}
bool dim_rev_mem_check(void)/*tmp*/
{
di_dev_t *di_devp = get_dim_de_devp();
if (di_devp && !di_devp->flag_cma && di_devp->mem_flg)
return true;
if (!di_devp) {
PR_ERR("%s:no dev\n", __func__);
return false;
}
PR_INF("%s\n", __func__);
dim_rev_mem(di_devp);
return true;
}
#define ARY_MATCH (1)
#ifdef ARY_MATCH
static const struct di_meson_data data_g12a = {
.name = "dim_g12a",
};
static const struct di_meson_data data_sm1 = {
.name = "dim_sm1",
};
/* #ifdef CONFIG_USE_OF */
static const struct of_device_id amlogic_deinterlace_dt_match[] = {
/*{ .compatible = "amlogic, deinterlace", },*/
{ .compatible = "amlogic, dim-g12a",
.data = &data_g12a,
}, { .compatible = "amlogic, dim-g12b",
.data = &data_sm1,
}, { .compatible = "amlogic, dim-sm1",
.data = &data_sm1,
}, {}
};
#endif
static int dim_probe(struct platform_device *pdev)
{
int ret = 0;
struct di_dev_s *di_devp = NULL;
int i;
#ifdef ARY_MATCH
const struct of_device_id *match;
struct di_data_l_s *pdata;
#endif
PR_INF("%s:\n", __func__);
#if 1 /*move from init to here*/
di_pdev = kzalloc(sizeof(*di_pdev), GFP_KERNEL);
if (!di_pdev) {
PR_ERR("%s fail to allocate memory.\n", __func__);
goto fail_kmalloc_dev;
}
/******************/
ret = alloc_chrdev_region(&di_pdev->devno, 0, DI_COUNT, DEVICE_NAME);
if (ret < 0) {
PR_ERR("%s: failed to allocate major number\n", __func__);
goto fail_alloc_cdev_region;
}
PR_INF("%s: major %d\n", __func__, MAJOR(di_pdev->devno));
di_pdev->pclss = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(di_pdev->pclss)) {
ret = PTR_ERR(di_pdev->pclss);
PR_ERR("%s: failed to create class\n", __func__);
goto fail_class_create;
}
#endif
di_devp = di_pdev;
/* *********new********* */
di_pdev->data_l = NULL;
di_pdev->data_l = kzalloc(sizeof(struct di_data_l_s), GFP_KERNEL);
if (!di_pdev->data_l) {
PR_ERR("%s fail to allocate data l.\n", __func__);
goto fail_kmalloc_datal;
}
/*memset(di_pdev->data_l, 0, sizeof(struct di_data_l_s));*/
/*pr_info("\tdata size: %ld\n", sizeof(struct di_data_l_s));*/
/************************/
if (!dip_prob())
goto fail_cdev_add;
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_devp->devno, DI_COUNT);
if (ret)
goto fail_cdev_add;
di_devp->devt = MKDEV(MAJOR(di_devp->devno), 0);
di_devp->dev = device_create(di_devp->pclss, &pdev->dev,
di_devp->devt, di_devp, "di%d", 0);
if (!di_devp->dev) {
pr_error("device_create create error\n");
goto fail_cdev_add;
}
dev_set_drvdata(di_devp->dev, di_devp);
platform_set_drvdata(pdev, di_devp);
#ifdef ARY_MATCH
/************************/
match = of_match_device(amlogic_deinterlace_dt_match,
&pdev->dev);
if (!match) {
PR_ERR("%s,no matched table\n", __func__);
goto fail_cdev_add;
}
pdata = (struct di_data_l_s *)di_pdev->data_l;
pdata->mdata = match->data;
PR_INF("match name: %s\n", pdata->mdata->name);
#endif
ret = of_reserved_mem_device_init(&pdev->dev);
if (ret != 0)
PR_INF("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__);
else
PR_INF("flag_cma=%d\n", di_devp->flag_cma);
dim_rev_mem(di_devp);
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*/
/*pre_hsc_down_en;*/
di_devp->h_sc_down_en = di_mp_uit_get(eDI_MP_pre_hsc_down_en);
if (di_devp->flag_cma >= 1) {
#ifdef CONFIG_CMA
di_devp->pdev = pdev;
di_devp->flags |= DI_MAP_FLAG;
#if 0
di_devp->mem_size = dma_get_cma_size_int_byte(&pdev->dev);
#else
if (di_devp->flag_cma == 1 ||
di_devp->flag_cma == 2) {
di_devp->mem_size
= dma_get_cma_size_int_byte(&pdev->dev);
PR_INF("mem size from dts:0x%x\n", di_devp->mem_size);
}
if (di_devp->mem_size <= 0x800000) {/*need check??*/
di_devp->mem_size = 0x2800000;
/*(flag_cma ? 3) reserved in*/
/*codec mm : cma in codec mm*/
if (di_devp->flag_cma != 3) {
/*no di cma, try use*/
/*cma from codec mm*/
di_devp->flag_cma = 4;
}
}
#endif
pr_info("DI: CMA size 0x%x.\n", di_devp->mem_size);
if (di_devp->flag_cma == 2) {
if (dim_cma_alloc_total(di_devp))
dip_cma_st_set_ready_all();
}
#endif
} else {
dip_cma_st_set_ready_all();
}
/* 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);
di_pr_info("%s allocate rdma channel %d.\n", __func__,
di_devp->rdma_handle);
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXL)) {
dim_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)
dimp_set(eDI_MP_post_wr_support, 0);/*post_wr_support = 0;*/
else /*post_wr_support = di_devp->post_wr_support;*/
dimp_set(eDI_MP_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)
dimp_set(eDI_MP_nr10bit_support, 0);/*nr10bit_support = 0;*/
else /*nr10bit_support = di_devp->nr10bit_support;*/
dimp_set(eDI_MP_nr10bit_support, di_devp->nr10bit_support);
#ifdef DI_USE_FIXED_CANVAS_IDX
if (dim_get_canvas()) {
pr_dbg("DI get canvas error.\n");
ret = -EEXIST;
return ret;
}
#endif
device_create_file(di_devp->dev, &dev_attr_config);
device_create_file(di_devp->dev, &dev_attr_debug);
device_create_file(di_devp->dev, &dev_attr_dump_pic);
device_create_file(di_devp->dev, &dev_attr_log);
device_create_file(di_devp->dev, &dev_attr_provider_vframe_status);
device_create_file(di_devp->dev, &dev_attr_frame_format);
device_create_file(di_devp->dev, &dev_attr_tvp_region);
/*pd_device_files_add*/
get_ops_pd()->prob(di_devp->dev);
get_ops_nr()->nr_drv_init(di_devp->dev);
for (i = 0; i < DI_CHANNEL_NUB; i++) {
set_init_flag(i, false);
set_reg_flag(i, false);
}
set_or_act_flag(true);
/*PR_INF("\t 11\n");*/
ret = devm_request_irq(&pdev->dev, di_devp->pre_irq, &dim_irq,
IRQF_SHARED,
"pre_di", (void *)"pre_di");
if (di_devp->post_wr_support) {
ret = devm_request_irq(&pdev->dev, di_devp->post_irq,
&dim_post_irq,
IRQF_SHARED, "post_di",
(void *)"post_di");
}
di_devp->sema_flg = 1; /*di_sema_init_flag = 1;*/
dimh_hw_init(dimp_get(eDI_MP_pulldown_enable),
dimp_get(eDI_MP_mcpre_en));
dim_set_di_flag();
task_start();
post_mif_sw(false);
dim_debugfs_init(); /*2018-07-18 add debugfs*/
dimh_patch_post_update_mc_sw(DI_MC_SW_IC, true);
pr_info("%s:ok\n", __func__);
return ret;
fail_cdev_add:
pr_info("%s:fail_cdev_add\n", __func__);
kfree(di_devp->data_l);
fail_kmalloc_datal:
pr_info("%s:fail_kmalloc datal\n", __func__);
#if 1 /*move from init*/
/*fail_pdrv_register:*/
class_destroy(di_pdev->pclss);
fail_class_create:
unregister_chrdev_region(di_pdev->devno, DI_COUNT);
fail_alloc_cdev_region:
kfree(di_pdev);
fail_kmalloc_dev:
return ret;
#endif
return ret;
}
static int dim_remove(struct platform_device *pdev)
{
struct di_dev_s *di_devp = NULL;
PR_INF("%s:\n", __func__);
di_devp = platform_get_drvdata(pdev);
dimh_hw_uninit();
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXLX))
clk_disable_unprepare(di_devp->vpu_clkb);
di_devp->di_event = 0xff;
dim_uninit_buf(1, 0);/*channel 0*/
di_set_flg_hw_int(false);
task_stop();
dim_rdma_exit();
/* 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*/
get_ops_pd()->remove(di_devp->dev);
get_ops_nr()->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 (di_pdev->nrds_enable) {
dim_nr_ds_buf_uninit(di_pdev->flag_cma,
&pdev->dev);
}
}
device_destroy(di_devp->pclss, di_devp->devno);
/* free drvdata */
dev_set_drvdata(&pdev->dev, NULL);
platform_set_drvdata(pdev, NULL);
#if 1 /*move to remove*/
class_destroy(di_pdev->pclss);
dim_debugfs_exit();
dip_exit();
unregister_chrdev_region(di_pdev->devno, DI_COUNT);
#endif
kfree(di_devp->data_l);
kfree(di_pdev);
PR_INF("%s:finish\n", __func__);
return 0;
}
static void dim_shutdown(struct platform_device *pdev)
{
struct di_dev_s *di_devp = NULL;
int i;
di_devp = platform_get_drvdata(pdev);
for (i = 0; i < DI_CHANNEL_NUB; i++)
set_init_flag(i, false);
if (is_meson_txlx_cpu())
dim_top_gate_control(true, true);
else
dim_DI_Wr(DI_CLKG_CTRL, 0x2);
if (!is_meson_txlx_cpu())
diext_clk_b_sw(false);
PR_INF("%s.\n", __func__);
}
#ifdef CONFIG_PM
static void di_clear_for_suspend(struct di_dev_s *di_devp)
{
unsigned int channel = get_current_channel(); /*tmp*/
pr_info("%s\n", __func__);
di_vframe_unreg(channel);/*have flag*/
if (dip_chst_get(channel) != eDI_TOP_STATE_IDLE)
dim_unreg_process_irq(channel);
dip_cma_close();
pr_info("%s end\n", __func__);
}
/* 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);
if (!is_meson_txlx_cpu())
diext_clk_b_sw(false);
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXHD))
clk_disable_unprepare(di_devp->vpu_clkb);
PR_INF("%s\n", __func__);
return 0;
}
/* must called before lcd */
static int di_resume(struct device *dev)
{
struct di_dev_s *di_devp = NULL;
PR_INF("%s\n", __func__);
di_devp = dev_get_drvdata(dev);
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXL))
clk_prepare_enable(di_devp->vpu_clkb);
di_devp->flags &= ~DI_SUSPEND_FLAG;
/************/
PR_INF("%s finish\n", __func__);
return 0;
}
static const struct dev_pm_ops di_pm_ops = {
.suspend_late = di_suspend,
.resume_early = di_resume,
};
#endif
#ifndef ARY_MATCH
/* #ifdef CONFIG_USE_OF */
static const struct of_device_id amlogic_deinterlace_dt_match[] = {
/*{ .compatible = "amlogic, deinterlace", },*/
{ .compatible = "amlogic, dim-g12a", },
{}
};
#endif
/* #else */
/* #define amlogic_deinterlace_dt_match NULL */
/* #endif */
static struct platform_driver di_driver = {
.probe = dim_probe,
.remove = dim_remove,
.shutdown = dim_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 dim_module_init(void)
{
int ret = 0;
PR_INF("%s\n", __func__);
ret = platform_driver_register(&di_driver);
if (ret != 0) {
PR_ERR("%s: failed to register driver\n", __func__);
/*goto fail_pdrv_register;*/
return -ENODEV;
}
PR_INF("%s finish\n", __func__);
return 0;
}
static void __exit dim_module_exit(void)
{
platform_driver_unregister(&di_driver);
PR_INF("%s: ok.\n", __func__);
}
module_init(dim_module_init);
module_exit(dim_module_exit);
MODULE_DESCRIPTION("AMLOGIC MULTI-DI driver");
MODULE_LICENSE("GPL");
MODULE_VERSION("4.0.0");

View File

@@ -0,0 +1,26 @@
/*
* drivers/amlogic/media/di_multi/di_sys.h
*
* 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.
*
*/
#ifndef __DI_SYS_H__
#define __DI_SYS_H__
#define DEVICE_NAME "di_multi"
#define CLASS_NAME "deinterlace"
bool dim_rev_mem_check(void);
#endif /*__DI_SYS_H__*/

View File

@@ -0,0 +1,315 @@
/*
* drivers/amlogic/media/di_multi/di_task.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/kthread.h> /*ary add*/
#include <linux/freezer.h>
#include <linux/semaphore.h>
#include <linux/kfifo.h>
#include <linux/spinlock.h>
#include "deinterlace.h"
#include "di_data_l.h"
#include "di_prc.h"
#include "di_task.h"
#include "di_vframe.h"
static void task_wakeup(struct di_task *tsk);
unsigned int di_dbg_task_flg; /*debug only*/
bool task_send_cmd(unsigned int cmd)
{
struct di_task *tsk = get_task();
unsigned int val;
dbg_reg("%s:cmd[%d]:\n", __func__, cmd);
if (kfifo_is_full(&tsk->fifo_cmd)) {
if (kfifo_out(&tsk->fifo_cmd, &val, sizeof(unsigned int))
!= sizeof(unsigned int)) {
PR_ERR("%s:can't out\n", __func__);
return false;
}
PR_ERR("%s:lost cmd[%d]\n", __func__, val);
tsk->err_cmd_cnt++;
/*return false;*/
}
kfifo_in_spinlocked(&tsk->fifo_cmd, &cmd, sizeof(unsigned int),
&tsk->lock_cmd);
task_wakeup(tsk);
return true;
}
void task_send_ready(void)
{
struct di_task *tsk = get_task();
task_wakeup(tsk);
}
#if 0
bool task_have_vf(unsigned int ch)
{
struct di_task *tsk = get_task();
task_wakeup(tsk);
}
#endif
bool task_get_cmd(unsigned int *cmd)
{
struct di_task *tsk = get_task();
unsigned int val;
if (kfifo_is_empty(&tsk->fifo_cmd))
return false;
if (kfifo_out(&tsk->fifo_cmd, &val, sizeof(unsigned int))
!= sizeof(unsigned int))
return false;
*cmd = val;
return true;
}
void task_polling_cmd(void)
{
int i;
union DI_L_CMD_BITS cmdbyte;
for (i = 0; i < MAX_KFIFO_L_CMD_NUB; i++) {
if (!task_get_cmd(&cmdbyte.cmd32))
break;
dip_chst_process_reg(cmdbyte.b.ch);
}
}
static int task_is_exiting(struct di_task *tsk)
{
if (tsk->exit)
return 1;
/* if (afepriv->dvbdev->writers == 1)
* if (time_after_eq(jiffies, fepriv->release_jiffies +
* dvb_shutdown_timeout * HZ))
* return 1;
*/
return 0;
}
static int task_should_wakeup(struct di_task *tsk)
{
if (tsk->wakeup) {
tsk->wakeup = 0;
/*dbg only dbg_tsk("wkg[%d]\n", di_dbg_task_flg);*/
return 1;
}
return task_is_exiting(tsk);
}
static void task_wakeup(struct di_task *tsk)
{
tsk->wakeup = 1;
wake_up_interruptible(&tsk->wait_queue);
/*dbg_tsk("wks[%d]\n", di_dbg_task_flg);*/
}
static int di_test_thread(void *data)
{
struct di_task *tsk = data;
bool semheld = false;
tsk->delay = HZ;
tsk->status = 0;
tsk->wakeup = 0;
#if 0
tsk->reinitialise = 0;
tsk->needfinish = 0;
tsk->finishflg = 0;
#endif
set_freezable();
while (1) {
up(&tsk->sem);/* is locked when we enter the thread... */
restart:
wait_event_interruptible_timeout(tsk->wait_queue,
task_should_wakeup(tsk) ||
kthread_should_stop() ||
freezing(current),
tsk->delay);
di_dbg_task_flg = 1;
if (kthread_should_stop() || task_is_exiting(tsk)) {
/* got signal or quitting */
if (!down_interruptible(&tsk->sem))
semheld = true;
tsk->exit = 1;
break;
}
if (try_to_freeze())
goto restart;
if (down_interruptible(&tsk->sem))
break;
#if 0
if (tsk->reinitialise) {
/*dvb_frontend_init(fe);*/
tsk->reinitialise = 0;
}
#endif
di_dbg_task_flg = 2;
task_polling_cmd();
di_dbg_task_flg = 3;
dip_chst_process_ch();
di_dbg_task_flg = 4;
if (get_reg_flag_all())
dip_hw_process();
di_dbg_task_flg = 0;
}
tsk->thread = NULL;
if (kthread_should_stop())
tsk->exit = 1;
else
tsk->exit = 0;
/*mb();*/
if (semheld)
up(&tsk->sem);
task_wakeup(tsk);/*?*/
return 0;
}
void task_stop(void/*struct di_task *tsk*/)
{
struct di_task *tsk = get_task();
#if 1 /*not use cmd*/
pr_info(".");
/*--------------------*/
/*cmd buf*/
if (tsk->flg_cmd) {
kfifo_free(&tsk->fifo_cmd);
tsk->flg_cmd = 0;
}
/*tsk->lock_cmd = SPIN_LOCK_UNLOCKED;*/
spin_lock_init(&tsk->lock_cmd);
tsk->err_cmd_cnt = 0;
/*--------------------*/
#endif
tsk->exit = 1;
/*mb();*/
if (!tsk->thread)
return;
kthread_stop(tsk->thread);
sema_init(&tsk->sem, 1);
tsk->status = 0;
/* paranoia check in case a signal arrived */
if (tsk->thread)
PR_ERR("warning: thread %p won't exit\n", tsk->thread);
}
int task_start(void)
{
int ret;
int flg_err;
struct di_task *tsk = get_task();
struct task_struct *fe_thread;
struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
pr_info(".");
flg_err = 0;
#if 1 /*not use cmd*/
/*--------------------*/
/*cmd buf*/
/*tsk->lock_cmd = SPIN_LOCK_UNLOCKED;*/
spin_lock_init(&tsk->lock_cmd);
tsk->err_cmd_cnt = 0;
ret = kfifo_alloc(&tsk->fifo_cmd,
sizeof(unsigned int) * MAX_KFIFO_L_CMD_NUB,
GFP_KERNEL);
if (ret < 0) {
tsk->flg_cmd = false;
PR_ERR("%s:can't get kfifo\n", __func__);
return -1;
}
tsk->flg_cmd = true;
#endif
/*--------------------*/
sema_init(&tsk->sem, 1);
init_waitqueue_head(&tsk->wait_queue);
if (tsk->thread) {
if (!tsk->exit)
return 0;
task_stop();
}
if (signal_pending(current)) {
if (tsk->flg_cmd) {
kfifo_free(&tsk->fifo_cmd);
tsk->flg_cmd = 0;
}
return -EINTR;
}
if (down_interruptible(&tsk->sem)) {
if (tsk->flg_cmd) {
kfifo_free(&tsk->fifo_cmd);
tsk->flg_cmd = 0;
}
return -EINTR;
}
tsk->status = 0;
tsk->exit = 0;
tsk->thread = NULL;
/*mb();*/
fe_thread = kthread_run(di_test_thread, tsk, "aml-ditest-0");
if (IS_ERR(fe_thread)) {
ret = PTR_ERR(fe_thread);
PR_ERR(" failed to start kthread (%d)\n", ret);
up(&tsk->sem);
tsk->flg_init = 0;
return ret;
}
sched_setscheduler_nocheck(fe_thread, SCHED_FIFO, &param);
tsk->flg_init = 1;
tsk->thread = fe_thread;
return 0;
}
void dbg_task(void)
{
struct di_task *tsk = get_task();
tsk->status = 1;
task_wakeup(tsk);
}

View File

@@ -0,0 +1,36 @@
/*
* drivers/amlogic/media/di_multi/di_task.h
*
* 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.
*
*/
#ifndef __DI_TASK_H__
#define __DI_TASK_H__
extern unsigned int di_dbg_task_flg; /*debug only*/
enum eTSK_STATE {
eTSK_STATE_IDLE,
eTSK_STATE_WORKING,
};
void task_stop(void);
int task_start(void);
void dbg_task(void);
bool task_send_cmd(unsigned int cmd);
void task_send_ready(void);
#endif /*__DI_TASK_H__*/

View File

@@ -0,0 +1,556 @@
/*
* drivers/amlogic/media/di_multi/di_vframe.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/semaphore.h>
#include <linux/kfifo.h>
#include <linux/spinlock.h>
#include "deinterlace.h"
#include "di_data_l.h"
#include "di_pre.h"
#include "di_prc.h"
#include "di_dbg.h"
#include "di_vframe.h"
struct dev_vfram_t *get_dev_vframe(unsigned int ch)
{
if (ch < DI_CHANNEL_NUB)
return &get_datal()->ch_data[ch].vfm;
pr_info("err:%s ch overflow %d\n", __func__, ch);
return &get_datal()->ch_data[0].vfm;
}
const char * const di_rev_name[4] = {
"deinterlace",
"dimulti.1",
"dimulti.2",
"dimulti.3",
};
void dev_vframe_reg(struct dev_vfram_t *pvfm)
{
if (pvfm->reg) {
PR_WARN("duplicate reg\n");
return;
}
vf_reg_provider(&pvfm->di_vf_prov);
vf_notify_receiver(pvfm->name, VFRAME_EVENT_PROVIDER_START, NULL);
pvfm->reg = 1;
}
void dev_vframe_unreg(struct dev_vfram_t *pvfm)
{
if (pvfm->reg) {
vf_unreg_provider(&pvfm->di_vf_prov);
pvfm->reg = 0;
} else {
PR_WARN("duplicate ureg\n");
}
}
void di_vframe_reg(unsigned int ch)
{
struct dev_vfram_t *pvfm;
pvfm = get_dev_vframe(ch);
dev_vframe_reg(pvfm);
}
void di_vframe_unreg(unsigned int ch)
{
struct dev_vfram_t *pvfm;
pvfm = get_dev_vframe(ch);
dev_vframe_unreg(pvfm);
}
/*--------------------------*/
const char * const di_receiver_event_cmd[] = {
"",
"_UNREG",
"_LIGHT_UNREG",
"_START",
NULL, /* "_VFRAME_READY", */
NULL, /* "_QUREY_STATE", */
"_RESET",
NULL, /* "_FORCE_BLACKOUT", */
"_REG",
"_LIGHT_UNREG_RETURN_VFRAME",
NULL, /* "_DPBUF_CONFIG", */
NULL, /* "_QUREY_VDIN2NR", */
NULL, /* "_SET_3D_VFRAME_INTERLEAVE", */
NULL, /* "_FR_HINT", */
NULL, /* "_FR_END_HINT", */
NULL, /* "_QUREY_DISPLAY_INFO", */
NULL, /* "_PROPERTY_CHANGED", */
};
#define VFRAME_EVENT_PROVIDER_CMD_MAX 16
static int di_receiver_event_fun(int type, void *data, void *arg)
{
struct dev_vfram_t *pvfm;
unsigned int ch;
int ret = 0;
ch = *(int *)arg;
pvfm = get_dev_vframe(ch);
if (type <= VFRAME_EVENT_PROVIDER_CMD_MAX &&
di_receiver_event_cmd[type]) {
dbg_ev("ch[%d]:%s,%d:%s\n", ch, __func__,
type,
di_receiver_event_cmd[type]);
}
switch (type) {
case VFRAME_EVENT_PROVIDER_UNREG:
ret = di_ori_event_unreg(ch);
/* task_send_cmd(LCMD1(eCMD_UNREG, 0));*/
break;
case VFRAME_EVENT_PROVIDER_REG:
/*dev_vframe_reg(pvfm);*/
ret = di_ori_event_reg(data, ch);
/* task_send_cmd(LCMD1(eCMD_REG, 0));*/
break;
case VFRAME_EVENT_PROVIDER_START:
break;
case VFRAME_EVENT_PROVIDER_LIGHT_UNREG:
ret = di_ori_event_light_unreg(ch);
break;
case VFRAME_EVENT_PROVIDER_VFRAME_READY:
ret = di_ori_event_ready(ch);
break;
case VFRAME_EVENT_PROVIDER_QUREY_STATE:
ret = di_ori_event_qurey_state(ch);
break;
case VFRAME_EVENT_PROVIDER_RESET:
ret = di_ori_event_reset(ch);
break;
case VFRAME_EVENT_PROVIDER_LIGHT_UNREG_RETURN_VFRAME:
ret = di_ori_event_light_unreg_revframe(ch);
break;
case VFRAME_EVENT_PROVIDER_QUREY_VDIN2NR:
ret = di_ori_event_qurey_vdin2nr(ch);
break;
case VFRAME_EVENT_PROVIDER_SET_3D_VFRAME_INTERLEAVE:
di_ori_event_set_3D(type, data, ch);
break;
case VFRAME_EVENT_PROVIDER_FR_HINT:
case VFRAME_EVENT_PROVIDER_FR_END_HINT:
vf_notify_receiver(pvfm->name, type, data);
break;
default:
break;
}
return ret;
}
static const struct vframe_receiver_op_s di_vf_receiver = {
.event_cb = di_receiver_event_fun
};
bool vf_type_is_prog(unsigned int type)
{
bool ret = (type & VIDTYPE_TYPEMASK) == 0 ? true : false;
return ret;
}
bool vf_type_is_interlace(unsigned int type)
{
bool ret = (type & VIDTYPE_INTERLACE) ? true : false;
return ret;
}
bool vf_type_is_top(unsigned int type)
{
bool ret = ((type & VIDTYPE_TYPEMASK) == VIDTYPE_INTERLACE_TOP)
? true : false;
return ret;
}
bool vf_type_is_bottom(unsigned int type)
{
bool ret = ((type & VIDTYPE_INTERLACE_BOTTOM)
== VIDTYPE_INTERLACE_BOTTOM)
? true : false;
return ret;
}
bool vf_type_is_inter_first(unsigned int type)
{
bool ret = (type & VIDTYPE_INTERLACE_TOP) ? true : false;
return ret;
}
bool vf_type_is_mvc(unsigned int type)
{
bool ret = (type & VIDTYPE_MVC) ? true : false;
return ret;
}
bool vf_type_is_no_video_en(unsigned int type)
{
bool ret = (type & VIDTYPE_NO_VIDEO_ENABLE) ? true : false;
return ret;
}
bool vf_type_is_VIU422(unsigned int type)
{
bool ret = (type & VIDTYPE_VIU_422) ? true : false;
return ret;
}
bool vf_type_is_VIU_FIELD(unsigned int type)
{
bool ret = (type & VIDTYPE_VIU_FIELD) ? true : false;
return ret;
}
bool vf_type_is_VIU_SINGLE(unsigned int type)
{
bool ret = (type & VIDTYPE_VIU_SINGLE_PLANE) ? true : false;
return ret;
}
bool vf_type_is_VIU444(unsigned int type)
{
bool ret = (type & VIDTYPE_VIU_444) ? true : false;
return ret;
}
bool vf_type_is_VIUNV21(unsigned int type)
{
bool ret = (type & VIDTYPE_VIU_NV21) ? true : false;
return ret;
}
bool vf_type_is_vscale_dis(unsigned int type)
{
bool ret = (type & VIDTYPE_VSCALE_DISABLE) ? true : false;
return ret;
}
bool vf_type_is_canvas_toggle(unsigned int type)
{
bool ret = (type & VIDTYPE_CANVAS_TOGGLE) ? true : false;
return ret;
}
bool vf_type_is_pre_interlace(unsigned int type)
{
bool ret = (type & VIDTYPE_PRE_INTERLACE) ? true : false;
return ret;
}
bool vf_type_is_highrun(unsigned int type)
{
bool ret = (type & VIDTYPE_HIGHRUN) ? true : false;
return ret;
}
bool vf_type_is_compress(unsigned int type)
{
bool ret = (type & VIDTYPE_COMPRESS) ? true : false;
return ret;
}
bool vf_type_is_pic(unsigned int type)
{
bool ret = (type & VIDTYPE_PIC) ? true : false;
return ret;
}
bool vf_type_is_scatter(unsigned int type)
{
bool ret = (type & VIDTYPE_SCATTER) ? true : false;
return ret;
}
bool vf_type_is_vd2(unsigned int type)
{
bool ret = (type & VIDTYPE_VD2) ? true : false;
return ret;
}
bool is_bypss_complete(struct dev_vfram_t *pvfm)
{
return pvfm->bypass_complete;
}
#if 0
bool is_reg(unsigned int ch)
{
struct dev_vfram_t *pvfm;
pvfm = get_dev_vframe(ch);
return pvfm->reg;
}
#endif
void set_bypass_complete(struct dev_vfram_t *pvfm, bool on)
{
if (on)
pvfm->bypass_complete = true;
else
pvfm->bypass_complete = false;
}
void set_bypass2_complete(unsigned int ch, bool on)
{
struct dev_vfram_t *pvfm;
pvfm = get_dev_vframe(ch);
set_bypass_complete(pvfm, on);
}
bool is_bypss2_complete(unsigned int ch)
{
struct dev_vfram_t *pvfm;
pvfm = get_dev_vframe(ch);
return is_bypss_complete(pvfm);
}
#if 0
static void set_reg(unsigned int ch, int on)
{
struct dev_vfram_t *pvfm;
pvfm = get_dev_vframe(ch);
if (on)
pvfm->reg = true;
else
pvfm->reg = false;
}
#endif
static struct vframe_s *di_vf_peek(void *arg)
{
unsigned int ch = *(int *)arg;
/*dim_print("%s:ch[%d]\n",__func__,ch);*/
if (di_is_pause(ch))
return NULL;
if (is_bypss2_complete(ch))
return pw_vf_peek(ch);
else
return di_vf_l_peek(ch);
}
static struct vframe_s *di_vf_get(void *arg)
{
unsigned int ch = *(int *)arg;
/*struct vframe_s *vfm;*/
dim_tr_ops.post_get2(5);
if (di_is_pause(ch))
return NULL;
di_pause_step_done(ch);
/*pvfm = get_dev_vframe(ch);*/
if (is_bypss2_complete(ch))
#if 0
vfm = pw_vf_peek(ch);
if (dim_bypass_detect(ch, vfm))
return NULL;
#endif
return pw_vf_get(ch);
return di_vf_l_get(ch);
}
static void di_vf_put(struct vframe_s *vf, void *arg)
{
unsigned int ch = *(int *)arg;
if (is_bypss2_complete(ch)) {
pw_vf_put(vf, ch);
pw_vf_notify_provider(ch,
VFRAME_EVENT_RECEIVER_PUT, NULL);
return;
}
di_vf_l_put(vf, ch);
}
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)
{
unsigned int ch = *(int *)arg;
if (!states)
return -1;
dim_print("%s:ch[%d]\n", __func__, ch);
di_vf_l_states(states, ch);
return 0;
}
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,
};
#if 1
struct vframe_s *pw_vf_get(unsigned int ch)
{
sum_g_inc(ch);
return vf_get(di_rev_name[ch]);
}
struct vframe_s *pw_vf_peek(unsigned int ch)
{
return vf_peek(di_rev_name[ch]);
}
void pw_vf_put(struct vframe_s *vf, unsigned int ch)
{
sum_p_inc(ch);
vf_put(vf, di_rev_name[ch]);
}
int pw_vf_notify_provider(unsigned int channel, int event_type, void *data)
{
return vf_notify_provider(di_rev_name[channel], event_type, data);
}
int pw_vf_notify_receiver(unsigned int channel, int event_type, void *data)
{
return vf_notify_receiver(di_rev_name[channel], event_type, data);
}
void pw_vf_light_unreg_provider(unsigned int ch)
{
struct dev_vfram_t *pvfm;
struct vframe_provider_s *prov;
pvfm = get_dev_vframe(ch);
prov = &pvfm->di_vf_prov;
vf_light_unreg_provider(prov);
}
#else
struct vframe_s *pw_vf_get(unsigned int channel)
{
return vf_get(VFM_NAME);
}
struct vframe_s *pw_vf_peek(unsigned int channel)
{
return vf_peek(VFM_NAME);
}
void pw_vf_put(struct vframe_s *vf, unsigned int channel)
{
vf_put(vf, VFM_NAME);
}
int pw_vf_notify_provider(unsigned int channel, int event_type, void *data)
{
return vf_notify_provider(VFM_NAME, event_type, data);
}
int pw_vf_notify_receiver(unsigned int channel, int event_type, void *data)
{
return vf_notify_receiver(VFM_NAME, event_type, data);
}
#endif
void dev_vframe_exit(void)
{
struct dev_vfram_t *pvfm;
int ch;
for (ch = 0; ch < DI_CHANNEL_NUB; ch++) {
pvfm = get_dev_vframe(ch);
vf_unreg_provider(&pvfm->di_vf_prov);
vf_unreg_receiver(&pvfm->di_vf_recv);
}
pr_info("%s finish\n", __func__);
}
void dev_vframe_init(void)
{
struct dev_vfram_t *pvfm;
int ch;
for (ch = 0; ch < DI_CHANNEL_NUB; ch++) {
pvfm = get_dev_vframe(ch);
pvfm->name = di_rev_name[ch];
pvfm->indx = ch;
/*set_bypass_complete(pvfm, true);*/ /*test only*/
/*receiver:*/
vf_receiver_init(&pvfm->di_vf_recv, pvfm->name,
&di_vf_receiver, &pvfm->indx);
vf_reg_receiver(&pvfm->di_vf_recv);
/*provider:*/
vf_provider_init(&pvfm->di_vf_prov, pvfm->name,
&deinterlace_vf_provider, &pvfm->indx);
}
pr_info("%s finish\n", __func__);
}

View File

@@ -0,0 +1,68 @@
/*
* drivers/amlogic/media/di_multi/di_vframe.h
*
* 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.
*
*/
#ifndef __DI_VFRAME_H__
#define __DI_VFRAME_H__
#include <linux/amlogic/media/vfm/vframe.h>
#include <linux/amlogic/media/vfm/vframe_provider.h>
#include <linux/amlogic/media/vfm/vframe_receiver.h>
void dev_vframe_init(void);
void dev_vframe_exit(void);
void di_vframe_reg(unsigned int ch);
void di_vframe_unreg(unsigned int ch);
bool vf_type_is_prog(unsigned int type);
bool vf_type_is_interlace(unsigned int type);
bool vf_type_is_top(unsigned int type);
bool vf_type_is_bottom(unsigned int type);
bool vf_type_is_inter_first(unsigned int type);
bool vf_type_is_mvc(unsigned int type);
bool vf_type_is_no_video_en(unsigned int type);
bool vf_type_is_VIU422(unsigned int type);
bool vf_type_is_VIU_FIELD(unsigned int type);
bool vf_type_is_VIU_SINGLE(unsigned int type);
bool vf_type_is_VIU444(unsigned int type);
bool vf_type_is_VIUNV21(unsigned int type);
bool vf_type_is_vscale_dis(unsigned int type);
bool vf_type_is_canvas_toggle(unsigned int type);
bool vf_type_is_pre_interlace(unsigned int type);
bool vf_type_is_highrun(unsigned int type);
bool vf_type_is_compress(unsigned int type);
bool vf_type_is_pic(unsigned int type);
bool vf_type_is_scatter(unsigned int type);
bool vf_type_is_vd2(unsigned int type);
extern const char * const di_rev_name[4];
struct vframe_s *pw_vf_get(unsigned int ch);
struct vframe_s *pw_vf_peek(unsigned int ch);
void pw_vf_put(struct vframe_s *vf, unsigned int ch);
int pw_vf_notify_provider(unsigned int channel,
int event_type,
void *data);
int pw_vf_notify_receiver(unsigned int channel,
int event_type,
void *data);
void pw_vf_light_unreg_provider(unsigned int ch);
void set_bypass2_complete(unsigned int ch, bool on);
bool is_bypss_complete(struct dev_vfram_t *pvfm);
bool is_bypss2_complete(unsigned int ch);
#endif /*__DI_VFRAME_H__*/

View File

@@ -0,0 +1,71 @@
/*
* drivers/amlogic/media/di_multi/dim_trace.h
*
* 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.
*
*/
#undef TRACE_SYSTEM
#define TRACE_SYSTEM dim
#if !defined(_DIM_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
#define _DIM_TRACE_H
#include <linux/tracepoint.h>
/* single lifecycle events */
DECLARE_EVENT_CLASS(di_event_class,
TP_PROTO(const char *name, int field_cnt, unsigned long time),
TP_ARGS(name, field_cnt, time),
TP_STRUCT__entry(
__string(name, name)
__field(int, field_cnt)
__field(unsigned long, time)
),
TP_fast_assign(
__assign_str(name, name);
__entry->field_cnt = field_cnt;
__entry->time = time;
),
TP_printk("[%s-%-4dth-%lums]", __get_str(name),
__entry->field_cnt, __entry->time)
);
#define DEFINE_DI_EVENT(name) \
DEFINE_EVENT(di_event_class, name, \
TP_PROTO(const char *name, int field_cnt, unsigned long time), \
TP_ARGS(name, field_cnt, time))
DEFINE_DI_EVENT(dim_pre);
DEFINE_DI_EVENT(dim_post);
/*2019-06-18*/
DEFINE_DI_EVENT(dim_pre_getxx);
DEFINE_DI_EVENT(dim_pre_setxx);
DEFINE_DI_EVENT(dim_pre_ready);
DEFINE_DI_EVENT(dim_pst_ready);
DEFINE_DI_EVENT(dim_pst_getxx);
DEFINE_DI_EVENT(dim_pst_setxx);
DEFINE_DI_EVENT(dim_pst_irxxx);
DEFINE_DI_EVENT(dim_pst_doing);
DEFINE_DI_EVENT(dim_pst_peekx);
DEFINE_DI_EVENT(dim_pst_get2x);
#endif /* _DIM_TRACE_H */
#if 0
#undef TRACE_INCLUDE_PATH
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_PATH .
#define TRACE_INCLUDE_FILE deinterlace_trace
#include <trace/define_trace.h>
#endif

View File

@@ -0,0 +1,218 @@
/*
* drivers/amlogic/media/di_multi/nr_downscale.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/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/dma-contiguous.h>
#include <linux/amlogic/iomap.h>
#include <linux/amlogic/media/canvas/canvas.h>
#include <linux/amlogic/media/canvas/canvas_mgr.h>
#include "register.h"
#include "nr_downscale.h"
#include "deinterlace.h"
#include "di_data_l.h"
#include "di_api.h"
static struct nr_ds_s nrds_dev;
static void nr_ds_hw_init(unsigned int width, unsigned int height)
{
unsigned char h_step = 0, v_step = 0;
unsigned int width_out, height_out;
width_out = NR_DS_WIDTH;
height_out = NR_DS_HEIGHT;
h_step = width / width_out;
v_step = height / height_out;
/*Switch MIF to NR_DS*/
dim_RDMA_WR_BITS(VIUB_MISC_CTRL0, 3, 5, 2);
/* config dsbuf_ocol*/
dim_RDMA_WR_BITS(NR_DS_BUF_SIZE_REG, width_out, 0, 8);
/* config dsbuf_orow*/
dim_RDMA_WR_BITS(NR_DS_BUF_SIZE_REG, height_out, 8, 8);
dim_RDMA_WR_BITS(NRDSWR_X, (width_out - 1), 0, 13);
dim_RDMA_WR_BITS(NRDSWR_Y, (height_out - 1), 0, 13);
dim_RDMA_WR_BITS(NRDSWR_CAN_SIZE, (height_out - 1), 0, 13);
dim_RDMA_WR_BITS(NRDSWR_CAN_SIZE, (width_out - 1), 16, 13);
/* little endian */
dim_RDMA_WR_BITS(NRDSWR_CAN_SIZE, 1, 13, 1);
dim_RDMA_WR_BITS(NR_DS_CTRL, v_step, 16, 6);
dim_RDMA_WR_BITS(NR_DS_CTRL, h_step, 24, 6);
}
/*
* init nr ds buffer
*/
void dim_nr_ds_buf_init(unsigned int cma_flag, unsigned long mem_start,
struct device *dev)
{
unsigned int i = 0;
bool ret;
struct dim_mm_s omm;
if (cma_flag == 0) {
nrds_dev.nrds_addr = mem_start;
} else {
#if 0
nrds_dev.nrds_pages = dma_alloc_from_contiguous(dev,
NR_DS_PAGE_NUM, 0);
if (nrds_dev.nrds_pages)
nrds_dev.nrds_addr = page_to_phys(nrds_dev.nrds_pages);
else
PR_ERR("DI: alloc nr ds mem error.\n");
#else
ret = dim_mm_alloc(cma_flag, NR_DS_PAGE_NUM, &omm);
if (ret) {
nrds_dev.nrds_pages = omm.ppage;
nrds_dev.nrds_addr = omm.addr;
} else {
PR_ERR("alloc nr ds mem error.\n");
}
#endif
}
for (i = 0; i < NR_DS_BUF_NUM; i++)
nrds_dev.buf[i] = nrds_dev.nrds_addr + (NR_DS_BUF_SIZE * i);
nrds_dev.cur_buf_idx = 0;
}
void dim_nr_ds_buf_uninit(unsigned int cma_flag, struct device *dev)
{
unsigned int i = 0;
if (cma_flag == 0) {
nrds_dev.nrds_addr = 0;
} else {
if (nrds_dev.nrds_pages) {
#if 0
dma_release_from_contiguous(dev,
nrds_dev.nrds_pages,
NR_DS_PAGE_NUM);
#else
dim_mm_release(cma_flag,
nrds_dev.nrds_pages,
NR_DS_PAGE_NUM,
nrds_dev.nrds_addr);
#endif
nrds_dev.nrds_addr = 0;
nrds_dev.nrds_pages = NULL;
} else
pr_info("DI: no release nr ds mem.\n");
}
for (i = 0; i < NR_DS_BUF_NUM; i++)
nrds_dev.buf[i] = 0;
nrds_dev.cur_buf_idx = 0;
}
/*
* hw config, alloc canvas
*/
void dim_nr_ds_init(unsigned int width, unsigned int height)
{
nr_ds_hw_init(width, height);
nrds_dev.field_num = 0;
if (nrds_dev.canvas_idx != 0)
return;
if (ext_ops.canvas_pool_alloc_canvas_table("nr_ds",
&nrds_dev.canvas_idx, 1, CANVAS_MAP_TYPE_1)) {
PR_ERR("%s alloc nrds canvas error.\n", __func__);
return;
}
pr_info("%s alloc nrds canvas %u.\n",
__func__, nrds_dev.canvas_idx);
}
/*
* config nr ds mif, switch buffer
*/
void dim_nr_ds_mif_config(void)
{
unsigned long mem_addr = 0;
mem_addr = nrds_dev.buf[nrds_dev.cur_buf_idx];
canvas_config(nrds_dev.canvas_idx, mem_addr,
NR_DS_WIDTH, NR_DS_HEIGHT, 0, 0);
dim_RDMA_WR_BITS(NRDSWR_CTRL,
nrds_dev.canvas_idx, 0, 8);
dim_nr_ds_hw_ctrl(true);
}
/*
* enable/disable nr ds mif&hw
*/
void dim_nr_ds_hw_ctrl(bool enable)
{
/*Switch MIF to NR_DS*/
dim_RDMA_WR_BITS(VIUB_MISC_CTRL0, enable ? 3 : 2, 5, 2);
dim_RDMA_WR_BITS(NRDSWR_CTRL, enable ? 1 : 0, 12, 1);
dim_RDMA_WR_BITS(NR_DS_CTRL, enable ? 1 : 0, 30, 1);
}
/*
* process in irq
*/
void dim_nr_ds_irq(void)
{
dim_nr_ds_hw_ctrl(false);
nrds_dev.field_num++;
nrds_dev.cur_buf_idx++;
if (nrds_dev.cur_buf_idx >= NR_DS_BUF_NUM)
nrds_dev.cur_buf_idx = 0;
}
/*
* get buf addr&size for dump
*/
void dim_get_nr_ds_buf(unsigned long *addr, unsigned long *size)
{
*addr = nrds_dev.nrds_addr;
*size = NR_DS_BUF_SIZE;
pr_info("%s addr 0x%lx, size 0x%lx.\n",
__func__, *addr, *size);
}
/*
* 0x37f9 ~ 0x37fc 0x3740 ~ 0x3743 8 regs
*/
void dim_dump_nrds_reg(unsigned int base_addr)
{
unsigned int i = 0x37f9;
pr_info("-----nrds reg start-----\n");
pr_info("[0x%x][0x%x]=0x%x\n",
base_addr + (0x2006 << 2), i, dim_RDMA_RD(0x2006));
for (i = 0x37f9; i < 0x37fd; i++)
pr_info("[0x%x][0x%x]=0x%x\n",
base_addr + (i << 2), i, dim_RDMA_RD(i));
for (i = 0x3740; i < 0x3744; i++)
pr_info("[0x%x][0x%x]=0x%x\n",
base_addr + (i << 2), i, dim_RDMA_RD(i));
pr_info("-----nrds reg end-----\n");
}

View File

@@ -0,0 +1,46 @@
/*
* drivers/amlogic/media/di_multi/nr_downscale.h
*
* 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.
*
*/
#ifndef _NR_DS_H
#define _NR_DS_H
#define NR_DS_WIDTH 128
#define NR_DS_HEIGHT 96
#define NR_DS_BUF_SIZE (96 << 7)
#define NR_DS_BUF_NUM 6
#define NR_DS_MEM_SIZE (NR_DS_BUF_SIZE * NR_DS_BUF_NUM)
#define NR_DS_PAGE_NUM (NR_DS_MEM_SIZE >> PAGE_SHIFT)
struct nr_ds_s {
unsigned int field_num;
unsigned long nrds_addr;
struct page *nrds_pages;
unsigned int canvas_idx;
unsigned char cur_buf_idx;
unsigned long buf[NR_DS_BUF_NUM];
};
void dim_nr_ds_buf_init(unsigned int cma_flag, unsigned long mem_start,
struct device *dev);
void dim_nr_ds_buf_uninit(unsigned int cma_flag, struct device *dev);
void dim_nr_ds_init(unsigned int width, unsigned int height);
void dim_nr_ds_mif_config(void);
void dim_nr_ds_hw_ctrl(bool enable);
void dim_nr_ds_irq(void);
void dim_get_nr_ds_buf(unsigned long *addr, unsigned long *size);
void dim_dump_nrds_reg(unsigned int base_addr);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,149 @@
/*
* drivers/amlogic/media/di_multi/register_nr4.h
*
* 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.
*
*/
#define NR4_DRT_CTRL ((0x2da4))
#define NR4_DRT_YSAD_GAIN ((0x2da5))
#define NR4_DRT_CSAD_GAIN ((0x2da6))
#define NR4_DRT_SAD_ALP_CORE ((0x2da7))
#define NR4_DRT_ALP_MINMAX ((0x2da8))
#define NR4_SNR_CTRL_REG ((0x2da9))
#define NR4_SNR_ALPHA0_MAX_MIN ((0x2daa))
#define NR4_ALP0C_ERR2CURV_LIMIT0 ((0x2dab))
#define NR4_ALP0C_ERR2CURV_LIMIT1 ((0x2dac))
#define NR4_ALP0Y_ERR2CURV_LIMIT0 ((0x2dad))
#define NR4_ALP0Y_ERR2CURV_LIMIT1 ((0x2dae))
#define NR4_SNR_ALPA1_RATE_AND_OFST ((0x2daf))
#define NR4_SNR_ALPHA1_MAX_MIN ((0x2db0))
#define NR4_ALP1C_ERR2CURV_LIMIT0 ((0x2db1))
#define NR4_ALP1C_ERR2CURV_LIMIT1 ((0x2db2))
#define NR4_ALP1Y_ERR2CURV_LIMIT0 ((0x2db3))
#define NR4_ALP1Y_ERR2CURV_LIMIT1 ((0x2db4))
#define NR4_MTN_CTRL ((0x2db5))
#define NR4_MTN_REF_PAR0 ((0x2db6))
#define NR4_MTN_REF_PAR1 ((0x2db7))
#define NR4_MCNR_LUMA_ENH_CTRL ((0x2db8))
#define NR4_MCNR_LUMA_STAT_LIMTX ((0x2db9))
#define NR4_MCNR_LUMA_STAT_LIMTY ((0x2dba))
#define NR4_MCNR_LUMA_DIF_CALC ((0x2dbb))
#define NR4_MCNR_LUMAPRE_CAL_PRAM ((0x2dbc))
#define NR4_MCNR_LUMACUR_CAL_PRAM ((0x2dbd))
#define NR4_MCNR_MV_CTRL_REG ((0x2dbe))
#define NR4_MCNR_MV_GAIN0 ((0x2dbf))
#define NR4_MCNR_LMV_PARM ((0x2dc0))
#define NR4_MCNR_ALP0_REG (0x2dc1)
#define NR4_MCNR_ALP1_AND_BET0_REG (0x2dc2)
#define NR4_MCNR_BET1_AND_BET2_REG (0x2dc3)
#define NR4_MCNR_AC_DC_CRTL (0x2dc4)
#define NR4_MCNR_CM_CTRL0 (0x2dc5)
#define NR4_MCNR_CM_PRAM (0x2dc6)
#define NR4_MCNR_CM_RSHFT_ALP0 (0x2dc7)
#define NR4_MCNR_BLUE_CENT (0x2dc8)
#define NR4_MCNR_BLUE_GAIN_PAR0 (0x2dc9)
#define NR4_MCNR_BLUE_GAIN_PAR1 (0x2dca)
#define NR4_MCNR_CM_BLUE_CLIP0 (0x2dcb)
#define NR4_MCNR_CM_BLUE_CLIP1 (0x2dcc)
#define NR4_MCNR_GREEN_CENT (0x2dcd)
#define NR4_MCNR_GREEN_GAIN_PAR0 (0x2dce)
#define NR4_MCNR_GREEN_GAIN_PAR1 (0x2dcf)
#define NR4_MCNR_GREEN_CLIP0 (0x2dd0)
#define NR4_MCNR_GREEN_CLIP2 (0x2dd1)
#define NR4_MCNR_SKIN_CENT (0x2dd2)
#define NR4_MCNR_SKIN_GAIN_PAR0 (0x2dd3)
#define NR4_MCNR_SKIN_GAIN_PAR1 (0x2dd4)
#define NR4_MCNR_SKIN_CLIP0 (0x2dd5)
#define NR4_MCNR_SKIN_CLIP1 (0x2dd6)
#define NR4_MCNR_ALP1_GLB_CTRL (0x2dd7)
#define NR4_MCNR_DC2NORM_LUT0 (0x2dd8)
#define NR4_MCNR_DC2NORM_LUT1 (0x2dd9)
#define NR4_MCNR_DC2NORM_LUT2 (0x2dda)
#define NR4_MCNR_AC2NORM_LUT0 (0x2ddb)
#define NR4_MCNR_AC2NORM_LUT1 (0x2ddc)
#define NR4_MCNR_AC2NORM_LUT2 (0x2ddd)
#define NR4_MCNR_SAD2ALP0_LUT0 (0x2dde)
#define NR4_MCNR_SAD2ALP0_LUT1 (0x2ddf)
#define NR4_MCNR_SAD2ALP0_LUT2 (0x2de0)
#define NR4_MCNR_SAD2ALP0_LUT3 (0x2de1)
#define NR4_MCNR_SAD2ALP1_LUT0 (0x2de2)
#define NR4_MCNR_SAD2ALP1_LUT1 (0x2de3)
#define NR4_MCNR_SAD2ALP1_LUT2 (0x2de4)
#define NR4_MCNR_SAD2ALP1_LUT3 (0x2de5)
#define NR4_MCNR_SAD2BET0_LUT0 (0x2de6)
#define NR4_MCNR_SAD2BET0_LUT1 (0x2de7)
#define NR4_MCNR_SAD2BET0_LUT2 (0x2de8)
#define NR4_MCNR_SAD2BET0_LUT3 (0x2de9)
#define NR4_MCNR_SAD2BET1_LUT0 (0x2dea)
#define NR4_MCNR_SAD2BET1_LUT1 (0x2deb)
#define NR4_MCNR_SAD2BET1_LUT2 (0x2dec)
#define NR4_MCNR_SAD2BET1_LUT3 (0x2ded)
#define NR4_MCNR_SAD2BET2_LUT0 (0x2dee)
#define NR4_MCNR_SAD2BET2_LUT1 (0x2def)
#define NR4_MCNR_SAD2BET2_LUT2 (0x2df0)
#define NR4_MCNR_SAD2BET2_LUT3 (0x2df1)
#define NR4_MCNR_RO_U_SUM (0x2df2)
#define NR4_MCNR_RO_V_SUM (0x2df3)
#define NR4_MCNR_RO_GRDU_SUM (0x2df4)
#define NR4_MCNR_RO_GRDV_SUM (0x2df5)
#define NR4_TOP_CTRL (0x2dff)
#define NR4_MCNR_SAD_GAIN (0x3700)
#define NR4_MCNR_LPF_CTRL (0x3701)
#define NR4_MCNR_BLD_VS3LUT0 (0x3702)
#define NR4_MCNR_BLD_VS3LUT1 (0x3703)
#define NR4_MCNR_BLD_VS3LUT2 (0x3704)
#define NR4_MCNR_BLD_VS2LUT0 (0x3705)
#define NR4_MCNR_BLD_VS2LUT1 (0x3706)
#define NR4_COEFBLT_LUT10 (0x3707)
#define NR4_COEFBLT_LUT11 (0x3708)
#define NR4_COEFBLT_LUT12 (0x3709)
#define NR4_COEFBLT_LUT20 (0x370a)
#define NR4_COEFBLT_LUT21 (0x370b)
#define NR4_COEFBLT_LUT22 (0x370c)
#define NR4_COEFBLT_LUT30 (0x370d)
#define NR4_COEFBLT_LUT31 (0x370e)
#define NR4_COEFBLT_LUT32 (0x370f)
#define NR4_COEFBLT_CONV (0x3710)
#define NR4_DBGWIN_YX0 (0x3711)
#define NR4_DBGWIN_YX1 (0x3712)
#define NR4_NM_X_CFG (0x3713)
#define NR4_NM_Y_CFG (0x3714)
#define NR4_NM_SAD_THD (0x3715)
#define NR4_MCNR_BANDSPLIT_PRAM (0x3716)
#define NR4_MCNR_ALP1_SGN_COR (0x3717)
#define NR4_MCNR_ALP1_SGN_PRAM (0x3718)
#define NR4_MCNR_ALP1_MVX_LUT1 (0x3719)
#define NR4_MCNR_ALP1_MVX_LUT2 (0x371a)
#define NR4_MCNR_ALP1_MVX_LUT3 (0x371b)
#define NR4_MCNR_ALP1_LP_PRAM (0x371c)
#define NR4_MCNR_ALP1_SGN_LUT1 (0x371d)
#define NR4_MCNR_ALP1_SGN_LUT2 (0x371e)
#define NR4_RO_NM_SAD_SUM (0x371f)
#define NR4_RO_NM_SAD_CNT (0x3720)
#define NR4_RO_NM_VAR_SUM (0x3721)
#define NR4_RO_NM_VAR_SCNT (0x3722)
#define NR4_RO_NM_VAR_MIN_MAX (0x3723)
#define NR4_RO_NR4_DBGPIX_NUM (0x3724)
#define NR4_RO_NR4_BLDVS2_SUM (0x3725)
#define NR4_BLDVS3_SUM (0x3726)
#define NR4_COEF12_SUM (0x3727)
#define NR4_COEF123_SUM (0x3728)
#define NR_DB_FLT_CTRL (0x3738)
#define NR_DB_FLT_YC_THRD (0x3739)
#define NR_DB_FLT_RANDLUT (0x373a)
#define NR_DB_FLT_PXI_THRD (0x373b)
#define NR_DB_FLT_SEED_Y (0x373c)
#define NR_DB_FLT_SEED_V (0x373e)
#define NR_DB_FLT_SEED3 (0x373f)
#define LBUF_TOP_CTRL (0x2fff)

View File

@@ -52,6 +52,8 @@
#define VIDTYPE_PRE_DI_AFBC 0x10000000
#define VIDTYPE_RGB_444 0x20000000
/* 2019-04-22 Suggestions from brian.zhu*/
#define VIDTYPE_DI_PW 0x40000000
#define DISP_RATIO_FORCECONFIG 0x80000000
#define DISP_RATIO_FORCE_NORMALWIDE 0x40000000
#define DISP_RATIO_FORCE_FULL_STRETCH 0x20000000