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

#include <linux/types.h>
#include <linux/kthread.h>

#include "alp_hal_if.h"
#include "alp_hal_internal.h"
#include "alp_lmt.h"
#include "atsc30_log.h"
#include "atsc30_utils.h"

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

//-------------------------------------------------------------------------------------------------
//  Constants
//-------------------------------------------------------------------------------------------------
// TODO: remove dependency of "atsc30_adap/mdrv_atsc30_if.h"
#define MDRV_ATSC30_RETURN_CODE_OK (0)

//-------------------------------------------------------------------------------------------------
//  Macros
//-------------------------------------------------------------------------------------------------
#define ALP_HAL_IF_LOCK(framer_idx) \
	mutex_lock(&alp_hal_if_lock)
#define ALP_HAL_IF_UNLOCK(framer_idx) \
	mutex_unlock(&alp_hal_if_lock)

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

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

//-------------------------------------------------------------------------------------------------
//  Variables
//-------------------------------------------------------------------------------------------------
static DEFINE_MUTEX(alp_hal_if_lock);

//-------------------------------------------------------------------------------------------------
//  Internal Functions
//-------------------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------------------
//  Public Functions
//-------------------------------------------------------------------------------------------------
bool alp_hal_if_init(
		const u8 framer_idx,
		const alp_hal_frontend_input_packet_type fe_input_pkt_type,
		const alp_hal_framer_mode_t hw_mode,
		const alp_hal_fw_config_t fw_cfg,
		const u32 hw_cfg_flags)
{
	bool ret;

	ALP_HAL_IF_LOCK(framer_idx);

	ret = alp_hal_priv_init_context(
		framer_idx,
		fe_input_pkt_type,
		hw_mode,
		fw_cfg,
		hw_cfg_flags);

	ALP_HAL_IF_UNLOCK(framer_idx);

	return ret;
}

bool alp_hal_if_deinit(u8 framer_idx)
{
	bool ret;

	ALP_HAL_IF_LOCK(framer_idx);

	ret = alp_hal_priv_deinit_context(framer_idx);

	ALP_HAL_IF_UNLOCK(framer_idx);

	return ret;
}

//-----------------------------------------------------------------------------
/** alp_hal_if_handle_packet
 *	Check Firmware(ucode) alp packet buffer and info buffer full
 *	and SW handle alp interrupt message queue
 *
 *	@retval bool - true: Full false: Not Full
 *	NOTE:
 */
//-----------------------------------------------------------------------------
bool alp_hal_if_handle_packet(
		u8 framer_idx,
		const uintptr_t addr_1,
		size_t addr_len_1,
		const uintptr_t addr_2,
		size_t addr_len_2)
{
	int ret = 0;
	alp_hal_context_t *a30_ctx = alp_hal_priv_get_hal_context(framer_idx);
	struct alp_fw_packet_descriptor desc = { .fw_nfy_pkt_type = FW_NFY_PKT_TYPE_RESERVED };
	struct atsc30_profile profile = {
		.log_level = A30_DBG_LVL_INFO,
		.log_module = ATSC30_LOG_MODULE_HAL,
		.log_prefix = __func__,
		.log_us = ATSC30_PROFILE_LOG_US_DEFAULT,
	};

	if (ALP_HAL_VERIFY(a30_ctx == NULL))
		return false;
	if (!a30_ctx->valid) {
		ALP_HAL_LOG_INFO("%s, No valid context\n", __func__);
		return true;
	}

	ALP_HAL_LOG_DEBUG(
		"addr_1 = 0x%llx\n",
		(u64)addr_1);
	ALP_HAL_LOG_DEBUG(
		"addr_len_1 = 0x%zx\n",
		addr_len_1);
	ALP_HAL_LOG_DEBUG(
		"addr_2 = 0x%llx\n",
		(u64)addr_2);
	ALP_HAL_LOG_DEBUG(
		"addr_len_2 = 0x%zx\n",
		addr_len_2);

	atsc30_profile_get_begin_time(&profile);
	// must be promise: a descriptor mapping to an alp packet
	desc = alp_desc_parse_descriptor(addr_1, addr_len_1, addr_2, addr_len_2);

#ifdef ALP_HAL_USE_PLP_CONTEXT_0_AS_SINGLE_PLP_MODE
	if (a30_ctx->plp_cnt == 1) {
		//For Single PLP case, HW does not record  PLP ID info as no plp_id packet
		//notified from Physical layer -> Link Layer, Driver need to set it properly
		desc.plp_id = a30_ctx->plp_id[0];
		ALP_HAL_LOG_DEBUG(
			"For Single PLP case, use a30_ctx->plp_id[0] = 0x%x instead\n",
			a30_ctx->plp_id[0]);
	}
#endif //ALP_HAL_USE_PLP_CONTEXT_0_AS_SINGLE_PLP_MODE

	ATSC30_PROFILE_GET_END_TIME(&profile);
	if (!alp_hal_priv_handle_fw_packet(framer_idx, &desc))
		ALP_HAL_LOG_ENHANCED_WARN(
			"alp_hal_priv_handle_fw_packet is failed\n");

	ATSC30_PROFILE_GET_END_TIME(&profile);
	ret = a30_ctx->desc_buf_update_rp_by_size(framer_idx, (addr_len_1 + addr_len_2));
	if (ret != MDRV_ATSC30_RETURN_CODE_OK) {
		ALP_HAL_LOG_ENHANCED_WARN(
			"update ring buf rp by size 0x%zx, fail\n",
			(addr_len_1 + addr_len_2));
	}
	ATSC30_PROFILE_GET_END_TIME(&profile);

	return (ret == MDRV_ATSC30_RETURN_CODE_OK);
}

