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

#include "alp_priv_packet_custom_0.h"

#include "bits_op.h"
#include "atsc30_utils.h"
#include "atsc30_log.h"

//-------------------------------------------------------------------------------------------------
//  Debug Constants and Macros
//-------------------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------------------
//  Constants
//-------------------------------------------------------------------------------------------------
#define CUSTOM_0_EXTENSION_TYPE_PTP		(0xF0)
#define CUSTOM_0_EXTENSION_TYPE_PLP_ID		(0xF1)

#define CUSTOM_0_EXTENSION_PLP_ID_LENGTH_MINUS_1 \
	(0x0)
#define CUSTOM_0_EXTENSION_PTP_LENGTH_MINUS_1	(0x7)

#define CUSTOM_0_EXTENSION_PLP_ID_SHIFT		(2)
#define CUSTOM_0_EXTENSION_PLP_ID_WIDTH		(6)
#define CUSTOM_0_EXTENSION_PTP_TIME_INFO_FLAG_SHIFT \
	(6)
#define CUSTOM_0_EXTENSION_PTP_TIME_INFO_FLAG_WIDTH \
	(2)

#define CUSTOM_0_EXTENSION_SEC_WIDTH 		(32)

//-------------------------------------------------------------------------------------------------
//  Macros
//-------------------------------------------------------------------------------------------------
#define CUSTOM_0_EXTENSION_GET(field_name, data) \
	ALP_GET_FIELD_U32( \
		data, \
		CUSTOM_0_EXTENSION_## field_name ##_WIDTH, \
		CUSTOM_0_EXTENSION_## field_name ##_SHIFT)

#define CUSTOM_0_EXTENSION_GET_PLP_ID(data) \
	CUSTOM_0_EXTENSION_GET(PLP_ID, data)

#define CUSTOM_0_EXTENSION_GET_PTP_TIME_INFO_FLAG(data) \
	CUSTOM_0_EXTENSION_GET(PTP_TIME_INFO_FLAG, data)

#define CUSTOM_0_EXTENSION_GET_PTP_TIME_SEC(byte0, byte1, byte2, byte3, byte4) \
	((((u32)ALP_GET_BITS_0_5(byte0)) << (8 * 3 + 2)) | \
	 (((u32)ALP_GET_BYTE(byte1)) << (8 * 2 + 2)) | \
	 (((u32)ALP_GET_BYTE(byte2)) << (8 * 1 + 2)) | \
	 (((u32)ALP_GET_BYTE(byte3)) << (8 * 0 + 2)) | \
	 (((u32)ALP_GET_BITS_6_7(byte4))))

#define CUSTOM_0_EXTENSION_GET_PTP_TIME_MSEC(byte0, byte1) \
	((((u32)ALP_GET_BITS_0_5(byte0)) << (4)) | \
	 (((u32)ALP_GET_BITS_4_7(byte1))))

#define CUSTOM_0_EXTENSION_GET_PTP_TIME_USEC(byte0, byte1) \
	((((u32)ALP_GET_BITS_0_3(byte0)) << (6)) | \
	 (((u32)ALP_GET_BITS_2_7(byte1))))

#define CUSTOM_0_EXTENSION_GET_PTP_TIME_NSEC(byte0, byte1) \
	((((u32)ALP_GET_BITS_0_1(byte0)) << (8 * 1)) | \
	 (((u32)ALP_GET_BYTE(byte1))))

//-------------------------------------------------------------------------------------------------
//  Structs and Enums
//-------------------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------------------
//  Functions Prototype
//-------------------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------------------
//  Variables
//-------------------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------------------
//  Internal Functions
//-------------------------------------------------------------------------------------------------
static bool custom_0_is_plp_id_pkt(const alp_header_t *alp_hdr)
{
	if (alp_priv_packet_is_pud_packet(alp_hdr)
		&& (alp_hdr->add_hdr.header_mode.hdr_ext.extension_type
			== CUSTOM_0_EXTENSION_TYPE_PLP_ID)
		&& (alp_hdr->add_hdr.header_mode.hdr_ext.extension_length_minus1
			== CUSTOM_0_EXTENSION_PLP_ID_LENGTH_MINUS_1))
		return true;

	return false;
}

static bool custom_0_is_ptp_pkt(const alp_header_t *alp_hdr)
{
	if (alp_priv_packet_is_pud_packet(alp_hdr)
		&& (alp_hdr->add_hdr.header_mode.hdr_ext.extension_type
			== CUSTOM_0_EXTENSION_TYPE_PTP)
		&& (alp_hdr->add_hdr.header_mode.hdr_ext.extension_length_minus1
			== CUSTOM_0_EXTENSION_PTP_LENGTH_MINUS_1))
		return true;

	return false;
}

//-------------------------------------------------------------------------------------------------
//  Public Functions
//-------------------------------------------------------------------------------------------------
enum alp_priv_packet_pud_packet_type
alp_priv_packet_custom_0_get_pud_packet_type(const alp_header_t *alp_hdr)
{
	enum alp_priv_packet_pud_packet_type
		pud_packet_type = ALP_PRIV_PACKET_PUD_PACKET_TYPE_UNKNOWN;

	if (custom_0_is_plp_id_pkt(alp_hdr))
		pud_packet_type = ALP_PRIV_PACKET_PUD_PACKET_TYPE_PLP_ID;
	else if (custom_0_is_ptp_pkt(alp_hdr))
		pud_packet_type = ALP_PRIV_PACKET_PUD_PACKET_TYPE_PTP;

	return pud_packet_type;
}

u8 alp_priv_packet_custom_0_parse_plp_id(
		const alp_header_t *alp_hdr)
{
	u8 plp_id = 0x0FF;

	plp_id = CUSTOM_0_EXTENSION_GET_PLP_ID(
			alp_hdr->add_hdr.header_mode.hdr_ext.extension_bytes[0]);

	return plp_id;
}

int alp_priv_packet_custom_0_parse_ptp(
		const alp_header_t *alp_hdr,
		struct time_info *time_info)
{
	const u8 *ext_bytes = NULL;
	int i = 0;

	if (ALP_PARSER_VERIFY(alp_hdr == NULL))
		return ALP_NULL_PTR;
	if (ALP_PARSER_VERIFY(time_info == NULL))
		return ALP_NULL_PTR;

	ext_bytes = alp_hdr->add_hdr.header_mode.hdr_ext.extension_bytes;
	time_info->time_info_flag =
		CUSTOM_0_EXTENSION_GET_PTP_TIME_INFO_FLAG(ext_bytes[0]);

	ALP_PARSER_LOG_DEBUG(
		"PTP raw Data Dump: ");
	for (i = 0; i <= CUSTOM_0_EXTENSION_PTP_LENGTH_MINUS_1; i++)
		ALP_PARSER_LOG_DEBUG(
			"0x%02X ",
			ext_bytes[i]);
	ALP_PARSER_LOG_DEBUG(
		"\n");

	time_info->sec =
		CUSTOM_0_EXTENSION_GET_PTP_TIME_SEC(
			ext_bytes[0],
			ext_bytes[1],
			ext_bytes[2],
			ext_bytes[3],
			ext_bytes[4]);

	time_info->msec =
		CUSTOM_0_EXTENSION_GET_PTP_TIME_MSEC(
			ext_bytes[4],
			ext_bytes[5]);

	time_info->usec =
		CUSTOM_0_EXTENSION_GET_PTP_TIME_USEC(
			ext_bytes[5],
			ext_bytes[6]);

	time_info->nsec =
		CUSTOM_0_EXTENSION_GET_PTP_TIME_NSEC(
			ext_bytes[6],
			ext_bytes[7]);

	return ALP_SUCCESS;
}

u64 alp_priv_packet_custom_0_get_stc_up_bound(u64 frequency) {
	return (((u64)1) << CUSTOM_0_EXTENSION_SEC_WIDTH) * frequency;
}
