/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
/*
 * Copyright (c) 2021 MediaTek Inc.
 */

#ifndef MTK_DMX_FILTER_H
#define MTK_DMX_FILTER_H

#include <linux/types.h>
#include <linux/dvb/dmx2_mtk.h>
#include "mtk_dmx_common.h"
#include "mtk_dmx_rm.h"

enum filter_dst_type {
	FILTER_DST_TYPE_VIDEO,
	FILTER_DST_TYPE_AUDIO,
	FILTER_DST_TYPE_PVR,
	FILTER_DST_TYPE_SEC,
	FILTER_DST_TYPE_MAX,
	FILTER_DST_TYPE_NULL = -1
};

// signaling information type
enum filter_si_type {
	FILTER_SI_TYPE_SECTION = 0,
	FILTER_SI_TYPE_PES,
	FILTER_SI_TYPE_PKT,
	FILTER_SI_TYPE_SWPCR,
	FILTER_SI_TYPE_TTX,
	FILTER_SI_TYPE_SECTION_VER_CHK,
	FILTER_SI_TYPE_MMT_SI = 0x100,
	FILTER_SI_TYPE_TLV_SI = 0x101,
	FILTER_SI_TYPE_TLV_TIMED_MPU = 0x102,
	FILTER_SI_TYPE_TLV_NON_TIMED_MPU = 0x103,
	FILTER_SI_TYPE_MMT_SI_MESSAGE = 0x104,
	FILTER_SI_TYPE_SECTION_NO_PUSI = 0x1000000,
	FILTER_SI_TYPE_NULL = -1
};

// signaling information control mode
enum filter_si_mode {
	FILTER_SI_MODE_CONTINUE			= 0x0,
	FILTER_SI_MODE_ONESHOT			= 0x1,
	FILTER_SI_MODE_CRC_CHECK		= 0x2,
	FILTER_SI_MODE_AUTO_CRC_CHECK	= 0x10000
};

enum filter_tlv_mode {
	FILTER_TLV_MODE_DISABLE = 0x0,
	FILTER_TLV_MODE_MMTP    = 0x1,
	FILTER_TLV_MODE_SI      = 0x2
};

enum stc_mode {
	STC_MODE_TS,
	STC_MODE_TLV,
};

enum scrambling_status_pos {
	SCRAMBLING_STATUS_POS_MIN = 0,

	SCRAMBLING_STATUS_POS_BEFORE_CA = SCRAMBLING_STATUS_POS_MIN,
	SCRAMBLING_STATUS_POS_AFTER_CA,

	SCRAMBLING_STATUS_POS_MAX,
};

struct stc_params {
	int count_to_reset_stc;
	int count_to_reset_cw;

	u64 stc_gap;
	u64 stc_up_bound;
	u64 stc_frequency;

	u64 diff_to_reset_count;
	u64 diff_to_increase_count;

	u8 pll_div_scale_alpha;
	u8 pll_div_scale_beta;

	u32 stc_cw;
	u32 stc_bypass_3_2;
};

struct stc_event {
	u64 new_stc;
	u64 timestamp;

	int (*get_stc_info)(
		struct dmx2_filter *dmx2_filter,
		void *data);

	int (*get_pcr_filter_cfg)(
		struct dmx2_filter *dmx2_filter,
		void *data);
	int (*set_pcr_filter_cfg)(
		struct dmx2_filter *dmx2_filter,
		void *data);
};

struct scrambling_status {
	enum dmx2_event_scramble_status status;
	enum scrambling_status_pos pos;
};

#define SECFLT_NMASK_FLD_ID			(17)

#define NULL_PID					(0x00001FFF)
#define NULL_PATH_ID				((u16)-1)
#define NULL_PACKET_ID				(0xFFFF)
#define NULL_IPFLT_ID				(0x1F)
#define SECFLT_PATTERN_DEPTH		(16)
#define STC_SYNTH_DEFAULT_CW		(0x28000000)
#define STC_SYNTH_DEFAULT_CW_TLV	(0x405F7E00)

#define OR_ADDR_SHIFT			(4)
#define PIDFLT_L_BASE			(0x210000)
#define PIDFLT_H_BASE			(0x210800)
#define PIDFLT_L_BASE1			(0x210400)
#define PIDFLT_H_BASE1			(0x210c00)
#define SECFLT_BASE_1			(0x211000)
#define SECFLT_BASE_2			(0x215000)
#define SECFLT_BASE_3			(0x220000)
#define SECFLT_BASE_EXT			(0x217000)
#define SECFLT_ENTRY_NUM		(16)
#define SECFLT_NMASK_DEPTH		(4)
#define PIDFLT_TLV_BASE			(0x240800)
#define IPFLT_BASE				(0x240000)
#define NTPFLT_BASE				(0x241000)
#define INVALID_CID				(0xFFF)

