diff options
Diffstat (limited to 'mpm/lib/rfdc/xrfdc_clock.c')
-rw-r--r-- | mpm/lib/rfdc/xrfdc_clock.c | 1801 |
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; +} +/** @} */ |