/******************************************************************************
* Copyright (C) 2019 - 2022 Xilinx, Inc.  All rights reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/


/*****************************************************************************/
/**
* @file xaiegbl.c
* @{
*
* This file contains the global initialization functions for the Tile.
* This is applicable for both the AIE tiles and Shim tiles.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver   Who     Date     Changes
* ----- ------  -------- -----------------------------------------------------
* 1.0   Tejus   09/24/2019  Initial creation
* 1.1   Tejus   10/22/2019  Enable AIE initilization
* 1.2   Tejus   06/09/2020  Call IO init api from XAie_CfgInitialize
* 1.3   Tejus   06/10/2020  Add api to change backend at runtime.
* 1.4   Dishita 07/28/2020  Add api to turn ECC On and Off.
* 1.5   Nishad  09/15/2020  Add check to validate XAie_MemCacheProp value in
*			    XAie_MemAllocate().
* </pre>
*
******************************************************************************/

/***************************** Include Files *********************************/
#include <string.h>
#include <stdlib.h>

#include "xaie_helper.h"
#include "xaie_io.h"
#include "xaie_rsc_internal.h"
#include "xaiegbl.h"
#include "xaiegbl_defs.h"
#include "xaiegbl_regdef.h"

/************************** Constant Definitions *****************************/

/**************************** Type Definitions *******************************/

/**************************** Macro Definitions ******************************/
#define XAIE_ECC_BROADCAST_ID		6U

/************************** Variable Definitions *****************************/
extern XAie_TileMod AieMod[XAIEGBL_TILE_TYPE_MAX];
extern XAie_TileMod AieMlMod[XAIEGBL_TILE_TYPE_MAX];

extern XAie_DeviceOps AieDevOps;
extern XAie_DeviceOps AieMlDevOps;

extern u8 XAieDevType;

#if XAIE_DEV_SINGLE_GEN == XAIE_DEV_GEN_AIEML
#define XAIE_DEV_SINGLE_MOD AieMlMod
#define XAIE_DEV_SINGLE_DEVOPS AieMlDevOps
#elif XAIE_DEV_SINGLE_GEN == XAIE_DEV_GEN_AIE
#define XAIE_DEV_SINGLE_MOD AieMod
#define XAIE_DEV_SINGLE_DEVOPS AieDevOps
#else
#ifdef XAIE_DEV_SINGLE_GEN
#error "Unsupported device defined."
#endif
#endif

/************************** Function Definitions *****************************/
/*****************************************************************************/
/**
*
* This API is to set up AI engine partition instance location and size.
*
* @param	Inst: Pointer of AI engine partition instance
* @param	PartBaseAddr: Partition base address
* @param	PartStartCol: Absolute partition start column
* @param	PartNumCols: number of columns of the partition
*
* @return	XAIE_OK.
*
* @note		If this API is not called, the AI engine partition instance
*		uses the base address and the number of columns from the device
*		config (XAie_Config), and the start column is 0 by default.
*		This function do not verify the PartBaseAddr, PartStartCol,
*		or the PartNumcols. The PartStartCol and the PartNumCols will
*		be validated in XAie_CfgInitialize().
*		This functions is supposed to be called before
*		XAie_CfgInitialize().
*
*******************************************************************************/
AieRC XAie_SetupPartitionConfig(XAie_DevInst *DevInst,
		u64 PartBaseAddr, u8 PartStartCol, u8 PartNumCols)
{
	if (DevInst == XAIE_NULL || DevInst->IsReady) {
		XAIE_ERROR("Invalid Device instance to set part config.\n");
		return XAIE_INVALID_DEVICE;
	}

	DevInst->BaseAddr = PartBaseAddr;
	DevInst->StartCol = PartStartCol;
	DevInst->NumCols = PartNumCols;

	return XAIE_OK;
}