#define TLV_AV_SRC_TLV0	(1)
#define TLV_AV_SRC_TLV1	(2)
#define TLV_AV_SRC_TLV2	(3)
#define TLV_AV_SRC_DSC0	(4)
#define TLV_AV_SRC_DSC1	(5)
#define TLV_AV_SRC_DSC2	(6)

#define TLV_SEC_SRC_TSIF0  (1)
#define TLV_SEC_SRC_TSIF1  (2)
#define TLV_SEC_SRC_TSIF2  (3)
#define TLV_SEC_SRC_DSC0   (4)
#define TLV_SEC_SRC_DSC1   (5)
#define TLV_SEC_SRC_DSC2   (6)

#define PIDFLT_L_ADDR(id)		\
	((id < 128) ? (PIDFLT_L_BASE + (id) * 0x4) : \
				 (PIDFLT_L_BASE1 + ((id) - 128) * 0x4))

#define PIDFLT_H_ADDR(id)		\
	((id < 128) ? (PIDFLT_H_BASE + (id) * 0x4) : \
	(PIDFLT_H_BASE1 + ((id) - 128) * 0x4))

#define SECFLT_ADDR(id)				\
	({								\
		u16 idx;					\
		u32 addr;					\
									\
		if (id < 64) {				\
			idx = id;				\
			addr = SECFLT_BASE_1;	\
		} else if (id < 128) {		\
			idx = id - 64;			\
			addr = SECFLT_BASE_2;	\
		} else {					\
			idx = id - 128;			\
			addr = SECFLT_BASE_3;	\
		}							\
									\
		addr += (idx * 0x80);		\
	})


#define SECFLT_ADDR_EXT(id)		(SECFLT_BASE_EXT + (id * 0x80))
#define PIDFLT_TLV_ADDR(id)		(PIDFLT_TLV_BASE + (id * 0x4))
#define IPFLT_ADDR(id)			(IPFLT_BASE + (id * 0x80))
#define NTPFLT_ADDR(id)			(NTPFLT_BASE + (id * 0x80))

#define STC_ENGINE_ID_INVALID (-1)
#define STC_BASE_90KHZ (1)

#define STC_HIGH_OFFSET (sizeof(u32) << 3)
#define STC_L(u64_stc_val) \
	((u64_stc_val) & GET_MASK_U64(STC_HIGH_OFFSET))
#define STC_H(u64_stc_val) \
	((u32) (((u64_stc_val) >> STC_HIGH_OFFSET) & GET_MASK_U64(STC_HIGH_OFFSET)))
#define STC(stc_h, stc_l) \
	(((u64) (stc_l)) + (((u64) (stc_h)) << STC_HIGH_OFFSET))

void mtk_dmx_filter_init(bool bInitSW, struct mtk_dmx_rm *rm);
void mtk_dmx_filter_exit(void);
//suspend to ram
int mtk_dmx_filter_suspend(bool suspend, void *parg);

void mtk_dmx_pid_filter_init(u16 filter_id);
void mtk_dmx_pid_filter_set_pid(u16 filter_id, u16 pid);
u16 mtk_dmx_pid_filter_get_pid(u16 filter_id);
void mtk_dmx_pid_filter_sel_src(u16 filter_id, u16 path);
u16 mtk_dmx_pid_filter_get_src(u16 filter_id);
void mtk_dmx_pid_filter_sel_dst(
	u16 filter_id,
	enum filter_dst_type type,
	u16 idx,
	struct mtk_dmx_rm *rm);
enum filter_dst_type mtk_dmx_pid_filter_get_dst_type(u16 filter_id);
void mtk_dmx_pid_filter_rush_pass(u16 filter_id, bool bPass);
void mtk_dmx_pid_filter_set_srcid(u16 filter_id, u8 srcid);
void mtk_dmx_pid_filter_sel_secflt(u16 filter_id, u16 sec_filter_id);
void mtk_dmx_pid_filter_set_tlv_mode(u16 filter_id, enum filter_tlv_mode mode);
void mtk_dmx_pid_filter_set_ip_filter_id(u16 filter_id, u16 ip_filter_id);
bool mtk_dmx_pid_filter_packet_valid(struct mtk_dmx_rm *rm, u16 filter_id);
bool mtk_dmx_pid_filter_get_scmb_status(
		u16 filter_id,
		bool filein,
		struct scrambling_status *scrambling_status);
