/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
 * drivers/amlogic/media/deinterlace/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/video_sink/video.h>

#include <linux/clk.h>
#include <linux/atomic.h>
#include "deinterlace_hw.h"
#include "nr_drv.h"
#include "../di_local/di_local.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_PROVIDER_UNREG	'n'
#define TRIGGER_PRE_BY_DEBUG_DISABLE	'd'
#define TRIGGER_PRE_BY_PROVIDER_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	9

/* buffer management related */
#define MAX_IN_BUF_NUM				20
#define MAX_LOCAL_BUF_NUM			10
#define MAX_POST_BUF_NUM			16

#define VFRAME_TYPE_IN				1
#define VFRAME_TYPE_LOCAL			2
#define VFRAME_TYPE_POST			3
#define VFRAME_TYPE_NUM				3

/*vframe define*/
#define vframe_t struct vframe_s

/* 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 short *mcinfo_vaddr;
	bool bflg_vmap;
	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_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*/
	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;
	u32 width_bk;
};
#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


#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

#define VFM_NAME		"deinterlace"

#ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA
extern void enable_rdma(int enable_flag);
extern int VSYNC_WR_MPEG_REG(u32 adr, u32 val);
extern int VSYNC_WR_MPEG_REG_BITS(u32 adr, u32 val, u32 start, u32 len);
extern u32 VSYNC_RD_MPEG_REG(u32 adr);
extern 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

#define TABLE_LEN_MAX 10000
#define TABLE_FLG_END	(0xfffffffe)

/******************************************
 * patch for TV-10258 multiwave group issue
 *****************************************/
#define DI_PATCH_MOV_MAX_NUB	5

struct di_patch_mov_d_s {
	unsigned int val;
	unsigned int mask;
	bool	en;
};

struct di_patch_mov_s {
	unsigned int reg_addr[DI_PATCH_MOV_MAX_NUB];
	struct di_patch_mov_d_s	val_db[DI_PATCH_MOV_MAX_NUB];
	struct di_patch_mov_d_s	val_pq[DI_PATCH_MOV_MAX_NUB];
	int	mode;/*-1 : not set; 0: set from db, 1: set from pq*/
	bool	en_support;
	bool	update;
	unsigned int nub;
};

bool di_patch_mov_db(unsigned int addr, unsigned int val);

struct di_dev_s {
	dev_t			   devt;
	struct cdev		   cdev; /* The cdev structure */
	struct device	   *dev;
	struct platform_device	*pdev;
	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;
	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;
	u32 h_sc_down_en;/*sm1, tm2 ...*/
	/*struct	mutex      cma_mutex;*/
	unsigned int	   flag_cma;
	struct page			*total_pages;
	atomic_t			mem_flag;
	struct dentry *dbg_root;	/*dbg_fs*/
	struct di_patch_mov_s mov;
	struct vpu_dev_s *di_vpu_clk_gate_dev;
	struct vpu_dev_s *di_vpu_pd_dec;
	struct vpu_dev_s *di_vpu_pd_dec1;
	struct vpu_dev_s *di_vpu_pd_vd1;
	struct vpu_dev_s *di_vpu_pd_post;
	u32 instance_id; /* di_instance_id; */
};

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;
	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_busy_timer_count;
	int	pre_de_process_done;    /* flag when irq done */
	int	pre_de_process_flag;    /* flag when pre_de_process done */
	int	pre_de_clear_flag;
	/* flag is set when VFRAME_EVENT_PROVIDER_UNREG*/
	int	unreg_req_flag;
	int	unreg_req_flag_irq;
	int	unreg_req_flag_cnt;
	int	reg_req_flag;
	/*int	reg_req_flag_irq;*/
	int	reg_req_flag_cnt;
	int	reg_irq_busy;
	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
*/
	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;
	unsigned int  pps_dsth;
	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_alloc_req;
	int cma_alloc_done;
	int cma_release_req;
	/* for performance debug */
	unsigned long irq_time[2];
	/* combing adaptive */
	struct combing_status_s *mtn_status;
	u64 afbc_rls_time;
	bool wait_afbc;
	/*****************/
	bool retry_en;
	unsigned int retry_index;
	unsigned int retry_cnt;
	/*****************/
	bool combing_fix_en;
	unsigned int comb_mode;
	/*struct di_patch_mov_s mov;*/
};

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;
	struct di_buf_s *cur_post_buf;
	struct di_buf_s *keep_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;
	/* performance debug */
	unsigned int  post_wr_cnt;
	unsigned long irq_time;
};

#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 di_mm_s {
	struct page	*ppage;
	unsigned long	addr;
};
extern bool di_mm_alloc(int cma_mode, size_t count, struct di_mm_s *o);
extern bool di_mm_release(int cma_mode,
			struct page *pages,
			int count,
			unsigned long addr);


unsigned char is_bypass(vframe_t *vf_in);

/*---get di state parameter---*/
struct di_dev_s *get_di_de_devp(void);
struct di_pre_stru_s *get_di_pre_stru(void);
struct di_post_stru_s *get_di_post_stru(void);
const char *get_di_version_s(void);
int get_di_dump_state_flag(void);
uint get_di_init_flag(void);
unsigned char get_di_recovery_flag(void);
unsigned int get_di_recovery_log_reason(void);
int get_di_di_blocking(void);
unsigned int get_di_recovery_log_queue_idx(void);
struct di_buf_s *get_di_recovery_log_di_buf(void);
int get_di_video_peek_cnt(void);
unsigned long get_di_reg_unreg_timeout_cnt(void);
struct vframe_s **get_di_vframe_in(void);

extern s32 di_request_afbc_hw(u8 id, bool on);
u32 di_request_afbc(u32 onoff);
unsigned int is_need_stop_reg(unsigned int addr);
/***********************/
extern bool di_wr_cue_int(void);
extern int reg_cue_int_show(struct seq_file *seq, void *v);

bool dil_attach_ext_api(const struct di_ext_ops *di_api);
/*--Different DI versions flag---*/
void dil_set_diff_ver_flag(unsigned int para);

unsigned int dil_get_diff_ver_flag(void);
/*-------------------------*/
struct di_buf_s *get_di_buf(int queue_idx, int *start_pos);

#define queue_for_each_entry(di_buf, ptm, queue_idx, list)      \
	for (itmp = 0; ((di_buf = get_di_buf(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)

/******************************************/
/*#define DI_KEEP_HIS	0*/
#endif