/*****************************************************************************/
/**
*
* This is the global initialization function for all the tiles of the AIE array
* The function sets up the Device Instance pointer with the appropriate values
* from the ConfigPtr.
*
* @param	InstPtr - Global AIE instance structure.
* @param	ConfigPtr - Global AIE configuration pointer.
*
* @return	XAIE_OK on success and error code on failure
*
* @note		This function needs to be called before calling any other AI
*		engine functions. After this function, as all tiles are gated
*		after system boots, XAie_PmRequestTiles() needs to be called
*		before calling other functions, otherwise, other functions
*		may access gated tiles.
*
******************************************************************************/
AieRC XAie_CfgInitialize(XAie_DevInst *InstPtr, XAie_Config *ConfigPtr)
{
	AieRC RC;

	if((InstPtr == XAIE_NULL) || (ConfigPtr == XAIE_NULL)) {
		XAIE_ERROR("Invalid input arguments\n",
				XAIE_INVALID_ARGS);
		return XAIE_INVALID_ARGS;
	}

	if (InstPtr->IsReady) {
		return XAIE_OK;
	}

	/* Initialize device property according to Device Type */
#ifdef XAIE_DEV_SINGLE_GEN
	if (ConfigPtr->AieGen == XAIE_DEV_SINGLE_GEN) {
		InstPtr->DevProp.DevMod = XAIE_DEV_SINGLE_MOD;
		InstPtr->DevProp.DevGen = XAIE_DEV_SINGLE_GEN;
		InstPtr->DevOps = &XAIE_DEV_SINGLE_DEVOPS;
#else
	if(ConfigPtr->AieGen == XAIE_DEV_GEN_AIEML) {
		InstPtr->DevProp.DevMod = AieMlMod;
		InstPtr->DevProp.DevGen = XAIE_DEV_GEN_AIEML;
		InstPtr->DevOps = &AieMlDevOps;
	} else if((ConfigPtr->AieGen == XAIE_DEV_GEN_AIE) ||
			(ConfigPtr->AieGen == XAIE_DEV_GEN_S100) ||
			(ConfigPtr->AieGen == XAIE_DEV_GEN_S200)) {
		InstPtr->DevProp.DevMod = AieMod;
		InstPtr->DevProp.DevGen = XAIE_DEV_GEN_AIE;
		InstPtr->DevOps = &AieDevOps;
		XAieDevType = ConfigPtr->AieGen;
#endif
	} else {
		XAIE_ERROR("Invalid device\n",
				XAIE_INVALID_DEVICE);
		return XAIE_INVALID_DEVICE;
	}

	if(InstPtr->NumCols == 0) {
		InstPtr->BaseAddr = ConfigPtr->BaseAddr;
		InstPtr->StartCol = 0;
		InstPtr->NumCols = ConfigPtr->NumCols;
	} else if((u32)InstPtr->StartCol + (u32)InstPtr->NumCols >
			(u32)ConfigPtr->NumCols) {
		XAIE_ERROR("Invalid Partition location or size.\n");
		return XAIE_INVALID_DEVICE;
	}

	InstPtr->IsReady = XAIE_COMPONENT_IS_READY;
	InstPtr->DevProp.RowShift = ConfigPtr->RowShift;
	InstPtr->DevProp.ColShift = ConfigPtr->ColShift;
	InstPtr->NumRows = ConfigPtr->NumRows;
	InstPtr->ShimRow = ConfigPtr->ShimRowNum;
	InstPtr->MemTileRowStart = ConfigPtr->MemTileRowStart;
	InstPtr->MemTileNumRows = ConfigPtr->MemTileNumRows;
	InstPtr->AieTileRowStart = ConfigPtr->AieTileRowStart;
	InstPtr->AieTileNumRows = ConfigPtr->AieTileNumRows;
	InstPtr->EccStatus = XAIE_ENABLE;
	InstPtr->TxnList.Next = NULL;

	RC = _XAie_RscMgrInit(InstPtr);
	if(RC != XAIE_OK) {
		return RC;
	}

	memcpy(&InstPtr->PartProp, &ConfigPtr->PartProp,
		sizeof(ConfigPtr->PartProp));

	RC = XAie_IOInit(InstPtr);
	if(RC != XAIE_OK) {
		return RC;
	}

	return XAIE_OK;
}

#if !defined(XAIE_FEATURE_LITE) && defined(XAIE_FEATURE_PRIVILEGED_ENABLE)
/*****************************************************************************/
/**
*
* This is the api to initialize the AI engine partition. It will initialize the
* AI engine partition hardware.
*
* @param	DevInst - Global AIE device instance pointer.
* @param	Opts - AI engine partition initialization options.
*			If @Opts is NULL, it will do the default options without
*			clock gating. The default options will:
*			* reset columns,
*			* reset shims,
*			* set to block NOC AXI MM decode and slave errors
*			* setup isolation
*			If @Opts is not NULL, it will follow the set bits of the
*			InitOpts field, the available options are as follows:
*			* XAIE_PART_INIT_OPT_DEFAULT
*			* XAIE_PART_INIT_OPT_COLUMN_RST
*			* XAIE_PART_INIT_OPT_SHIM_RST
*			* XAIE_PART_INIT_OPT_BLOCK_NOCAXIMMERR
*			* XAIE_PART_INIT_OPT_ISOLATE
*			* XAIE_PART_INIT_OPT_ZEROIZEMEM (not on by default)
*
* @return	XAIE_OK on success and error code on failure.
*
* @note		None.
*
******************************************************************************/
AieRC XAie_PartitionInitialize(XAie_DevInst *DevInst, XAie_PartInitOpts *Opts)
{
	AieRC RC;

	if((DevInst == XAIE_NULL) ||
			(DevInst->IsReady != XAIE_COMPONENT_IS_READY)) {
		XAIE_ERROR("Invalid Device Instance\n");
		return XAIE_INVALID_ARGS;
	}

	RC = XAie_RunOp(DevInst, XAIE_BACKEND_OP_PARTITION_INITIALIZE,
			(void *)Opts);
	if (RC != XAIE_OK) {
		XAIE_ERROR("Failed to initialize partition.\n");
		return RC;
	}

	return XAIE_OK;
}

/*****************************************************************************/
/**
*
* This is the api to teardown the AI engine partition. It will initialize
* the AI engine partition hardware.
*
* @param	DevInst - Global AIE device instance pointer.
*
* @return	XAIE_OK on success and error code on failure.
*
* @note		None.
*
******************************************************************************/
AieRC XAie_PartitionTeardown(XAie_DevInst *DevInst)
{
	AieRC RC;

	if((DevInst == XAIE_NULL) ||
			(DevInst->IsReady != XAIE_COMPONENT_IS_READY)) {
		XAIE_ERROR("Invalid Device Instance\n");
		return XAIE_INVALID_ARGS;
	}

	RC = XAie_RunOp(DevInst, XAIE_BACKEND_OP_PARTITION_TEARDOWN,
			NULL);
	if (RC != XAIE_OK) {
		XAIE_ERROR("Failed to teardown partition.\n");
		return RC;
	}

	return XAIE_OK;
}

/*****************************************************************************/
/**
*
* The API clears partition context
*
* @param        DevInst - Global AIE device instance pointer.
*
* @return       XAIE_OK on success and error code on failure.
*
* @note         None.
*
******************************************************************************/
AieRC XAie_ClearPartitionContext(XAie_DevInst *DevInst)
{
	AieRC RC;

	if((DevInst == XAIE_NULL) ||
			(DevInst->IsReady != XAIE_COMPONENT_IS_READY)) {
		XAIE_ERROR("Invalid Device Instance\n");
		return XAIE_INVALID_ARGS;
	}

	RC = XAie_RunOp(DevInst, XAIE_BACKEND_OP_PARTITION_CLEAR_CONTEXT,
			NULL);
	if (RC != XAIE_OK) {
		XAIE_ERROR("Failed to clear context of partition\n");
		return RC;
	}

	return XAIE_OK;
}
#endif /* !XAIE_FEATURE_LITE && XAIE_FEATURE_PRIVILEGED_ENABLE */

/*****************************************************************************/
/**
*
* This is the api to setup the AI engine partition intialization. It is
* supposed to be called after the partition resets.
*
* @param	DevInst - Global AIE device instance pointer.
*
* @return	XAIE_OK on success and error code on failure.
*
* @note		This is a temporary wrapper. Expect all users will migrate
*		to use partition initialization function instead. And then
*		this wrapper function can be removed in future.
*
******************************************************************************/
AieRC _XAie_PartitionIsolationInitialize(XAie_DevInst *DevInst)
{
	if((DevInst == XAIE_NULL) ||
			(DevInst->IsReady != XAIE_COMPONENT_IS_READY)) {
		XAIE_ERROR("Invalid Device Instance\n");
		return XAIE_INVALID_ARGS;
	}

	return DevInst->DevOps->SetPartIsolationAfterRst(DevInst);

}

/*****************************************************************************/
/**
*
* This is the api to finish the AI enigne partition. It will release
* the occupied AI engine resource
*
* @param	DevInst - Global AIE device instance pointer.
*
* @return	XAIE_OK on success and error code on failure.
*
* @note		None.
*
******************************************************************************/
AieRC XAie_Finish(XAie_DevInst *DevInst)
{
	const XAie_Backend *CurrBackend;
	AieRC RC;

	if((DevInst == XAIE_NULL) ||
			(DevInst->IsReady != XAIE_COMPONENT_IS_READY)) {
		XAIE_ERROR("Invalid Device Instance\n");
		return XAIE_INVALID_ARGS;
	}

	/* Free transaction mode resources, if any */
	_XAie_TxnResourceCleanup(DevInst);

	CurrBackend = DevInst->Backend;
	RC = CurrBackend->Ops.Finish(DevInst->IOInst);
	if (RC != XAIE_OK) {
		XAIE_ERROR("Failed to close backend instance.\n");
		return RC;
	}

	RC = _XAie_RscMgrFinish(DevInst);
	if(RC != XAIE_OK) {
		return RC;
	}

	DevInst->IsReady = 0;

	return XAIE_OK;
}

/*****************************************************************************/
/**
*
* This is the api to set the IO backend of the driver at runtime.
*
* @param	DevInst - Global AIE device instance pointer.
* @param	Backend - Backend IO type to switch to.
*
* @return	XAIE_OK on success and error code on failure.
*
* @note		None.
*
******************************************************************************/
AieRC XAie_SetIOBackend(XAie_DevInst *DevInst, XAie_BackendType Backend)
{
	AieRC RC;
	const XAie_Backend *CurrBackend, *NewBackend;

	if((DevInst == XAIE_NULL) ||
			(DevInst->IsReady != XAIE_COMPONENT_IS_READY)) {
		XAIE_ERROR("Invalid Device Instance\n");
		return XAIE_INVALID_ARGS;
	}

	if(Backend >= XAIE_IO_BACKEND_MAX ||
		_XAie_GetBackendPtr(Backend) == NULL) {
		XAIE_ERROR("Invalid backend request \n");
		return XAIE_INVALID_ARGS;
	}

	/* Release resources for current backend */
	CurrBackend = DevInst->Backend;
	RC = CurrBackend->Ops.Finish((void *)(DevInst->IOInst));
	if(RC != XAIE_OK) {
		XAIE_ERROR("Failed to close backend instance."
				"Falling back to backend %d\n",
				CurrBackend->Type);
		return RC;
	}

	/* Get new backend and initialize the backend */
	NewBackend = _XAie_GetBackendPtr(Backend);
	RC = NewBackend->Ops.Init(DevInst);
	if(RC != XAIE_OK) {
		XAIE_ERROR("Failed to initialize backend %d\n",
				Backend);
		return RC;
	}

	XAIE_DBG("Switching backend to %d\n", Backend);
	DevInst->Backend = NewBackend;

	return XAIE_OK;
}

/*****************************************************************************/
/**
*
* This is the memory function to allocate a memory
*
* @param	DevInst: Device Instance
* @param	Size: Size of the memory
* @param	Cache: Buffer to be cacheable or not
*
* @return	Pointer to the allocated memory instance.
*
* @note		None.
*
*******************************************************************************/
XAie_MemInst* XAie_MemAllocate(XAie_DevInst *DevInst, u64 Size,
		XAie_MemCacheProp Cache)
{
	const XAie_Backend *Backend;

	if((DevInst == XAIE_NULL) ||
			(DevInst->IsReady != XAIE_COMPONENT_IS_READY)) {
		XAIE_ERROR("Invalid Device Instance\n");
		return NULL;
	}

	if(Cache > XAIE_MEM_NONCACHEABLE) {
		XAIE_ERROR("Invalid cache property\n");
		return NULL;
	}

	Backend = DevInst->Backend;

	return Backend->Ops.MemAllocate(DevInst, Size, Cache);
}

/*****************************************************************************/
/**
*
* This is the memory function to free the memory
*
* @param	MemInst: Memory instance pointer.
*
* @return	XAIE_OK on success, Error code on failure.
*
* @note		None.
*
*******************************************************************************/
AieRC XAie_MemFree(XAie_MemInst *MemInst)
{
	const XAie_Backend *Backend;

	if(MemInst == XAIE_NULL) {
		XAIE_ERROR("Invalid memory instance\n");
		return XAIE_ERR;
	}

	Backend = MemInst->DevInst->Backend;

	return Backend->Ops.MemFree(MemInst);
}

/*****************************************************************************/
/**
*
* This is the memory function to sync the memory for CPU
*
* @param	MemInst: Memory instance pointer.
*
* @return	XAIE_OK on success, Error code on failure.
*
* @note		None.
*
*******************************************************************************/
AieRC XAie_MemSyncForCPU(XAie_MemInst *MemInst)
{
	const XAie_Backend *Backend;

	if(MemInst == XAIE_NULL) {
		XAIE_ERROR("Invalid memory instance\n");
		return XAIE_ERR;
	}

	Backend = MemInst->DevInst->Backend;

	return Backend->Ops.MemSyncForCPU(MemInst);
}

/*****************************************************************************/
/**
*
* This is the memory function to sync the memory for device
*
* @param	MemInst: Memory instance pointer.
*
* @return	XAIE_OK on success, Error code on failure.
*
* @note		None.
*
*******************************************************************************/
AieRC XAie_MemSyncForDev(XAie_MemInst *MemInst)
{
	const XAie_Backend *Backend;

	if(MemInst == XAIE_NULL) {
		XAIE_ERROR("Invalid memory instance\n");
		return XAIE_ERR;
	}

	Backend = MemInst->DevInst->Backend;

	return Backend->Ops.MemSyncForDev(MemInst);
}

/*****************************************************************************/
/**
*
* This is the memory function to return the virtual address of the memory
* instance
*
* @param	MemInst: Memory instance pointer.
*
* @return	Mapped virtual address of the memory instance.
*
* @note		None.
*
*******************************************************************************/
void* XAie_MemGetVAddr(XAie_MemInst *MemInst)
{
	if(MemInst == XAIE_NULL) {
		XAIE_ERROR("Invalid memory instance\n");
		return NULL;
	}

	return MemInst->VAddr;
}

/*****************************************************************************/
/**
*
* This is the memory function to return the physical address of the memory
* instance
*
* @param	MemInst: Memory instance pointer.
*
* @return	Physical address of the memory instance.
*
* @note		None.
*
*******************************************************************************/
u64 XAie_MemGetDevAddr(XAie_MemInst *MemInst)
{
	if(MemInst == XAIE_NULL) {
		XAIE_ERROR("Invalid memory instance\n");
		return XAIE_ERR;
	}

	return MemInst->DevAddr;
}

/*****************************************************************************/
/**
*
* This is the memory function to attach user allocated memory to the AI engine
* partition device instance.
*
* @param	DevInst: Device Instance
* @param	MemInst: pointer to memory instance which will be filled with
*			 attached AI engine memory instance information by
*			 this function.
* @param	DevAddr: Device address of the allocated memory. It is usually
*			 the physical address of the memory. For Linux dmabuf
*			 memory, it is the offset to the start of the dmabuf.
* @param	VAddr: Virtual address of the allocated memory. For Linux
*		       dmabuf memory, it is not required, it can be NULL.
*		Cache: Buffer is cacheable or not.
*		MemHandle: Handle of the allocated memory. It is ignored for
*			   other backends except Linux backend. For Linux
*			   backend, it is the file descriptor of a dmabuf.
*
* @return	XAIE_OK for success, or error code for failure.
*
* @note		None.
*
*******************************************************************************/
AieRC XAie_MemAttach(XAie_DevInst *DevInst, XAie_MemInst *MemInst, u64 DevAddr,
		u64 VAddr, u64 Size, XAie_MemCacheProp Cache, u64 MemHandle)
{
	if((DevInst == XAIE_NULL) ||
		(DevInst->IsReady != XAIE_COMPONENT_IS_READY) ||
		(DevInst->Backend == XAIE_NULL)) {
		XAIE_ERROR("Invalid Device Instance\n");
		return XAIE_INVALID_ARGS;
	}

	if(MemInst == XAIE_NULL) {
		XAIE_ERROR("Invalid memory instance\n");
		return XAIE_INVALID_ARGS;
	}

	if(Cache > XAIE_MEM_NONCACHEABLE) {
		XAIE_ERROR("Invalid cache property\n");
		return XAIE_INVALID_ARGS;
	}

	MemInst->DevInst = DevInst;
	MemInst->VAddr = (void *)(uintptr_t)VAddr;
	MemInst->DevAddr = DevAddr;
	MemInst->Size = Size;
	MemInst->Cache = Cache;

	return DevInst->Backend->Ops.MemAttach(MemInst, MemHandle);
}

/*****************************************************************************/
/**
*
* This is the memory function to dettach user allocated memory from the AI engine
* partition device instance.
*
* @param	MemInst: Memory Instance
*
* @return	XAIE_OK for success, and error code for failure.
*
* @note		None.
*
*******************************************************************************/
AieRC XAie_MemDetach(XAie_MemInst *MemInst)
{
	XAie_DevInst *DevInst;

	if(MemInst == XAIE_NULL) {
		XAIE_ERROR("Invalid memory instance\n");
		return XAIE_INVALID_ARGS;
	}

	DevInst = MemInst->DevInst;
	if((DevInst == XAIE_NULL) ||
		(DevInst->IsReady != XAIE_COMPONENT_IS_READY) ||
		(DevInst->Backend == XAIE_NULL)) {
		XAIE_ERROR("Invalid Device Instance\n");
		return XAIE_INVALID_ARGS;
	}

	return DevInst->Backend->Ops.MemDetach(MemInst);
}

/*****************************************************************************/
/*
* This API disables the ECC flag in the Device Instance of the partition. It
* should be called before calling elf loader to disable ECC. ECC configuration
* is done from elf loader.
*
* @param        DevInst: Device Instance
*
* @return       XAIE_OK on success
* @note         None
*
*******************************************************************************/
AieRC XAie_TurnEccOff(XAie_DevInst *DevInst)
{
	if((DevInst == XAIE_NULL) ||
		(DevInst->IsReady != XAIE_COMPONENT_IS_READY)) {
		XAIE_ERROR("Invalid Device Instance\n");
		return XAIE_INVALID_ARGS;
	}

	DevInst->EccStatus = XAIE_DISABLE;

	return XAIE_OK;
}

/*****************************************************************************/
/*
* This API enables the ECC flag in the Device Instance of the partition. ECC
* configuration is done from elf loader.
*
* @param        DevInst: Device Instance
*
* @return       XAIE_OK on success
* @note         None
*
*******************************************************************************/
AieRC XAie_TurnEccOn(XAie_DevInst *DevInst)
{
	XAie_UserRsc *RscsBc;
	u32 UserRscNum = 0;
	AieRC RC;

	if((DevInst == XAIE_NULL) ||
		(DevInst->IsReady != XAIE_COMPONENT_IS_READY)) {
		XAIE_ERROR("Invalid Device Instance\n");
		return XAIE_INVALID_ARGS;
	}

	/* Reserve broadcast channel for ECC */
	/* Reserved for error broadcast channel */
	for(u32 i = 0; i < XAIEGBL_TILE_TYPE_MAX; i++) {
		if(i == XAIEGBL_TILE_TYPE_SHIMNOC ||
			i == XAIEGBL_TILE_TYPE_SHIMPL) {
			UserRscNum += DevInst->NumCols;
		} else {
			UserRscNum += (DevInst->DevProp.DevMod[i].NumModules) *
				_XAie_GetNumRows(DevInst, i) * DevInst->NumCols;
		}
	}

	RscsBc = (XAie_UserRsc *)malloc(UserRscNum * sizeof(*RscsBc));
	if(RscsBc == NULL) {
		XAIE_ERROR("Memory allocation failed for ECC BC resource\n");
		return XAIE_ERR;
	}

	RC = XAie_RequestSpecificBroadcastChannel(DevInst,
		XAIE_ECC_BROADCAST_ID, &UserRscNum, RscsBc, 1U);
	free(RscsBc);
	if(RC != XAIE_OK) {
		XAIE_ERROR("Failed to request ECC BC for partition.\n");
		return RC;
	}

	DevInst->EccStatus = XAIE_ENABLE;

	return XAIE_OK;
}

/*****************************************************************************/
/**
*
* This api starts the execution of the driver in transaction mode. All the
* resulting IO operations are stored in an internally managed buffer. The user
* has to explicitly submit the transaction for the driver to execute the IO
* operations to configure the device. The transaction instance allocated by this
* api is tied to the thread id of the executing context. SubmitTransaction api
* must be called from the same context with NULL for the TxnInst parameter.
*
* @param	DevInst - Device instance pointer.
* @param	Flags - Flags passed by the user.
*			XAIE_TRANSACTION_ENABLE/DISBALE_AUTO_FLUSH
*
* @return	XAIE_OK on success and error code on failure.
*
* @note		If the ENABLE_AUTO_FLUSH flag is set, the driver will
*		automatically flush the transaction buffer when an API results
*		in Read/MaskPoll/BlockWrite/BlockSet/CmdWrite/RunOp operation.
*		If the DISABLE_AUTO_FLUSH flag is set, the driver will return an
*		error when an API results in Read/MaskPoll/CmdWrite/RunOp
*		operation. In both cases, the user has to call
*		XAie_SubmitTransaction API to flush all the pending IO
*		operations stored in the command buffer.
*
******************************************************************************/
AieRC XAie_StartTransaction(XAie_DevInst *DevInst, u32 Flags)
{
	if((DevInst == XAIE_NULL) ||
		(DevInst->IsReady != XAIE_COMPONENT_IS_READY)) {
		XAIE_ERROR("Invalid arguments\n");
		return XAIE_INVALID_ARGS;
	}

	return _XAie_Txn_Start(DevInst, Flags);
}

/*****************************************************************************/
/**
*
* This api executes all the pending IO operations stored in the command buffer.
* The transaction instance returned by the StartTransaction api is tied to the
* thread id of the executing context. If TxnInst is NULL, the transaction
* instance is automatically fetched using the thread id of the current context.
* If the TxnInst is not NULL, the transaction instance passed by the user is
* executed.
*
* @param	DevInst - Device instance pointer.
* @param	TxnInst - Transaction instance pointer.
*
* @return	XAIE_OK on success and Error code or failure.
*
* @note		None.
*
******************************************************************************/
AieRC XAie_SubmitTransaction(XAie_DevInst *DevInst, XAie_TxnInst *TxnInst)
{
	if((DevInst == XAIE_NULL) ||
		(DevInst->IsReady != XAIE_COMPONENT_IS_READY)) {
		XAIE_ERROR("Invalid arguments\n");
		return XAIE_INVALID_ARGS;
	}

	return _XAie_Txn_Submit(DevInst, TxnInst);
}

/*****************************************************************************/
/**
*
* This api copies an existing transaction instance and returns a copy of the
* instance with all the commands for users to save the commands and use them
* at a later point.
*
* @param	DevInst - Device instance pointer.
*
* @return	Pointer to copy of transaction instance on success and NULL
*		on error.
*
* @note		The copy of the transaction instance must be explicitly freed
*		using the XAie_FreeTransactionInstance API. If Auto flush was
*		enabled during the creating of the initial transaction, the
*		instance returned by this API will not have the commands that
*		are already flushed. The transaction instance must be exported
*		before it is submitted as the XAie_SubmitTransaction api will
*		free all the resources associated with it.
*
******************************************************************************/
XAie_TxnInst* XAie_ExportTransactionInstance(XAie_DevInst *DevInst)
{
	if((DevInst == XAIE_NULL) ||
		(DevInst->IsReady != XAIE_COMPONENT_IS_READY)) {
		XAIE_ERROR("Invalid arguments\n");
		return NULL;
	}

	return _XAie_TxnExport(DevInst);
}

/*****************************************************************************/
/**
*
* This api releases the memory resources used by exported transaction instance.
*
* @param	TxnInst - Existing Transaction instance
*
* @return	XAIE_OK on success or error code on failure.
*
* @note		None.
*
******************************************************************************/
AieRC XAie_FreeTransactionInstance(XAie_TxnInst *TxnInst)
{
	if(TxnInst == NULL) {
		XAIE_ERROR("Invalid arguments\n");
		return XAIE_INVALID_ARGS;
	}

	return _XAie_TxnFree(TxnInst);
}

/*****************************************************************************/
/**
*
* This is the API to return if the device generation has checkboarded tiles for
* broadcast ungating
*
* @param	DevInst - Global AIE device instance pointer.
* @param	IsCheckerBoard - pointer to be set if tile is checkerboarded
* @return	XAIE_OK on success
*
* @note		None.
*
******************************************************************************/
AieRC XAie_IsDeviceCheckerboard(XAie_DevInst *DevInst, u8 *IsCheckerBoard)
{
	if((DevInst == XAIE_NULL) ||
		(DevInst->IsReady != XAIE_COMPONENT_IS_READY) ||
		(IsCheckerBoard == NULL)) {
		XAIE_ERROR("Invalid arguments\n");
		return XAIE_INVALID_ARGS;
	}

	*IsCheckerBoard = DevInst->DevOps->IsCheckerBoard;

	return XAIE_OK;
}

AieRC XAie_UpdateNpiAddr(XAie_DevInst *DevInst, u64 NpiAddr)
{
	if((DevInst == NULL) || (DevInst->IsReady != XAIE_COMPONENT_IS_READY)) {
		XAIE_ERROR("Invalid Device Instance\n");
		return XAIE_INVALID_ARGS;
	}

	return XAie_RunOp(DevInst, XAIE_BACKEND_OP_UPDATE_NPI_ADDR,
			(void *)&NpiAddr);
}

/*****************************************************************************/
/**
*
* This api copies an existing transaction instance and returns a copy of the
* instance with all the commands for users to save the commands and use them
* at a later point.
*
* @param	DevInst - Device instance pointer.
* @param	NumConsumers - Number of consumers for the generated
*		transactions (Unused for now)
* @param	Flags - Flags (Unused for now)
*
* @return	Pointer to copy of transaction instance on success and NULL
*		on error.
*
* @note		None.
*
******************************************************************************/
u8* XAie_ExportSerializedTransaction(XAie_DevInst *DevInst,
		u8 NumConsumers, u32 Flags)
{
	if((DevInst == XAIE_NULL) ||
		(DevInst->IsReady != XAIE_COMPONENT_IS_READY)) {
		XAIE_ERROR("Invalid arguments\n");
		return NULL;
	}

	return _XAie_TxnExportSerialized(DevInst, NumConsumers, Flags);
}

/*****************************************************************************/
/**
*
* This api deallocates the memory allocated for the serialized transaction
* buffer.
*
* @param	Ptr - Pointer to the transaction buffer.
*
* @return	None.
*
* @note		None.
*
******************************************************************************/
void XAie_FreeSerializedTransaction(void *Ptr)
{
	if (Ptr == NULL) {
		XAIE_ERROR("Invalid argument\n");
		return;
	}
	_XAie_FreeTxnPtr(Ptr);
}

AieRC XAie_ClearTransaction(XAie_DevInst* DevInst)
{
	if((DevInst == XAIE_NULL) ||
		(DevInst->IsReady != XAIE_COMPONENT_IS_READY)) {
		XAIE_ERROR("Invalid arguments\n");
		return XAIE_INVALID_ARGS;
	}

	return _XAie_ClearTransaction(DevInst);
}

/** @} */