void mtk_dmx_pid_filter_clear_scmb_status(u16 filter_id);

void mtk_dmx_sec_filter_init(u16 filter_id, struct mtk_dmx_rm *rm);
bool mtk_dmx_sec_filter_set_pattern(u16 filter_id, u8 *pmask, u8 *pNmask, u8 *pmatch);
bool mtk_dmx_sec_filter_clear_pattern(u16 filter_id);
void mtk_dmx_sec_filter_set_type(u16 filter_id, enum filter_si_type type);
void mtk_dmx_sec_filter_set_mode(u16 filter_id, enum filter_si_mode mode);
void mtk_dmx_sec_filter_clear_ctrl(u16 filter_id);
void mtk_dmx_sec_filter_clear_req(u16 filter_id);

void mtk_dmx_sec_filter_start_addr(u16 filter_id, u64 *paddr, bool bSet);
void mtk_dmx_sec_filter_end_addr(u16 filter_id, u64 *paddr, bool bSet);
void mtk_dmx_sec_filter_read_addr(u16 filter_id, u64 *paddr, bool bSet);
void mtk_dmx_sec_filter_write_addr(u16 filter_id, u64 *paddr, bool bSet);
void mtk_dmx_sec_filter_reset_buffer(u16 filter_id, struct mtk_dmx_rm *rm);
void mtk_dmx_sec_filter_current_addr(u16 filter_id, u64 *paddr, bool bSet);

// Bit width of the MMTP section message's length field.
void mtk_dmx_sec_filter_length_field_width(u16 filter_id, u32 width);

void mtk_dmx_sec_filter_dma_ctrl(u16 filter_id, bool start);
void mtk_dmx_set_sec_src_tlv(u16 path_id, bool set_src);

void mtk_dmx_pcr_filter_init(u16 filter_id);
void mtk_dmx_pcr_filter_sel_src(u16 filter_id, u16 path);
u16 mtk_dmx_pcr_filter_get_src(u16 filter_id);
void mtk_dmx_pcr_filter_set_srcid(u16 filter_id, u8 srcid);
void mtk_dmx_pcr_filter_pid(u16 filter_id, u16 *pPID, bool bSet);
void mtk_dmx_pcr_filter_get_PCR(u16 filter_id, u32 *pPCR_base, u32 *pPCR_base_32);
void mtk_dmx_pcr_filter_enable(u16 filter_id, bool bEnable);

void mtk_dmx_tlv_ip_filter_init(int filter_id);
void mtk_dmx_tlv_ip_filter_set_ip(int filter_id, struct dmx2_ip_addr *ip_addr);
void mtk_dmx_tlv_ip_filter_set_src(int filter_id, int path);
void mtk_dmx_tlv_ip_filter_set_enable(int filter_id, bool enable);
void mtk_dmx_tlv_ip_filter_set_cid(int filter_id, bool enable, bool hw_update, int cid);
u32 mtk_dmx_tlv_ip_filter_get_cid(int filter_id);

void mtk_dmx_tlv_ntp_filter_init(int path);
void mtk_dmx_tlv_ntp_filter_set_ip(int path, struct dmx2_ip_addr *ip_addr);
u64  mtk_dmx_tlv_get_ntp(int path, u8 *leap_ind);
void mtk_dmx_tlv_ntp_read(int path, bool enable);

void mtk_dmx_stc_cw(u16 eng_id, u32 *pcw, bool bypass_3_2, bool bSet);
void mtk_dmx_stc(u16 eng_id, u32 *pSTC_L, u32 *pSTC_H, bool bSet);
void mtk_dmx_stc_set_mode(u16 eng_id, enum stc_mode mode);
void mtk_dmx_stc_bypass_3_2(u16 eng_id, bool bBypass_3_2);

void mtk_dmx_set_fifo_src(enum filter_dst_type type, u16 idx, u16 path_id);

void mtk_dmx_stc_dump_params(
		const char *ftrace_tag,
		struct stc_params *stc_params);

void mtk_dmx_set_aeon_dmaw_protect(u64 lbound_paddr, u64 hbound_paddr, bool bSet);

#endif /* MTK_DMX_FILTER_H */
