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

#ifndef ATSC30_ALP_HAL_FW_DESC_H
#define ATSC30_ALP_HAL_FW_DESC_H
#include <linux/types.h>

#include "bits_op.h"

// DescWord0
#define ALP_DESC_FW_NOTIFY_PACKET_TYPE_SHIFT	(8 * 0)
#define ALP_DESC_FW_NOTIFY_PACKET_TYPE_WIDTH	(8)
#define ALP_DESC_PLP_ID_SHIFT			(8 * 1)
#define ALP_DESC_PLP_ID_WIDTH			(8)
#define ALP_DESC_MAX_CID_SHIFT			(8 * 2)
#define ALP_DESC_MAX_CID_WIDTH			(8)
#define ALP_DESC_LAST_INDICATOR_FLAG_SHIFT	(8 * 3 + 2)
#define ALP_DESC_LAST_INDICATOR_FLAG_WIDTH	(1)
#define ALP_DESC_SEQ_NO_SHIFT			(8 * 3 + 3)
#define ALP_DESC_SEQ_NO_WIDTH			(5)
//  DescWord1
#define ALP_DESC_STREAM_IDX_SHIFT		(8 * 0)
#define ALP_DESC_STREAM_IDX_WIDTH		(8)
#define ALP_DESC_PUD_TYPE_SHIFT			(8 * 1)
#define ALP_DESC_PUD_TYPE_WIDTH			(8)
// DescWord4
#define ALP_DESC_TIMESTAMP_SHIFT		(8 * 0)
#define ALP_DESC_TIMESTAMP_WIDTH		(8 * 4)

// DescWord0
#define ALP_DESC_FW_NOTIFY_PACKET_TYPE_MASK \
	ALP_GET_MASK_U32(ALP_DESC_FW_NOTIFY_PACKET_TYPE_WIDTH)
#define ALP_DESC_PLP_ID_MASK \
	ALP_GET_MASK_U32(ALP_DESC_PLP_ID_WIDTH)
#define ALP_DESC_MAX_CID_MASK \
	ALP_GET_MASK_U32(ALP_DESC_MAX_CID_WIDTH)
#define ALP_DESC_LAST_INDICATOR_FLAG_MASK \
	ALP_GET_MASK_U32(ALP_DESC_LAST_INDICATOR_FLAG_WIDTH)
#define ALP_DESC_SEQ_NO_MASK \
	ALP_GET_MASK_U32(ALP_DESC_SEQ_NO_WIDTH)
//  DescWord1
#define ALP_DESC_STREAM_IDX_MASK \
	ALP_GET_MASK_U32(ALP_DESC_STREAM_IDX_WIDTH)
#define ALP_DESC_PUD_TYPE_MASK \
	ALP_GET_MASK_U32(ALP_DESC_PUD_TYPE_WIDTH)
//  DescWord4
#define ALP_DESC_TIMESTAMP_MASK \
	ALP_GET_MASK_U32(ALP_DESC_TIMESTAMP_WIDTH)

