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


#ifndef XPM_CLOCK_H_
#define XPM_CLOCK_H_

#include "xpm_common.h"
#include "xpm_clock_plat.h"
#include "xpm_node.h"
#include "xpm_power.h"

#ifdef __cplusplus
extern "C" {
#endif

#define ISOUTCLK(id)	((NODECLASS(id) == (u32)XPM_NODECLASS_CLOCK) && \
			 (NODESUBCLASS(id) == (u32)XPM_NODESUBCL_CLOCK_OUT) && \
			 (NODEINDEX(id) < (u32)XPM_NODEIDX_CLK_MAX))
#define ISREFCLK(id)	((NODECLASS(id) == (u32)XPM_NODECLASS_CLOCK) && \
			 (NODESUBCLASS(id) == (u32)XPM_NODESUBCL_CLOCK_REF) && \
			 (NODEINDEX(id) < (u32)XPM_NODEIDX_CLK_MAX))

/* Topology types */
#define	TOPOLOGY_GENERIC_PLL		1U
#define	TOPOLOGY_NOC_PLL		2U
#define TOPOLOGY_GENERIC_MUX_DIV	3U
#define TOPOLOGY_GENERIC_MUX_GATE	4U
#define TOPOLOGY_GENERIC_DIV_GATE	5U
#define TOPOLOGY_GENERIC_MUX_DIV_GATE_1	6U
#define TOPOLOGY_GENERIC_MUX_DIV_GATE_2	7U
#define TOPOLOGY_CUSTOM			8U
#define MAX_TOPOLOGY			9U

#define MAX_MUX_PARENTS		8U
#define MAX_NAME_BYTES		16U

/* Clock Flags */
#define CLK_FLAG_READ_ONLY		(1U << 0U)

/**
 * The topology node class.	 This is the class to represent each node
 * in clock topology. It can be mux/div/gate/fixed factor.
 */
struct XPm_ClkTopologyNode {
	u32 Reg;
	uint16_t Clkflags;
	uint16_t Typeflags;
	union {uint8_t Shift; uint8_t Mult;}Param1;
	union {uint8_t Width; uint8_t Div;}Param2;
	uint8_t Type;
};

typedef struct XPm_ClkTopology {
	struct XPm_ClkTopologyNode(*Nodes)[];
	uint8_t Id;
	uint8_t NumNodes;
	u16 MuxSources[MAX_MUX_PARENTS]; /**< Clock index of mux sources */
}XPm_ClkTopology;

typedef struct XPm_ClockNode XPm_ClockNode;
typedef struct XPm_ClockHandle XPm_ClockHandle;

/**
 * The clock class.	 This is the base class for all the clocks.
 */
struct XPm_ClockNode {
	XPm_Node Node;
	char Name[MAX_NAME_BYTES];
	u16 ParentIdx;
	u8 NumParents;
	u8 Flags;
	u8 UseCount;
	XPm_ClockHandle *ClkHandles; /**< Pointer to the clock/device pairs */
	XPm_Power *PwrDomain;
	u32 ClkRate;
};

/**
 * XPm_ClockHandle - This models clock/device pair.
 */
struct XPm_ClockHandle {
	XPm_ClockNode *Clock; /**< Clock used by device */
	struct XPm_DeviceNode *Device; /**< Device which uses the clock */
	XPm_ClockHandle *NextClock; /**< Next handle of same device */
	XPm_ClockHandle *NextDevice; /**< Next handle of same clock */
};

typedef struct XPm_OutClockNode {
	XPm_ClockNode ClkNode;
	XPm_ClkTopology Topology;
}XPm_OutClockNode;

/* Common topology definitions */

enum XPm_ClockSubnodeType {
	TYPE_INVALID,
	TYPE_MUX,
	TYPE_PLL,
	TYPE_FIXEDFACTOR,
	TYPE_DIV1,
	TYPE_DIV2,
	TYPE_GATE,
	TYPE_MAX,
};

/* Clock states: */
#define	XPM_CLK_STATE_OFF		0U
#define XPM_CLK_STATE_REQUESTED	1U			//For all clocks with/without gate
#define XPM_CLK_STATE_ON			2U			//For clocks with gate

/* Peripheral Clocks */
#define PERIPH_MUX_SHIFT			0
#define PERIPH_MUX_WIDTH			3
#define PERIPH_DIV_SHIFT			8
#define PERIPH_DIV_WIDTH			10
#define PERIPH_GATE1_SHIFT			25
#define PERIPH_GATE2_SHIFT			24
#define PERIPH_GATE_WIDTH			1

