aboutsummaryrefslogtreecommitdiffstats
path: root/mpm/lib/rfdc/xrfdc_clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'mpm/lib/rfdc/xrfdc_clock.c')
-rw-r--r--mpm/lib/rfdc/xrfdc_clock.c1801
1 files changed, 1801 insertions, 0 deletions
diff --git a/mpm/lib/rfdc/xrfdc_clock.c b/mpm/lib/rfdc/xrfdc_clock.c
new file mode 100644
index 000000000..73a19fda5
--- /dev/null
+++ b/mpm/lib/rfdc/xrfdc_clock.c
@@ -0,0 +1,1801 @@
+/******************************************************************************
+*
+* Copyright (C) 2019 Xilinx, Inc. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*
+* Except as contained in this notice, the name of the Xilinx shall not be used
+* in advertising or otherwise to promote the sale, use or other dealings in
+* this Software without prior written authorization from Xilinx.
+*
+******************************************************************************/
+/*****************************************************************************/
+/**
+*
+* @file xrfdc_clock.c
+* @addtogroup xrfdc_v6_0
+* @{
+*
+* Contains the interface functions of the Mixer Settings in XRFdc driver.
+* See xrfdc.h for a detailed description of the device and driver.
+*
+* <pre>
+* MODIFICATION HISTORY:
+*
+* Ver Who Date Changes
+* ----- --- -------- -----------------------------------------------
+* 6.0 cog 02/17/19 Initial release.
+* cog 03/12/19 Invert clock detection bits to support IP change.
+* cog 03/12/19 Fix bug where incorrect FS, RefClk and were output
+* divider were being returned.
+* cog 04/09/19 Discriminate between Gen 3 IP and lower for checking
+* if internal PLL is enabled.
+* cog 04/09/19 Fixed issue where tile was not autostarting after PLL
+* rate change.
+* </pre>
+*
+******************************************************************************/
+
+/***************************** Include Files *********************************/
+#include "mpm/rfdc/xrfdc.h"
+
+/************************** Constant Definitions *****************************/
+static u32 PllTuningMatrix[8][4][2] = {
+ {{0x7F8A, 0x3FFF}, {0x7F9C, 0x3FFF}, {0x7FE2, 0x3FFF} },
+ {{0x7FE9, 0xFFFF}, {0x7F8E, 0xFFFF}, {0x7F9C, 0xFFFF} },
+ {{0x7F95, 0xFFFF}, {0x7F8E, 0xFFFF}, { 0x7F9A, 0xFFFF}, {0x7F8C, 0xFFFF} },
+ {{0x7F95, 0x3FFF}, {0x7FEE, 0x3FFF}, { 0x7F9A, 0xFFFF}, {0x7F9C, 0xFFFF} },
+ {{0x7F95, 0x3FFF}, {0x7FEE, 0x3FFF}, { 0x7F9A, 0xFFFF}, {0x7F9C, 0xFFFF} },
+ {{0x7F95, 0xFFFF}, {0x7F8E, 0xFFFF}, { 0x7FEA, 0xFFFF}, {0x7F9C, 0xFFFF} },
+ {{0x7FE9, 0xFFFF}, {0x7F8E, 0xFFFF}, { 0x7F9A, 0xFFFF}, {0x7F9C, 0xFFFF} },
+ {{0x7FEC, 0xFFFF}, {0x7FEE, 0x3FFF}, { 0x7F9C, 0xFFFF} }
+};
+
+
+/**************************** Type Definitions *******************************/
+
+/***************** Macros (Inline Functions) Definitions *********************/
+static u32 XRFdc_CheckClkDistValid(XRFdc *InstancePtr, XRFdc_Distribution_Settings *DistributionSettingsPtr);
+static u32 XRFdc_SetPLLConfig(XRFdc *InstancePtr, u32 Type, u32 Tile_Id,
+ double RefClkFreq, double SamplingRate);
+
+/************************** Function Prototypes ******************************/
+
+/*****************************************************************************/
+/**
+*
+* This function is used to set the clock settings
+*
+* @param InstancePtr is a pointer to the XRfdc instance.
+* @param Type indicates ADC/DAC.
+* @param Tile_Id indicates Tile number (0-3).
+* @param SettingsPtr pointer to set the clock settings
+*
+* @return
+* - XRFDC_SUCCESS if successful.
+* - XRFDC_FAILURE if no valid distribution found.
+*
+******************************************************************************/
+u32 XRFdc_SetTileClkSettings(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, XRFdc_Tile_Clock_Settings *SettingsPtr)
+{
+ u32 Status;
+ u32 BaseAddr;
+ u16 PLLSource;
+ u16 NetworkCtrlReg;
+ u16 DistCtrlReg;
+ u16 PLLRefDivReg;
+ u16 PLLOpDivReg;
+ u32 TileIndex;
+ u16 DivideMode = 0;
+ u16 DivideValue = 0;
+
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(SettingsPtr != NULL);
+ Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY);
+
+ if (InstancePtr->RFdc_Config.IPType < 2) {
+ Status = XRFDC_FAILURE;
+ metal_log(METAL_LOG_ERROR,
+ "\n Requested fuctionality not "
+ "available for this IP in %s\r\n",
+ __func__);
+ goto RETURN_PATH;
+ }
+
+ TileIndex = (Type == XRFDC_DAC_TILE) ? Tile_Id : Tile_Id + XRFDC_CLK_DST_ADC0;
+ Status = XRFdc_CheckTileEnabled(InstancePtr, Type, Tile_Id);
+ if (Status != XRFDC_SUCCESS) {
+ metal_log(METAL_LOG_ERROR,
+ "\n Requested Tile not "
+ "available in %s\r\n",
+ __func__);
+ goto RETURN_PATH;
+ }
+ if (SettingsPtr->SourceTile > XRFDC_CLK_DST_ADC3) {
+ metal_log(METAL_LOG_ERROR,
+ "\n Invalid Parameter Value "
+ "for Source in %s\r\n",
+ __func__);
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+ if (SettingsPtr->DistributedClock > XRFDC_DIST_OUT_OUTDIV) {
+ metal_log(METAL_LOG_ERROR,
+ "\n Invalid Parameter Value "
+ "for Distribution Out in %s\r\n",
+ __func__);
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+ if (SettingsPtr->PLLEnable > 1) {
+ metal_log(METAL_LOG_ERROR,
+ "\n Invalid Parameter Value "
+ "for PLLEnable in %s\r\n",
+ __func__);
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+ if ((SettingsPtr->PLLEnable == XRFDC_ENABLED) && (SettingsPtr->DivisionFactor < 1)) {
+ metal_log(METAL_LOG_ERROR, "\n Invalid Configuration in %s\r\n", __func__);
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+ if ((SettingsPtr->DistributedClock == XRFDC_DIST_OUT_OUTDIV) &&
+ ((SettingsPtr->DivisionFactor < 2) && (SettingsPtr->PLLEnable == XRFDC_DISABLED))) {
+ metal_log(METAL_LOG_ERROR, "\n Invalid Configuration in %s\r\n", __func__);
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+ if ((SettingsPtr->SourceTile != TileIndex) && (SettingsPtr->DistributedClock != XRFDC_DIST_OUT_NONE)) {
+ metal_log(METAL_LOG_ERROR, "\n Cannot Redistribute Clock in %s\r\n", __func__);
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+
+ /*configure PLL & divider or just divider*/
+ if (SettingsPtr->PLLEnable == XRFDC_ENABLED) {
+ metal_log(METAL_LOG_WARNING,
+ "\n Output divider settings may "
+ "be overridden in %s\r\n",
+ __func__);
+ PLLSource = XRFDC_INTERNAL_PLL_CLK;
+ Status = XRFdc_DynamicPLLConfig(InstancePtr, Type, Tile_Id, PLLSource,
+ SettingsPtr->PLLSettings.RefClkFreq,
+ SettingsPtr->PLLSettings.SampleRate);
+ SettingsPtr->DivisionFactor = SettingsPtr->PLLSettings.OutputDivider;
+ if (Status != XRFDC_SUCCESS) {
+ metal_log(METAL_LOG_ERROR,
+ "\n Could not set up PLL "
+ "in %s\r\n",
+ __func__);
+ goto RETURN_PATH;
+ }
+ } else if (SettingsPtr->DivisionFactor > 1) {
+ if (SettingsPtr->DivisionFactor == 2U) {
+ DivideMode = XRFDC_PLL_OUTDIV_MODE_2;
+ } else if (SettingsPtr->DivisionFactor == 3U) {
+ DivideMode = XRFDC_PLL_OUTDIV_MODE_3;
+ DivideValue = XRFDC_PLL_OUTDIV_MODE_3_VAL;
+ } else if (SettingsPtr->DivisionFactor >= 4U) {
+ DivideMode = XRFDC_PLL_OUTDIV_MODE_N;
+ DivideValue = ((SettingsPtr->DivisionFactor - 4U) >> 1);
+ }
+ XRFdc_ClrSetReg(InstancePtr, XRFDC_DRP_BASE(Type, Tile_Id) + XRFDC_HSCOM_ADDR, XRFDC_PLL_DIVIDER0,
+ XRFDC_PLL_DIVIDER0_MASK, ((DivideMode << XRFDC_PLL_DIVIDER0_SHIFT) | DivideValue));
+ }
+ DistCtrlReg = 0;
+ PLLRefDivReg = 0;
+ PLLOpDivReg = 0;
+ NetworkCtrlReg = 0;
+ if (SettingsPtr->SourceTile == TileIndex) {
+ if (SettingsPtr->DistributedClock == XRFDC_DIST_OUT_NONE) {
+ if (SettingsPtr->PLLEnable == XRFDC_DISABLED) {
+ PLLRefDivReg |= XRFDC_PLLREFDIV_INPUT_OFF;
+ NetworkCtrlReg |= XRFDC_NET_CTRL_CLK_REC_DIST_T1;
+ if (SettingsPtr->DivisionFactor < 2) {
+ /*
+ T1 from Self
+ No PLL
+ Do Not Use PLL Output Divider
+ Do Not Distribute
+ */
+ NetworkCtrlReg |= XRFDC_NET_CTRL_CLK_T1_SRC_LOCAL;
+ DistCtrlReg |= XRFDC_DIST_CTRL_CLK_T1_SRC_LOCAL;
+ } else {
+ /*
+ T1 from Self
+ No PLL
+ Do Not Distribute
+ */
+ PLLOpDivReg |= XRFDC_PLLOPDIV_INPUT_DIST_LOCAL;
+ }
+ } else {
+ /*
+ T1 from Self
+ PLL
+ Use PLL Output Divider
+ Do Not Distribute
+ */
+ NetworkCtrlReg |= XRFDC_NET_CTRL_CLK_REC_PLL;
+ }
+ } else {
+ NetworkCtrlReg |= XRFDC_NET_CTRL_CLK_T1_SRC_DIST;
+ DistCtrlReg |= XRFDC_DIST_CTRL_TO_T1;
+ if (SettingsPtr->PLLEnable == XRFDC_DISABLED) {
+ NetworkCtrlReg |= XRFDC_NET_CTRL_CLK_REC_DIST_T1;
+ PLLRefDivReg |= XRFDC_PLLREFDIV_INPUT_OFF;
+ if (SettingsPtr->DivisionFactor < 2) {
+ /*
+ T1 From Distribution
+ No PLL
+ Do Not Use PLL Output Divider
+ Send to Distribution
+ */
+ DistCtrlReg |= XRFDC_DIST_CTRL_DIST_SRC_LOCAL;
+ } else {
+ /*
+ T1 From Distribution
+ No PLL
+ Use PLL Output Divider
+ Send to Distribution
+ */
+ PLLOpDivReg |= XRFDC_PLLOPDIV_INPUT_DIST_LOCAL;
+ DistCtrlReg |= (SettingsPtr->DistributedClock == XRFDC_DIST_OUT_RX) ?
+ XRFDC_DIST_CTRL_DIST_SRC_LOCAL :
+ XRFDC_DIST_CTRL_DIST_SRC_PLL;
+ }
+
+ } else {
+ /*
+ T1 From Distribution
+ PLL
+ Use PLL Output Divider
+ Send to Distribution
+ */
+ DistCtrlReg |= (SettingsPtr->DistributedClock == XRFDC_DIST_OUT_RX) ?
+ XRFDC_DIST_CTRL_DIST_SRC_LOCAL :
+ XRFDC_DIST_CTRL_DIST_SRC_PLL;
+ NetworkCtrlReg |= XRFDC_NET_CTRL_CLK_REC_PLL;
+ }
+ }
+ } else {
+ if (SettingsPtr->PLLEnable == XRFDC_DISABLED) {
+ PLLRefDivReg |= XRFDC_PLLREFDIV_INPUT_OFF;
+ if (SettingsPtr->DivisionFactor > 1) {
+ /*
+ Source From Distribution
+ No PLL
+ Use PLL Output Divider
+ Do Not Distribute
+ */
+
+ PLLOpDivReg |= XRFDC_PLLOPDIV_INPUT_DIST_LOCAL;
+ NetworkCtrlReg |= XRFDC_NET_CTRL_CLK_INPUT_DIST;
+ DistCtrlReg |= XRFDC_DIST_CTRL_TO_PLL_DIV;
+ } else {
+ /*
+ Source From Distribution
+ No PLL
+ Do Not Use PLL Output Divider
+ Do Not Distribute
+ */
+ NetworkCtrlReg |= XRFDC_NET_CTRL_CLK_T1_SRC_DIST;
+ DistCtrlReg |= XRFDC_DIST_CTRL_TO_T1;
+ }
+ } else {
+ /*
+ Source From Distribution
+ PLL
+ Use PLL Output Divider
+ Do Not Distribute
+ */
+ PLLRefDivReg |= XRFDC_PLLREFDIV_INPUT_DIST;
+ DistCtrlReg |= XRFDC_DIST_CTRL_TO_PLL_DIV;
+ }
+ }
+
+ /*Write to Registers*/
+ if (Type == XRFDC_ADC_TILE) {
+ BaseAddr = XRFDC_ADC_TILE_DRP_ADDR(Tile_Id);
+ } else {
+ BaseAddr = XRFDC_DAC_TILE_DRP_ADDR(Tile_Id);
+ }
+ BaseAddr += XRFDC_HSCOM_ADDR;
+ XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_HSCOM_CLK_DSTR_OFFSET, XRFDC_HSCOM_CLK_DSTR_MASK_ALT, DistCtrlReg);
+ XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CLK_NETWORK_CTRL1, XRFDC_HSCOM_NETWORK_CTRL1_MASK, NetworkCtrlReg);
+ XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_PLL_REFDIV, XRFDC_PLL_REFDIV_MASK, PLLRefDivReg);
+ XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_PLL_DIVIDER0, XRFDC_PLL_DIVIDER0_ALT_MASK, PLLOpDivReg);
+ Status = XRFDC_SUCCESS;
+RETURN_PATH:
+ return Status;
+}
+/*****************************************************************************/
+/**
+*
+* This function is used to check the distribution chosen is valid
+*
+* @param InstancePtr is a pointer to the XRfdc instance.
+* @param DistributionSettingsPtr pointer to the distribution settings struct
+*
+* @return
+* - XRFDC_SUCCESS if Valid.
+* - XRFDC_FAILURE if Not Valid.
+*
+******************************************************************************/
+static u32 XRFdc_CheckClkDistValid(XRFdc *InstancePtr, XRFdc_Distribution_Settings *DistributionSettingsPtr)
+{
+ u32 Status;
+ u8 CurrentTile;
+ u8 *Source;
+ u8 Sources[8] = { DistributionSettingsPtr->DAC[0].SourceTile, DistributionSettingsPtr->DAC[1].SourceTile,
+ DistributionSettingsPtr->DAC[2].SourceTile, DistributionSettingsPtr->DAC[3].SourceTile,
+ DistributionSettingsPtr->ADC[0].SourceTile, DistributionSettingsPtr->ADC[1].SourceTile,
+ DistributionSettingsPtr->ADC[2].SourceTile, DistributionSettingsPtr->ADC[3].SourceTile };
+ u8 LowBoundary;
+ u16 EFuse;
+ XRFdc_Distribution *DistributionPtr;
+
+ /*init for first distribution*/
+ DistributionPtr = DistributionSettingsPtr->DistributionStatus;
+ Source = Sources;
+ LowBoundary = DistributionSettingsPtr->DAC[0].SourceTile;
+ DistributionPtr->DistributionSource = DistributionSettingsPtr->DAC[0].SourceTile;
+ DistributionPtr->Enabled = XRFDC_ENABLED;
+ DistributionPtr->LowerBound = 0;
+
+ for (CurrentTile = 0; CurrentTile < XRFDC_DIST_MAX; CurrentTile++, Source++) {
+ if (*Source >= XRFDC_DIST_MAX) {
+ Status = XRFDC_FAILURE; /*out of range*/
+ metal_log(METAL_LOG_ERROR,
+ "\n Invalid Source "
+ "value in %s - Out of Range\r\n",
+ __func__);
+ goto RETURN_PATH;
+ }
+ if (*Source < LowBoundary) {
+ Status = XRFDC_FAILURE; /*SW: no hopovers*/
+ metal_log(METAL_LOG_ERROR,
+ "\n Invalid Configuration "
+ "Hopping Over Not Allowed in %s\r\n",
+ __func__);
+ goto RETURN_PATH;
+ }
+ if (Sources[*Source] != *Source) { /*SW: check source is a distributer*/
+ Status = XRFDC_FAILURE;
+ metal_log(METAL_LOG_ERROR,
+ "\n Invalid Source "
+ "Sourcing from Tile that is not Distributing in %s\r\n",
+ __func__);
+ goto RETURN_PATH;
+ }
+ if ((*Source == XRFDC_CLK_DST_DAC0) &&
+ (InstancePtr->RFdc_Config.DACTile_Config[XRFDC_CLK_DST_DAC0].NumSlices == 2)) { /*HW: only 2 clks*/
+ Status = XRFDC_FAILURE;
+ metal_log(METAL_LOG_ERROR,
+ "\n Invalid Source "
+ "Sourcing from Tile Without Clock in %s\r\n",
+ __func__);
+ goto RETURN_PATH;
+ }
+ if ((*Source == XRFDC_CLK_DST_DAC2) &&
+ (InstancePtr->RFdc_Config.DACTile_Config[XRFDC_CLK_DST_DAC2].NumSlices == 2)) { /*HW: only 2 clks*/
+ metal_log(METAL_LOG_ERROR,
+ "\n Invalid Source "
+ "Sourcing from Tile Without Clock in %s\r\n",
+ __func__);
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+ if ((CurrentTile < XRFDC_CLK_DST_ADC0) &&
+ (*Source > XRFDC_CLK_DST_DAC3)) { /*Cut between ADC0 MUX8 && DAC3 STH*/
+ metal_log(METAL_LOG_ERROR,
+ "\n Invalid Configuration "
+ "DAC Cannot Source from ADC in %s\r\n",
+ __func__);
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+ if (CurrentTile < XRFDC_CLK_DST_ADC0) { /*DAC*/
+ EFuse = XRFdc_ReadReg16(InstancePtr,
+ XRFDC_DRP_BASE(XRFDC_DAC_TILE, CurrentTile) + XRFDC_HSCOM_ADDR,
+ XRFDC_HSCOM_EFUSE_2_OFFSET);
+ } else { /*ADC*/
+ EFuse = XRFdc_ReadReg16(InstancePtr,
+ XRFDC_DRP_BASE(XRFDC_ADC_TILE, (CurrentTile - XRFDC_CLK_DST_ADC0)) +
+ XRFDC_HSCOM_ADDR,
+ XRFDC_HSCOM_EFUSE_2_OFFSET);
+ }
+ /*if PKG <2*/
+
+ if ((DistributionSettingsPtr->DAC[0].SourceTile != DistributionSettingsPtr->DAC[1].SourceTile) ||
+ (DistributionSettingsPtr->DAC[0].SourceTile != DistributionSettingsPtr->DAC[2].SourceTile) ||
+ (DistributionSettingsPtr->DAC[0].SourceTile != DistributionSettingsPtr->DAC[3].SourceTile) ||
+ (DistributionSettingsPtr->DAC[0].SourceTile != DistributionSettingsPtr->ADC[0].SourceTile) ||
+ (DistributionSettingsPtr->DAC[0].SourceTile != DistributionSettingsPtr->ADC[1].SourceTile) ||
+ (DistributionSettingsPtr->DAC[0].SourceTile != DistributionSettingsPtr->ADC[2].SourceTile) ||
+ (DistributionSettingsPtr->DAC[0].SourceTile != DistributionSettingsPtr->ADC[3].SourceTile) ||
+ (DistributionSettingsPtr->DAC[0].PLLEnable != XRFDC_ENABLED) ||
+ (DistributionSettingsPtr->DAC[1].PLLEnable != XRFDC_ENABLED) ||
+ (DistributionSettingsPtr->DAC[2].PLLEnable != XRFDC_ENABLED) ||
+ (DistributionSettingsPtr->DAC[3].PLLEnable != XRFDC_ENABLED) ||
+ (DistributionSettingsPtr->ADC[0].PLLEnable != XRFDC_ENABLED) ||
+ (DistributionSettingsPtr->ADC[1].PLLEnable != XRFDC_ENABLED) ||
+ (DistributionSettingsPtr->ADC[2].PLLEnable != XRFDC_ENABLED) ||
+ (DistributionSettingsPtr->ADC[3].PLLEnable != XRFDC_ENABLED)) { /*special case that is allowed.*/
+
+ /*if PKG <2*/
+ if (EFuse & XRFDC_PREMIUMCTRL_CLKDIST) {
+ if ((CurrentTile > XRFDC_CLK_DST_ADC1) &&
+ (*Source != CurrentTile)) { /*E: no dist past adc1*/
+ Status = XRFDC_FAILURE;
+ metal_log(METAL_LOG_ERROR,
+ "\n Invalid Configuration "
+ "- Licensing - Not Premium in %s\r\n",
+ __func__);
+ goto RETURN_PATH;
+ }
+ }
+ /*if PKG <1*/
+ if ((EFuse & XRFDC_EXPORTCTRL_CLKDIST) == XRFDC_EXPORTCTRL_CLKDIST) {
+ if ((CurrentTile > XRFDC_CLK_DST_DAC3) && (*Source != CurrentTile)) { /*E: No ADC Dist*/
+ Status = XRFDC_FAILURE;
+ metal_log(METAL_LOG_ERROR,
+ "\n Invalid Configuration "
+ "- Licensing in %s\r\n",
+ __func__);
+ goto RETURN_PATH;
+ }
+ if ((CurrentTile == XRFDC_CLK_DST_DAC0) &&
+ (*Source != XRFDC_CLK_DST_DAC1)) { /*E: DAC0 must source from DAC1*/
+ Status = XRFDC_FAILURE;
+ metal_log(METAL_LOG_ERROR,
+ "\n Invalid Configuration "
+ "- Licensing in - Export Control %s\r\n",
+ __func__);
+ goto RETURN_PATH;
+ }
+ if ((CurrentTile == XRFDC_CLK_DST_DAC2) &&
+ (*Source != XRFDC_CLK_DST_DAC3)) { /*E: DAC2 must source from DAC3*/
+ Status = XRFDC_FAILURE;
+ metal_log(METAL_LOG_ERROR,
+ "\n Invalid Configuration "
+ "- Licensing in %s\r\n",
+ __func__);
+ goto RETURN_PATH;
+ }
+ }
+ }
+
+ if (*Source != DistributionPtr->DistributionSource) { /*i.e. if new distribution*/
+ DistributionPtr->UpperBound = CurrentTile - 1;
+ DistributionPtr++;
+ DistributionPtr->Enabled = XRFDC_ENABLED;
+ LowBoundary = *Source;
+ DistributionPtr->DistributionSource = *Source;
+ DistributionPtr->LowerBound = CurrentTile;
+ }
+ }
+ DistributionPtr->UpperBound = CurrentTile - 1;
+ Status = XRFDC_SUCCESS;
+RETURN_PATH:
+ if (Status == XRFDC_FAILURE) {
+ memset(DistributionSettingsPtr, 0, sizeof(XRFdc_Distribution_Settings));
+ }
+ return Status;
+}
+/*****************************************************************************/
+/**
+*
+* This function is used to set the clock distribution
+*
+* @param InstancePtr is a pointer to the XRfdc instance.
+* @param DistributionSettingsPtr pointer to the distribution settings struct
+*
+* @return
+* - XRFDC_SUCCESS if successful.
+* - XRFDC_FAILURE if could not set distribution.
+*
+******************************************************************************/
+u32 XRFdc_SetClkDistribution(XRFdc *InstancePtr, XRFdc_Distribution_Settings *DistributionSettingsPtr)
+{
+ u32 Status;
+ u8 DelayLeft;
+ u8 DelayRight;
+ s8 Delay;
+ s8 ClkDetItr;
+ u8 *Delays[8];
+ u8 DelayOutSourceLeft;
+ u8 DelayOutSourceRight;
+ XRFdc_Distribution *Distribution;
+ u8 DistributionCount;
+ u16 Reg;
+ u16 ClkDetectReg;
+ u8 FeedBackForInputRight = 0;
+ u8 FeedBackForInputLeft = 0;
+ u8 Tile;
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(DistributionSettingsPtr != NULL);
+ Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY);
+
+ if (InstancePtr->RFdc_Config.IPType < 2) {
+ Status = XRFDC_FAILURE;
+ metal_log(METAL_LOG_ERROR,
+ "\n Requested fuctionality not "
+ "available for this IP in %s\r\n",
+ __func__);
+ goto RETURN_PATH;
+ }
+
+ Status = XRFdc_CheckClkDistValid(InstancePtr, DistributionSettingsPtr);
+ if (Status != XRFDC_SUCCESS) {
+ metal_log(METAL_LOG_ERROR,
+ "\n Invalid Distribution "
+ "in %s\r\n",
+ __func__);
+ goto RETURN_PATH;
+ }
+ Delays[0] = &DistributionSettingsPtr->DAC[0].Delay;
+ Delays[1] = &DistributionSettingsPtr->DAC[1].Delay;
+ Delays[2] = &DistributionSettingsPtr->DAC[2].Delay;
+ Delays[3] = &DistributionSettingsPtr->DAC[3].Delay;
+ Delays[4] = &DistributionSettingsPtr->ADC[0].Delay;
+ Delays[5] = &DistributionSettingsPtr->ADC[1].Delay;
+ Delays[6] = &DistributionSettingsPtr->ADC[2].Delay;
+ Delays[7] = &DistributionSettingsPtr->ADC[3].Delay;
+ Status = XRFdc_Shutdown(InstancePtr, XRFDC_ADC_TILE, -1);
+ if (Status != XRFDC_SUCCESS) {
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+ Status = XRFdc_Shutdown(InstancePtr, XRFDC_DAC_TILE, -1);
+ if (Status != XRFDC_SUCCESS) {
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+ for (Distribution = DistributionSettingsPtr->DistributionStatus, DistributionCount = 0;
+ DistributionCount < XRFDC_DIST_MAX; Distribution++, DistributionCount++) {
+ if (Distribution->Enabled == XRFDC_DISABLED) {
+ break;
+ }
+ DelayLeft = (-Distribution->LowerBound + Distribution->DistributionSource);
+ DelayRight = (Distribution->UpperBound - Distribution->DistributionSource);
+ DelayOutSourceLeft = 0;
+ DelayOutSourceRight = 0;
+ Distribution->MaxDelay = 0;
+ Distribution->MinDelay = 255;
+ Distribution->IsDelayBalanced = 0;
+ if ((DelayLeft == 0) && (DelayRight == 0)) { /*self contained*/
+ Reg = XRFDC_CLK_DISTR_OFF;
+ } else {
+ Reg = XRFDC_CLK_DISTR_MUX9_SRC_INT;
+ if (DelayLeft == 0) {
+ Reg |= XRFDC_CLK_DISTR_MUX8_SRC_NTH;
+ } else {
+ Reg |= XRFDC_CLK_DISTR_MUX8_SRC_INT;
+ }
+ if (((Distribution->DistributionSource == XRFDC_CLK_DST_DAC3) ||
+ (Distribution->DistributionSource == XRFDC_CLK_DST_ADC3)) &&
+ ((DelayLeft > 1) || (DelayRight > 1))) /*cases for no FB from tile to right*/
+ {
+ Reg |= XRFDC_CLK_DISTR_MUX4A_SRC_INT | XRFDC_CLK_DISTR_MUX6_SRC_INT |
+ XRFDC_CLK_DISTR_MUX7_SRC_INT;
+ FeedBackForInputRight = 0;
+ FeedBackForInputLeft = 0;
+ } else {
+ if (DelayLeft > 1) {
+ Reg |= XRFDC_CLK_DISTR_MUX4A_SRC_STH | XRFDC_CLK_DISTR_MUX6_SRC_NTH |
+ XRFDC_CLK_DISTR_MUX7_SRC_INT;
+ DelayOutSourceRight = 2;
+ FeedBackForInputRight = 0;
+ FeedBackForInputLeft = 1;
+ } else {
+ Reg |= XRFDC_CLK_DISTR_MUX4A_SRC_INT;
+ FeedBackForInputRight = 1;
+ FeedBackForInputLeft = 0;
+ if ((DelayRight > 1) &&
+ (Distribution->DistributionSource != XRFDC_CLK_DST_DAC2)) {
+ Reg |= XRFDC_CLK_DISTR_MUX7_SRC_STH;
+ DelayOutSourceLeft = 2;
+ } else {
+ Reg |= XRFDC_CLK_DISTR_MUX7_SRC_INT;
+ }
+ if (DelayRight == 0) {
+ Reg |= XRFDC_CLK_DISTR_MUX6_SRC_OFF;
+ } else {
+ Reg |= XRFDC_CLK_DISTR_MUX6_SRC_INT;
+ }
+ }
+ }
+ }
+
+ *Delays[Distribution->DistributionSource] =
+ (Reg == XRFDC_CLK_DISTR_OFF) ? 0 : DelayOutSourceLeft + DelayOutSourceRight + 2;
+ Distribution->MaxDelay = MAX(Distribution->MaxDelay, (*Delays[Distribution->DistributionSource]));
+ Distribution->MinDelay = MIN(Distribution->MinDelay, (*Delays[Distribution->DistributionSource]));
+
+ /* setup clk detect register */
+ ClkDetectReg = (XRFDC_CLOCK_DETECT_CLK <<
+ ((XRFDC_CLK_DST_ADC3 - Distribution->DistributionSource) << 1));
+
+ if ((Distribution->DistributionSource) < XRFDC_CLK_DST_ADC0) { /*DAC*/
+ XRFdc_ClrSetReg(InstancePtr,
+ XRFDC_DRP_BASE(XRFDC_DAC_TILE, (Distribution->DistributionSource)) +
+ XRFDC_HSCOM_ADDR,
+ XRFDC_HSCOM_CLK_DSTR_OFFSET, XRFDC_HSCOM_CLK_DSTR_MASK, Reg);
+ XRFdc_ClrSetReg(InstancePtr,
+ XRFDC_CTRL_STS_BASE(XRFDC_DAC_TILE, (Distribution->DistributionSource)),
+ XRFDC_CLOCK_DETECT_OFFSET, XRFDC_CLOCK_DETECT_MASK, ClkDetectReg);
+ } else { /*ADC*/
+ XRFdc_ClrSetReg(InstancePtr,
+ XRFDC_DRP_BASE(XRFDC_ADC_TILE,
+ (Distribution->DistributionSource - XRFDC_CLK_DST_ADC0)) +
+ XRFDC_HSCOM_ADDR,
+ XRFDC_HSCOM_CLK_DSTR_OFFSET, XRFDC_HSCOM_CLK_DSTR_MASK, Reg);
+ XRFdc_ClrSetReg(InstancePtr,
+ XRFDC_CTRL_STS_BASE(XRFDC_ADC_TILE,
+ (Distribution->DistributionSource - XRFDC_CLK_DST_ADC0)),
+ XRFDC_CLOCK_DETECT_OFFSET, XRFDC_CLOCK_DETECT_MASK, ClkDetectReg);
+ }
+ /*Leftmost tile*/
+ if (DelayLeft) {
+ *Delays[Distribution->LowerBound] = DelayOutSourceLeft + (DelayLeft << 1);
+ Distribution->MaxDelay = MAX(Distribution->MaxDelay, (*Delays[Distribution->LowerBound]));
+ Distribution->MinDelay = MIN(Distribution->MinDelay, (*Delays[Distribution->LowerBound]));
+ Reg = XRFDC_CLK_DISTR_MUX4A_SRC_STH | XRFDC_CLK_DISTR_MUX6_SRC_OFF |
+ XRFDC_CLK_DISTR_MUX7_SRC_OFF | XRFDC_CLK_DISTR_MUX8_SRC_NTH |
+ XRFDC_CLK_DISTR_MUX9_SRC_INT;
+
+ /* setup clk detect register */
+ ClkDetectReg = (XRFDC_CLOCK_DETECT_BOTH <<
+ ((XRFDC_CLK_DST_ADC3 - Distribution->DistributionSource) << 1));
+ for (ClkDetItr = DelayLeft - 1; ClkDetItr > 0; ClkDetItr--) {
+ ClkDetectReg |= (XRFDC_CLOCK_DETECT_DIST <<
+ ((XRFDC_CLK_DST_ADC3 - (Distribution->DistributionSource - ClkDetItr)) << 1));
+ }
+
+ if ((Distribution->DistributionSource - DelayLeft) < XRFDC_CLK_DST_ADC0) { /*DAC*/
+ XRFdc_ClrSetReg(InstancePtr,
+ XRFDC_DRP_BASE(XRFDC_DAC_TILE,
+ (Distribution->DistributionSource - DelayLeft)) +
+ XRFDC_HSCOM_ADDR,
+ XRFDC_HSCOM_CLK_DSTR_OFFSET, XRFDC_HSCOM_CLK_DSTR_MASK, Reg);
+ XRFdc_ClrSetReg(InstancePtr,
+ XRFDC_CTRL_STS_BASE(XRFDC_DAC_TILE, (Distribution->DistributionSource - DelayLeft)),
+ XRFDC_CLOCK_DETECT_OFFSET, XRFDC_CLOCK_DETECT_MASK, ClkDetectReg);
+ } else { /*ADC*/
+ XRFdc_ClrSetReg(InstancePtr,
+ XRFDC_DRP_BASE(XRFDC_ADC_TILE, (Distribution->DistributionSource -
+ DelayLeft - XRFDC_CLK_DST_ADC0)) +
+ XRFDC_HSCOM_ADDR,
+ XRFDC_HSCOM_CLK_DSTR_OFFSET, XRFDC_HSCOM_CLK_DSTR_MASK, Reg);
+ XRFdc_ClrSetReg(InstancePtr,
+ XRFDC_CTRL_STS_BASE(XRFDC_ADC_TILE,
+ (Distribution->DistributionSource - DelayLeft - XRFDC_CLK_DST_ADC0)),
+ XRFDC_CLOCK_DETECT_OFFSET, XRFDC_CLOCK_DETECT_MASK, ClkDetectReg);
+ }
+ }
+ /*Rest of tiles left of Distribution->DistributionSource*/
+ for (Delay = 1; Delay < DelayLeft; Delay++) {
+ Reg = XRFDC_CLK_DISTR_MUX6_SRC_OFF | XRFDC_CLK_DISTR_MUX7_SRC_STH |
+ XRFDC_CLK_DISTR_MUX8_SRC_INT | XRFDC_CLK_DISTR_MUX9_SRC_INT;
+ if (FeedBackForInputLeft == 0) {
+ Reg |= XRFDC_CLK_DISTR_MUX4A_SRC_STH;
+ } else {
+ Reg |= XRFDC_CLK_DISTR_MUX4A_SRC_INT;
+ }
+ *Delays[Distribution->DistributionSource - Delay] =
+ DelayOutSourceLeft + ((Delay + FeedBackForInputLeft) << 1);
+ Distribution->MaxDelay =
+ MAX(Distribution->MaxDelay, (*Delays[Distribution->DistributionSource - Delay]));
+ Distribution->MinDelay =
+ MIN(Distribution->MinDelay, (*Delays[Distribution->DistributionSource - Delay]));
+ FeedBackForInputLeft = !FeedBackForInputLeft;
+
+ /* setup clk detect register */
+ ClkDetectReg = (XRFDC_CLOCK_DETECT_BOTH <<
+ ((XRFDC_CLK_DST_ADC3 - Distribution->DistributionSource) << 1));
+ for (ClkDetItr = Delay - 1; ClkDetItr > 0; ClkDetItr--) {
+ ClkDetectReg |= (XRFDC_CLOCK_DETECT_DIST <<
+ ((XRFDC_CLK_DST_ADC3 - (Distribution->DistributionSource - ClkDetItr)) << 1));
+ }
+
+ if ((Distribution->DistributionSource - Delay) < XRFDC_CLK_DST_ADC0) { /*DAC*/
+ XRFdc_ClrSetReg(InstancePtr,
+ XRFDC_DRP_BASE(XRFDC_DAC_TILE,
+ (Distribution->DistributionSource - Delay)) +
+ XRFDC_HSCOM_ADDR,
+ XRFDC_HSCOM_CLK_DSTR_OFFSET, XRFDC_HSCOM_CLK_DSTR_MASK, Reg);
+ XRFdc_ClrSetReg(InstancePtr,
+ XRFDC_CTRL_STS_BASE(XRFDC_DAC_TILE, (Distribution->DistributionSource - Delay)),
+ XRFDC_CLOCK_DETECT_OFFSET, XRFDC_CLOCK_DETECT_MASK, ClkDetectReg);
+ } else { /*ADC*/
+ XRFdc_ClrSetReg(InstancePtr,
+ XRFDC_DRP_BASE(XRFDC_ADC_TILE, (Distribution->DistributionSource -
+ Delay - XRFDC_CLK_DST_ADC0)) +
+ XRFDC_HSCOM_ADDR,
+ XRFDC_HSCOM_CLK_DSTR_OFFSET, XRFDC_HSCOM_CLK_DSTR_MASK, Reg);
+ XRFdc_ClrSetReg(InstancePtr,
+ XRFDC_CTRL_STS_BASE(XRFDC_ADC_TILE,
+ (Distribution->DistributionSource - Delay - XRFDC_CLK_DST_ADC0)),
+ XRFDC_CLOCK_DETECT_OFFSET, XRFDC_CLOCK_DETECT_MASK, ClkDetectReg);
+ }
+ }
+ /*Rightmost tile*/
+ if (DelayRight) {
+ Reg = XRFDC_CLK_DISTR_MUX4A_SRC_INT | XRFDC_CLK_DISTR_MUX6_SRC_OFF |
+ XRFDC_CLK_DISTR_MUX7_SRC_OFF | XRFDC_CLK_DISTR_MUX8_SRC_NTH |
+ XRFDC_CLK_DISTR_MUX9_SRC_NTH;
+ *Delays[Distribution->UpperBound] = DelayOutSourceRight + (DelayRight << 1);
+ Distribution->MaxDelay = MAX(Distribution->MaxDelay, (*Delays[Distribution->UpperBound]));
+ Distribution->MinDelay = MIN(Distribution->MinDelay, (*Delays[Distribution->UpperBound]));
+
+ /* setup clk detect register */
+ ClkDetectReg = (XRFDC_CLOCK_DETECT_BOTH <<
+ ((XRFDC_CLK_DST_ADC3 - Distribution->DistributionSource) << 1));
+ for (ClkDetItr = DelayRight - 1; ClkDetItr > 0; ClkDetItr--) {
+ ClkDetectReg |= (XRFDC_CLOCK_DETECT_DIST <<
+ ((XRFDC_CLK_DST_ADC3 - (Distribution->DistributionSource + ClkDetItr)) << 1));
+ }
+
+ if ((Distribution->DistributionSource + DelayRight) < XRFDC_CLK_DST_ADC0) { /*DAC*/
+ XRFdc_ClrSetReg(InstancePtr,
+ XRFDC_DRP_BASE(XRFDC_DAC_TILE,
+ (Distribution->DistributionSource + DelayRight)) +
+ XRFDC_HSCOM_ADDR,
+ XRFDC_HSCOM_CLK_DSTR_OFFSET, XRFDC_HSCOM_CLK_DSTR_MASK, Reg);
+ XRFdc_ClrSetReg(InstancePtr,
+ XRFDC_CTRL_STS_BASE(XRFDC_DAC_TILE, (Distribution->DistributionSource + DelayRight)),
+ XRFDC_CLOCK_DETECT_OFFSET, XRFDC_CLOCK_DETECT_MASK, ClkDetectReg);
+ } else { /*ADC*/
+ XRFdc_ClrSetReg(InstancePtr,
+ XRFDC_DRP_BASE(XRFDC_ADC_TILE, (Distribution->DistributionSource +
+ DelayRight - XRFDC_CLK_DST_ADC0)) +
+ XRFDC_HSCOM_ADDR,
+ XRFDC_HSCOM_CLK_DSTR_OFFSET, XRFDC_HSCOM_CLK_DSTR_MASK, Reg);
+ XRFdc_ClrSetReg(InstancePtr,
+ XRFDC_CTRL_STS_BASE(XRFDC_ADC_TILE,
+ (Distribution->DistributionSource + DelayRight - XRFDC_CLK_DST_ADC0)),
+ XRFDC_CLOCK_DETECT_OFFSET, XRFDC_CLOCK_DETECT_MASK, ClkDetectReg);
+ }
+ }
+ /*rest of tiles to right*/
+ for (Delay = 1; Delay < DelayRight; Delay++) {
+ if (((Delay + Distribution->DistributionSource) == 3) || (FeedBackForInputRight == 0)) {
+ FeedBackForInputRight = 0;
+ Reg = XRFDC_CLK_DISTR_MUX4A_SRC_INT;
+ *Delays[Distribution->DistributionSource + Delay] = DelayOutSourceRight + (Delay << 1);
+ } else {
+ Reg = XRFDC_CLK_DISTR_MUX4A_SRC_STH;
+ *Delays[Distribution->DistributionSource + Delay] =
+ DelayOutSourceRight + ((Delay + 1) << 1);
+ }
+ Distribution->MaxDelay =
+ MAX(Distribution->MaxDelay, (*Delays[Distribution->DistributionSource + Delay]));
+ Distribution->MinDelay =
+ MIN(Distribution->MinDelay, (*Delays[Distribution->DistributionSource + Delay]));
+ FeedBackForInputRight = !FeedBackForInputRight;
+ Reg |= XRFDC_CLK_DISTR_MUX6_SRC_NTH | XRFDC_CLK_DISTR_MUX7_SRC_OFF |
+ XRFDC_CLK_DISTR_MUX8_SRC_NTH | XRFDC_CLK_DISTR_MUX9_SRC_NTH;
+
+ /* setup clk detect register */
+ ClkDetectReg = (XRFDC_CLOCK_DETECT_BOTH <<
+ ((XRFDC_CLK_DST_ADC3 - Distribution->DistributionSource) << 1));
+ for (ClkDetItr = Delay - 1; ClkDetItr > 0; ClkDetItr--) {
+ ClkDetectReg |= (XRFDC_CLOCK_DETECT_DIST <<
+ ((XRFDC_CLK_DST_ADC3 - (Distribution->DistributionSource + ClkDetItr)) << 1));
+ }
+
+ if ((Distribution->DistributionSource + Delay) < XRFDC_CLK_DST_ADC0) { /*DAC*/
+ XRFdc_ClrSetReg(InstancePtr,
+ XRFDC_DRP_BASE(XRFDC_DAC_TILE,
+ (Distribution->DistributionSource + Delay)) +
+ XRFDC_HSCOM_ADDR,
+ XRFDC_HSCOM_CLK_DSTR_OFFSET, XRFDC_HSCOM_CLK_DSTR_MASK, Reg);
+ XRFdc_ClrSetReg(InstancePtr,
+ XRFDC_CTRL_STS_BASE(XRFDC_DAC_TILE, (Distribution->DistributionSource + Delay)),
+ XRFDC_CLOCK_DETECT_OFFSET, XRFDC_CLOCK_DETECT_MASK, ClkDetectReg);
+ } else { /*ADC*/
+ XRFdc_ClrSetReg(InstancePtr,
+ XRFDC_DRP_BASE(XRFDC_ADC_TILE, (Distribution->DistributionSource +
+ Delay - XRFDC_CLK_DST_ADC0)) +
+ XRFDC_HSCOM_ADDR,
+ XRFDC_HSCOM_CLK_DSTR_OFFSET, XRFDC_HSCOM_CLK_DSTR_MASK, Reg);
+ XRFdc_ClrSetReg(InstancePtr,
+ XRFDC_CTRL_STS_BASE(XRFDC_ADC_TILE,
+ (Distribution->DistributionSource + Delay - XRFDC_CLK_DST_ADC0)),
+ XRFDC_CLOCK_DETECT_OFFSET, XRFDC_CLOCK_DETECT_MASK, ClkDetectReg);
+ }
+ }
+ Distribution->IsDelayBalanced = (Distribution->MaxDelay == Distribution->MinDelay) ? 1 : 0;
+ }
+ for (Tile = 0; Tile < XRFDC_NUM_OF_TILES4; Tile++) {
+ XRFdc_SetTileClkSettings(InstancePtr, XRFDC_ADC_TILE, Tile, &DistributionSettingsPtr->ADC[Tile]);
+ XRFdc_SetTileClkSettings(InstancePtr, XRFDC_DAC_TILE, Tile, &DistributionSettingsPtr->DAC[Tile]);
+ }
+ Status = XRFdc_StartUp(InstancePtr, XRFDC_ADC_TILE, -1);
+ if (Status != XRFDC_SUCCESS) {
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+ Status = XRFdc_StartUp(InstancePtr, XRFDC_DAC_TILE, -1);
+ if (Status != XRFDC_SUCCESS) {
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+ Status = XRFDC_SUCCESS;
+RETURN_PATH:
+ return Status;
+}
+/*****************************************************************************/
+/**
+*
+* This function is used to get the clock distribution
+*
+* @param InstancePtr is a pointer to the XRfdc instance.
+* @param DistributionSettingsPtr pointer to get the distribution settings
+*
+* @return
+* - XRFDC_SUCCESS if successful.
+* - XRFDC_FAILURE if no valid distribution found.
+*
+******************************************************************************/
+u32 XRFdc_GetClkDistribution(XRFdc *InstancePtr, XRFdc_Distribution_Settings *DistributionSettingsPtr)
+{
+ u32 Status;
+ u16 ReadReg;
+ u8 *Tile[8];
+ u8 CurrentTile;
+ s8 AdjacentTile;
+ u8 DelayOutSourceLeft;
+ u8 DelayOutSourceRight;
+ u8 *Delays[8];
+ XRFdc_Distribution *Distribution;
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(DistributionSettingsPtr != NULL);
+ Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY);
+
+ if (InstancePtr->RFdc_Config.IPType < 2) {
+ Status = XRFDC_FAILURE;
+ metal_log(METAL_LOG_ERROR,
+ "\n Requested fuctionality not "
+ "available for this IP in %s\r\n",
+ __func__);
+ goto RETURN_PATH;
+ }
+
+ Distribution = DistributionSettingsPtr->DistributionStatus;
+ Delays[0] = &DistributionSettingsPtr->DAC[0].Delay;
+ Delays[1] = &DistributionSettingsPtr->DAC[1].Delay;
+ Delays[2] = &DistributionSettingsPtr->DAC[2].Delay;
+ Delays[3] = &DistributionSettingsPtr->DAC[3].Delay;
+ Delays[4] = &DistributionSettingsPtr->ADC[0].Delay;
+ Delays[5] = &DistributionSettingsPtr->ADC[1].Delay;
+ Delays[6] = &DistributionSettingsPtr->ADC[2].Delay;
+ Delays[7] = &DistributionSettingsPtr->ADC[3].Delay;
+ Tile[0] = &DistributionSettingsPtr->DAC[0].SourceTile;
+ Tile[1] = &DistributionSettingsPtr->DAC[1].SourceTile;
+ Tile[2] = &DistributionSettingsPtr->DAC[2].SourceTile;
+ Tile[3] = &DistributionSettingsPtr->DAC[3].SourceTile;
+ Tile[4] = &DistributionSettingsPtr->ADC[0].SourceTile;
+ Tile[5] = &DistributionSettingsPtr->ADC[1].SourceTile;
+ Tile[6] = &DistributionSettingsPtr->ADC[2].SourceTile;
+ Tile[7] = &DistributionSettingsPtr->ADC[3].SourceTile;
+ memset(DistributionSettingsPtr, XRFDC_CLK_DST_INVALID, sizeof(XRFdc_Distribution_Settings));
+
+ for (CurrentTile = 0; CurrentTile < XRFDC_DIST_MAX; CurrentTile++) {
+ DelayOutSourceLeft = 0;
+ DelayOutSourceRight = 0;
+ if (*Tile[CurrentTile] != XRFDC_CLK_DST_INVALID) {
+ continue;
+ }
+
+ if (CurrentTile < XRFDC_CLK_DST_ADC0) { /*DAC*/
+ ReadReg = XRFdc_ReadReg16(InstancePtr,
+ XRFDC_DRP_BASE(XRFDC_DAC_TILE, CurrentTile) + XRFDC_HSCOM_ADDR,
+ XRFDC_HSCOM_CLK_DSTR_OFFSET) &
+ XRFDC_HSCOM_CLK_DSTR_MASK;
+ } else { /*ADC*/
+ ReadReg = XRFdc_ReadReg16(InstancePtr,
+ XRFDC_DRP_BASE(XRFDC_ADC_TILE, (CurrentTile - XRFDC_CLK_DST_ADC0)) +
+ XRFDC_HSCOM_ADDR,
+ XRFDC_HSCOM_CLK_DSTR_OFFSET) &
+ XRFDC_HSCOM_CLK_DSTR_MASK;
+ }
+
+ if (ReadReg == XRFDC_CLK_DISTR_OFF) { /*it is its own source no dist*/
+ *Tile[CurrentTile] = CurrentTile;
+ *Delays[CurrentTile] = 0;
+ Distribution->MaxDelay = 0;
+ Distribution->MinDelay = 0;
+ Distribution->IsDelayBalanced = 1;
+ Distribution++;
+ } else if (ReadReg & (XRFDC_CLK_DISTR_MUX6_SRC_INT |
+ XRFDC_CLK_DISTR_MUX7_SRC_INT)) { /*it is its own source, distributes its clk*/
+ Distribution->MaxDelay = 0;
+ Distribution->MinDelay = 255;
+ Distribution->IsDelayBalanced = 0;
+ *Tile[CurrentTile] = CurrentTile;
+ if (ReadReg & XRFDC_CLK_DISTR_MUX7_SRC_STH) {
+ DelayOutSourceLeft = 2;
+ } else if (ReadReg & XRFDC_CLK_DISTR_MUX6_SRC_NTH) {
+ DelayOutSourceRight = 2;
+ }
+ *Delays[CurrentTile] = DelayOutSourceLeft + DelayOutSourceRight + 2;
+ Distribution->MaxDelay = MAX(Distribution->MaxDelay, (*Delays[CurrentTile]));
+ Distribution->MinDelay = MIN(Distribution->MinDelay, (*Delays[CurrentTile]));
+ /*work right*/
+ for (AdjacentTile = CurrentTile + 1; AdjacentTile <= XRFDC_CLK_DST_ADC3; AdjacentTile++) {
+ if (AdjacentTile < XRFDC_CLK_DST_ADC0) { /*DAC*/
+ ReadReg = XRFdc_ReadReg16(InstancePtr,
+ XRFDC_DRP_BASE(XRFDC_DAC_TILE, AdjacentTile) +
+ XRFDC_HSCOM_ADDR,
+ XRFDC_HSCOM_CLK_DSTR_OFFSET) &
+ XRFDC_HSCOM_CLK_DSTR_MASK;
+ } else { /*ADC*/
+ ReadReg = XRFdc_ReadReg16(InstancePtr,
+ XRFDC_DRP_BASE(XRFDC_ADC_TILE,
+ (AdjacentTile - XRFDC_CLK_DST_ADC0)) +
+ XRFDC_HSCOM_ADDR,
+ XRFDC_HSCOM_CLK_DSTR_OFFSET) &
+ XRFDC_HSCOM_CLK_DSTR_MASK;
+ }
+ if ((ReadReg == XRFDC_CLK_DISTR_CONT_RIGHT_EVEN) &&
+ (AdjacentTile != XRFDC_CLK_DST_DAC3)) {
+ *Tile[AdjacentTile] = CurrentTile;
+ *Delays[AdjacentTile] =
+ DelayOutSourceRight + ((AdjacentTile - CurrentTile) << 1) + 2;
+ Distribution->MaxDelay = MAX(Distribution->MaxDelay, (*Delays[AdjacentTile]));
+ Distribution->MinDelay = MIN(Distribution->MinDelay, (*Delays[AdjacentTile]));
+ } else if (ReadReg == XRFDC_CLK_DISTR_CONT_RIGHT_HWL_ODD) {
+ *Tile[AdjacentTile] = CurrentTile;
+ *Delays[AdjacentTile] =
+ DelayOutSourceRight + ((AdjacentTile - CurrentTile) << 1);
+ Distribution->MaxDelay = MAX(Distribution->MaxDelay, (*Delays[AdjacentTile]));
+ Distribution->MinDelay = MIN(Distribution->MinDelay, (*Delays[AdjacentTile]));
+ } else if (ReadReg == XRFDC_CLK_DISTR_RIGHTMOST_TILE) {
+ *Tile[AdjacentTile] = CurrentTile;
+ *Delays[AdjacentTile] =
+ DelayOutSourceRight + ((AdjacentTile - CurrentTile) << 1);
+ Distribution->MaxDelay = MAX(Distribution->MaxDelay, (*Delays[AdjacentTile]));
+ Distribution->MinDelay = MIN(Distribution->MinDelay, (*Delays[AdjacentTile]));
+ break;
+ } else {
+ break;
+ }
+ }
+ /*work left*/
+ for (AdjacentTile = CurrentTile - 1; AdjacentTile >= XRFDC_CLK_DST_DAC0; AdjacentTile--) {
+ if (*Tile[AdjacentTile] != XRFDC_CLK_DST_INVALID) {
+ break;
+ }
+ if (AdjacentTile < XRFDC_CLK_DST_ADC0) { /*DAC*/
+ ReadReg = XRFdc_ReadReg16(InstancePtr,
+ XRFDC_DRP_BASE(XRFDC_DAC_TILE, AdjacentTile) +
+ XRFDC_HSCOM_ADDR,
+ XRFDC_HSCOM_CLK_DSTR_OFFSET) &
+ XRFDC_HSCOM_CLK_DSTR_MASK;
+ } else { /*ADC*/
+ ReadReg = XRFdc_ReadReg16(InstancePtr,
+ XRFDC_DRP_BASE(XRFDC_ADC_TILE,
+ (AdjacentTile - XRFDC_CLK_DST_ADC0)) +
+ XRFDC_HSCOM_ADDR,
+ XRFDC_HSCOM_CLK_DSTR_OFFSET) &
+ XRFDC_HSCOM_CLK_DSTR_MASK;
+ }
+ if (ReadReg == XRFDC_CLK_DISTR_LEFTMOST_TILE) {
+ *Tile[AdjacentTile] = CurrentTile;
+ *Delays[AdjacentTile] =
+ DelayOutSourceLeft + ((CurrentTile - AdjacentTile) << 1);
+ break;
+ } else if (ReadReg == XRFDC_CLK_DISTR_CONT_LEFT_EVEN) {
+ *Tile[AdjacentTile] = CurrentTile;
+ *Delays[AdjacentTile] =
+ DelayOutSourceLeft + ((CurrentTile - AdjacentTile) << 1) + 2;
+ } else if (ReadReg == XRFDC_CLK_DISTR_CONT_LEFT_ODD) {
+ *Delays[AdjacentTile] =
+ DelayOutSourceLeft + ((CurrentTile - AdjacentTile) << 1);
+ *Tile[AdjacentTile] = CurrentTile;
+ } else {
+ break;
+ }
+ Distribution->MaxDelay = MAX(Distribution->MaxDelay, (*Delays[AdjacentTile]));
+ Distribution->MinDelay = MIN(Distribution->MinDelay, (*Delays[AdjacentTile]));
+ }
+ Distribution->IsDelayBalanced = (Distribution->MaxDelay == Distribution->MinDelay) ? 1 : 0;
+ Distribution++;
+ }
+ }
+ Status = XRFdc_CheckClkDistValid(InstancePtr, DistributionSettingsPtr);
+ if (Status != XRFDC_SUCCESS) {
+ metal_log(METAL_LOG_ERROR,
+ "\n Invalid Distribution "
+ "in %s\r\n",
+ __func__);
+ goto RETURN_PATH;
+ }
+ Status = XRFDC_SUCCESS;
+RETURN_PATH:
+ return Status;
+}
+/*****************************************************************************/
+/**
+*
+* This function gets Clock source
+*
+* @param InstancePtr is a pointer to the XRfdc instance.
+* @param Type indicates ADC/DAC.
+* @param Tile_Id indicates Tile number (0-3).
+* @param ClockSourcePtr Pointer to return the clock source
+*
+* @return
+* - XRFDC_SUCCESS if successful.
+* - XRFDC_FAILURE if Tile not enabled.
+*
+* @note None.
+*
+******************************************************************************/
+u32 XRFdc_GetClockSource(XRFdc *InstancePtr, u32 Type, u32 Tile_Id,
+ u32 *ClockSourcePtr)
+{
+ u32 BaseAddr;
+ u32 Status;
+
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(ClockSourcePtr != NULL);
+
+ Status = XRFdc_CheckTileEnabled(InstancePtr, Type, Tile_Id);
+ if (Status != XRFDC_SUCCESS) {
+ metal_log(METAL_LOG_ERROR, "\n Requested tile not "
+ "available in %s\r\n", __func__);
+ goto RETURN_PATH;
+ }
+
+ BaseAddr = XRFDC_DRP_BASE(Type, Tile_Id) + XRFDC_HSCOM_ADDR;
+
+ *ClockSourcePtr = XRFdc_RDReg(InstancePtr, BaseAddr,
+ XRFDC_CLK_NETWORK_CTRL1, XRFDC_CLK_NETWORK_CTRL1_USE_PLL_MASK);
+
+ Status = XRFDC_SUCCESS;
+RETURN_PATH:
+ return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function gets PLL lock status
+*
+* @param InstancePtr is a pointer to the XRfdc instance.
+* @param Type indicates ADC/DAC.
+* @param Tile_Id indicates Tile number (0-3).
+* @param LockStatusPtr Pointer to return the PLL lock status
+*
+* @return
+* - XRFDC_SUCCESS if successful.
+* - XRFDC_FAILURE if Tile not enabled.
+*
+* @note None.
+*
+******************************************************************************/
+u32 XRFdc_GetPLLLockStatus(XRFdc *InstancePtr, u32 Type, u32 Tile_Id,
+ u32 *LockStatusPtr)
+{
+ u32 BaseAddr;
+ u32 ReadReg;
+ u32 ClkSrc = 0U;
+ u32 Status;
+
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(LockStatusPtr != NULL);
+
+ /*
+ * Get Tile clock source information
+ */
+ if (XRFdc_GetClockSource(InstancePtr, Type, Tile_Id, &ClkSrc)
+ != XRFDC_SUCCESS) {
+ metal_log(METAL_LOG_ERROR, "\n Get clock source request Tile %d "
+ "failed in %s\r\n", Tile_Id, __func__);
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+
+ if (ClkSrc == XRFDC_EXTERNAL_CLK) {
+ metal_log(METAL_LOG_DEBUG, "\n Requested Tile %d "
+ "uses external clock source in %s\r\n", Tile_Id, __func__);
+ *LockStatusPtr = XRFDC_PLL_LOCKED;
+ } else {
+ if (Type == XRFDC_ADC_TILE) {
+ BaseAddr = XRFDC_ADC_TILE_CTRL_STATS_ADDR(Tile_Id);
+ } else {
+ BaseAddr = XRFDC_DAC_TILE_CTRL_STATS_ADDR(Tile_Id);
+ }
+
+ ReadReg = XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_STATUS_OFFSET,
+ XRFDC_PLL_LOCKED_MASK);
+ if (ReadReg != 0U) {
+ *LockStatusPtr = XRFDC_PLL_LOCKED;
+ } else {
+ *LockStatusPtr = XRFDC_PLL_UNLOCKED;
+ }
+ }
+
+ Status = XRFDC_SUCCESS;
+RETURN_PATH:
+ return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function used for configuring the internal PLL registers
+* based on reference clock and sampling rate
+*
+* @param InstancePtr is a pointer to the XRfdc instance.
+* @param Type indicates ADC/DAC.
+* @param Tile_Id indicates Tile number (0-3).
+* @param RefClkFreq Reference Clock Frequency MHz(50MHz - 1.2GHz)
+* @param SamplingRate Sampling Rate in MHz(0.5- 4 GHz)
+*
+* @return
+* - XRFDC_SUCCESS if successful.
+* - XRFDC_FAILURE if Tile not enabled.
+*
+* @note None.
+*
+******************************************************************************/
+static u32 XRFdc_SetPLLConfig(XRFdc *InstancePtr, u32 Type, u32 Tile_Id,
+ double RefClkFreq, double SamplingRate)
+{
+ u32 BaseAddr;
+ u32 Status;
+ u32 FeedbackDiv;
+ u32 OutputDiv;
+ double CalcSamplingRate;
+ double PllFreq;
+ double SamplingError;
+ u32 Best_FeedbackDiv = 0x0U;
+ u32 Best_OutputDiv = 0x2U;
+ double Best_Error = 0xFFFFFFFFU;
+ u32 DivideMode = 0x0U;
+ u32 DivideValue = 0x0U;
+ u32 PllFreqIndex = 0x0U;
+ u32 FbDivIndex = 0x0U;
+ u32 RefClkDiv = 0x1;
+ u16 ReadReg;
+
+ if (Type == XRFDC_ADC_TILE) {
+ BaseAddr = XRFDC_ADC_TILE_DRP_ADDR(Tile_Id);
+ } else {
+ BaseAddr = XRFDC_DAC_TILE_DRP_ADDR(Tile_Id);
+ }
+
+ BaseAddr += XRFDC_HSCOM_ADDR;
+
+ ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, XRFDC_PLL_REFDIV);
+ if (ReadReg & XRFDC_REFCLK_DIV_1_MASK) {
+ RefClkDiv = XRFDC_REF_CLK_DIV_1;
+ } else {
+ switch (ReadReg & XRFDC_REFCLK_DIV_MASK) {
+ case XRFDC_REFCLK_DIV_2_MASK:
+ RefClkDiv = XRFDC_REF_CLK_DIV_2;
+ break;
+ case XRFDC_REFCLK_DIV_3_MASK:
+ RefClkDiv = XRFDC_REF_CLK_DIV_3;
+ break;
+ case XRFDC_REFCLK_DIV_4_MASK:
+ RefClkDiv = XRFDC_REF_CLK_DIV_4;
+ break;
+ default:
+ /*
+ * IP currently supporting 1 to 4 divider values. This
+ * error condition might change in future based on IP update.
+ */
+ metal_log(METAL_LOG_ERROR, "\n Unsupported Reference "
+ "clock Divider value in %s\r\n", __func__);
+ return XRFDC_FAILURE;
+ }
+ }
+
+ RefClkFreq /= RefClkDiv;
+
+ /*
+ * Sweep valid integer values of FeedbackDiv(N) and record a list
+ * of values that fall in the valid VCO range 8.5GHz - 12.8GHz
+ */
+ for (FeedbackDiv = PLL_FPDIV_MIN; FeedbackDiv <= PLL_FPDIV_MAX;
+ FeedbackDiv++) {
+
+ PllFreq = FeedbackDiv * RefClkFreq;
+
+ if ((PllFreq >= VCO_RANGE_MIN) && (PllFreq <= VCO_RANGE_MAX)) {
+ /*
+ * Sweep values of OutputDiv(M) to find the output frequency
+ * that best matches the user requested value
+ */
+
+ for (OutputDiv = PLL_DIVIDER_MIN; OutputDiv <= PLL_DIVIDER_MAX;
+ OutputDiv += 2U) {
+
+ CalcSamplingRate = (PllFreq / OutputDiv);
+
+ if (SamplingRate > CalcSamplingRate) {
+ SamplingError = SamplingRate - CalcSamplingRate;
+ } else {
+ SamplingError = CalcSamplingRate - SamplingRate;
+ }
+
+ if (Best_Error > SamplingError) {
+ Best_FeedbackDiv = FeedbackDiv;
+ Best_OutputDiv = OutputDiv;
+ Best_Error = SamplingError;
+ }
+ }
+
+ OutputDiv = 3U;
+ CalcSamplingRate = (PllFreq / OutputDiv);
+
+ if (SamplingRate > CalcSamplingRate) {
+ SamplingError = SamplingRate - CalcSamplingRate;
+ } else {
+ SamplingError = CalcSamplingRate - SamplingRate;
+ }
+
+ if (Best_Error > SamplingError) {
+ Best_FeedbackDiv = FeedbackDiv;
+ Best_OutputDiv = OutputDiv;
+ Best_Error = SamplingError;
+ }
+ }
+
+ /*
+ * PLL Static configuration
+ */
+ XRFdc_WriteReg16(InstancePtr, BaseAddr, XRFDC_PLL_SDM_CFG0, 0x80U);
+ XRFdc_WriteReg16(InstancePtr, BaseAddr, XRFDC_PLL_SDM_SEED0, 0x111U);
+ XRFdc_WriteReg16(InstancePtr, BaseAddr, XRFDC_PLL_SDM_SEED1, 0x11U);
+ XRFdc_WriteReg16(InstancePtr, BaseAddr, XRFDC_PLL_VREG, 0x45U);
+ XRFdc_WriteReg16(InstancePtr, BaseAddr, XRFDC_PLL_VCO0, 0x5800U);
+ XRFdc_WriteReg16(InstancePtr, BaseAddr, XRFDC_PLL_VCO1, 0x08U);
+
+ /*
+ * Set Feedback divisor value
+ */
+ XRFdc_WriteReg16(InstancePtr, BaseAddr, XRFDC_PLL_FPDIV,
+ Best_FeedbackDiv - 2U);
+
+ /*
+ * Set Output divisor value
+ */
+ if (Best_OutputDiv == 2U) {
+ DivideMode = 0x1U;
+ } else if (Best_OutputDiv == 3U) {
+ DivideMode = 0x2U;
+ DivideValue = 0x1U;
+ } else if (Best_OutputDiv >= 4U) {
+ DivideMode = 0x3U;
+ DivideValue = ((Best_OutputDiv - 4U)/2U);
+ }
+
+ XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_PLL_DIVIDER0,
+ XRFDC_PLL_DIVIDER0_MASK, ((DivideMode << XRFDC_PLL_DIVIDER0_SHIFT) | DivideValue));
+
+ /*
+ * Enable fine sweep
+ */
+ XRFdc_WriteReg16(InstancePtr, BaseAddr, XRFDC_PLL_CRS2, XRFDC_PLL_CRS2_VAL);
+
+ /*
+ * Set default PLL spare inputs LSB
+ */
+ XRFdc_WriteReg16(InstancePtr, BaseAddr, XRFDC_PLL_SPARE0, 0x507U);
+
+ /*
+ * Set PLL spare inputs MSB
+ */
+ XRFdc_WriteReg16(InstancePtr, BaseAddr, XRFDC_PLL_SPARE1, 0x0U);
+
+ PllFreq = RefClkFreq * Best_FeedbackDiv;
+
+ if (PllFreq < 9400U) {
+ PllFreqIndex = 0U;
+ FbDivIndex = 2U;
+ if (Best_FeedbackDiv < 21U) {
+ FbDivIndex = 0U;
+ } else if (Best_FeedbackDiv < 30U) {
+ FbDivIndex = 1U;
+ }
+ } else if (PllFreq < 10070U) {
+ PllFreqIndex = 1U;
+ FbDivIndex = 2U;
+ if (Best_FeedbackDiv < 18U) {
+ FbDivIndex = 0U;
+ } else if (Best_FeedbackDiv < 30U) {
+ FbDivIndex = 1U;
+ }
+ } else if (PllFreq < 10690U) {
+ PllFreqIndex = 2U;
+ FbDivIndex = 3U;
+ if (Best_FeedbackDiv < 18U) {
+ FbDivIndex = 0U;
+ } else if (Best_FeedbackDiv < 25U) {
+ FbDivIndex = 1U;
+ } else if (Best_FeedbackDiv < 35U) {
+ FbDivIndex = 2U;
+ }
+ } else if (PllFreq < 10990U) {
+ PllFreqIndex = 3U;
+ FbDivIndex = 3U;
+ if (Best_FeedbackDiv < 19U) {
+ FbDivIndex = 0U;
+ } else if (Best_FeedbackDiv < 27U) {
+ FbDivIndex = 1U;
+ } else if (Best_FeedbackDiv < 38U) {
+ FbDivIndex = 2U;
+ }
+ } else if (PllFreq < 11430U) {
+ PllFreqIndex = 4U;
+ FbDivIndex = 3U;
+ if (Best_FeedbackDiv < 19U) {
+ FbDivIndex = 0U;
+ } else if (Best_FeedbackDiv < 27U) {
+ FbDivIndex = 1U;
+ } else if (Best_FeedbackDiv < 38U) {
+ FbDivIndex = 2U;
+ }
+ } else if (PllFreq < 12040U) {
+ PllFreqIndex = 5U;
+ FbDivIndex = 3U;
+ if (Best_FeedbackDiv < 20U) {
+ FbDivIndex = 0U;
+ } else if (Best_FeedbackDiv < 28U) {
+ FbDivIndex = 1U;
+ } else if (Best_FeedbackDiv < 40U) {
+ FbDivIndex = 2U;
+ }
+ } else if (PllFreq < 12530U) {
+ PllFreqIndex = 6U;
+ FbDivIndex = 3U;
+ if (Best_FeedbackDiv < 23U) {
+ FbDivIndex = 0U;
+ } else if (Best_FeedbackDiv < 30U) {
+ FbDivIndex = 1U;
+ } else if (Best_FeedbackDiv < 42U) {
+ FbDivIndex = 2U;
+ }
+ } else if (PllFreq < 20000U) {
+ PllFreqIndex = 7U;
+ FbDivIndex = 2U;
+ if (Best_FeedbackDiv < 20U) {
+ FbDivIndex = 0U;
+ /*
+ * Set PLL spare inputs LSB
+ */
+ XRFdc_WriteReg16(InstancePtr, BaseAddr, XRFDC_PLL_SPARE0, 0x577);
+ } else if (Best_FeedbackDiv < 39U) {
+ FbDivIndex = 1U;
+ }
+ }
+
+ /*
+ * Enable automatic selection of the VCO, this will work with the
+ * IP version 2.0.1 and above and using older version of IP is
+ * not likely to work.
+ */
+ XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_PLL_CRS1,
+ XRFDC_PLL_VCO_SEL_AUTO_MASK, XRFDC_PLL_VCO_SEL_AUTO_MASK);
+
+ /*
+ * PLL bits for loop filters LSB
+ */
+ XRFdc_WriteReg16(InstancePtr, BaseAddr, XRFDC_PLL_LPF0,
+ PllTuningMatrix[PllFreqIndex][FbDivIndex][0]);
+
+ /*
+ * PLL bits for loop filters MSB
+ */
+ XRFdc_WriteReg16(InstancePtr, BaseAddr, XRFDC_PLL_LPF1, XRFDC_PLL_LPF1_VAL);
+
+ /*
+ * Set PLL bits for charge pumps
+ */
+ XRFdc_WriteReg16(InstancePtr, BaseAddr, XRFDC_PLL_CHARGEPUMP,
+ PllTuningMatrix[PllFreqIndex][FbDivIndex][1]);
+ }
+
+ CalcSamplingRate = (Best_FeedbackDiv * RefClkFreq) / Best_OutputDiv;
+ CalcSamplingRate /= XRFDC_MILLI;
+
+ if (Type == XRFDC_ADC_TILE) {
+ InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.SampleRate =
+ CalcSamplingRate;
+ InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.RefClkDivider = RefClkDiv;
+ InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.FeedbackDivider = Best_FeedbackDiv;
+ InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.OutputDivider = Best_OutputDiv;
+ } else {
+ InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.SampleRate =
+ CalcSamplingRate;
+ InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.RefClkDivider = RefClkDiv;
+ InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.FeedbackDivider = Best_FeedbackDiv;
+ InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.OutputDivider = Best_OutputDiv;
+ }
+
+ Status = XRFDC_SUCCESS;
+
+ return Status;
+}
+/*****************************************************************************/
+/**
+*
+* This API is used to get the PLL Configurations.
+*
+* @param InstancePtr is a pointer to the XRfdc instance.
+* @param Type represents ADC or DAC.
+* @param Tile_Id Valid values are 0-3.
+* @param PLLSettings pointer to the XRFdc_PLL_Settings structure to get
+* the PLL configurations
+*
+* @return None
+*
+******************************************************************************/
+u32 XRFdc_GetPLLConfig(XRFdc *InstancePtr, u32 Type,
+ u32 Tile_Id, XRFdc_PLL_Settings *PLLSettings)
+{
+ u32 Status;
+ u32 BaseAddr;
+ u16 ReadReg;
+ double RefClkFreq;
+ double SampleRate;
+ u32 FeedbackDivider;
+ u8 OutputDivider;
+ u32 RefClkDivider;
+ u32 Enabled;
+ u8 DivideMode;
+ u32 PLLFreq;
+ u32 PLLFS;
+
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY);
+ Xil_AssertNonvoid(PLLSettings != NULL);
+
+ Status = XRFdc_CheckTileEnabled(InstancePtr, Type, Tile_Id);
+ if (Status != XRFDC_SUCCESS) {
+ metal_log(METAL_LOG_ERROR, "\n Requested tile not "
+ "available in %s\r\n", __func__);
+ goto RETURN_PATH;
+ }
+
+ BaseAddr = XRFDC_CTRL_STS_BASE(Type, Tile_Id);
+ PLLFreq = XRFdc_ReadReg(InstancePtr, BaseAddr, XRFDC_PLL_FREQ);
+
+ RefClkFreq = ((double)PLLFreq)/1000;
+ PLLFS = XRFdc_ReadReg(InstancePtr, BaseAddr, XRFDC_PLL_FS);
+ SampleRate = ((double)PLLFS)/1000000;
+ if (PLLFS == 0) {
+ /*This code is here to support the old IPs.*/
+ if (Type == XRFDC_ADC_TILE) {
+ PLLSettings->Enabled =
+ InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.Enabled;
+ PLLSettings->FeedbackDivider =
+ InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.FeedbackDivider;
+ PLLSettings->OutputDivider =
+ InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.OutputDivider;
+ PLLSettings->RefClkDivider =
+ InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.RefClkDivider;
+ PLLSettings->RefClkFreq =
+ InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.RefClkFreq;
+ PLLSettings->SampleRate =
+ InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.SampleRate;
+ Status = XRFDC_SUCCESS;
+ goto RETURN_PATH;
+ } else {
+ PLLSettings->Enabled =
+ InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.Enabled;
+ PLLSettings->FeedbackDivider =
+ InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.FeedbackDivider;
+ PLLSettings->OutputDivider =
+ InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.OutputDivider;
+ PLLSettings->RefClkDivider =
+ InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.RefClkDivider;
+ PLLSettings->RefClkFreq =
+ InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.RefClkFreq;
+ PLLSettings->SampleRate =
+ InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.SampleRate;
+ Status = XRFDC_SUCCESS;
+ goto RETURN_PATH;
+ }
+ } else {
+ if (Type == XRFDC_ADC_TILE) {
+ BaseAddr = XRFDC_ADC_TILE_DRP_ADDR(Tile_Id);
+ } else {
+ BaseAddr = XRFDC_DAC_TILE_DRP_ADDR(Tile_Id);
+ }
+
+ BaseAddr += XRFDC_HSCOM_ADDR;
+
+ FeedbackDivider = XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_PLL_FPDIV, 0x00FF) + 2;
+
+ ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, XRFDC_PLL_REFDIV);
+ if (ReadReg & XRFDC_REFCLK_DIV_1_MASK) {
+ RefClkDivider = XRFDC_REF_CLK_DIV_1;
+ } else {
+ switch (ReadReg & XRFDC_REFCLK_DIV_MASK) {
+ case XRFDC_REFCLK_DIV_2_MASK:
+ RefClkDivider = XRFDC_REF_CLK_DIV_2;
+ break;
+ case XRFDC_REFCLK_DIV_3_MASK:
+ RefClkDivider = XRFDC_REF_CLK_DIV_3;
+ break;
+ case XRFDC_REFCLK_DIV_4_MASK:
+ RefClkDivider = XRFDC_REF_CLK_DIV_4;
+ break;
+ default:
+ /*
+ * IP currently supporting 1 to 4 divider values. This
+ * error condition might change in future based on IP update.
+ */
+ metal_log(METAL_LOG_ERROR, "\n Unsupported Reference "
+ "clock Divider value in %s\r\n", __func__);
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+ }
+ if (InstancePtr->RFdc_Config.IPType < 2) {
+ if (XRFdc_GetClockSource(InstancePtr, Type, Tile_Id, &Enabled)
+ != XRFDC_SUCCESS) {
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+ } else {
+ Enabled = (ReadReg & XRFDC_PLLREFDIV_INPUT_OFF)?XRFDC_DISABLED:XRFDC_ENABLED;
+ }
+
+ ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, XRFDC_PLL_DIVIDER0);
+ DivideMode = (ReadReg & XRFDC_PLL_DIVIDER0_MODE_MASK) >> XRFDC_PLL_DIVIDER0_SHIFT;
+
+ switch(DivideMode) {
+ case XRFDC_PLL_OUTDIV_MODE_1:
+ OutputDivider = 1;
+ break;
+ case XRFDC_PLL_OUTDIV_MODE_2:
+ OutputDivider = 2;
+ break;
+ case XRFDC_PLL_OUTDIV_MODE_3:
+ OutputDivider = 3;
+ break;
+ case XRFDC_PLL_OUTDIV_MODE_N:
+ OutputDivider = ((ReadReg & XRFDC_PLL_DIVIDER0_VALUE_MASK) + 2) << 1;
+ break;
+ default:
+ metal_log(METAL_LOG_ERROR, "\n Unsupported Output "
+ "clock Divider value in %s\r\n", __func__);
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ break;
+ }
+ PLLSettings->Enabled = Enabled;
+ PLLSettings->FeedbackDivider = FeedbackDivider;
+ PLLSettings->OutputDivider = OutputDivider;
+ PLLSettings->RefClkDivider = RefClkDivider;
+ PLLSettings->RefClkFreq = RefClkFreq;
+ PLLSettings->SampleRate = SampleRate;
+ }
+
+ Status = XRFDC_SUCCESS;
+RETURN_PATH:
+
+ return Status;
+}
+
+/*****************************************************************************/
+/**
+*
+* This function used for dynamically switch between internal PLL and
+* external clcok source and configuring the internal PLL
+*
+* @param InstancePtr is a pointer to the XRfdc instance.
+* @param Type indicates ADC/DAC
+* @param Tile_Id indicates Tile number (0-3)
+* @param Source Clock source internal PLL or external clock source
+* @param RefClkFreq Reference Clock Frequency in MHz(102.40625MHz - 1.2GHz)
+* @param SamplingRate Sampling Rate in MHz(0.1- 6.554GHz for DAC and
+* 0.5/1.0 - 2.058/4.116GHz for ADC based on the device package).
+*
+* @return
+* - XRFDC_SUCCESS if successful.
+* - XRFDC_FAILURE if Tile not enabled.
+*
+* @note This API enables automatic selection of the VCO which will work in
+* IP version 2.0.1 and above. Using older version of IP this API is
+* not likely to work.
+*
+******************************************************************************/
+u32 XRFdc_DynamicPLLConfig(XRFdc *InstancePtr, u32 Type, u32 Tile_Id,
+ u8 Source, double RefClkFreq, double SamplingRate)
+{
+ u32 ClkSrc = 0U;
+ u32 Status;
+ u32 BaseAddr;
+ u32 PLLEnable = 0x0;
+ u32 InitialPowerUpState;
+ double MaxSampleRate;
+ double MinSampleRate;
+ u32 PLLFreq;
+ u32 PLLFS;
+
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY);
+
+ if ((Source != XRFDC_INTERNAL_PLL_CLK) &&
+ (Source != XRFDC_EXTERNAL_CLK)) {
+ metal_log(METAL_LOG_ERROR, "\n Invalid Source "
+ "value in %s\r\n", __func__);
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+
+ Status = XRFdc_CheckTileEnabled(InstancePtr, Type, Tile_Id);
+ if (Status != XRFDC_SUCCESS) {
+ metal_log(METAL_LOG_ERROR, "\n Requested tile not "
+ "available in %s\r\n", __func__);
+ goto RETURN_PATH;
+ }
+
+ /*
+ * Get Tile clock source information
+ */
+ if (XRFdc_GetClockSource(InstancePtr, Type, Tile_Id, &ClkSrc)
+ != XRFDC_SUCCESS) {
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+
+ if (XRFdc_GetMaxSampleRate(InstancePtr, Type, Tile_Id, &MaxSampleRate) != XRFDC_SUCCESS) {
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+ if (XRFdc_GetMinSampleRate(InstancePtr, Type, Tile_Id, &MinSampleRate) != XRFDC_SUCCESS) {
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+ if ((SamplingRate < MinSampleRate) ||
+ (SamplingRate > MaxSampleRate)) {
+ metal_log(METAL_LOG_ERROR, "\n Invalid sampling "
+ "rate value in %s\r\n", __func__);
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+
+ BaseAddr = XRFDC_CTRL_STS_BASE(Type, Tile_Id);
+
+ if (Source == XRFDC_INTERNAL_PLL_CLK) {
+ if ((RefClkFreq < XRFDC_REFFREQ_MIN) ||
+ (RefClkFreq > XRFDC_REFFREQ_MAX)) {
+ metal_log(METAL_LOG_ERROR, "\n Input reference clock "
+ "frequency does not respect the specifications "
+ "for internal PLL usage. Please use a different "
+ "frequency or bypass the internal PLL", __func__);
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+ }
+
+ PLLFreq = (u32)(RefClkFreq*1000);
+ PLLFS = (u32)(SamplingRate*1000);
+ XRFdc_WriteReg(InstancePtr, BaseAddr, XRFDC_PLL_FREQ, PLLFreq);
+ XRFdc_WriteReg(InstancePtr, BaseAddr, XRFDC_PLL_FS, PLLFS);
+
+ if ((Source != XRFDC_INTERNAL_PLL_CLK) &&
+ (ClkSrc != XRFDC_INTERNAL_PLL_CLK)) {
+ metal_log(METAL_LOG_DEBUG, "\n Requested Tile %d "
+ "uses external clock source in %s\r\n", Tile_Id, __func__);
+ if (Type == XRFDC_ADC_TILE) {
+ InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.SampleRate =
+ (double)(SamplingRate/1000);
+ InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.RefClkFreq = RefClkFreq;
+ } else {
+ InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.SampleRate =
+ (double)(SamplingRate/1000);
+ InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.RefClkFreq = RefClkFreq;
+ }
+ Status = XRFDC_SUCCESS;
+ goto RETURN_PATH;
+ }
+
+ if (Type == XRFDC_ADC_TILE) {
+ BaseAddr = XRFDC_ADC_TILE_CTRL_STATS_ADDR(Tile_Id);
+ InitialPowerUpState = XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_STATUS_OFFSET, XRFDC_PWR_UP_STAT_MASK) >> XRFDC_PWR_UP_STAT_SHIFT;
+ BaseAddr = XRFDC_ADC_TILE_DRP_ADDR(Tile_Id) + XRFDC_HSCOM_ADDR;
+ } else {
+ BaseAddr = XRFDC_DAC_TILE_CTRL_STATS_ADDR(Tile_Id);
+ InitialPowerUpState = XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_STATUS_OFFSET, XRFDC_PWR_UP_STAT_MASK) >> XRFDC_PWR_UP_STAT_SHIFT;
+ BaseAddr = XRFDC_DAC_TILE_DRP_ADDR(Tile_Id) + XRFDC_HSCOM_ADDR;
+ }
+
+ /*
+ * Stop the ADC or DAC tile by putting tile in reset state if not stopped already
+ */
+ if (InitialPowerUpState != XRFDC_DISABLED) {
+ Status = XRFdc_Shutdown(InstancePtr, Type, Tile_Id) ;
+ if (Status != XRFDC_SUCCESS) {
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+ }
+ if (Source == XRFDC_INTERNAL_PLL_CLK) {
+ PLLEnable = 0x1;
+ /*
+ * Configure the PLL
+ */
+ if (XRFdc_SetPLLConfig(InstancePtr, Type, Tile_Id, RefClkFreq,
+ SamplingRate) != XRFDC_SUCCESS) {
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+
+ XRFdc_ClrSetReg(InstancePtr, BaseAddr,
+ XRFDC_CLK_NETWORK_CTRL1, XRFDC_CLK_NETWORK_CTRL1_USE_PLL_MASK,
+ XRFDC_CLK_NETWORK_CTRL1_USE_PLL_MASK);
+ XRFdc_WriteReg16(InstancePtr, BaseAddr, XRFDC_HSCOM_PWR_STATE_OFFSET,
+ XRFDC_HSCOM_PWR_STATS_PLL);
+ } else {
+ XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CLK_NETWORK_CTRL1,
+ XRFDC_CLK_NETWORK_CTRL1_USE_PLL_MASK, 0x0);
+ XRFdc_WriteReg16(InstancePtr, BaseAddr, XRFDC_HSCOM_PWR_STATE_OFFSET,
+ XRFDC_HSCOM_PWR_STATS_EXTERNAL);
+ SamplingRate /= XRFDC_MILLI;
+
+ if (Type == XRFDC_ADC_TILE) {
+ InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.SampleRate =
+ SamplingRate;
+ InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.RefClkDivider = 0x0U;
+ InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.FeedbackDivider = 0x0U;
+ InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.OutputDivider = 0x0U;
+ } else {
+ InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.SampleRate =
+ SamplingRate;
+ InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.RefClkDivider = 0x0U;
+ InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.FeedbackDivider = 0x0U;
+ InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.OutputDivider = 0x0U;
+ }
+ }
+
+ /*
+ * Re-start the ADC or DAC tile if tile was shut down in this function
+ */
+ if (InitialPowerUpState != XRFDC_DISABLED) {
+ Status = XRFdc_StartUp(InstancePtr, Type, Tile_Id) ;
+ if (Status != XRFDC_SUCCESS) {
+ Status = XRFDC_FAILURE;
+ goto RETURN_PATH;
+ }
+ }
+
+ if (Type == XRFDC_ADC_TILE) {
+ InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.RefClkFreq = RefClkFreq;
+ InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.Enabled = PLLEnable;
+ } else {
+ InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.RefClkFreq = RefClkFreq;
+ InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.Enabled = PLLEnable;
+ }
+
+ Status = XRFDC_SUCCESS;
+RETURN_PATH:
+ return Status;
+}
+/** @} */