#define ALP_DESC_GET(field_name, data) \
	ALP_GET_FIELD_U32( \
		data, \
		ALP_DESC_## field_name ##_WIDTH, \
		ALP_DESC_## field_name ##_SHIFT)
// DescWord0
#define ALP_DESC_GET_FW_NOTIFY_PACKET_TYPE(data) \
	ALP_DESC_GET(FW_NOTIFY_PACKET_TYPE, data)
#define ALP_DESC_GET_PLP_ID(data) \
	ALP_DESC_GET(PLP_ID, data)
#define ALP_DESC_GET_MAX_CID(data) \
	ALP_DESC_GET(MAX_CID, data)
#define ALP_DESC_GET_LAST_INDICATOR_FLAG(data) \
	ALP_DESC_GET(LAST_INDICATOR_FLAG, data)
#define ALP_DESC_GET_SEQ_NO(data) \
	ALP_DESC_GET(SEQ_NO, data)
//DescWord1
// stream_idx is the filter_id provided to HW when filter is configured.
#define ALP_DESC_GET_STREAM_IDX(data) \
	ALP_DESC_GET(STREAM_IDX, data)
#define ALP_DESC_GET_PUD_TYPE(data) \
	ALP_DESC_GET(PUD_TYPE, data)
//DescWord4
#define ALP_DESC_GET_TIMESTAMP(data) \
	ALP_DESC_GET(TIMESTAMP, data)

#define ALP_PACKET_TYPE_BIT			(0xE0)
#define ALP_PAYLOAD_CONFIGURATION_BIT		(0x10)
#define ALP_HEADER_MODE_BIT			(0x08)
#define ALP_SEGMENTATION_CONCATENATION_BIT	(0x08)
#define ALP_PAYLOAD_LENGTH_BIT			(0x07FF)
#define ALP_SINGLE_HEADER_BYTE			(2)
#define ALP_ADD_HEADER_MSB_BIT			(0xF8)
#define ALP_ADD_HEADER_RESERVED_BIT		(0x04)
#define ALP_ADD_HEADER_SIF_BIT			(0x02)
#define ALP_ADD_HEADER_HEF_BIT			(0x01)
#define ALP_FW_DESCRIPTOR_LENGTH		(16UL)

#define ALP_FW_IS_COMP_PACKET(t) \
	((t == FW_NFY_PKT_TYPE_COMP_IP) \
		|| ((t) == FW_NFY_PKT_TYPE_SEG_COMP_IP))

enum {
	DESC_WORD_0 = 0,
	DESC_WORD_1,
	DESC_WORD_PACKET_END,
#ifdef CONFIG_64BIT
	DESC_WORD_PACKET_START = DESC_WORD_PACKET_END + 2, // u32x2
	DESC_WORD_TIMESTAMP = DESC_WORD_PACKET_START + 2, // u32x2
	DESC_WORD_MAX,
#else
	DESC_WORD_PACKET_START,
	DESC_WORD_TIMESTAMP,
	DESC_WORD_MAX,
#endif //#ifdef CONFIG_64BIT

	DESC_WORD_NULL = -1,

	DESC_WORD_SEG_INFO = DESC_WORD_0,
	DESC_WORD_MAX_CID = DESC_WORD_0,
	DESC_WORD_PLP_ID = DESC_WORD_0,
	DESC_WORD_FW_PKT_TYPE = DESC_WORD_0,

	DESC_WORD_PUD_TYPE = DESC_WORD_1,
	DESC_WORD_STREAM_IDX = DESC_WORD_1,
};

typedef enum {
	FW_NFY_PKT_TYPE_RESERVED  = 0x0,
	FW_NFY_PKT_TYPE_IP = 0x1,
	FW_NFY_PKT_TYPE_COMP_IP  = 0x2,
	FW_NFY_PKT_TYPE_ALP_LLS = 0x3,
	FW_NFY_PKT_TYPE_SEG_IP = 0x4,
	FW_NFY_PKT_TYPE_NET_PKT_ALP = 0x5,
	FW_NFY_PKT_TYPE_PUD_ALP = 0x6,	//Private User Defined ALP
	FW_NFY_PKT_TYPE_SEG_COMP_IP = 0x7,
	FW_NFY_PKT_TYPE_MAX,

	FW_NFY_PKT_TYPE_NULL = -1,
} alp_fw_notify_packet_type_t;

struct alp_fw_packet_descriptor {
	u8	plp_id;
	u8	max_cid;
	u8	strm_idx;
	bool   last_seg_indicator;
	u8	seg_num;
	u8	pud_type;
	u32	timestamp;
	alp_fw_notify_packet_type_t fw_nfy_pkt_type;
	uintptr_t pkt_start;
	uintptr_t pkt_end;
};

alp_fw_notify_packet_type_t alp_desc_extract_fw_notify_packet_type(
		const u32 *data);
u8 alp_desc_extract_plp_id(const u32 *data);
u8 alp_desc_extract_comp_rohc_max_cid(const u32 *data);
u8 alp_desc_extract_segment_seg_seq_no(const u32 *data);
bool alp_desc_extract_segment_last_indicator_flag(const u32 *data);
u8 alp_desc_extract_stream_idx(const u32 *data);
u8 alp_desc_extract_pud_type(const u32 *data);
u32 alp_desc_extract_timestamp(const u32 *data);

struct alp_fw_packet_descriptor alp_desc_parse_descriptor(
		const uintptr_t addr_1,
		size_t addr_len_1,
		const uintptr_t addr_2,
		size_t addr_len_2);

void alp_desc_dump_descriptor(
		int log_level,
		struct alp_fw_packet_descriptor *descriptor);

#endif /* ATSC30_ALP_HAL_FW_DESC_H */