void alp_hal_if_reset_stream_filters(u8 framer_idx)
{
	ALP_HAL_IF_LOCK(framer_idx);

	alp_hal_priv_reset_stream_filters(framer_idx);

	ALP_HAL_IF_UNLOCK(framer_idx);
}

alp_stream_ID alp_hal_if_set_stream_filter(
		u8 framer_idx,
		const alp_stream_t *const strm)
{
	u8 strm_id = INVALID_ALP_STREAM_ID;

	if (ALP_HAL_VERIFY(strm == NULL))
		return INVALID_ALP_STREAM_ID;

	ALP_HAL_IF_LOCK(framer_idx);

	strm_id = alp_hal_priv_set_stream_filter(framer_idx, strm);

	ALP_HAL_IF_UNLOCK(framer_idx);

	return strm_id;
}

bool alp_hal_if_set_plp_id_filter(
		u8 framer_idx,
		const u8 *const plp_id_arr,
		u8 plp_cnt)
{
	bool ret = false;

	if (ALP_HAL_VERIFY(plp_id_arr == NULL))
		return false;

	ALP_HAL_IF_LOCK(framer_idx);

	ret = alp_hal_priv_set_plp_id_filter(
		framer_idx,
		plp_id_arr,
		plp_cnt);

	ALP_HAL_IF_UNLOCK(framer_idx);

	return ret;
}

bool alp_hal_if_clear_plp_id_filter(
		u8 framer_idx,
		const u8 *const plp_id_arr,
		u8 plp_cnt)
{
	bool ret = false;

	if (ALP_HAL_VERIFY(plp_id_arr == NULL))
		return false;

	ALP_HAL_IF_LOCK(framer_idx);

	ret = alp_hal_priv_clear_plp_id_filter(
		framer_idx,
		plp_id_arr,
		plp_cnt);

	ALP_HAL_IF_UNLOCK(framer_idx);

	return ret;
}

bool alp_hal_if_clear_all_plp_id_filters(
		u8 framer_idx)
{
	bool ret = false;

	ALP_HAL_IF_LOCK(framer_idx);

	ret = alp_hal_priv_clear_all_plp_id_filters(framer_idx);

	ALP_HAL_IF_UNLOCK(framer_idx);

	return ret;
}

u8 alp_hal_if_get_plp_num(
		u8 framer_idx)
{
	u8 plp_num = (MAX_PLP_NUMBER_SUPPORTED + 1);

	ALP_HAL_IF_LOCK(framer_idx);

	plp_num = alp_hal_priv_get_plp_num(framer_idx);

	ALP_HAL_IF_UNLOCK(framer_idx);

	return plp_num;
}

bool alp_hal_if_get_plp_id(
		u8 framer_idx,
		u8 *plp_id_arr,
		u8 plp_cnt_max)
{
	bool ret = false;

	ALP_HAL_IF_LOCK(framer_idx);

	ret = alp_hal_priv_get_plp_id(
		framer_idx,
		plp_id_arr,
		plp_cnt_max);

	ALP_HAL_IF_UNLOCK(framer_idx);

	return ret;
}

void alp_hal_if_alp_packet_msg_dump(
		int log_level,
		alp_packet_msg_t *msg)
{
	if (ALP_HAL_VERIFY(msg == NULL))
		return;

	ALP_HAL_LOG(
		log_level,
		"addr_1 = 0x%llx\n",
		(u64)msg->addr_1);
	ALP_HAL_LOG(
		log_level,
		"addr_len_1 = 0x%zx\n",
		msg->addr_len_1);
	ALP_HAL_LOG(
		log_level,
		"addr_2 = 0x%llx\n",
		(u64)msg->addr_2);
	ALP_HAL_LOG(
		log_level,
		"addr_len_2 = 0x%zx\n",
		msg->addr_len_2);

}