/* Common Flags */
#define NA_TYPE_FLAGS			0U
#define CLK_SET_RATE_GATE		BIT16(0) /* must be gated across rate change */
#define CLK_SET_PARENT_GATE		BIT16(1) /* must be gated across re-parent */
#define CLK_SET_RATE_PARENT		BIT16(2) /* propagate rate change up one level */
#define CLK_IGNORE_UNUSED		BIT16(3) /* do not gate even if unused */
						 /* BIT(4) unused */
						 /* BIT(5) unused */
#define CLK_GET_RATE_NOCACHE		BIT16(6) /* do not use the cached clk rate */
#define CLK_SET_RATE_NO_REPARENT	BIT16(7) /* don't re-parent on rate change */
#define CLK_GET_ACCURACY_NOCACHE	BIT16(8) /* do not use the cached clk accuracy */
#define CLK_RECALC_NEW_RATES		BIT16(9) /* recalc rates after notifications */
#define CLK_SET_RATE_UNGATE		BIT16(10) /* clock needs to run to set rate */
#define CLK_IS_CRITICAL			BIT16(11) /* do not gate, ever */

/* Type Flags for divider clock */
#define CLK_DIVIDER_ONE_BASED		BIT(0)
#define CLK_DIVIDER_POWER_OF_TWO	BIT(1)
#define CLK_DIVIDER_ALLOW_ZERO		BIT(2)
#define CLK_DIVIDER_HIWORD_MASK		BIT(3)
#define CLK_DIVIDER_ROUND_CLOSEST	BIT(4)
#define CLK_DIVIDER_READ_ONLY		BIT16(5)
#define CLK_DIVIDER_MAX_AT_ZERO		BIT(6)

/* Type Flags for mux clock */
#define CLK_MUX_INDEX_ONE               BIT(0)
#define CLK_MUX_INDEX_BIT               BIT(1)
#define CLK_MUX_HIWORD_MASK             BIT(2)
#define CLK_MUX_READ_ONLY               BIT16(3)
#define CLK_MUX_ROUND_CLOSEST           BIT(4)
#define CLK_MUX_BIG_ENDIAN              BIT(5)

/************************** Function Prototypes ******************************/
XStatus XPmClock_AddNode(u32 Id, u32 ControlReg, u8 TopologyType,
			 u8 NumCustomNodes, u8 NumParents, u32 PowerDomainId,
			 u8 ClkFlags);
XStatus XPmClock_AddClkName(u32 Id, const char *Name);
XStatus XPmClock_AddSubNode(u32 Id, u32 Type, u32 ControlReg, u8 Param1, u8 Param2, u32 Flags);
XStatus XPmClock_AddParent(u32 Id, const u32 *Parents, u8 NumParents);
XPm_ClockNode* XPmClock_GetById(u32 ClockId);
XPm_ClockNode* XPmClock_GetByIdx(u32 ClockIdx);
XStatus XPmClock_SetById(u32 ClockId, XPm_ClockNode *Clk);
XStatus XPmClock_Request(const XPm_ClockHandle *ClkHandle);
XStatus XPmClock_Release(const XPm_ClockHandle *ClkHandle);
XStatus XPmClock_SetGate(XPm_OutClockNode *Clk, u32 Enable);
XStatus XPmClock_SetParent(XPm_OutClockNode *Clk, u32 ParentIdx);
XStatus XPmClock_SetDivider(const XPm_OutClockNode *Clk, u32 Divider);
XStatus XPmClock_GetClockData(const XPm_OutClockNode *Clk, u32 Nodetype, u32 *Value);
XStatus XPmClock_QueryName(u32 ClockId, u32 *Resp);
XStatus XPmClock_QueryTopology(u32 ClockId, u32 Index, u32 *Resp);
XStatus XPmClock_QueryFFParams(u32 ClockId, u32 *Resp);
XStatus XPmClock_QueryMuxSources(u32 ClockId, u32 Index, u32 *Resp);
XStatus XPmClock_QueryAttributes(u32 ClockIndex, u32 *Resp);
XStatus XPmClock_GetNumClocks(u32 *Resp);
XStatus XPmClock_CheckPermissions(u32 SubsystemIdx, u32 ClockId);
XStatus XPmClock_GetMaxDivisor(u32 ClockId, u32 DivType, u32 *Resp);
XStatus XPmClock_SetRate(XPm_ClockNode *Clk, const u32 ClkRate);
XStatus XPmClock_GetRate(const XPm_ClockNode *Clk, u32 *ClkRate);

#ifdef __cplusplus
}
#endif

#endif /* XPM_CLOCK_H_ */
