diff options
author | Lars Amsel <lars.amsel@ni.com> | 2021-06-04 08:27:50 +0200 |
---|---|---|
committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2021-06-10 12:01:53 -0500 |
commit | 2a575bf9b5a4942f60e979161764b9e942699e1e (patch) | |
tree | 2f0535625c30025559ebd7494a4b9e7122550a73 /mpm/lib/rfdc | |
parent | e17916220cc955fa219ae37f607626ba88c4afe3 (diff) | |
download | uhd-2a575bf9b5a4942f60e979161764b9e942699e1e.tar.gz uhd-2a575bf9b5a4942f60e979161764b9e942699e1e.tar.bz2 uhd-2a575bf9b5a4942f60e979161764b9e942699e1e.zip |
uhd: Add support for the USRP X410
Co-authored-by: Lars Amsel <lars.amsel@ni.com>
Co-authored-by: Michael Auchter <michael.auchter@ni.com>
Co-authored-by: Martin Braun <martin.braun@ettus.com>
Co-authored-by: Paul Butler <paul.butler@ni.com>
Co-authored-by: Cristina Fuentes <cristina.fuentes-curiel@ni.com>
Co-authored-by: Humberto Jimenez <humberto.jimenez@ni.com>
Co-authored-by: Virendra Kakade <virendra.kakade@ni.com>
Co-authored-by: Lane Kolbly <lane.kolbly@ni.com>
Co-authored-by: Max Köhler <max.koehler@ni.com>
Co-authored-by: Andrew Lynch <andrew.lynch@ni.com>
Co-authored-by: Grant Meyerhoff <grant.meyerhoff@ni.com>
Co-authored-by: Ciro Nishiguchi <ciro.nishiguchi@ni.com>
Co-authored-by: Thomas Vogel <thomas.vogel@ni.com>
Diffstat (limited to 'mpm/lib/rfdc')
-rw-r--r-- | mpm/lib/rfdc/CMakeLists.txt | 19 | ||||
-rw-r--r-- | mpm/lib/rfdc/README.md | 6 | ||||
-rw-r--r-- | mpm/lib/rfdc/patches/xrfdc.h.patch | 53 | ||||
-rw-r--r-- | mpm/lib/rfdc/patches/xrfdc_sinit.c.patch | 10 | ||||
-rw-r--r-- | mpm/lib/rfdc/rfdc_ctrl.cpp | 745 | ||||
-rw-r--r-- | mpm/lib/rfdc/rfdc_throw.cpp | 24 | ||||
-rw-r--r-- | mpm/lib/rfdc/xrfdc.c | 5345 | ||||
-rw-r--r-- | mpm/lib/rfdc/xrfdc_clock.c | 1801 | ||||
-rw-r--r-- | mpm/lib/rfdc/xrfdc_g.c | 619 | ||||
-rw-r--r-- | mpm/lib/rfdc/xrfdc_intr.c | 771 | ||||
-rw-r--r-- | mpm/lib/rfdc/xrfdc_mb.c | 786 | ||||
-rw-r--r-- | mpm/lib/rfdc/xrfdc_mixer.c | 1091 | ||||
-rw-r--r-- | mpm/lib/rfdc/xrfdc_mts.c | 1308 | ||||
-rw-r--r-- | mpm/lib/rfdc/xrfdc_sinit.c | 272 |
14 files changed, 12850 insertions, 0 deletions
diff --git a/mpm/lib/rfdc/CMakeLists.txt b/mpm/lib/rfdc/CMakeLists.txt new file mode 100644 index 000000000..a7401fd7b --- /dev/null +++ b/mpm/lib/rfdc/CMakeLists.txt @@ -0,0 +1,19 @@ +# +# Copyright 2019 Ettus Research, National Instruments Brand +# +# SPDX-License-Identifier: GPL-3.0 +# +set(RFDC_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/rfdc_ctrl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rfdc_throw.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/xrfdc_clock.c + ${CMAKE_CURRENT_SOURCE_DIR}/xrfdc_g.c + ${CMAKE_CURRENT_SOURCE_DIR}/xrfdc_intr.c + ${CMAKE_CURRENT_SOURCE_DIR}/xrfdc_mb.c + ${CMAKE_CURRENT_SOURCE_DIR}/xrfdc_mixer.c + ${CMAKE_CURRENT_SOURCE_DIR}/xrfdc_mts.c + ${CMAKE_CURRENT_SOURCE_DIR}/xrfdc_sinit.c + ${CMAKE_CURRENT_SOURCE_DIR}/xrfdc.c +) + +USRP_PERIPHS_ADD_OBJECT(rfdc ${RFDC_SOURCES}) diff --git a/mpm/lib/rfdc/README.md b/mpm/lib/rfdc/README.md new file mode 100644 index 000000000..ecf4fc054 --- /dev/null +++ b/mpm/lib/rfdc/README.md @@ -0,0 +1,6 @@ +The `xrfdc*.c` files here (and the files `mpm/include/mpm/rfdc/xrfdc*.h`) are derived from files in the `xilinx-v2019.1` tag of [embeddedsw](https://github.com/Xilinx/embeddedsw/), with the following changes: +* Include paths +* `Xil_Assert` macros in `xrfdc.h` were replaced with custom functionality. + * See `patches/xrfdc.h.patch` for the patch applied to that file. +* Call `closedir` in `xrfdc_sinit.c` + * See `patches/xrfdc_sinic.c.patch` for the patch diff --git a/mpm/lib/rfdc/patches/xrfdc.h.patch b/mpm/lib/rfdc/patches/xrfdc.h.patch new file mode 100644 index 000000000..d2fceb13a --- /dev/null +++ b/mpm/lib/rfdc/patches/xrfdc.h.patch @@ -0,0 +1,53 @@ +--- embeddedsw/XilinxProcessorIPLib/drivers/rfdc/src/xrfdc.h 2020-07-16 16:23:14.839402600 -0500 ++++ uhddev/mpm/include/mpm/rfdc/xrfdc.h 2020-08-17 12:31:24.477432400 -0500 +@@ -235,6 +235,7 @@ + + /***************************** Include Files *********************************/ + ++#include "rfdc_throw.h" + #include <stdlib.h> + #include <stdint.h> + +@@ -650,24 +651,24 @@ + + /***************** Macros (Inline Functions) Definitions *********************/ + +-#ifndef __BAREMETAL__ +-#define Xil_AssertNonvoid(Expression) \ +-{ \ +- if (!(Expression)) { \ +- while (1); \ +- } \ +-} +-#define Xil_AssertVoid(Expression) \ +-{ \ +- if (!(Expression)) { \ +- while (1); \ +- } \ +-} +-#define Xil_AssertVoidAlways() \ +-{ \ +- while (1); \ +-} +-#endif ++# ifndef __BAREMETAL__ ++# define Xil_AssertNonvoid(Expression) \ ++ { \ ++ if (!(Expression)) { \ ++ rfdc_throw(#Expression); \ ++ } \ ++ } ++# define Xil_AssertVoid(Expression) \ ++ { \ ++ if (!(Expression)) { \ ++ rfdc_throw(#Expression); \ ++ } \ ++ } ++# define Xil_AssertVoidAlways() \ ++ { \ ++ rfdc_throw("Assert false"); \ ++ } ++# endif + + #define MAX(x,y) (x>y)?x:y + #define MIN(x,y) (x<y)?x:y diff --git a/mpm/lib/rfdc/patches/xrfdc_sinit.c.patch b/mpm/lib/rfdc/patches/xrfdc_sinit.c.patch new file mode 100644 index 000000000..69a97e5df --- /dev/null +++ b/mpm/lib/rfdc/patches/xrfdc_sinit.c.patch @@ -0,0 +1,10 @@ +--- ../embeddedsw/XilinxProcessorIPLib/drivers/rfdc/src/xrfdc_sinit.c 2021-01-14 10:22:52.195957400 -0600 ++++ mpm/lib/rfdc/xrfdc_sinit.c 2021-01-14 10:24:59.611972600 -0600 +@@ -180,6 +180,7 @@ + metal_device_close(DevicePtr); + } + } ++ closedir(DirPtr); + } + return Status; + } diff --git a/mpm/lib/rfdc/rfdc_ctrl.cpp b/mpm/lib/rfdc/rfdc_ctrl.cpp new file mode 100644 index 000000000..94cd85c73 --- /dev/null +++ b/mpm/lib/rfdc/rfdc_ctrl.cpp @@ -0,0 +1,745 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#include "mpm/rfdc/rfdc_ctrl.hpp" +#include <mpm/exception.hpp> +#include <set> + +#define BUS_NAME "platform" + +namespace mpm { namespace rfdc { + +rfdc_ctrl::rfdc_ctrl() +{ + rfdc_inst_ptr = &rfdc_inst; + rfdc_inst_ptr->device = nullptr; + rfdc_inst_ptr->io = nullptr; + + // Populates default values to the struct + XRFdc_MultiConverter_Init(&rfdc_dac_sync_config, nullptr, nullptr); + XRFdc_MultiConverter_Init(&rfdc_adc_sync_config, nullptr, nullptr); +} + +rfdc_ctrl::~rfdc_ctrl() +{ + if (rfdc_inst_ptr && rfdc_inst_ptr->device) { + metal_device_close(rfdc_inst_ptr->device); + } + if (metal_init_complete) { + metal_finish(); + } +} + +void rfdc_ctrl::init(uint16_t rfdc_device_id) +{ + XRFdc_Config* config_ptr; + char device_name[NAME_MAX]; + + this->rfdc_device_id = rfdc_device_id; + + struct metal_init_params init_param = METAL_INIT_DEFAULTS; + + if (metal_init(&init_param)) { + throw mpm::runtime_error("Failed to run metal initialization for rfdc.\n"); + } + metal_init_complete = true; + + /* Get configuration data for te RFdc device */ + /* config_ptr is an entry of the XRFdc_ConfigTablePtr array managed by xrfdc_sinit.c + * This memory is not explicitly freed because we do not have access to + * XRFdc_ConfigTablePtr in this scope. */ + config_ptr = XRFdc_LookupConfig(rfdc_device_id); + if (config_ptr == NULL) { + throw mpm::runtime_error("Rfdc config lookup failed.\n"); + } + + /* Initializes the controller with loaded config information */ + if (XRFdc_CfgInitialize(rfdc_inst_ptr, config_ptr) != XRFDC_SUCCESS) { + throw mpm::runtime_error("Rfdc controller init failed.\n"); + } + + /* Set UpdateMixerScale into valid state. For some reason the + XRFdc config functions do not set this value. It will be + overwritten when XRFdc_SetMixerSettings is called next. */ + rfdc_inst_ptr->UpdateMixerScale = 0; + + if (XRFdc_GetDeviceNameByDeviceId(device_name, rfdc_device_id) < 0) { + throw mpm::runtime_error("Failed to find rfdc device with device id \n"); + } + + if (metal_device_open(BUS_NAME, device_name, &rfdc_inst_ptr->device)) { + throw mpm::runtime_error("Failed to open device.\n"); + } + + /* Map RFDC device IO region. 0 is the IO region index on the device. */ + rfdc_inst_ptr->io = metal_device_io_region(rfdc_inst_ptr->device, 0); + if (!rfdc_inst_ptr->io) { + throw mpm::runtime_error("Failed to map RFDC regio\n"); + } + + /* Set all gain threshold stickies to manual clear mode */ + for (int tile_id = 0; tile_id <= XRFDC_TILE_ID_MAX; tile_id++) { + for (int block_id = 0; block_id <= XRFDC_BLOCK_ID_MAX; block_id++) { + for (int threshold_id = 0; threshold_id < THRESHOLDS_PER_BLOCK; + threshold_id++) { + threshold_clr_modes[tile_id][block_id][threshold_id] = + THRESHOLD_CLRMD_UNKNOWN; + } + set_threshold_clr_mode( + tile_id, block_id, THRESHOLD_BOTH, THRESHOLD_CLRMD_MANUAL); + } + } +} + +bool rfdc_ctrl::startup_tile(int tile_id, bool is_dac) +{ + return XRFdc_StartUp(rfdc_inst_ptr, is_dac, tile_id) == XRFDC_SUCCESS; +} + +bool rfdc_ctrl::shutdown_tile(int tile_id, bool is_dac) +{ + return XRFdc_Shutdown(rfdc_inst_ptr, is_dac, tile_id) == XRFDC_SUCCESS; +} + +bool rfdc_ctrl::reset_tile(int tile_id, bool is_dac) +{ + return XRFdc_Reset(rfdc_inst_ptr, is_dac, tile_id) == XRFDC_SUCCESS; +} + +bool rfdc_ctrl::trigger_update_event( + uint32_t tile_id, uint32_t block_id, bool is_dac, event_type_options event_type) +{ + return XRFdc_UpdateEvent(rfdc_inst_ptr, is_dac, tile_id, block_id, event_type) + == XRFDC_SUCCESS; +} + +bool rfdc_ctrl::reset_mixer_settings(uint32_t tile_id, uint32_t block_id, bool is_dac) +{ + XRFdc_Mixer_Settings mixer_settings; + + mixer_settings.Freq = 200; + mixer_settings.PhaseOffset = 0; + mixer_settings.EventSource = XRFDC_EVNT_SRC_SYSREF; + mixer_settings.CoarseMixFreq = 16; + mixer_settings.MixerMode = is_dac ? MIXER_MODE_C2R : MIXER_MODE_R2C; + mixer_settings.FineMixerScale = 0; + mixer_settings.MixerType = XRFDC_MIXER_TYPE_FINE; + + return (XRFdc_SetMixerSettings( + rfdc_inst_ptr, is_dac, tile_id, block_id, &mixer_settings) + == XRFDC_SUCCESS); +} + +bool rfdc_ctrl::set_gain_enable( + uint32_t tile_id, uint32_t block_id, bool is_dac, bool enable) +{ + XRFdc_QMC_Settings qmc_settings; + + // Get current QMC settings for the values that will not be changed + if (XRFdc_GetQMCSettings(rfdc_inst_ptr, is_dac, tile_id, block_id, &qmc_settings) + != XRFDC_SUCCESS) { + return false; + } + + qmc_settings.EnableGain = enable; + // Update the setting on a SYSREF trigger + qmc_settings.EventSource = XRFDC_EVNT_SRC_SYSREF; + + return (XRFdc_SetQMCSettings(rfdc_inst_ptr, is_dac, tile_id, block_id, &qmc_settings) + == XRFDC_SUCCESS); +} + +bool rfdc_ctrl::set_gain(uint32_t tile_id, uint32_t block_id, bool is_dac, double gain) +{ + XRFdc_QMC_Settings qmc_settings; + + // Get current QMC settings for the values that will not be changed + if (XRFdc_GetQMCSettings(rfdc_inst_ptr, is_dac, tile_id, block_id, &qmc_settings) + != XRFDC_SUCCESS) { + return false; + } + + qmc_settings.EnableGain = 1; + qmc_settings.GainCorrectionFactor = gain; + // Update the setting on a SYSREF trigger + qmc_settings.EventSource = XRFDC_EVNT_SRC_SYSREF; + + return (XRFdc_SetQMCSettings(rfdc_inst_ptr, is_dac, tile_id, block_id, &qmc_settings) + == XRFDC_SUCCESS); +} + +bool rfdc_ctrl::set_threshold_settings(uint32_t tile_id, + uint32_t block_id, + threshold_id_options threshold_id, + threshold_mode_options mode, + uint32_t average_val, + uint32_t under_val, + uint32_t over_val) +{ + XRFdc_Threshold_Settings threshold_settings; + + // Get current threshold settings for the values that will not be changed + if (XRFdc_GetThresholdSettings(rfdc_inst_ptr, tile_id, block_id, &threshold_settings) + != XRFDC_SUCCESS) { + return false; + } + threshold_settings.UpdateThreshold = threshold_id; + + // Index 0 and 1 of the threshold settings struct correspond to threshold 0 and 1. + if (threshold_id == THRESHOLD_0 || threshold_id == THRESHOLD_BOTH) { + threshold_settings.ThresholdMode[0] = mode; + threshold_settings.ThresholdAvgVal[0] = average_val; + threshold_settings.ThresholdUnderVal[0] = under_val; + threshold_settings.ThresholdOverVal[0] = over_val; + } + if (threshold_id == THRESHOLD_1 || threshold_id == THRESHOLD_BOTH) { + threshold_settings.ThresholdMode[1] = mode; + threshold_settings.ThresholdAvgVal[1] = average_val; + threshold_settings.ThresholdUnderVal[1] = under_val; + threshold_settings.ThresholdOverVal[1] = over_val; + } + + return XRFdc_SetThresholdSettings( + rfdc_inst_ptr, tile_id, block_id, &threshold_settings) + == XRFDC_SUCCESS; +} + +bool rfdc_ctrl::clear_threshold_sticky( + uint32_t tile_id, uint32_t block_id, threshold_id_options threshold_id) +{ + bool result; + threshold_clr_mode_options old_clear_mode_0 = THRESHOLD_CLRMD_UNKNOWN, + old_clear_mode_1 = THRESHOLD_CLRMD_UNKNOWN; + + // Check current threshold clear mode + old_clear_mode_0 = get_threshold_clr_mode(tile_id, block_id, THRESHOLD_0); + old_clear_mode_1 = get_threshold_clr_mode(tile_id, block_id, THRESHOLD_1); + + // Set the clear mode to manual + if (!set_threshold_clr_mode( + tile_id, block_id, threshold_id, THRESHOLD_CLRMD_MANUAL)) { + return false; + } + + // Clear the sticky + // Do not return on a failure as the clear mode still needs to be returned to the + // previous value. + result = (XRFdc_ThresholdStickyClear(rfdc_inst_ptr, tile_id, block_id, threshold_id) + == XRFDC_SUCCESS); + + // Set the threshold clear mode back to the original setting + // If the old setting is the same or UNKNOWN this will do nothing. + result = result + && set_threshold_clr_mode(tile_id, block_id, THRESHOLD_0, old_clear_mode_0); + result = result + && set_threshold_clr_mode(tile_id, block_id, THRESHOLD_1, old_clear_mode_1); + return result; +} + +bool rfdc_ctrl::set_threshold_clr_mode(uint32_t tile_id, + uint32_t block_id, + threshold_id_options threshold_id, + threshold_clr_mode_options clear_mode) +{ + bool result; + bool mode_matches = false; + uint32_t old_clear_mode_0 = THRESHOLD_CLRMD_UNKNOWN, + old_clear_mode_1 = THRESHOLD_CLRMD_UNKNOWN; + + if ((tile_id > XRFDC_TILE_ID_MAX) || (block_id > XRFDC_BLOCK_ID_MAX)) { + return false; + } + // Do not change the clear mode to UNKNOWN + if (clear_mode == THRESHOLD_CLRMD_UNKNOWN) { + return false; + } + + // Check current threshold clear mode + switch (threshold_id) { + case THRESHOLD_0: + old_clear_mode_0 = get_threshold_clr_mode(tile_id, block_id, THRESHOLD_0); + mode_matches = (old_clear_mode_0 == clear_mode); + break; + case THRESHOLD_1: + old_clear_mode_1 = get_threshold_clr_mode(tile_id, block_id, THRESHOLD_1); + mode_matches = (old_clear_mode_1 == clear_mode); + break; + case THRESHOLD_BOTH: + old_clear_mode_0 = get_threshold_clr_mode(tile_id, block_id, THRESHOLD_0); + old_clear_mode_1 = get_threshold_clr_mode(tile_id, block_id, THRESHOLD_1); + mode_matches = + ((old_clear_mode_0 == clear_mode) && (old_clear_mode_1 == clear_mode)); + break; + } + // Do not change the clear mode if the new value matches the existing value + if (mode_matches) { + return true; + } + + result = (XRFdc_SetThresholdClrMode( + rfdc_inst_ptr, tile_id, block_id, threshold_id, clear_mode) + == XRFDC_SUCCESS); + // If the setting was not successful, save the clear mode as unknown + if (!result) { + clear_mode = THRESHOLD_CLRMD_UNKNOWN; + } + + // Set the new threshold clear mode + switch (threshold_id) { + case THRESHOLD_0: + threshold_clr_modes[tile_id][block_id][0] = clear_mode; + break; + case THRESHOLD_1: + threshold_clr_modes[tile_id][block_id][1] = clear_mode; + break; + case THRESHOLD_BOTH: + threshold_clr_modes[tile_id][block_id][0] = clear_mode; + threshold_clr_modes[tile_id][block_id][1] = clear_mode; + break; + } + return result; +} + +rfdc_ctrl::threshold_clr_mode_options rfdc_ctrl::get_threshold_clr_mode( + uint32_t tile_id, uint32_t block_id, threshold_id_options threshold_id) +{ + int threshold_index; + + // The XRFdc Threshold ID values (1-2) do not match the array indexes (0-1) + if (threshold_id == THRESHOLD_0) { + threshold_index = 0; + } else if (threshold_id == THRESHOLD_1) { + threshold_index = 1; + } + // An invalid Threshold ID was given + else { + return THRESHOLD_CLRMD_UNKNOWN; + } + if ((tile_id > XRFDC_TILE_ID_MAX) || (block_id > XRFDC_BLOCK_ID_MAX) + || (threshold_index >= THRESHOLDS_PER_BLOCK)) { + return THRESHOLD_CLRMD_UNKNOWN; + } + + return threshold_clr_modes[tile_id][block_id][threshold_index]; +} + +bool rfdc_ctrl::set_decoder_mode( + uint32_t tile_id, uint32_t block_id, decoder_mode_options decoder_mode) +{ + return XRFdc_SetDecoderMode(rfdc_inst_ptr, tile_id, block_id, decoder_mode) + == XRFDC_SUCCESS; +} + +bool rfdc_ctrl::reset_nco_phase(uint32_t tile_id, uint32_t block_id, bool is_dac) +{ + XRFdc_Mixer_Settings mixer_settings; + + // Get current mixer settings for the values that will not be changed + if (XRFdc_GetMixerSettings(rfdc_inst_ptr, is_dac, tile_id, block_id, &mixer_settings) + != XRFDC_SUCCESS) { + return false; + } + + // Reset the phase on a SYSREF trigger + mixer_settings.EventSource = XRFDC_EVNT_SRC_SYSREF; + + // Set the mixer settings to set the NCO event source + if (XRFdc_SetMixerSettings(rfdc_inst_ptr, is_dac, tile_id, block_id, &mixer_settings) + != XRFDC_SUCCESS) { + return false; + } + + return (XRFdc_ResetNCOPhase(rfdc_inst_ptr, is_dac, tile_id, block_id) + == XRFDC_SUCCESS); +} + +bool rfdc_ctrl::set_nco_freq( + uint32_t tile_id, uint32_t block_id, bool is_dac, double freq) +{ + XRFdc_Mixer_Settings mixer_settings; + + // Get current mixer settings for the values that will not be changed + if (XRFdc_GetMixerSettings(rfdc_inst_ptr, is_dac, tile_id, block_id, &mixer_settings) + != XRFDC_SUCCESS) { + return false; + } + + // The XRFdc API expects the NCO frequency in MHz + mixer_settings.Freq = freq / 1e6; + // Only the fine mixer uses an NCO to shift the data frequency + mixer_settings.MixerType = XRFDC_MIXER_TYPE_FINE; + // Update the setting on a tile-wide event trigger + mixer_settings.EventSource = XRFDC_EVNT_SRC_TILE; + + return (XRFdc_SetMixerSettings( + rfdc_inst_ptr, is_dac, tile_id, block_id, &mixer_settings) + == XRFDC_SUCCESS) + && trigger_update_event(tile_id, block_id, is_dac, MIXER_EVENT); +} + +double rfdc_ctrl::get_nco_freq(uint32_t tile_id, uint32_t block_id, bool is_dac) +{ + XRFdc_Mixer_Settings mixer_settings; + + if (XRFdc_GetMixerSettings(rfdc_inst_ptr, is_dac, tile_id, block_id, &mixer_settings) + != XRFDC_SUCCESS) { + throw mpm::runtime_error("Error in RFDC code: Failed to get mixer settings"); + } + // The XRFdc API returns the frequency in MHz + return mixer_settings.Freq * 1e6; +} + +bool rfdc_ctrl::set_nco_event_src(uint32_t tile_id, uint32_t block_id, bool is_dac) +{ + XRFdc_Mixer_Settings mixer_settings; + + // Get current mixer settings for the values that will not be changed + if (XRFdc_GetMixerSettings(rfdc_inst_ptr, is_dac, tile_id, block_id, &mixer_settings) + != XRFDC_SUCCESS) { + return false; + } + + // Reset the phase on a SYSREF trigger + mixer_settings.EventSource = XRFDC_EVNT_SRC_SYSREF; + + // Set the mixer settings to set the NCO event source + return (XRFdc_SetMixerSettings(rfdc_inst_ptr, is_dac, tile_id, block_id, &mixer_settings) + == XRFDC_SUCCESS); +} + +bool rfdc_ctrl::set_mixer_mode( + uint32_t tile_id, uint32_t block_id, bool is_dac, mixer_mode_options mixer_mode) +{ + XRFdc_Mixer_Settings mixer_settings; + + // Get current mixer settings for the values that will not be changed + if (XRFdc_GetMixerSettings(rfdc_inst_ptr, is_dac, tile_id, block_id, &mixer_settings) + != XRFDC_SUCCESS) { + return false; + } + + mixer_settings.MixerMode = mixer_mode; + // Update the setting on a tile-wide event trigger + mixer_settings.EventSource = XRFDC_EVNT_SRC_TILE; + + return (XRFdc_SetMixerSettings( + rfdc_inst_ptr, is_dac, tile_id, block_id, &mixer_settings) + == XRFDC_SUCCESS) + && trigger_update_event(tile_id, block_id, is_dac, MIXER_EVENT); +} + +bool rfdc_ctrl::set_nyquist_zone( + uint32_t tile_id, uint32_t block_id, bool is_dac, nyquist_zone_options nyquist_zone) +{ + return XRFdc_SetNyquistZone(rfdc_inst_ptr, is_dac, tile_id, block_id, nyquist_zone) + == XRFDC_SUCCESS; +} + +bool rfdc_ctrl::set_calibration_mode( + uint32_t tile_id, uint32_t block_id, calibration_mode_options calibration_mode) +{ + return XRFdc_SetCalibrationMode(rfdc_inst_ptr, tile_id, block_id, calibration_mode) + == XRFDC_SUCCESS; +} + +bool rfdc_ctrl::enable_inverse_sinc_filter( + uint32_t tile_id, uint32_t block_id, bool enable) +{ + return XRFdc_SetInvSincFIR(rfdc_inst_ptr, tile_id, block_id, enable) == XRFDC_SUCCESS; +} + +bool rfdc_ctrl::set_sample_rate(uint32_t tile_id, bool is_dac, double sample_rate) +{ + // The XRFdc API expects the sample rate in MHz + double sample_rate_mhz = sample_rate / 1e6; + return XRFdc_DynamicPLLConfig(rfdc_inst_ptr, + is_dac, + tile_id, + XRFDC_EXTERNAL_CLK, + sample_rate_mhz, + sample_rate_mhz) + == XRFDC_SUCCESS; +} + +double rfdc_ctrl::get_sample_rate(uint32_t tile_id, uint32_t block_id, bool is_dac) +{ + XRFdc_BlockStatus block_status; + + if (XRFdc_GetBlockStatus(rfdc_inst_ptr, is_dac, tile_id, block_id, &block_status) + != XRFDC_SUCCESS) { + throw mpm::runtime_error("Error in RFDC code: Failed to get Block status"); + } + // The XRFdc API returns the sampling frequency in GHz + return block_status.SamplingFreq * 1e9; +} + +bool rfdc_ctrl::set_if(uint32_t tile_id, uint32_t block_id, bool is_dac, double if_freq) +{ + nyquist_zone_options nyquist_zone; + mixer_mode_options mixer_mode; + bool enable_inverse_sinc; + double nco_freq; + + double nyquist_cutoff = get_sample_rate(tile_id, block_id, is_dac) / 2; + + if (if_freq <= nyquist_cutoff) { // First Nyquist Zone + nyquist_zone = ODD_NYQUIST_ZONE; + mixer_mode = is_dac ? MIXER_MODE_C2R : MIXER_MODE_R2C; + enable_inverse_sinc = true; + } else { // Second Nyquist Zone + nyquist_zone = EVEN_NYQUIST_ZONE; + mixer_mode = is_dac ? MIXER_MODE_C2R : MIXER_MODE_R2C; + enable_inverse_sinc = false; + } + + return set_nyquist_zone(tile_id, block_id, is_dac, nyquist_zone) + && set_mixer_mode(tile_id, block_id, is_dac, mixer_mode) + && (is_dac ? enable_inverse_sinc_filter(tile_id, block_id, enable_inverse_sinc) + : true) + && set_nco_freq(tile_id, block_id, is_dac, if_freq) + && set_nco_event_src(tile_id, block_id, is_dac); +} + +bool rfdc_ctrl::set_decimation_factor( + uint32_t tile_id, uint32_t block_id, interp_decim_options decimation_factor) +{ + return XRFdc_SetDecimationFactor(rfdc_inst_ptr, tile_id, block_id, decimation_factor) + == XRFDC_SUCCESS; +} + +rfdc_ctrl::interp_decim_options rfdc_ctrl::get_decimation_factor( + uint32_t tile_id, uint32_t block_id) +{ + uint32_t decimation_factor; + if (XRFdc_GetDecimationFactor(rfdc_inst_ptr, tile_id, block_id, &decimation_factor) + != XRFDC_SUCCESS) { + throw mpm::runtime_error("Error in RFDC code: Failed to get decimation factor"); + } + return (interp_decim_options)decimation_factor; +} + +bool rfdc_ctrl::set_interpolation_factor( + uint32_t tile_id, uint32_t block_id, interp_decim_options interpolation_factor) +{ + return XRFdc_SetInterpolationFactor( + rfdc_inst_ptr, tile_id, block_id, interpolation_factor) + == XRFDC_SUCCESS; +} + +rfdc_ctrl::interp_decim_options rfdc_ctrl::get_interpolation_factor( + uint32_t tile_id, uint32_t block_id) +{ + uint32_t interpolation_factor; + if (XRFdc_GetInterpolationFactor( + rfdc_inst_ptr, tile_id, block_id, &interpolation_factor) + != XRFDC_SUCCESS) { + throw mpm::runtime_error( + "Error in RFDC code: Failed to get interpolation factor"); + } + return (interp_decim_options)interpolation_factor; +} + +bool rfdc_ctrl::set_data_read_rate( + uint32_t tile_id, uint32_t block_id, uint32_t valid_read_words) +{ + return XRFdc_SetFabRdVldWords(rfdc_inst_ptr, tile_id, block_id, valid_read_words) + == XRFDC_SUCCESS; +} + +uint32_t rfdc_ctrl::get_data_read_rate(uint32_t tile_id, uint32_t block_id, bool is_dac) +{ + uint32_t valid_read_words; + if (XRFdc_GetFabRdVldWords( + rfdc_inst_ptr, is_dac, tile_id, block_id, &valid_read_words) + != XRFDC_SUCCESS) { + throw mpm::runtime_error("Error in RFDC code: Failed to get data read rate"); + } + return valid_read_words; +} + +bool rfdc_ctrl::set_data_write_rate( + uint32_t tile_id, uint32_t block_id, uint32_t valid_write_words) +{ + return XRFdc_SetFabWrVldWords(rfdc_inst_ptr, tile_id, block_id, valid_write_words) + == XRFDC_SUCCESS; +} + +uint32_t rfdc_ctrl::get_data_write_rate(uint32_t tile_id, uint32_t block_id, bool is_dac) +{ + uint32_t valid_write_words; + if (XRFdc_GetFabWrVldWords( + rfdc_inst_ptr, is_dac, tile_id, block_id, &valid_write_words) + != XRFDC_SUCCESS) { + throw mpm::runtime_error("Error in RFDC code: Failed to get data write rate"); + } + return valid_write_words; +} + +bool rfdc_ctrl::set_fabric_clk_div( + uint32_t tile_id, bool is_dac, fabric_clk_div_options divider) +{ + return XRFdc_SetFabClkOutDiv(rfdc_inst_ptr, is_dac, tile_id, divider) + == XRFDC_SUCCESS; +} + +rfdc_ctrl::fabric_clk_div_options rfdc_ctrl::get_fabric_clk_div( + uint32_t tile_id, bool is_dac) +{ + uint16_t divider; + if (XRFdc_GetFabClkOutDiv(rfdc_inst_ptr, is_dac, tile_id, ÷r) + != XRFDC_SUCCESS) { + throw mpm::runtime_error( + "Error in RFDC code: Failed to get fabric clock divider"); + } + return (fabric_clk_div_options)divider; +} + +bool rfdc_ctrl::set_data_fifo_state(uint32_t tile_id, bool is_dac, bool enable) +{ + return XRFdc_SetupFIFO(rfdc_inst_ptr, is_dac, tile_id, enable) == XRFDC_SUCCESS; +} + +bool rfdc_ctrl::get_data_fifo_state(uint32_t tile_id, bool is_dac) +{ + uint8_t enabled; + if (XRFdc_GetFIFOStatus(rfdc_inst_ptr, is_dac, tile_id, &enabled) != XRFDC_SUCCESS) { + throw mpm::runtime_error("Error in RFDC code: Failed to get FIFO status"); + } + return (bool)enabled; +} + +void rfdc_ctrl::clear_data_fifo_interrupts( + const uint32_t tile_id, const uint32_t block_id, const bool is_dac) +{ + if (XRFdc_IntrClr(rfdc_inst_ptr, + static_cast<u32>(is_dac), + tile_id, + block_id, + XRFDC_IXR_FIFOUSRDAT_MASK) + != XRFDC_SUCCESS) { + throw mpm::runtime_error( + "Error in RFDC code: Failed to clear data FIFO interrupts"); + } +} + +bool rfdc_ctrl::sync_tiles(const std::vector<uint32_t>& tiles, bool is_dac, uint32_t latency) +{ + XRFdc_MultiConverter_Sync_Config* sync_config = is_dac ? &rfdc_dac_sync_config + : &rfdc_adc_sync_config; + sync_config->Tiles = 0; + sync_config->Target_Latency = latency; + + for (auto tile = tiles.begin(); tile != tiles.end(); ++tile) { + // sync_config->Tiles is a bitmask, we need to "bump" each bit (0->1) + // that corresponds to the specified indices + sync_config->Tiles |= (1 << *tile); + } + + return XRFDC_MTS_OK + == XRFdc_MultiConverter_Sync( + &rfdc_inst, is_dac ? XRFDC_DAC_TILE : XRFDC_ADC_TILE, sync_config); +} + +uint32_t rfdc_ctrl::get_tile_latency(uint32_t tile_index, bool is_dac) +{ + XRFdc_MultiConverter_Sync_Config* sync_config = is_dac ? &rfdc_dac_sync_config + : &rfdc_adc_sync_config; + // If user has called sync with this tile_index, this + // attribute should be populated in our sync config + if ((1 << tile_index) & sync_config->Tiles) { + return sync_config->Latency[tile_index]; + } + if (is_dac) { + throw mpm::runtime_error("rfdc_ctrl: Failed to get DAC Tile Latency"); + } else { + throw mpm::runtime_error("rfdc_ctrl: Failed to get ADC Tile Latency"); + } +} + +uint32_t rfdc_ctrl::get_tile_offset(uint32_t tile_index, bool is_dac) +{ + XRFdc_MultiConverter_Sync_Config* sync_config = is_dac ? &rfdc_dac_sync_config + : &rfdc_adc_sync_config; + // If user has called sync with this tile_index, this + // attribute should be populated in our sync config + if ((1 << tile_index) & sync_config->Tiles) { + return sync_config->Offset[tile_index]; + } + if (is_dac) { + throw mpm::runtime_error("rfdc_ctrl: Failed to get DAC Tile Offset"); + } else { + throw mpm::runtime_error("rfdc_ctrl: Failed to get ADC Tile Offset"); + } +} + +void rfdc_ctrl::set_cal_frozen( + const uint32_t tile_id, const uint32_t block_id, const bool frozen) +{ + XRFdc_Cal_Freeze_Settings cal_freeze_settings; + cal_freeze_settings.CalFrozen = false; + cal_freeze_settings.DisableFreezePin = true; + cal_freeze_settings.FreezeCalibration = frozen; + if (XRFdc_SetCalFreeze(&rfdc_inst, tile_id, block_id, &cal_freeze_settings) + != XRFDC_SUCCESS) { + throw mpm::runtime_error( + "Error in RFDC code: Failed to set calibration freeze status"); + } +} + +bool rfdc_ctrl::get_cal_frozen(const uint32_t tile_id, const uint32_t block_id) +{ + XRFdc_Cal_Freeze_Settings cal_freeze_settings; + if (XRFdc_GetCalFreeze(&rfdc_inst, tile_id, block_id, &cal_freeze_settings) + != XRFDC_SUCCESS) { + throw mpm::runtime_error( + "Error in RFDC code: Failed to get calibration freeze status"); + } + return cal_freeze_settings.CalFrozen; +} + +void rfdc_ctrl::set_adc_cal_coefficients(uint32_t tile_id, uint32_t block_id, uint32_t cal_block, std::vector<uint32_t> coefs) +{ + if (coefs.size() != 8) + { + throw mpm::runtime_error("set_adc_cal_coefficients requires that exactly 8 coefficients be passed"); + } + + XRFdc_Calibration_Coefficients cs; + cs.Coeff0 = coefs[0]; + cs.Coeff1 = coefs[1]; + cs.Coeff2 = coefs[2]; + cs.Coeff3 = coefs[3]; + cs.Coeff4 = coefs[4]; + cs.Coeff5 = coefs[5]; + cs.Coeff6 = coefs[6]; + cs.Coeff7 = coefs[7]; + + if (XRFdc_SetCalCoefficients(&rfdc_inst, tile_id, block_id, cal_block, &cs) != XRFDC_SUCCESS) { + throw mpm::runtime_error("Error returned from XRFdc_SetCalCoefficients"); + } +} + +std::vector<uint32_t> rfdc_ctrl::get_adc_cal_coefficients(uint32_t tile_id, uint32_t block_id, uint32_t cal_block) +{ + std::vector<uint32_t> result; + XRFdc_Calibration_Coefficients cs; + if (XRFdc_GetCalCoefficients(&rfdc_inst, tile_id, block_id, cal_block, &cs) != XRFDC_SUCCESS) { + throw mpm::runtime_error("Error returned from XRFdc_GetCalCoefficients"); + } + + result.push_back(cs.Coeff0); + result.push_back(cs.Coeff1); + result.push_back(cs.Coeff2); + result.push_back(cs.Coeff3); + result.push_back(cs.Coeff4); + result.push_back(cs.Coeff5); + result.push_back(cs.Coeff6); + result.push_back(cs.Coeff7); + + return result; +} + +}} // namespace mpm::rfdc diff --git a/mpm/lib/rfdc/rfdc_throw.cpp b/mpm/lib/rfdc/rfdc_throw.cpp new file mode 100644 index 000000000..a50fe7c96 --- /dev/null +++ b/mpm/lib/rfdc/rfdc_throw.cpp @@ -0,0 +1,24 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +extern "C" { +#include "mpm/rfdc/rfdc_throw.h" +} +#include <mpm/exception.hpp> +#include <string> + +/** + * A function to throw MPM exceptions from within the Xilinx RFdc API + */ +void rfdc_throw(const char* msg) +{ + if (msg) { + std::string error_msg(msg); + throw mpm::assertion_error("Error in RFDC code: " + error_msg); + } else { + throw mpm::assertion_error("Error in RFDC code."); + } +} diff --git a/mpm/lib/rfdc/xrfdc.c b/mpm/lib/rfdc/xrfdc.c new file mode 100644 index 000000000..6261db774 --- /dev/null +++ b/mpm/lib/rfdc/xrfdc.c @@ -0,0 +1,5345 @@ +/****************************************************************************** +* +* Copyright (C) 2017-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.c +* @addtogroup xrfdc_v6_0 +* @{ +* +* Contains the interface functions of the XRFdc driver. +* See xrfdc.h for a detailed description of the device and driver. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- -------- ----------------------------------------------- +* 1.0 sk 05/16/17 Initial release +* 2.0 sk 08/09/17 Fixed coarse Mixer configuration settings +* CR# 977266, 977872. +* Return error for Slice Event on 4G ADC Block. +* 08/16/17 Add support for SYSREF and PL event sources. +* 08/18/17 Add API to enable and disable FIFO. +* 08/23/17 Add API to configure Nyquist zone. +* 08/30/17 Add additional info to BlockStatus. +* 08/30/17 Add support for Coarse Mixer BYPASS mode. +* 08/31/17 Removed Tile Reset Assert and Deassert. +* 09/07/17 Add support for negative NCO freq. +* 09/15/17 Fixed NCO freq precision issue. +* 09/15/17 Fixed Immediate Event source issue and also +* updated the Immediate Macro value to 0. +* 2.1 sk 09/15/17 Remove Libmetal library dependency for MB. +* sk 09/25/17 Modified XRFdc_GetBlockStatus API to give +* correct information and also updates the +* description for Vector Param in intr handler +* Add API to get Output current and removed +* GetTermVoltage and GetOutputCurr inline functions. +* 2.2 sk 10/05/17 Fixed XRFdc_GetNoOfADCBlocks API for 4GSPS. +* Enable the decoder clock based on decoder mode. +* Add API to get the current FIFO status. +* Updated XRFdc_DumpRegs API for better readability +* of output register dump. +* Add support for 4GSPS CoarseMixer frequency. +* 10/11/17 Modify float types to double to increase precision. +* 10/12/17 Update BlockStatus API to give current status. +* In BYPASS mode, input datatype can be Real or IQ, +* hence checked both while reading the mixer mode. +* 10/17/17 Fixed Set Threshold API Issue. +* 2.3 sk 11/06/17 Fixed PhaseOffset truncation issue. +* Provide user configurability for FineMixerScale. +* 11/08/17 Return error for DAC R2C mode and ADC C2R mode. +* 11/20/17 Fixed StartUp, Shutdown and Reset API for Tile_Id -1. +* 11/20/17 Remove unwanted ADC block checks in 4GSPS mode. +* 3.0 sk 12/11/17 Added DDC and DUC support. +* 12/13/17 Add CoarseMixMode field in Mixer_Settings structure. +* 12/15/17 Add support to switch calibration modes. +* 12/15/17 Add support for mixer frequencies > Fs/2 and < -Fs/2. +* sg 13/01/18 Added PLL and external clock switch support. +* Added API to get PLL lock status. +* Added API to get clock source. +* 3.1 jm 01/24/18 Add Multi-tile sync support. +* sk 01/25/18 Updated Set and Get Interpolation/Decimation factor +* API's to consider the actual factor value. +* 3.2 sk 02/02/18 Add API's to configure inverse-sinc. +* sk 02/27/18 Add API's to configure Multiband. +* sk 03/09/18 Update PLL structure in XRFdc_DynamicPLLConfig API. +* sk 03/09/18 Update ADC and DAC datatypes in Mixer API and use +* input datatype for ADC in threshold and QMC APIs. +* sk 03/09/18 Removed FIFO disable check in DDC and DUC APIs. +* sk 03/09/18 Add support for Marker event source for DAC block. +* sk 03/22/18 Updated PLL settings based on latest IP values. +* 4.0 sk 04/17/18 Corrected Set/Get MixerSettings API description for +* FineMixerScale parameter. +* sk 04/19/18 Enable VCO Auto selection while configuring the clock. +* sk 04/24/18 Add API to get PLL Configurations. +* sk 04/24/18 Add API to get the Link Coupling mode. +* sk 04/28/18 Implement timeouts for PLL Lock, Startup and shutdown. +* sk 05/30/18 Removed CalibrationMode check for DAC. +* sk 06/05/18 Updated minimum Ref clock value to 102.40625MHz. +* 5.0 sk 06/25/18 Update DAC min sampling rate to 500MHz and also update +* VCO Range, PLL_DIVIDER and PLL_FPDIV ranges. +* sk 06/25/18 Add XRFdc_GetFabClkOutDiv() API to read fabric clk div. +* Add Inline APIs XRFdc_CheckBlockEnabled(), +* XRFdc_CheckTileEnabled(). +* sk 07/06/18 Add support to dump HSCOM regs in XRFdc_DumpRegs() API +* sk 07/12/18 Fixed Multiband crossbar settings in C2C mode. +* sk 07/19/18 Add MixerType member to MixerSettings structure and +* Update Mixer Settings APIs to consider the MixerType +* variable. +* sk 07/19/18 Add XRFdc_GetMultibandConfig() API to read Multiband +* configuration. +* sk 07/20/18 Update the APIs to check the corresponding section +* (Digital/Analog)enable/disable. +* sk 07/26/18 Fixed Doxygen, coverity warnings. +* sk 08/03/18 Fixed MISRAC warnings. +* sk 08/24/18 Move mixer related APIs to xrfdc_mixer.c file. +* Define asserts for Linux, Re-arranged XRFdc_RestartIPSM, +* XRFdc_CfgInitialize() and XRFdc_MultiBand() APIs. +* Reorganize the code to improve readability and +* optimization. +* sk 09/24/18 Update powerup-state value based on PLL mode in +* XRFdc_DynamicPLLConfig() API. +* sk 10/10/18 Check for DigitalPath enable in XRFdc_GetNyquistZone() +* and XRFdc_GetCalibrationMode() APIs for Multiband. +* sk 10/13/18 Add support to read the REFCLKDIV param from design. +* Update XRFdc_SetPLLConfig() API to support range of +* REF_CLK_DIV values(1 to 4). +* 5.1 cog 01/29/19 Replace structure reference ADC checks with +* function. +* cog 01/29/19 Added XRFdc_SetDither() and XRFdc_GetDither() APIs. +* cog 01/29/19 Rename DataType for mixer input to MixerInputDataType +* for readability. +* cog 01/29/19 Refactoring of interpolation and decimation APIs and +* changed fabric rate for decimation X8 for non-high speed ADCs. +* cog 01/29/19 New inline functions to determine max & min sampling rates +* rates in PLL range checking. +* 6.0 cog 02/17/19 Added decimation & interpolation modes +* 02/17/19 Added Inverse-Sinc Second Nyquist Zone Support +* cog 02/17/19 Added new clock Distribution functionality. +* cog 02/17/19 Refactored to improve delay balancing in clock +* distribution. +* cog 02/17/19 Added delay calculation & metal log messages. +* cog 02/17/19 Added intratile clock settings. +* cog 02/17/19 Moved multiband to a new file xrfdc_mb.c +* cog 02/17/19 Moved clocking functionality to a new file xrfdc_clock.c +* cog 02/17/19 Added XRFdc_SetIMRPassMode() and XRFdc_SetIMRPassMode() APIs +* cog 02/17/19 Added XRFdc_SetDACMode() and XRFdc_GetDACMode() APIs +* cog 02/17/19 Added XRFdc_SetSignalDetector() and XRFdc_GetSignalDetector() APIs. +* cog 02/17/19 Added XRFdc_DisableCoefficientsOverride(), XRFdc_SetCalCoefficients +* and XRFdc_GetCalCoefficients APIs. +* cog 02/21/19 Added XRFdc_SetCalFreeze() and XRFdc_GetCalFreeze() APIs. +* cog 04/09/19 Changed Calibrtation coefficient override control register for OCB1. +* cog 04/15/19 Rename XRFdc_SetDACMode() and XRFdc_GetDACMode() APIs to +* XRFdc_SetDataPathMode() and XRFdc_GetDataPathMode() respectively. +* cog 04/30/19 Made Changes to the bypass calibration functionality to support Gen2 +* and below. +* +* </pre> +* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include "mpm/rfdc/xrfdc.h" + +/************************** Constant Definitions *****************************/ +#define XRFDC_PLL_LOCK_DLY_CNT 1000U + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ +static u32 XRFdc_RestartIPSM(XRFdc *InstancePtr, u32 Type, int Tile_Id, + u32 Start, u32 End); +static void StubHandler(void *CallBackRefPtr, u32 Type, u32 Tile_Id, + u32 Block_Id, u32 StatusEvent); +static void XRFdc_ADCInitialize(XRFdc *InstancePtr); +static void XRFdc_DACInitialize(XRFdc *InstancePtr); +static void XRFdc_DACMBConfigInit(XRFdc *InstancePtr, u32 Tile_Id, + u32 Block_Id); +static void XRFdc_ADCMBConfigInit(XRFdc *InstancePtr, u32 Tile_Id, + u32 Block_Id); +static void XRFdc_UpdatePLLStruct(XRFdc *InstancePtr, u32 Type, u32 Tile_Id); +static u32 XRFdc_GetADCBlockStatus(XRFdc *InstancePtr, u32 BaseAddr, + u32 Tile_Id, u32 Block_Id, XRFdc_BlockStatus *BlockStatusPtr); +static u32 XRFdc_GetDACBlockStatus(XRFdc *InstancePtr, u32 BaseAddr, + u32 Tile_Id, u32 Block_Id, XRFdc_BlockStatus *BlockStatusPtr); +static void XRFdc_DumpHSCOMRegs(XRFdc *InstancePtr, u32 Type, int Tile_Id); +static void XRFdc_DumpDACRegs(XRFdc *InstancePtr, int Tile_Id); +static void XRFdc_DumpADCRegs(XRFdc *InstancePtr, int Tile_Id); +static u32 XRFdc_WaitForRestartClr(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 BaseAddr, u32 End); + +/************************** Function Prototypes ******************************/ + +/*****************************************************************************/ +/** +* +* Initializes a specific XRFdc instance such that the driver is ready to use. +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param ConfigPtr is a reference to a structure containing information +* about xrfdc. This function initializes an InstancePtr object +* for a specific device specified by the contents of Config. +* +* @return +* - XRFDC_SUCCESS if successful. +* +* @note The user needs to first call the XRFdc_LookupConfig() API +* which returns the Configuration structure pointer which is +* passed as a parameter to the XRFdc_CfgInitialize() API. +* +******************************************************************************/ +u32 XRFdc_CfgInitialize(XRFdc *InstancePtr, XRFdc_Config *ConfigPtr) +{ + u32 Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(ConfigPtr != NULL); + + InstancePtr->io = (struct metal_io_region *) + metal_allocate_memory(sizeof(struct metal_io_region)); + metal_io_init(InstancePtr->io, (void *)(metal_phys_addr_t)ConfigPtr->BaseAddr, + &ConfigPtr->BaseAddr, XRFDC_REGION_SIZE, (unsigned)(-1), 0, NULL); + + /* + * Set the values read from the device config and the base address. + */ + InstancePtr->BaseAddr = ConfigPtr->BaseAddr; + InstancePtr->RFdc_Config = *ConfigPtr; + InstancePtr->ADC4GSPS = ConfigPtr->ADCType; + InstancePtr->StatusHandler = StubHandler; + + /* Initialize ADC */ + XRFdc_ADCInitialize(InstancePtr); + + /* Initialize DAC */ + XRFdc_DACInitialize(InstancePtr); + + /* + * Indicate the instance is now ready to use and + * initialized without error. + */ + InstancePtr->IsReady = XRFDC_COMPONENT_IS_READY; + + Status = XRFDC_SUCCESS; + return Status; +} + +/*****************************************************************************/ +/** +* +* Initialize ADC Tiles. +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* +* @return +* - None. +* +* @note Static API used to initialize ADC Tiles +* +******************************************************************************/ +static void XRFdc_ADCInitialize(XRFdc *InstancePtr) +{ + u32 Tile_Id; + u32 Block_Id; + u8 MixerType; + + for (Tile_Id = XRFDC_TILE_ID0; Tile_Id < XRFDC_TILE_ID4; Tile_Id++) { + InstancePtr->ADC_Tile[Tile_Id].NumOfADCBlocks = 0U; + for (Block_Id = XRFDC_BLK_ID0; Block_Id < XRFDC_BLK_ID4; Block_Id++) { + if (XRFdc_IsADCBlockEnabled(InstancePtr, Tile_Id, Block_Id) != 0U) { + InstancePtr->ADC_Tile[Tile_Id].NumOfADCBlocks += 1U; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Analog_Datapath[Block_Id]. + AnalogPathEnabled = XRFDC_ANALOGPATH_ENABLE; + } + /* Initialize Data Type */ + if (InstancePtr->RFdc_Config.ADCTile_Config[Tile_Id]. + ADCBlock_Analog_Config[Block_Id].MixMode == XRFDC_MIXER_MODE_BYPASS) { + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[Block_Id].MixerInputDataType = + InstancePtr->RFdc_Config.ADCTile_Config[Tile_Id].ADCBlock_Digital_Config[Block_Id].MixerInputDataType; + } else { + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[Block_Id].MixerInputDataType = + InstancePtr->RFdc_Config.ADCTile_Config[Tile_Id]. + ADCBlock_Analog_Config[Block_Id].MixMode; + } + /* Initialize MixerType */ + MixerType = InstancePtr->RFdc_Config.ADCTile_Config[Tile_Id]. + ADCBlock_Digital_Config[Block_Id].MixerType; + InstancePtr->ADC_Tile[Tile_Id]. + ADCBlock_Digital_Datapath[Block_Id].Mixer_Settings.MixerType = MixerType; + + InstancePtr->ADC_Tile[Tile_Id]. + ADCBlock_Digital_Datapath[Block_Id].ConnectedIData = -1; + InstancePtr->ADC_Tile[Tile_Id]. + ADCBlock_Digital_Datapath[Block_Id].ConnectedQData = -1; + InstancePtr->ADC_Tile[Tile_Id].MultibandConfig = + InstancePtr->RFdc_Config.ADCTile_Config[Tile_Id].MultibandConfig; + if (XRFdc_IsADCDigitalPathEnabled(InstancePtr, Tile_Id, Block_Id) != 0U) { + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[Block_Id].DigitalPathAvailable = + XRFDC_DIGITALPATH_ENABLE; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[Block_Id].DigitalPathEnabled = + XRFDC_DIGITALPATH_ENABLE; + /* Initialize ConnectedI/QData, MB Config */ + XRFdc_ADCMBConfigInit(InstancePtr, Tile_Id, Block_Id); + } + } + + /* Initialize PLL Structure */ + XRFdc_UpdatePLLStruct(InstancePtr, XRFDC_ADC_TILE, Tile_Id); + } +} + +/*****************************************************************************/ +/** +* +* Initialize DAC Tiles. +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* +* @return +* - None. +* +* @note Static API used to initialize DAC Tiles +* +******************************************************************************/ +static void XRFdc_DACInitialize(XRFdc *InstancePtr) +{ + u32 Tile_Id; + u32 Block_Id; + u8 MixerType; + + for (Tile_Id = XRFDC_TILE_ID0; Tile_Id < XRFDC_TILE_ID4; Tile_Id++) { + InstancePtr->DAC_Tile[Tile_Id].NumOfDACBlocks = 0U; + for (Block_Id = XRFDC_BLK_ID0; Block_Id < XRFDC_BLK_ID4; Block_Id++) { + if (XRFdc_IsDACBlockEnabled(InstancePtr, Tile_Id, Block_Id) != 0U) { + InstancePtr->DAC_Tile[Tile_Id].NumOfDACBlocks += 1U; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Analog_Datapath[Block_Id].AnalogPathEnabled = + XRFDC_ANALOGPATH_ENABLE; + } + /* Initialize Data Type */ + if (InstancePtr->RFdc_Config.DACTile_Config[Tile_Id]. + DACBlock_Analog_Config[Block_Id].MixMode == XRFDC_MIXER_MODE_BYPASS) { + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[Block_Id].MixerInputDataType = + InstancePtr->RFdc_Config.DACTile_Config[Tile_Id].DACBlock_Digital_Config[Block_Id].MixerInputDataType; + } else { + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[Block_Id].MixerInputDataType = + XRFDC_DATA_TYPE_IQ; + } + /* Initialize MixerType */ + MixerType = InstancePtr->RFdc_Config.DACTile_Config[Tile_Id]. + DACBlock_Digital_Config[Block_Id].MixerType; + InstancePtr->DAC_Tile[Tile_Id]. + DACBlock_Digital_Datapath[Block_Id].Mixer_Settings.MixerType = MixerType; + + InstancePtr->DAC_Tile[Tile_Id]. + DACBlock_Digital_Datapath[Block_Id].ConnectedIData = -1; + InstancePtr->DAC_Tile[Tile_Id]. + DACBlock_Digital_Datapath[Block_Id].ConnectedQData = -1; + InstancePtr->DAC_Tile[Tile_Id].MultibandConfig = + InstancePtr->RFdc_Config.DACTile_Config[Tile_Id].MultibandConfig; + if (XRFdc_IsDACDigitalPathEnabled(InstancePtr, Tile_Id, Block_Id) != 0U) { + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[Block_Id].DigitalPathAvailable = + XRFDC_DIGITALPATH_ENABLE; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[Block_Id].DigitalPathEnabled = + XRFDC_DIGITALPATH_ENABLE; + /* Initialize ConnectedI/QData, MB Config */ + XRFdc_DACMBConfigInit(InstancePtr, Tile_Id, Block_Id); + } + } + /* Initialize PLL Structure */ + XRFdc_UpdatePLLStruct(InstancePtr, XRFDC_DAC_TILE, Tile_Id); + } +} + +/*****************************************************************************/ +/** +* +* Initialize Multiband Configuration for DAC Tiles. +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3, and -1. +* @param Block_Id is DAC block number inside the tile. Valid values +* are 0-3. +* +* @return +* - None. +* +* @note Static API used to initialize DAC MB Config +* +******************************************************************************/ +static void XRFdc_DACMBConfigInit(XRFdc *InstancePtr, u32 Tile_Id, + u32 Block_Id) +{ + if (InstancePtr->RFdc_Config.DACTile_Config[Tile_Id]. + DACBlock_Analog_Config[Block_Id].MixMode == XRFDC_MIXER_MODE_C2C) { + /* Mixer Mode is C2C */ + switch (InstancePtr->DAC_Tile[Tile_Id].MultibandConfig) { + case XRFDC_MB_MODE_4X: + XRFdc_SetConnectedIQData(InstancePtr, XRFDC_DAC_TILE, Tile_Id, + Block_Id, XRFDC_BLK_ID0, XRFDC_BLK_ID1); + break; + case XRFDC_MB_MODE_2X_BLK01_BLK23: + case XRFDC_MB_MODE_2X_BLK01: + case XRFDC_MB_MODE_2X_BLK23: + if ((Block_Id == XRFDC_BLK_ID0) || (Block_Id == XRFDC_BLK_ID1)) { + XRFdc_SetConnectedIQData(InstancePtr, XRFDC_DAC_TILE, Tile_Id, + Block_Id, XRFDC_BLK_ID0, XRFDC_BLK_ID1); + } else { + XRFdc_SetConnectedIQData(InstancePtr, XRFDC_DAC_TILE, Tile_Id, + Block_Id, XRFDC_BLK_ID2, XRFDC_BLK_ID3); + } + break; + default: + XRFdc_SetConnectedIQData(InstancePtr, XRFDC_DAC_TILE, Tile_Id, + Block_Id, Block_Id, Block_Id + 1U); + break; + } + } else if (InstancePtr->RFdc_Config.DACTile_Config[Tile_Id]. + DACBlock_Analog_Config[Block_Id].MixMode == 0x0) { + /* Mixer Mode is C2R */ + switch (InstancePtr->DAC_Tile[Tile_Id].MultibandConfig) { + case XRFDC_MB_MODE_4X: + XRFdc_SetConnectedIQData(InstancePtr, XRFDC_DAC_TILE, Tile_Id, + Block_Id, XRFDC_BLK_ID0, -1); + break; + case XRFDC_MB_MODE_2X_BLK01_BLK23: + case XRFDC_MB_MODE_2X_BLK01: + case XRFDC_MB_MODE_2X_BLK23: + if ((Block_Id == XRFDC_BLK_ID0) || (Block_Id == XRFDC_BLK_ID1)) { + XRFdc_SetConnectedIQData(InstancePtr, XRFDC_DAC_TILE, Tile_Id, + Block_Id, XRFDC_BLK_ID0, -1); + } else { + XRFdc_SetConnectedIQData(InstancePtr, XRFDC_DAC_TILE, Tile_Id, + Block_Id, XRFDC_BLK_ID2, -1); + } + break; + default: + XRFdc_SetConnectedIQData(InstancePtr, XRFDC_DAC_TILE, Tile_Id, + Block_Id, Block_Id, -1); + break; + } + } else { + /* Mixer Mode is BYPASS */ + XRFdc_SetConnectedIQData(InstancePtr, XRFDC_DAC_TILE, Tile_Id, + Block_Id, Block_Id, -1); + } +} +/*****************************************************************************/ +/** +* +* Initialize Multiband Configuration for ADC Tiles. +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3, and -1. +* @param Block_Id is ADC block number inside the tile. Valid values +* are 0-3. +* +* @return +* - None. +* +* @note Static API used to initialize ADC MB Config +* +******************************************************************************/ +static void XRFdc_ADCMBConfigInit(XRFdc *InstancePtr, u32 Tile_Id, + u32 Block_Id) +{ + if (InstancePtr->RFdc_Config.ADCTile_Config[Tile_Id]. + ADCBlock_Analog_Config[Block_Id].MixMode == XRFDC_MIXER_MODE_C2C) { + /* Mixer mode is C2C */ + switch (InstancePtr->ADC_Tile[Tile_Id].MultibandConfig) { + case XRFDC_MB_MODE_4X: + XRFdc_SetConnectedIQData(InstancePtr, XRFDC_ADC_TILE, Tile_Id, + Block_Id, XRFDC_BLK_ID0, XRFDC_BLK_ID1); + break; + case XRFDC_MB_MODE_2X_BLK01_BLK23: + case XRFDC_MB_MODE_2X_BLK01: + case XRFDC_MB_MODE_2X_BLK23: + if ((Block_Id == XRFDC_BLK_ID0) || (Block_Id == XRFDC_BLK_ID1)) { + XRFdc_SetConnectedIQData(InstancePtr, XRFDC_ADC_TILE, Tile_Id, + Block_Id, XRFDC_BLK_ID0, XRFDC_BLK_ID1); + } else { + XRFdc_SetConnectedIQData(InstancePtr, XRFDC_ADC_TILE, Tile_Id, + Block_Id, XRFDC_BLK_ID2, XRFDC_BLK_ID3); + } + break; + default: + XRFdc_SetConnectedIQData(InstancePtr, XRFDC_ADC_TILE, Tile_Id, + Block_Id, Block_Id, Block_Id + 1U); + break; + } + } else if (InstancePtr->RFdc_Config.ADCTile_Config[Tile_Id]. + ADCBlock_Analog_Config[Block_Id].MixMode == 0x0) { + /* Mixer mode is R2C */ + switch (InstancePtr->ADC_Tile[Tile_Id].MultibandConfig) { + case XRFDC_MB_MODE_4X: + XRFdc_SetConnectedIQData(InstancePtr, XRFDC_ADC_TILE, Tile_Id, + Block_Id, XRFDC_BLK_ID0, -1); + break; + case XRFDC_MB_MODE_2X_BLK01_BLK23: + case XRFDC_MB_MODE_2X_BLK01: + case XRFDC_MB_MODE_2X_BLK23: + if ((Block_Id == XRFDC_BLK_ID0) || (Block_Id == XRFDC_BLK_ID1)) { + XRFdc_SetConnectedIQData(InstancePtr, XRFDC_ADC_TILE, Tile_Id, + Block_Id, XRFDC_BLK_ID0, -1); + } else { + XRFdc_SetConnectedIQData(InstancePtr, XRFDC_ADC_TILE, Tile_Id, + Block_Id, XRFDC_BLK_ID2, -1); + } + break; + default: + XRFdc_SetConnectedIQData(InstancePtr, XRFDC_ADC_TILE, Tile_Id, + Block_Id, Block_Id, -1); + break; + } + } else { + /* Mixer mode is BYPASS */ + XRFdc_SetConnectedIQData(InstancePtr, XRFDC_ADC_TILE, Tile_Id, + Block_Id, Block_Id, -1); + } +} + +/*****************************************************************************/ +/** +* +* This API updates PLL Structure. +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC. +* @param Tile_Id Valid values are 0-3, and -1. +* +* @return +* - None. +* +* @note Static API used to initialize PLL Settings for ADC and DAC +* +******************************************************************************/ +static void XRFdc_UpdatePLLStruct(XRFdc *InstancePtr, u32 Type, u32 Tile_Id) +{ + if (Type == XRFDC_ADC_TILE) { + InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.SampleRate = + InstancePtr->RFdc_Config.ADCTile_Config[Tile_Id].SamplingRate; + InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.RefClkFreq = + InstancePtr->RFdc_Config.ADCTile_Config[Tile_Id].RefClkFreq; + InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.Enabled = + InstancePtr->RFdc_Config.ADCTile_Config[Tile_Id].PLLEnable; + InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.FeedbackDivider = + InstancePtr->RFdc_Config.ADCTile_Config[Tile_Id].FeedbackDiv; + InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.OutputDivider = + InstancePtr->RFdc_Config.ADCTile_Config[Tile_Id].OutputDiv; + InstancePtr->ADC_Tile[Tile_Id].PLL_Settings.RefClkDivider = + InstancePtr->RFdc_Config.ADCTile_Config[Tile_Id].RefClkDiv; + } else { + InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.SampleRate = + InstancePtr->RFdc_Config.DACTile_Config[Tile_Id].SamplingRate; + InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.RefClkFreq = + InstancePtr->RFdc_Config.DACTile_Config[Tile_Id].RefClkFreq; + InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.Enabled = + InstancePtr->RFdc_Config.DACTile_Config[Tile_Id].PLLEnable; + InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.FeedbackDivider = + InstancePtr->RFdc_Config.DACTile_Config[Tile_Id].FeedbackDiv; + InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.OutputDivider = + InstancePtr->RFdc_Config.DACTile_Config[Tile_Id].OutputDiv; + InstancePtr->DAC_Tile[Tile_Id].PLL_Settings.RefClkDivider = + InstancePtr->RFdc_Config.DACTile_Config[Tile_Id].RefClkDiv; + } +} + +/*****************************************************************************/ +/** +* +* The API Restarts the requested tile. It can restart a single tile and +* alternatively can restart all the tiles. Existing register settings are not +* lost or altered in the process. It just starts the requested tile(s). +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3, and -1. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if tile is not enabled or available +* +* @note None +* +******************************************************************************/ +u32 XRFdc_StartUp(XRFdc *InstancePtr, u32 Type, int Tile_Id) +{ + u32 Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_RestartIPSM(InstancePtr, Type, Tile_Id, XRFDC_SM_STATE1, + XRFDC_SM_STATE15); + return Status; + +} + +/*****************************************************************************/ +/** +* +* The API stops the tile as requested. It can also stop all the tiles if +* asked for. It does not clear any of the existing register settings. It just +* stops the requested tile(s). +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3, and -1. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if tile is not enabled or available +* +* @note None +* +******************************************************************************/ +u32 XRFdc_Shutdown(XRFdc *InstancePtr, u32 Type, int Tile_Id) +{ + u32 Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_RestartIPSM(InstancePtr, Type, Tile_Id, XRFDC_SM_STATE1, + XRFDC_SM_STATE1); + return Status; + +} + +/*****************************************************************************/ +/** +* +* The API resets the requested tile. It can reset all the tiles as well. In +* the process, all existing register settings are cleared and are replaced +* with the settings initially configured (through the GUI). +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3, and -1. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if tile is not enabled or available +* +* @note None +******************************************************************************/ +u32 XRFdc_Reset(XRFdc *InstancePtr, u32 Type, int Tile_Id) +{ + u32 Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_RestartIPSM(InstancePtr, Type, Tile_Id, XRFDC_SM_STATE0, + XRFDC_SM_STATE15); + return Status; + +} + +/*****************************************************************************/ +/** +* +* This Static API will be used to wait for restart bit clears and also check +* for PLL Lock if clock source is internal PLL. +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param End is end state of State Machine. +* +* @return - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if timeout occurs. +* +* @note None +* +******************************************************************************/ +static u32 XRFdc_WaitForRestartClr(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 BaseAddr, u32 End) +{ + u32 ClkSrc = 0U; + u32 DelayCount; + u32 LockStatus = 0U; + u32 Status; + + /* + * Get Tile clock source information + */ + if (XRFdc_GetClockSource(InstancePtr, Type, Tile_Id, &ClkSrc) + != XRFDC_SUCCESS) { + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + if ((ClkSrc == XRFDC_INTERNAL_PLL_CLK) && (End == XRFDC_SM_STATE15)) { + /* + * Wait for internal PLL to lock + */ + if (XRFdc_GetPLLLockStatus(InstancePtr, Type, Tile_Id, + &LockStatus) != XRFDC_SUCCESS) { + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + DelayCount = 0U; + while (LockStatus != XRFDC_PLL_LOCKED) { + if (DelayCount == XRFDC_PLL_LOCK_DLY_CNT) { + metal_log(METAL_LOG_ERROR, "\n PLL Lock timeout " + "error in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } else { + /* Wait for 1 msec */ +#ifdef __BAREMETAL__ + usleep(1000); +#else + metal_sleep_usec(1000); +#endif + DelayCount++; + (void)XRFdc_GetPLLLockStatus(InstancePtr, Type, Tile_Id, + &LockStatus); + } + } + } + + /* Wait till restart bit clear */ + DelayCount = 0U; + while (XRFdc_ReadReg16(InstancePtr, BaseAddr, XRFDC_RESTART_OFFSET) != 0U) { + if (DelayCount == XRFDC_PLL_LOCK_DLY_CNT) { + metal_log(METAL_LOG_ERROR, "\n Failed to clear " + "the restart bit in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } else { + /* Wait for 1 msec */ +#ifdef __BAREMETAL__ + usleep(1000); +#else + metal_sleep_usec(1000); +#endif + DelayCount++; + } + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} +/*****************************************************************************/ +/** +* +* Restarts a requested the tile and ensures that starts from a defined start +* state and reaches the requested or defined end state. +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3, and -1. +* @param Start is start state of State Machine +* @param End is end state of State Machine. +* +* @return - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if tile is not enabled or available +* +* @note None +* +******************************************************************************/ +static u32 XRFdc_RestartIPSM(XRFdc *InstancePtr, u32 Type, int Tile_Id, + u32 Start, u32 End) +{ + u32 Status; + u32 BaseAddr; + u16 NoOfTiles; + u16 Index; + + /* An input tile if of -1 selects all tiles */ + if (Tile_Id == XRFDC_SELECT_ALL_TILES) { + NoOfTiles = XRFDC_NUM_OF_TILES4; + Index = XRFDC_TILE_ID0; + } else { + NoOfTiles = Tile_Id + 1; + Index = Tile_Id; + } + + for (; Index < NoOfTiles; Index++) { + BaseAddr = XRFDC_CTRL_STS_BASE(Type, Index); + Status = XRFdc_CheckTileEnabled(InstancePtr, Type, Index); + if ((Status != XRFDC_SUCCESS) && (Tile_Id != XRFDC_SELECT_ALL_TILES)) { + metal_log(METAL_LOG_ERROR, "\n Requested tile%d not " + "available in %s\r\n", Index, __func__); + goto RETURN_PATH; + } else if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_DEBUG, "\n Tile%d not " + "available in %s\r\n", Index, __func__); + continue; + } else { + /* Write Start and End states */ + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_RESTART_STATE_OFFSET, + XRFDC_PWR_STATE_MASK, (Start << XRFDC_RSR_START_SHIFT) | End); + + /* Trigger restart */ + XRFdc_WriteReg(InstancePtr, BaseAddr, XRFDC_RESTART_OFFSET, + XRFDC_RESTART_MASK); + + /* Wait for restart bit clear */ + Status = XRFdc_WaitForRestartClr(InstancePtr, Type, Index, + BaseAddr, End); + if (Status != XRFDC_SUCCESS) { + goto RETURN_PATH; + } + } + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* The API returns the IP status. +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param IPStatusPtr Pointer to the XRFdc_IPStatus structure through +* which the status is returned. +* +* @return +* - XRFDC_SUCCESS if successful. +* +* @note None. +* +******************************************************************************/ +u32 XRFdc_GetIPStatus(XRFdc *InstancePtr, XRFdc_IPStatus *IPStatusPtr) +{ + u32 Tile_Id; + u32 Block_Id; + u32 BaseAddr; + u16 ReadReg; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(IPStatusPtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + for (Tile_Id = XRFDC_TILE_ID0; Tile_Id < XRFDC_TILE_ID4; Tile_Id++) { + IPStatusPtr->ADCTileStatus[Tile_Id].BlockStatusMask = 0x0; + IPStatusPtr->DACTileStatus[Tile_Id].BlockStatusMask = 0x0; + for (Block_Id = XRFDC_BLK_ID0; Block_Id < XRFDC_BLK_ID4; Block_Id++) { + if (XRFdc_IsADCBlockEnabled(InstancePtr, Tile_Id, + Block_Id) != 0U) { + IPStatusPtr->ADCTileStatus[Tile_Id].IsEnabled = 1; + IPStatusPtr->ADCTileStatus[Tile_Id].BlockStatusMask |= + (1U << Block_Id); + BaseAddr = XRFDC_ADC_TILE_CTRL_STATS_ADDR(Tile_Id); + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_STATUS_OFFSET); + IPStatusPtr->ADCTileStatus[Tile_Id].PowerUpState = (ReadReg & + XRFDC_PWR_UP_STAT_MASK) >> XRFDC_PWR_UP_STAT_SHIFT; + IPStatusPtr->ADCTileStatus[Tile_Id].PLLState = (ReadReg & + XRFDC_PLL_LOCKED_MASK) >> XRFDC_PLL_LOCKED_SHIFT; + IPStatusPtr->ADCTileStatus[Tile_Id].TileState = + XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_CURRENT_STATE_OFFSET); + } + if (XRFdc_IsDACBlockEnabled(InstancePtr, Tile_Id, + Block_Id) != 0U) { + IPStatusPtr->DACTileStatus[Tile_Id].IsEnabled = 1; + IPStatusPtr->DACTileStatus[Tile_Id].BlockStatusMask |= + (1U << Block_Id); + BaseAddr = XRFDC_DAC_TILE_CTRL_STATS_ADDR(Tile_Id); + IPStatusPtr->DACTileStatus[Tile_Id].TileState = + XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_CURRENT_STATE_OFFSET); + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_STATUS_OFFSET); + IPStatusPtr->DACTileStatus[Tile_Id].PowerUpState = (ReadReg & + XRFDC_PWR_UP_STAT_MASK) >> XRFDC_PWR_UP_STAT_SHIFT; + IPStatusPtr->DACTileStatus[Tile_Id].PLLState = (ReadReg & + XRFDC_PLL_LOCKED_MASK) >> XRFDC_PLL_LOCKED_SHIFT; + } + } + } + + /*TODO IP state*/ + + return XRFDC_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* The API returns the requested block status. +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. XRFdc_BlockStatus. +* @param BlockStatusPtr is Pointer to the XRFdc_BlockStatus structure through +* which the ADC/DAC block status is returned. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note Common API for ADC/DAC blocks. +* +******************************************************************************/ +u32 XRFdc_GetBlockStatus(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 Block_Id, XRFdc_BlockStatus *BlockStatusPtr) +{ + u32 Status; + u32 Block; + u16 ReadReg; + u32 BaseAddr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(BlockStatusPtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, Type, Tile_Id, Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + Block = Block_Id; + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Block_Id == XRFDC_BLK_ID1) && (Type == XRFDC_ADC_TILE)) { + Block_Id = XRFDC_BLK_ID2; + } + + BaseAddr = XRFDC_BLOCK_BASE(Type, Tile_Id, Block_Id); + if (Type == XRFDC_ADC_TILE) { + Status = XRFdc_GetADCBlockStatus(InstancePtr, BaseAddr, Tile_Id, + Block, BlockStatusPtr); + } else { + Status = XRFdc_GetDACBlockStatus(InstancePtr, BaseAddr, Tile_Id, + Block, BlockStatusPtr); + } + if (Status != XRFDC_SUCCESS) { + goto RETURN_PATH; + } + + ReadReg = XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CLK_EN_OFFSET, + XRFDC_DAT_CLK_EN_MASK); + if (ReadReg == XRFDC_DAT_CLK_EN_MASK) { + BlockStatusPtr->DataPathClocksStatus = 0x1U; + } else { + BlockStatusPtr->DataPathClocksStatus = 0x0U; + } + + Status = XRFDC_SUCCESS; + +RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* +* The API returns the requested block status for ADC block +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. XRFdc_BlockStatus. +* @param BlockStatus is Pointer to the XRFdc_BlockStatus structure through +* which the ADC/DAC block status is returned. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note Static API for ADC blocks. +* +******************************************************************************/ +static u32 XRFdc_GetADCBlockStatus(XRFdc *InstancePtr, u32 BaseAddr, + u32 Tile_Id, u32 Block_Id, XRFdc_BlockStatus *BlockStatusPtr) +{ + u8 FIFOEnable = 0U; + u32 DecimationFactor = 0U; + u8 MixerMode; + u16 ReadReg; + u32 Status; + + BlockStatusPtr->SamplingFreq = InstancePtr->ADC_Tile[Tile_Id]. + PLL_Settings.SampleRate; + + /* DigitalDataPathStatus */ + (void)XRFdc_GetFIFOStatus(InstancePtr, XRFDC_ADC_TILE, + Tile_Id, &FIFOEnable); + BlockStatusPtr->DigitalDataPathStatus = FIFOEnable; + (void)XRFdc_GetDecimationFactor(InstancePtr, Tile_Id, + Block_Id, &DecimationFactor); + BlockStatusPtr->DigitalDataPathStatus |= + (DecimationFactor << XRFDC_DIGI_ANALOG_SHIFT4); + + ReadReg = XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_MXR_MODE_OFFSET, + (XRFDC_EN_I_IQ_MASK | XRFDC_EN_Q_IQ_MASK)); + switch (ReadReg) { + case XRFDC_MIXER_MODE_C2C_MASK: + MixerMode = XRFDC_MIXER_MODE_C2C; + break; + case XRFDC_MIXER_MODE_R2C_MASK: + MixerMode = XRFDC_MIXER_MODE_R2C; + break; + case XRFDC_MIXER_MODE_OFF_MASK: + MixerMode = XRFDC_MIXER_MODE_OFF; + break; + default: + metal_log(METAL_LOG_ERROR, "\n Invalid MixerMode " + "for ADC in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + BlockStatusPtr->DigitalDataPathStatus |= + (MixerMode << XRFDC_DIGI_ANALOG_SHIFT8); + + /* + * Checking ADC block enable for ADC AnalogPath. + * This can be changed later, + */ + BlockStatusPtr->AnalogDataPathStatus = + XRFdc_IsADCBlockEnabled(InstancePtr, Tile_Id, Block_Id); + BlockStatusPtr->IsFIFOFlagsEnabled = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_ADC_FABRIC_IMR_OFFSET, XRFDC_FAB_IMR_USRDAT_MASK); + BlockStatusPtr->IsFIFOFlagsAsserted = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_ADC_FABRIC_ISR_OFFSET, XRFDC_FAB_ISR_USRDAT_MASK); + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* The API returns the requested block status for DAC block +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. XRFdc_BlockStatus. +* @param BlockStatus is Pointer to the XRFdc_BlockStatus structure through +* which the DAC block status is returned. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note Static API for DAC blocks. +* +******************************************************************************/ +static u32 XRFdc_GetDACBlockStatus(XRFdc *InstancePtr, u32 BaseAddr, + u32 Tile_Id, u32 Block_Id, XRFdc_BlockStatus *BlockStatusPtr) +{ + u32 InterpolationFactor = 0U; + u32 DecoderMode = 0U; + u8 MixerMode; + u16 ReadReg; + u32 Status; + u8 FIFOEnable = 0U; + + BlockStatusPtr->SamplingFreq = InstancePtr->DAC_Tile[Tile_Id]. + PLL_Settings.SampleRate; + + /* DigitalDataPathStatus */ + (void)XRFdc_GetFIFOStatus(InstancePtr, XRFDC_DAC_TILE, + Tile_Id, &FIFOEnable); + BlockStatusPtr->DigitalDataPathStatus = FIFOEnable; + (void)XRFdc_GetInterpolationFactor(InstancePtr, Tile_Id, + Block_Id, &InterpolationFactor); + BlockStatusPtr->DigitalDataPathStatus |= + (InterpolationFactor << XRFDC_DIGI_ANALOG_SHIFT4); + /* Adder Enable */ + ReadReg = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_DAC_MB_CFG_OFFSET, XRFDC_EN_MB_MASK); + ReadReg = ReadReg >> XRFDC_EN_MB_SHIFT; + BlockStatusPtr->DigitalDataPathStatus |= + (ReadReg << XRFDC_DIGI_ANALOG_SHIFT8); + ReadReg = XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_MXR_MODE_OFFSET, + (XRFDC_EN_I_IQ_MASK | XRFDC_EN_Q_IQ_MASK)); + switch (ReadReg) { + case XRFDC_MIXER_MODE_C2C_MASK: + MixerMode = XRFDC_MIXER_MODE_C2C; + break; + case XRFDC_MIXER_MODE_C2R_MASK: + MixerMode = XRFDC_MIXER_MODE_C2R; + break; + case XRFDC_MIXER_MODE_OFF_MASK: + MixerMode = XRFDC_MIXER_MODE_OFF; + break; + default: + metal_log(METAL_LOG_ERROR, "\n Invalid MixerMode " + "for ADC in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + BlockStatusPtr->DigitalDataPathStatus |= + (MixerMode << XRFDC_DIGI_ANALOG_SHIFT12); + + /* AnalogDataPathStatus */ + BlockStatusPtr->AnalogDataPathStatus = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_DAC_INVSINC_OFFSET, (InstancePtr->RFdc_Config.IPType < 2)?XRFDC_EN_INVSINC_MASK:XRFDC_MODE_INVSINC_MASK); + (void)XRFdc_GetDecoderMode(InstancePtr, Tile_Id, Block_Id, + &DecoderMode); + BlockStatusPtr->AnalogDataPathStatus |= + (DecoderMode << XRFDC_DIGI_ANALOG_SHIFT4); + + /* FIFO Flags status */ + BlockStatusPtr->IsFIFOFlagsEnabled = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_DAC_FABRIC_IMR_OFFSET, XRFDC_FAB_IMR_USRDAT_MASK); + BlockStatusPtr->IsFIFOFlagsAsserted = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_DAC_FABRIC_ISR_OFFSET, XRFDC_FAB_ISR_USRDAT_MASK); + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* This API is used to update various QMC settings, eg gain, phase, offset etc. +* QMC settings passed are used to update the corresponding +* block level registers. Driver structure is updated with the new values. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param QMCSettingsPtr is Pointer to the XRFdc_QMC_Settings structure +* in which the QMC settings are passed. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note None +* +******************************************************************************/ +u32 XRFdc_SetQMCSettings(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 Block_Id, XRFdc_QMC_Settings *QMCSettingsPtr) +{ + u32 Status; + XRFdc_QMC_Settings *QMCConfigPtr; + u32 BaseAddr; + s32 PhaseCorrectionFactor; + u32 GainCorrectionFactor; + u32 Index; + u32 NoOfBlocks; + u32 Offset; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(QMCSettingsPtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, Type, Tile_Id, Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + Index = Block_Id; + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Type == XRFDC_ADC_TILE)) { + NoOfBlocks = XRFDC_NUM_OF_BLKS2; + if (Block_Id == XRFDC_BLK_ID1) { + Index = XRFDC_BLK_ID2; + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + if (InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[Index]. + MixerInputDataType == XRFDC_DATA_TYPE_IQ) { + Index = Block_Id; + NoOfBlocks = XRFDC_NUM_OF_BLKS3; + if (Block_Id == XRFDC_BLK_ID1) { + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + } + } else { + NoOfBlocks = Block_Id + 1U; + } + + for (; Index < NoOfBlocks;) { + if (Type == XRFDC_ADC_TILE) { + /* ADC */ + QMCConfigPtr = &InstancePtr->ADC_Tile[Tile_Id]. + ADCBlock_Analog_Datapath[Index].QMC_Settings; + } else { + QMCConfigPtr = &InstancePtr->DAC_Tile[Tile_Id]. + DACBlock_Analog_Datapath[Index].QMC_Settings; + } + + BaseAddr = XRFDC_BLOCK_BASE(Type, Tile_Id, Index); + + if ((QMCSettingsPtr->EnableGain != 0U) && + (QMCSettingsPtr->EnableGain != 1U)) { + metal_log(METAL_LOG_ERROR, "\n Invalid QMC gain option " + "in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + if ((QMCSettingsPtr->EnablePhase != 0U) && + (QMCSettingsPtr->EnablePhase != 1U)) { + metal_log(METAL_LOG_ERROR, "\n Invalid QMC phase option " + "in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + if ((QMCSettingsPtr->PhaseCorrectionFactor <= XRFDC_MIN_PHASE_CORR_FACTOR) || + (QMCSettingsPtr->PhaseCorrectionFactor >= XRFDC_MAX_PHASE_CORR_FACTOR)) { + metal_log(METAL_LOG_ERROR, "\n Invalid QMC Phase Correction " + "factor in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + if ((QMCSettingsPtr->GainCorrectionFactor < XRFDC_MIN_GAIN_CORR_FACTOR) || + (QMCSettingsPtr->GainCorrectionFactor >= XRFDC_MAX_GAIN_CORR_FACTOR)) { + metal_log(METAL_LOG_ERROR, "\n Invalid QMC Gain Correction " + "factor in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + if ((QMCSettingsPtr->EventSource > XRFDC_EVNT_SRC_PL) || + ((QMCSettingsPtr->EventSource == XRFDC_EVNT_SRC_MARKER) && + (Type == XRFDC_ADC_TILE))) { + metal_log(METAL_LOG_ERROR, "\n Invalid event source selection " + "in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Type == XRFDC_ADC_TILE) && + ((QMCSettingsPtr->EventSource == XRFDC_EVNT_SRC_SLICE) || + (QMCSettingsPtr->EventSource == + XRFDC_EVNT_SRC_IMMEDIATE))) { + metal_log(METAL_LOG_ERROR, "\n Invalid Event Source, " + "event source is not supported in 4GSPS ADC %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_QMC_CFG_OFFSET, + XRFDC_QMC_CFG_EN_GAIN_MASK, QMCSettingsPtr->EnableGain); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_QMC_CFG_OFFSET, + XRFDC_QMC_CFG_EN_PHASE_MASK, + (QMCSettingsPtr->EnablePhase << XRFDC_QMC_CFG_PHASE_SHIFT)); + + /* Phase Correction factor is applicable to ADC/DAC IQ mode only */ + if (((Type == XRFDC_ADC_TILE) && + (InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[Index]. + MixerInputDataType == XRFDC_DATA_TYPE_IQ)) || + ((Type == XRFDC_DAC_TILE) && + (InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[Index]. + MixerInputDataType == XRFDC_DATA_TYPE_IQ))) { + PhaseCorrectionFactor = + ((QMCSettingsPtr->PhaseCorrectionFactor / XRFDC_MAX_PHASE_CORR_FACTOR) * + XRFDC_QMC_PHASE_MULT); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_QMC_PHASE_OFFSET, + XRFDC_QMC_PHASE_CRCTN_MASK, PhaseCorrectionFactor); + } + + /* Gain Correction factor */ + GainCorrectionFactor = ((QMCSettingsPtr->GainCorrectionFactor * + XRFDC_QMC_GAIN_MULT) / XRFDC_MAX_GAIN_CORR_FACTOR); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_QMC_GAIN_OFFSET, + XRFDC_QMC_GAIN_CRCTN_MASK, GainCorrectionFactor); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_QMC_OFF_OFFSET, + XRFDC_QMC_OFFST_CRCTN_MASK, QMCSettingsPtr->OffsetCorrectionFactor); + + /* Event Source */ + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_QMC_UPDT_OFFSET, + XRFDC_QMC_UPDT_MODE_MASK, QMCSettingsPtr->EventSource); + + if (QMCSettingsPtr->EventSource == XRFDC_EVNT_SRC_IMMEDIATE) { + if (Type == XRFDC_ADC_TILE) { + Offset = XRFDC_ADC_UPDATE_DYN_OFFSET; + } else { + Offset = XRFDC_DAC_UPDATE_DYN_OFFSET; + } + XRFdc_ClrSetReg(InstancePtr, BaseAddr, Offset, + XRFDC_UPDT_EVNT_MASK, XRFDC_UPDT_EVNT_QMC_MASK); + } + /* Update the instance with new values */ + QMCConfigPtr->EventSource = QMCSettingsPtr->EventSource; + QMCConfigPtr->PhaseCorrectionFactor = + QMCSettingsPtr->PhaseCorrectionFactor; + QMCConfigPtr->GainCorrectionFactor = + QMCSettingsPtr->GainCorrectionFactor; + QMCConfigPtr->OffsetCorrectionFactor = + QMCSettingsPtr->OffsetCorrectionFactor; + QMCConfigPtr->EnablePhase = QMCSettingsPtr->EnablePhase; + QMCConfigPtr->EnableGain = QMCSettingsPtr->EnableGain; + if ((Type == XRFDC_ADC_TILE) && + (InstancePtr->ADC_Tile[Tile_Id]. + ADCBlock_Digital_Datapath[Index].MixerInputDataType == + XRFDC_DATA_TYPE_IQ) && (XRFdc_IsHighSpeedADC(InstancePtr, + Tile_Id) == 1)) { + Index += XRFDC_BLK_ID2; + } else { + Index += XRFDC_BLK_ID1; + } + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* QMC settings are returned back to the caller through this API. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param QMCSettingsPtr Pointer to the XRFdc_QMC_Settings structure +* in which the QMC settings are passed. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note None +* +******************************************************************************/ +u32 XRFdc_GetQMCSettings(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 Block_Id, XRFdc_QMC_Settings *QMCSettingsPtr) +{ + u32 Status; + u32 BaseAddr; + s32 PhaseCorrectionFactor; + u32 GainCorrectionFactor; + s32 OffsetCorrectionFactor; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(QMCSettingsPtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, Type, Tile_Id, Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Block_Id == XRFDC_BLK_ID1) && (Type == XRFDC_ADC_TILE) && + (InstancePtr->ADC_Tile[Tile_Id]. + ADCBlock_Digital_Datapath[Block_Id].MixerInputDataType != + XRFDC_DATA_TYPE_IQ)) { + Block_Id = XRFDC_BLK_ID2; + } + + BaseAddr = XRFDC_BLOCK_BASE(Type, Tile_Id, Block_Id); + + QMCSettingsPtr->EnableGain = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_QMC_CFG_OFFSET, XRFDC_QMC_CFG_EN_GAIN_MASK); + QMCSettingsPtr->EnablePhase = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_QMC_CFG_OFFSET, XRFDC_QMC_CFG_EN_PHASE_MASK) >> + XRFDC_QMC_CFG_PHASE_SHIFT; + + /* Phase Correction factor */ + if (((Type == XRFDC_ADC_TILE) && + (InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[Block_Id]. + MixerInputDataType == XRFDC_DATA_TYPE_IQ)) || + ((Type == XRFDC_DAC_TILE) && + (InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[Block_Id]. + MixerInputDataType == XRFDC_DATA_TYPE_IQ))) { + PhaseCorrectionFactor = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_QMC_PHASE_OFFSET, XRFDC_QMC_PHASE_CRCTN_MASK); + PhaseCorrectionFactor = (PhaseCorrectionFactor >> + 11) == 0 ? PhaseCorrectionFactor : + ((-1 ^ 0xFFF) | PhaseCorrectionFactor); + QMCSettingsPtr->PhaseCorrectionFactor = + ((PhaseCorrectionFactor * XRFDC_MAX_PHASE_CORR_FACTOR) / + XRFDC_QMC_PHASE_MULT); + } else { + QMCSettingsPtr->PhaseCorrectionFactor = 0U; + } + + /* Gain Correction factor */ + GainCorrectionFactor = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_QMC_GAIN_OFFSET, XRFDC_QMC_GAIN_CRCTN_MASK); + QMCSettingsPtr->GainCorrectionFactor = ((GainCorrectionFactor * + XRFDC_MAX_GAIN_CORR_FACTOR) / XRFDC_QMC_GAIN_MULT); + OffsetCorrectionFactor = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_QMC_OFF_OFFSET, XRFDC_QMC_OFFST_CRCTN_MASK); + QMCSettingsPtr->OffsetCorrectionFactor = + (OffsetCorrectionFactor >> 11) == 0 ? OffsetCorrectionFactor : + ((-1 ^ 0xFFF) | OffsetCorrectionFactor); + + /* Event Source */ + QMCSettingsPtr->EventSource = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_QMC_UPDT_OFFSET, XRFDC_QMC_UPDT_MODE_MASK); + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* Coarse delay settings passed are used to update the corresponding +* block level registers. Driver structure is updated with the new values. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param CoarseDelaySettingsPtr is Pointer to the XRFdc_CoarseDelay_Settings +* structure in which the CoarseDelay settings are passed. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note None +* +******************************************************************************/ +u32 XRFdc_SetCoarseDelaySettings(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 Block_Id, XRFdc_CoarseDelay_Settings *CoarseDelaySettingsPtr) +{ + u32 Status; + u32 BaseAddr; + u32 Index; + u32 NoOfBlocks; + u16 Mask; + u16 MaxDelay; + XRFdc_CoarseDelay_Settings *CoarseDelayConfigPtr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(CoarseDelaySettingsPtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Mask = (InstancePtr->RFdc_Config.IPType < 2)?XRFDC_CRSE_DLY_CFG_MASK:XRFDC_CRSE_DLY_CFG_MASK_EXT; + MaxDelay = (InstancePtr->RFdc_Config.IPType < 2)?XRFDC_CRSE_DLY_MAX:XRFDC_CRSE_DLY_MAX_EXT; + Status = XRFdc_CheckBlockEnabled(InstancePtr, Type, Tile_Id, Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + Index = Block_Id; + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Type == XRFDC_ADC_TILE)) { + NoOfBlocks = XRFDC_NUM_OF_BLKS2; + if (Block_Id == XRFDC_BLK_ID1) { + Index = XRFDC_BLK_ID2; + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + } else { + NoOfBlocks = Block_Id + 1U; + } + + for (; Index < NoOfBlocks; Index++) { + if (Type == XRFDC_ADC_TILE) { + CoarseDelayConfigPtr = &InstancePtr->ADC_Tile[Tile_Id]. + ADCBlock_Analog_Datapath[Index]. + CoarseDelay_Settings; + } else { + CoarseDelayConfigPtr = &InstancePtr->DAC_Tile[Tile_Id]. + DACBlock_Analog_Datapath[Index]. + CoarseDelay_Settings; + } + + BaseAddr = XRFDC_BLOCK_BASE(Type, Tile_Id, Index); + + if (CoarseDelaySettingsPtr->CoarseDelay > MaxDelay) { + metal_log(METAL_LOG_ERROR, "\n Requested coarse " + "delay not valid in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + if ((CoarseDelaySettingsPtr->EventSource > XRFDC_EVNT_SRC_PL) || + ((CoarseDelaySettingsPtr->EventSource == XRFDC_EVNT_SRC_MARKER) && + (Type == XRFDC_ADC_TILE))) { + metal_log(METAL_LOG_ERROR, "\n Invalid event " + "source selection in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Type == XRFDC_ADC_TILE) && + ((CoarseDelaySettingsPtr->EventSource == + XRFDC_EVNT_SRC_SLICE) || + (CoarseDelaySettingsPtr->EventSource == + XRFDC_EVNT_SRC_IMMEDIATE))) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, "\n Invalid Event " + "Source, event source is not supported in " + "4GSPS ADC %s\r\n", __func__); + goto RETURN_PATH; + } + if (Type == XRFDC_ADC_TILE) { + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_CRSE_DLY_CFG_OFFSET, Mask, CoarseDelaySettingsPtr->CoarseDelay); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, + XRFDC_ADC_CRSE_DLY_UPDT_OFFSET, XRFDC_QMC_UPDT_MODE_MASK, + CoarseDelaySettingsPtr->EventSource); + if (CoarseDelaySettingsPtr->EventSource == + XRFDC_EVNT_SRC_IMMEDIATE) { + XRFdc_ClrSetReg(InstancePtr, BaseAddr, + XRFDC_ADC_UPDATE_DYN_OFFSET, XRFDC_UPDT_EVNT_MASK, + XRFDC_ADC_UPDT_CRSE_DLY_MASK); + } + } else { + XRFdc_ClrSetReg(InstancePtr, BaseAddr, + XRFDC_DAC_CRSE_DLY_CFG_OFFSET, Mask, + CoarseDelaySettingsPtr->CoarseDelay); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, + XRFDC_DAC_CRSE_DLY_UPDT_OFFSET, XRFDC_QMC_UPDT_MODE_MASK, + CoarseDelaySettingsPtr->EventSource); + if (CoarseDelaySettingsPtr->EventSource == + XRFDC_EVNT_SRC_IMMEDIATE) { + XRFdc_ClrSetReg(InstancePtr, BaseAddr, + XRFDC_DAC_UPDATE_DYN_OFFSET, XRFDC_UPDT_EVNT_MASK, + XRFDC_DAC_UPDT_CRSE_DLY_MASK); + } + } + /* Update the instance with new values */ + CoarseDelayConfigPtr->CoarseDelay = + CoarseDelaySettingsPtr->CoarseDelay; + CoarseDelayConfigPtr->EventSource = + CoarseDelaySettingsPtr->EventSource; + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* Coarse delay settings are returned back to the caller. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param CoarseDelaySettingsPtr Pointer to the XRFdc_CoarseDelay_Settings +* structure in which the Coarse Delay settings are passed. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note None. +* +******************************************************************************/ +u32 XRFdc_GetCoarseDelaySettings(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 Block_Id, XRFdc_CoarseDelay_Settings *CoarseDelaySettingsPtr) +{ + u32 Status; + u32 BaseAddr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(CoarseDelaySettingsPtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, Type, Tile_Id, Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Block_Id == XRFDC_BLK_ID1) && (Type == XRFDC_ADC_TILE)) { + Block_Id = XRFDC_BLK_ID2; + } + + BaseAddr = XRFDC_BLOCK_BASE(Type, Tile_Id, Block_Id); + + if (Type == XRFDC_ADC_TILE) { + CoarseDelaySettingsPtr->CoarseDelay = + XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_ADC_CRSE_DLY_CFG_OFFSET); + CoarseDelaySettingsPtr->EventSource = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_ADC_CRSE_DLY_UPDT_OFFSET, XRFDC_QMC_UPDT_MODE_MASK); + } else { + CoarseDelaySettingsPtr->CoarseDelay = + XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_DAC_CRSE_DLY_CFG_OFFSET); + CoarseDelaySettingsPtr->EventSource = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_DAC_CRSE_DLY_UPDT_OFFSET, XRFDC_QMC_UPDT_MODE_MASK); + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* This function will trigger the update event for an event. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param Event is for which dynamic update event will trigger. +* XRFDC_EVENT_* defines the different events. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note Common API for ADC/DAC blocks +* +******************************************************************************/ +u32 XRFdc_UpdateEvent(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, u32 Block_Id, + u32 Event) +{ + u32 Status; + u32 BaseAddr; + u32 EventSource; + u32 NoOfBlocks; + u32 Index; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Index = Block_Id; + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Type == XRFDC_ADC_TILE)) { + NoOfBlocks = XRFDC_NUM_OF_BLKS2; + if (Block_Id == XRFDC_BLK_ID1) { + Index = XRFDC_BLK_ID2; + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + if ((Event == XRFDC_EVENT_QMC) && (InstancePtr->ADC_Tile[Tile_Id]. + ADCBlock_Digital_Datapath[Index].MixerInputDataType == + XRFDC_DATA_TYPE_IQ)) { + Index = Block_Id; + NoOfBlocks = XRFDC_NUM_OF_BLKS3; + if (Block_Id == XRFDC_BLK_ID1) { + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + } + } else { + NoOfBlocks = Block_Id + 1U; + } + + if ((Event != XRFDC_EVENT_MIXER) && (Event != XRFDC_EVENT_QMC) && + (Event != XRFDC_EVENT_CRSE_DLY)) { + metal_log(METAL_LOG_ERROR, "\n Invalid Event " + "value in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + for (; Index < NoOfBlocks;) { + /* Identify the Event Source */ + BaseAddr = XRFDC_BLOCK_BASE(Type, Tile_Id, Index); + if (Event == XRFDC_EVENT_MIXER) { + Status = XRFdc_CheckDigitalPathEnabled(InstancePtr, Type, + Tile_Id, Block_Id); + EventSource = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_NCO_UPDT_OFFSET, XRFDC_NCO_UPDT_MODE_MASK); + } else if (Event == XRFDC_EVENT_CRSE_DLY) { + Status = XRFdc_CheckBlockEnabled(InstancePtr, Type, + Tile_Id, Block_Id); + EventSource = XRFdc_RDReg(InstancePtr, BaseAddr, + (Type == XRFDC_ADC_TILE) ? XRFDC_ADC_CRSE_DLY_UPDT_OFFSET : + XRFDC_DAC_CRSE_DLY_UPDT_OFFSET, XRFDC_QMC_UPDT_MODE_MASK); + } else { + Status = XRFdc_CheckBlockEnabled(InstancePtr, Type, + Tile_Id, Block_Id); + EventSource = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_QMC_UPDT_OFFSET, XRFDC_QMC_UPDT_MODE_MASK); + } + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + if ((EventSource == XRFDC_EVNT_SRC_SYSREF) || + (EventSource == XRFDC_EVNT_SRC_PL) || + (EventSource == XRFDC_EVNT_SRC_MARKER)) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, "\n Invalid Event " + "Source, this should be issued external to " + "the driver %s\r\n", __func__); + goto RETURN_PATH; + } + if (Type == XRFDC_ADC_TILE) { + if (EventSource == XRFDC_EVNT_SRC_SLICE) { + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_UPDATE_DYN_OFFSET, 0x1); + } else { + BaseAddr = XRFDC_ADC_TILE_DRP_ADDR(Tile_Id) + + XRFDC_HSCOM_ADDR; + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_HSCOM_UPDT_DYN_OFFSET, 0x1); + } + } else { + if (EventSource == XRFDC_EVNT_SRC_SLICE) { + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_DAC_UPDATE_DYN_OFFSET, 0x1); + } else { + BaseAddr = XRFDC_DAC_TILE_DRP_ADDR(Tile_Id) + + XRFDC_HSCOM_ADDR; + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_HSCOM_UPDT_DYN_OFFSET, 0x1); + } + } + if ((Event == XRFDC_EVENT_QMC) && (InstancePtr->ADC_Tile[Tile_Id]. + ADCBlock_Digital_Datapath[Index].MixerInputDataType == + XRFDC_DATA_TYPE_IQ) && (XRFdc_IsHighSpeedADC(InstancePtr, + Tile_Id) == 1) && (Type == XRFDC_ADC_TILE)) { + Index += XRFDC_BLK_ID2; + } else { + Index += XRFDC_BLK_ID1; + } + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* This API is to set the decimation factor and also update the FIFO write +* words w.r.t to decimation factor. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param DecimationFactor to be set for DAC block. +* XRFDC_INTERP_DECIM_* defines the valid values. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note Only ADC blocks +* +******************************************************************************/ +u32 XRFdc_SetDecimationFactor(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, + u32 DecimationFactor) +{ + u32 Status; + u32 BaseAddr; + u32 Index; + u32 NoOfBlocks; + u16 FabricRate; + u8 DataType; + u32 Factor; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckDigitalPathEnabled(InstancePtr, XRFDC_ADC_TILE, Tile_Id, + Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block digital path not " + "enabled in %s\r\n", __func__); + goto RETURN_PATH; + } + + if ((DecimationFactor != XRFDC_INTERP_DECIM_OFF) && + (DecimationFactor != XRFDC_INTERP_DECIM_1X) && + (DecimationFactor != XRFDC_INTERP_DECIM_2X) && + (DecimationFactor != XRFDC_INTERP_DECIM_4X) && + (DecimationFactor != XRFDC_INTERP_DECIM_8X) && + ((InstancePtr->RFdc_Config.IPType < 2) || + ((DecimationFactor != XRFDC_INTERP_DECIM_3X) && + (DecimationFactor != XRFDC_INTERP_DECIM_5X) && + (DecimationFactor != XRFDC_INTERP_DECIM_6X) && + (DecimationFactor != XRFDC_INTERP_DECIM_10X) && + (DecimationFactor != XRFDC_INTERP_DECIM_12X) && + (DecimationFactor != XRFDC_INTERP_DECIM_16X) && + (DecimationFactor != XRFDC_INTERP_DECIM_20X) && + (DecimationFactor != XRFDC_INTERP_DECIM_24X) && + (DecimationFactor != XRFDC_INTERP_DECIM_40X)))) { + metal_log(METAL_LOG_ERROR, "\n Invalid Decimation factor " + "value in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + Index = Block_Id; + if (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) { + NoOfBlocks = XRFDC_NUM_OF_BLKS2; + if (Block_Id == XRFDC_BLK_ID1) { + Index = XRFDC_BLK_ID2; + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + } else { + NoOfBlocks = Block_Id + 1U; + } + + for (; Index < NoOfBlocks; Index++) { + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_ADC_TILE, Tile_Id, Index); + DataType = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_ADC_DECI_CONFIG_OFFSET, XRFDC_DEC_CFG_MASK); + + /* Decimation factor */ + Factor = DecimationFactor; + if (InstancePtr->RFdc_Config.IPType < 2) { + if (DecimationFactor == XRFDC_INTERP_DECIM_4X) { + Factor = 0x3; + } + if (DecimationFactor == XRFDC_INTERP_DECIM_8X) { + Factor = 0x4; + } + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_DECI_MODE_OFFSET, + XRFDC_DEC_MOD_MASK, Factor); + } else { + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_DECI_MODE_OFFSET, + XRFDC_DEC_MOD_MASK_EXT, Factor); + } + + + + /* Fabric rate */ + FabricRate = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_ADC_FABRIC_RATE_OFFSET, XRFDC_ADC_FAB_RATE_WR_MASK); + if ((DataType == XRFDC_DECIM_2G_IQ_DATA_TYPE) || + (DataType == XRFDC_DECIM_4G_DATA_TYPE) || + (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1)) { + switch (DecimationFactor) { + case XRFDC_INTERP_DECIM_1X: + FabricRate = XRFDC_FAB_RATE_8; + break; + case XRFDC_INTERP_DECIM_2X: + case XRFDC_INTERP_DECIM_3X: + FabricRate = XRFDC_FAB_RATE_4; + break; + case XRFDC_INTERP_DECIM_4X: + case XRFDC_INTERP_DECIM_5X: + case XRFDC_INTERP_DECIM_6X: + FabricRate = XRFDC_FAB_RATE_2; + break; + case XRFDC_INTERP_DECIM_10X: + case XRFDC_INTERP_DECIM_12X: + case XRFDC_INTERP_DECIM_8X: + FabricRate = XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) ? + XRFDC_FAB_RATE_1:XRFDC_FAB_RATE_2; + break; + case XRFDC_INTERP_DECIM_16X: + case XRFDC_INTERP_DECIM_20X: + case XRFDC_INTERP_DECIM_24X: + case XRFDC_INTERP_DECIM_40X: + FabricRate = XRFDC_FAB_RATE_1; + break; + default: + metal_log(METAL_LOG_DEBUG, "\n Decimation block " + "is OFF in %s\r\n", __func__); + break; + } + } else { + switch (DecimationFactor) { + case XRFDC_INTERP_DECIM_1X: + FabricRate = XRFDC_FAB_RATE_4; + break; + case XRFDC_INTERP_DECIM_2X: + case XRFDC_INTERP_DECIM_3X: + FabricRate = XRFDC_FAB_RATE_2; + break; + case XRFDC_INTERP_DECIM_4X: + case XRFDC_INTERP_DECIM_8X: + case XRFDC_INTERP_DECIM_5X: + case XRFDC_INTERP_DECIM_6X: + case XRFDC_INTERP_DECIM_10X: + case XRFDC_INTERP_DECIM_12X: + case XRFDC_INTERP_DECIM_16X: + case XRFDC_INTERP_DECIM_20X: + case XRFDC_INTERP_DECIM_24X: + case XRFDC_INTERP_DECIM_40X: + FabricRate = XRFDC_FAB_RATE_1; + break; + default: + metal_log(METAL_LOG_DEBUG, "\n Decimation block " + "is OFF in %s\r\n", __func__); + break; + } + } + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_FABRIC_RATE_OFFSET, + XRFDC_ADC_FAB_RATE_WR_MASK, FabricRate); + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* This API is to set the divider for clock fabric out. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param FabClkDiv to be set for a tile. +* XRFDC_FAB_CLK_* defines the valid divider values. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note ADC and DAC Tiles +* +******************************************************************************/ +u32 XRFdc_SetFabClkOutDiv(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u16 FabClkDiv) +{ + u32 Status; + u32 BaseAddr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + 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 ((FabClkDiv != XRFDC_FAB_CLK_DIV1) && + (FabClkDiv != XRFDC_FAB_CLK_DIV2) && + (FabClkDiv != XRFDC_FAB_CLK_DIV4) && + (FabClkDiv != XRFDC_FAB_CLK_DIV8) && + (FabClkDiv != XRFDC_FAB_CLK_DIV16)) { + metal_log(METAL_LOG_ERROR, "\n Invalid Fabric clock out " + "divider value in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + BaseAddr = XRFDC_DRP_BASE(Type, Tile_Id) + XRFDC_HSCOM_ADDR; + + if ((Type == XRFDC_ADC_TILE) && + (FabClkDiv == XRFDC_FAB_CLK_DIV1)) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, "\n Invalid clock divider " + "in %s \r\n", __func__); + goto RETURN_PATH; + } else { + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_HSCOM_CLK_DIV_OFFSET, + XRFDC_FAB_CLK_DIV_MASK, FabClkDiv); + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* This API is to get the divider for clock fabric out. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param FabClkDivPtr is a pointer to get fabric clock for a tile. +* XRFDC_FAB_CLK_* defines the valid divider values. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Tile not enabled. +* +* @note API is applicable for both ADC and DAC Tiles +* +******************************************************************************/ +u32 XRFdc_GetFabClkOutDiv(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u16 *FabClkDivPtr) +{ + u32 Status; + u32 BaseAddr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(FabClkDivPtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + 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; + + *FabClkDivPtr = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_HSCOM_CLK_DIV_OFFSET, XRFDC_FAB_CLK_DIV_MASK); + + if ((*FabClkDivPtr < XRFDC_FAB_CLK_DIV1) || + (*FabClkDivPtr > XRFDC_FAB_CLK_DIV16)) { + *FabClkDivPtr = XRFDC_FAB_CLK_DIV16; + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* This API is to set the interpolation factor and also update the FIFO read +* words w.r.t to interpolation factor. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param InterpolationFactor to be set for DAC block. +* XRFDC_INTERP_DECIM_* defines the valid values. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note Only DAC blocks +* +******************************************************************************/ +u32 XRFdc_SetInterpolationFactor(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, + u32 InterpolationFactor) +{ + u32 Status; + u32 BaseAddr; + u16 FabricRate; + u8 DataType; + u32 Factor; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckDigitalPathEnabled(InstancePtr, XRFDC_DAC_TILE, Tile_Id, + Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block digital path not " + "enabled in %s\r\n", __func__); + goto RETURN_PATH; + } + + if ((InterpolationFactor != XRFDC_INTERP_DECIM_OFF) && + (InterpolationFactor != XRFDC_INTERP_DECIM_1X) && + (InterpolationFactor != XRFDC_INTERP_DECIM_2X) && + (InterpolationFactor != XRFDC_INTERP_DECIM_4X) && + (InterpolationFactor != XRFDC_INTERP_DECIM_8X) && + ((InstancePtr->RFdc_Config.IPType < 2) || + ((InterpolationFactor != XRFDC_INTERP_DECIM_3X) && + (InterpolationFactor != XRFDC_INTERP_DECIM_5X) && + (InterpolationFactor != XRFDC_INTERP_DECIM_6X) && + (InterpolationFactor != XRFDC_INTERP_DECIM_10X) && + (InterpolationFactor != XRFDC_INTERP_DECIM_12X) && + (InterpolationFactor != XRFDC_INTERP_DECIM_16X) && + (InterpolationFactor != XRFDC_INTERP_DECIM_20X) && + (InterpolationFactor != XRFDC_INTERP_DECIM_24X) && + (InterpolationFactor != XRFDC_INTERP_DECIM_40X)))) { + metal_log(METAL_LOG_ERROR, "\n Invalid Interpolation factor " + "divider value in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_DAC_TILE, Tile_Id, Block_Id); + + DataType = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_DAC_ITERP_DATA_OFFSET); + if ((DataType == XRFDC_ADC_MIXER_MODE_IQ) && + (InterpolationFactor == + XRFDC_INTERP_DECIM_1X)) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, "\n Invalid interpolation " + "factor in %s\r\n", __func__); + goto RETURN_PATH; + } + + /* Interpolation factor */ + Factor = InterpolationFactor; + + if (InstancePtr->RFdc_Config.IPType < 2) { + if (InterpolationFactor == XRFDC_INTERP_DECIM_4X) { + Factor = 0x3; + } + if (InterpolationFactor == XRFDC_INTERP_DECIM_8X) { + Factor = 0x4; + } + } + if (DataType == XRFDC_ADC_MIXER_MODE_IQ) { + Factor |= Factor << ((InstancePtr->RFdc_Config.IPType < 2)?XRFDC_INTERP_MODE_Q_SHIFT:XRFDC_INTERP_MODE_Q_SHIFT_EXT); + } + + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_DAC_INTERP_CTRL_OFFSET, + (InstancePtr->RFdc_Config.IPType < 2)?XRFDC_INTERP_MODE_MASK:XRFDC_INTERP_MODE_MASK_EXT, Factor); + + /* Fabric rate */ + FabricRate = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_ADC_FABRIC_RATE_OFFSET, XRFDC_FAB_RATE_RD_MASK); + FabricRate = FabricRate >> XRFDC_FAB_RATE_RD_SHIFT; + if (DataType == XRFDC_ADC_MIXER_MODE_IQ) { + switch (InterpolationFactor) { + case XRFDC_INTERP_DECIM_2X: + case XRFDC_INTERP_DECIM_3X: + FabricRate = XRFDC_FAB_RATE_8; + break; + case XRFDC_INTERP_DECIM_4X: + case XRFDC_INTERP_DECIM_5X: + case XRFDC_INTERP_DECIM_6X: + FabricRate = XRFDC_FAB_RATE_4; + break; + case XRFDC_INTERP_DECIM_8X: + case XRFDC_INTERP_DECIM_10X: + case XRFDC_INTERP_DECIM_12X: + FabricRate = XRFDC_FAB_RATE_2; + break; + case XRFDC_INTERP_DECIM_16X: + case XRFDC_INTERP_DECIM_20X: + case XRFDC_INTERP_DECIM_24X: + case XRFDC_INTERP_DECIM_40X: + FabricRate = XRFDC_FAB_RATE_1; + break; + default: + metal_log(METAL_LOG_DEBUG, "\n Interpolation block " + "is OFF in %s\r\n", __func__); + break; + } + } else { + switch (InterpolationFactor) { + case XRFDC_INTERP_DECIM_1X: + FabricRate = XRFDC_FAB_RATE_8; + break; + case XRFDC_INTERP_DECIM_2X: + case XRFDC_INTERP_DECIM_3X: + FabricRate = XRFDC_FAB_RATE_4; + break; + case XRFDC_INTERP_DECIM_4X: + case XRFDC_INTERP_DECIM_5X: + case XRFDC_INTERP_DECIM_6X: + FabricRate = XRFDC_FAB_RATE_2; + break; + case XRFDC_INTERP_DECIM_8X: + case XRFDC_INTERP_DECIM_10X: + case XRFDC_INTERP_DECIM_12X: + case XRFDC_INTERP_DECIM_16X: + case XRFDC_INTERP_DECIM_20X: + case XRFDC_INTERP_DECIM_24X: + case XRFDC_INTERP_DECIM_40X: + FabricRate = XRFDC_FAB_RATE_1; + break; + default: + metal_log(METAL_LOG_DEBUG, "\n Interpolation block " + "is OFF in %s\r\n", __func__); + break; + } + } + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_FABRIC_RATE_OFFSET, + XRFDC_FAB_RATE_RD_MASK, (FabricRate << XRFDC_FAB_RATE_RD_SHIFT)); + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* Interpolation factor are returned back to the caller. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param InterpolationFactorPtr Pointer to return the interpolation factor +* for DAC blocks. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note Only for DAC blocks +* +******************************************************************************/ +u32 XRFdc_GetInterpolationFactor(XRFdc *InstancePtr, u32 Tile_Id, + u32 Block_Id, u32 *InterpolationFactorPtr) +{ + u32 Status; + u32 BaseAddr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InterpolationFactorPtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckDigitalPathEnabled(InstancePtr, XRFDC_DAC_TILE, Tile_Id, + Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block digital path not " + "enabled in %s\r\n", __func__); + goto RETURN_PATH; + } + + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_DAC_TILE, Tile_Id, Block_Id); + + if (InstancePtr->RFdc_Config.IPType < 2) { + *InterpolationFactorPtr = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_DAC_INTERP_CTRL_OFFSET, XRFDC_INTERP_MODE_I_MASK); + if (*InterpolationFactorPtr == 0x3U) { + *InterpolationFactorPtr = XRFDC_INTERP_DECIM_4X; + } else if (*InterpolationFactorPtr == 0x4U) { + *InterpolationFactorPtr = XRFDC_INTERP_DECIM_8X; + } + } else { + *InterpolationFactorPtr = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_DAC_INTERP_CTRL_OFFSET, XRFDC_INTERP_MODE_I_MASK_EXT); + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* Decimation factor are returned back to the caller. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param DecimationFactorPtr Pointer to return the Decimation factor +* for DAC blocks. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note Only for ADC blocks +* +******************************************************************************/ +u32 XRFdc_GetDecimationFactor(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, + u32 *DecimationFactorPtr) +{ + u32 Status; + u32 BaseAddr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(DecimationFactorPtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckDigitalPathEnabled(InstancePtr, XRFDC_ADC_TILE, Tile_Id, + Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block digital path not " + "enabled in %s\r\n", __func__); + goto RETURN_PATH; + } + + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Block_Id == XRFDC_BLK_ID1)) { + Block_Id = XRFDC_BLK_ID2; + } + + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_ADC_TILE, Tile_Id, Block_Id); + + + + if (InstancePtr->RFdc_Config.IPType < 2) { + *DecimationFactorPtr = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_ADC_DECI_MODE_OFFSET, XRFDC_DEC_MOD_MASK); + if (*DecimationFactorPtr == 0x3U) { + *DecimationFactorPtr = XRFDC_INTERP_DECIM_4X; + } else if (*DecimationFactorPtr == 0x4U) { + *DecimationFactorPtr = XRFDC_INTERP_DECIM_8X; + } + } else { + *DecimationFactorPtr = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_ADC_DECI_MODE_OFFSET, XRFDC_DEC_MOD_MASK_EXT); + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* Fabric data rate for the requested DAC block is set by writing to the +* corresponding register. The function writes the number of valid write words +* for the requested DAC block. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param FabricWrVldWords is write fabric rate to be set for DAC block. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note Only for DAC blocks +* +******************************************************************************/ +u32 XRFdc_SetFabWrVldWords(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, + u32 FabricWrVldWords) +{ + u32 Status; + u32 BaseAddr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckDigitalPathEnabled(InstancePtr, XRFDC_DAC_TILE, Tile_Id, + Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block digital path not " + "enabled in %s\r\n", __func__); + goto RETURN_PATH; + } + + if (FabricWrVldWords > XRFDC_DAC_MAX_WR_FAB_RATE) { + metal_log(METAL_LOG_ERROR, "\n Requested write valid words " + "is Invalid in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_DAC_TILE, Tile_Id, Block_Id); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_FABRIC_RATE_OFFSET, + XRFDC_DAC_FAB_RATE_WR_MASK, FabricWrVldWords); + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* +* Fabric data rate for the requested ADC block is set by writing to the +* corresponding register. The function writes the number of valid read words +* for the requested ADC block. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC block number inside the tile. Valid values +* are 0-3. +* @param FabricRdVldWords is Read fabric rate to be set for ADC block. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note Only for ADC blocks +* +******************************************************************************/ +u32 XRFdc_SetFabRdVldWords(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, + u32 FabricRdVldWords) +{ + u32 Status; + u32 BaseAddr; + u32 Index; + u32 NoOfBlocks; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckDigitalPathEnabled(InstancePtr, XRFDC_ADC_TILE, Tile_Id, + Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block digital path not " + "enabled in %s\r\n", __func__); + goto RETURN_PATH; + } + + if (FabricRdVldWords > XRFDC_ADC_MAX_RD_FAB_RATE) { + metal_log(METAL_LOG_ERROR, "\n Requested read " + "valid words is Invalid in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + Index = Block_Id; + if (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) { + NoOfBlocks = XRFDC_NUM_OF_BLKS2; + if (Block_Id == XRFDC_BLK_ID1) { + Index = XRFDC_BLK_ID2; + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + } else { + NoOfBlocks = Block_Id + 1U; + } + + for (; Index < NoOfBlocks; Index++) { + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_ADC_TILE, Tile_Id, Index); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, + XRFDC_ADC_FABRIC_RATE_OFFSET, XRFDC_FAB_RATE_RD_MASK, + (FabricRdVldWords << XRFDC_FAB_RATE_RD_SHIFT)); + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* +* This API returns the the number of fabric write valid words requested +* for the block. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param FabricWrVldWordsPtr Pointer to return the fabric data rate for +* DAC block +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note ADC/DAC blocks +* +******************************************************************************/ +u32 XRFdc_GetFabWrVldWords(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 Block_Id, u32 *FabricWrVldWordsPtr) +{ + u32 Status; + u32 BaseAddr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(FabricWrVldWordsPtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckDigitalPathEnabled(InstancePtr, Type, Tile_Id, Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block digital path not " + "enabled in %s\r\n", __func__); + goto RETURN_PATH; + } + + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Block_Id == XRFDC_BLK_ID1) && (Type == XRFDC_ADC_TILE)) { + Block_Id = XRFDC_BLK_ID2; + } + + BaseAddr = XRFDC_BLOCK_BASE(Type, Tile_Id, Block_Id); + + *FabricWrVldWordsPtr = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_ADC_FABRIC_RATE_OFFSET); + if (Type == XRFDC_ADC_TILE) { + *FabricWrVldWordsPtr &= XRFDC_ADC_FAB_RATE_WR_MASK; + } else { + *FabricWrVldWordsPtr &= XRFDC_DAC_FAB_RATE_WR_MASK; + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* This API returns the the number of fabric read valid words requested +* for the block. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param FabricRdVldWordsPtr Pointer to return the fabric data rate for +* ADC/DAC block +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note ADC/DAC blocks +* +******************************************************************************/ +u32 XRFdc_GetFabRdVldWords(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 Block_Id, u32 *FabricRdVldWordsPtr) +{ + u32 Status; + u32 BaseAddr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(FabricRdVldWordsPtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckDigitalPathEnabled(InstancePtr, Type, Tile_Id, Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block digital path not " + "enabled in %s\r\n", __func__); + goto RETURN_PATH; + } + + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Block_Id == XRFDC_BLK_ID1) && (Type == XRFDC_ADC_TILE)) { + Block_Id = XRFDC_BLK_ID2; + } + BaseAddr = XRFDC_BLOCK_BASE(Type, Tile_Id, Block_Id); + + *FabricRdVldWordsPtr = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_ADC_FABRIC_RATE_OFFSET, XRFDC_FAB_RATE_RD_MASK); + *FabricRdVldWordsPtr = (*FabricRdVldWordsPtr) >> XRFDC_FAB_RATE_RD_SHIFT; + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* This API is to clear the Sticky bit in threshold config registers. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param ThresholdToUpdate Select which Threshold (Threshold0 or +* Threshold1 or both) to update. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note Only ADC blocks +* +******************************************************************************/ +u32 XRFdc_ThresholdStickyClear(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, + u32 ThresholdToUpdate) +{ + u32 Status; + u32 BaseAddr; + u32 Index; + u32 NoOfBlocks; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_ADC_TILE, Tile_Id, + Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + if ((ThresholdToUpdate != XRFDC_UPDATE_THRESHOLD_0) && + (ThresholdToUpdate != XRFDC_UPDATE_THRESHOLD_1) && + (ThresholdToUpdate != XRFDC_UPDATE_THRESHOLD_BOTH)) { + metal_log(METAL_LOG_ERROR, "\n Invalid ThresholdToUpdate " + "value in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + Index = Block_Id; + if (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) { + NoOfBlocks = XRFDC_NUM_OF_BLKS2; + if (Block_Id == XRFDC_BLK_ID1) { + Index = XRFDC_BLK_ID2; + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + if (InstancePtr->ADC_Tile[Tile_Id]. + ADCBlock_Digital_Datapath[Index].MixerInputDataType == + XRFDC_DATA_TYPE_IQ) { + Index = Block_Id; + NoOfBlocks = XRFDC_NUM_OF_BLKS3; + if (Block_Id == XRFDC_BLK_ID1) { + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + } + } else { + NoOfBlocks = Block_Id + 1U; + } + + for (; Index < NoOfBlocks;) { + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_ADC_TILE, Tile_Id, Index); + /* Update for Threshold0 */ + if ((ThresholdToUpdate == XRFDC_UPDATE_THRESHOLD_0) || + (ThresholdToUpdate == XRFDC_UPDATE_THRESHOLD_BOTH)) { + XRFdc_ClrSetReg(InstancePtr, BaseAddr, + XRFDC_ADC_TRSHD0_CFG_OFFSET, XRFDC_TRSHD0_STIKY_CLR_MASK, + XRFDC_TRSHD0_STIKY_CLR_MASK); + } + /* Update for Threshold1 */ + if ((ThresholdToUpdate == XRFDC_UPDATE_THRESHOLD_1) || + (ThresholdToUpdate == XRFDC_UPDATE_THRESHOLD_BOTH)) { + XRFdc_ClrSetReg(InstancePtr, BaseAddr, + XRFDC_ADC_TRSHD1_CFG_OFFSET, XRFDC_TRSHD1_STIKY_CLR_MASK, + XRFDC_TRSHD1_STIKY_CLR_MASK); + } + + if ((InstancePtr->ADC_Tile[Tile_Id]. + ADCBlock_Digital_Datapath[Index].MixerInputDataType == + XRFDC_DATA_TYPE_IQ) && (XRFdc_IsHighSpeedADC(InstancePtr, + Tile_Id) == 1)) { + Index += XRFDC_BLK_ID2; + } else { + Index += XRFDC_BLK_ID1; + } + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* This API sets the threshold clear mode. The clear mode can be through +* explicit DRP access (manual) or auto clear (QMC gain update event). +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADCC block number inside the tile. Valid values +* are 0-3. +* @param ThresholdToUpdate Select which Threshold (Threshold0 or +* Threshold1 or both) to update. +* @param ClrMode can be DRP access (manual) or auto clear (QMC gain +* update event). +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note Only ADC blocks +* +******************************************************************************/ +u32 XRFdc_SetThresholdClrMode(XRFdc *InstancePtr, u32 Tile_Id, + u32 Block_Id, u32 ThresholdToUpdate, u32 ClrMode) +{ + u32 Status; + u16 ReadReg; + u32 BaseAddr; + u32 Index; + u32 NoOfBlocks; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_ADC_TILE, Tile_Id, + Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + if ((ThresholdToUpdate != XRFDC_UPDATE_THRESHOLD_0) && + (ThresholdToUpdate != XRFDC_UPDATE_THRESHOLD_1) && + (ThresholdToUpdate != XRFDC_UPDATE_THRESHOLD_BOTH)) { + metal_log(METAL_LOG_ERROR, "\n Invalid ThresholdToUpdate " + "value in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + if ((ClrMode != XRFDC_THRESHOLD_CLRMD_MANUAL_CLR) && + (ClrMode != XRFDC_THRESHOLD_CLRMD_AUTO_CLR)) { + metal_log(METAL_LOG_ERROR, "\n Invalid Clear mode " + "value in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + Index = Block_Id; + if (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) { + NoOfBlocks = XRFDC_NUM_OF_BLKS2; + if (Block_Id == XRFDC_BLK_ID1) { + Index = XRFDC_BLK_ID2; + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + if (InstancePtr->ADC_Tile[Tile_Id]. + ADCBlock_Digital_Datapath[Index].MixerInputDataType == + XRFDC_DATA_TYPE_IQ) { + Index = Block_Id; + NoOfBlocks = XRFDC_NUM_OF_BLKS3; + if (Block_Id == XRFDC_BLK_ID1) { + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + } + } else { + NoOfBlocks = Block_Id + 1U; + } + + for (; Index < NoOfBlocks;) { + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_ADC_TILE, Tile_Id, Index); + /* Update for Threshold0 */ + if ((ThresholdToUpdate == XRFDC_UPDATE_THRESHOLD_0) || + (ThresholdToUpdate == XRFDC_UPDATE_THRESHOLD_BOTH)) { + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_ADC_TRSHD0_CFG_OFFSET); + if (ClrMode == XRFDC_THRESHOLD_CLRMD_MANUAL_CLR) { + ReadReg &= ~XRFDC_TRSHD0_CLR_MOD_MASK; + } else { + ReadReg |= XRFDC_TRSHD0_CLR_MOD_MASK; + } + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_TRSHD0_CFG_OFFSET, ReadReg); + } + /* Update for Threshold1 */ + if ((ThresholdToUpdate == XRFDC_UPDATE_THRESHOLD_1) || + (ThresholdToUpdate == XRFDC_UPDATE_THRESHOLD_BOTH)) { + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_ADC_TRSHD1_CFG_OFFSET); + if (ClrMode == XRFDC_THRESHOLD_CLRMD_MANUAL_CLR) { + ReadReg &= ~XRFDC_TRSHD1_CLR_MOD_MASK; + } else { + ReadReg |= XRFDC_TRSHD1_CLR_MOD_MASK; + } + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_TRSHD1_CFG_OFFSET, ReadReg); + } + if ((InstancePtr->ADC_Tile[Tile_Id]. + ADCBlock_Digital_Datapath[Index].MixerInputDataType == + XRFDC_DATA_TYPE_IQ) && (XRFdc_IsHighSpeedADC(InstancePtr, + Tile_Id) == 1)) { + Index += XRFDC_BLK_ID2; + } else { + Index += XRFDC_BLK_ID1; + } + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* Threshold settings are updated into the relevant registers. Driver structure +* is updated with the new values. There can be two threshold settings: +* threshold0 and threshold1. Both of them are independent of each other. +* The function returns the requested threshold (which can be threshold0, +* threshold1, or both. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param ThresholdSettingsPtr Pointer through which the register settings for +* thresholds are passed to the API. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note Only ADC blocks +* +******************************************************************************/ +u32 XRFdc_SetThresholdSettings(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, + XRFdc_Threshold_Settings *ThresholdSettingsPtr) +{ + u32 Status; + u32 BaseAddr; + u32 Index; + u32 NoOfBlocks; + XRFdc_Threshold_Settings *ThresholdConfigPtr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(ThresholdSettingsPtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_ADC_TILE, Tile_Id, + Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + Index = Block_Id; + if (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) { + NoOfBlocks = XRFDC_NUM_OF_BLKS2; + if (Block_Id == XRFDC_BLK_ID1) { + Index = XRFDC_BLK_ID2; + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + if (InstancePtr->ADC_Tile[Tile_Id]. + ADCBlock_Digital_Datapath[Index].MixerInputDataType == + XRFDC_DATA_TYPE_IQ) { + Index = Block_Id; + NoOfBlocks = XRFDC_NUM_OF_BLKS3; + if (Block_Id == XRFDC_BLK_ID1) { + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + } + } else { + NoOfBlocks = Block_Id + 1U; + } + + for (; Index < NoOfBlocks;) { + ThresholdConfigPtr = &InstancePtr->ADC_Tile[Tile_Id]. + ADCBlock_Analog_Datapath[Index].Threshold_Settings; + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_ADC_TILE, Tile_Id, Index); + + if ((ThresholdSettingsPtr->UpdateThreshold != XRFDC_UPDATE_THRESHOLD_0) && + (ThresholdSettingsPtr->UpdateThreshold != XRFDC_UPDATE_THRESHOLD_1) && + (ThresholdSettingsPtr->UpdateThreshold != XRFDC_UPDATE_THRESHOLD_BOTH)) { + metal_log(METAL_LOG_ERROR, "\n Invalid UpdateThreshold " + "value in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + if (((ThresholdSettingsPtr->UpdateThreshold == + XRFDC_UPDATE_THRESHOLD_0) || + (ThresholdSettingsPtr->UpdateThreshold == + XRFDC_UPDATE_THRESHOLD_BOTH)) && + (ThresholdSettingsPtr->ThresholdMode[0] > XRFDC_TRSHD_HYSTERISIS)) { + metal_log(METAL_LOG_ERROR, "\n Requested threshold " + "mode for threshold0 is invalid " + "in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + if (((ThresholdSettingsPtr->UpdateThreshold == + XRFDC_UPDATE_THRESHOLD_1) || + (ThresholdSettingsPtr->UpdateThreshold == + XRFDC_UPDATE_THRESHOLD_BOTH)) && + (ThresholdSettingsPtr->ThresholdMode[1] > XRFDC_TRSHD_HYSTERISIS)) { + metal_log(METAL_LOG_ERROR, "\n Requested threshold " + "mode for threshold1 is invalid " + "in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + /* Update for Threshold0 */ + if ((ThresholdSettingsPtr->UpdateThreshold == + XRFDC_UPDATE_THRESHOLD_0) || + (ThresholdSettingsPtr->UpdateThreshold == + XRFDC_UPDATE_THRESHOLD_BOTH)) { + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_TRSHD0_CFG_OFFSET, + XRFDC_TRSHD0_EN_MOD_MASK, + ThresholdSettingsPtr->ThresholdMode[0]); + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_TRSHD0_AVG_LO_OFFSET, + (u16)ThresholdSettingsPtr->ThresholdAvgVal[0]); + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_TRSHD0_AVG_UP_OFFSET, + (u16)(ThresholdSettingsPtr->ThresholdAvgVal[0] >> + XRFDC_TRSHD0_AVG_UPP_SHIFT)); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, + XRFDC_ADC_TRSHD0_UNDER_OFFSET, XRFDC_TRSHD0_UNDER_MASK, + ThresholdSettingsPtr->ThresholdUnderVal[0]); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, + XRFDC_ADC_TRSHD0_OVER_OFFSET, XRFDC_TRSHD0_OVER_MASK, + ThresholdSettingsPtr->ThresholdOverVal[0]); + + ThresholdConfigPtr->ThresholdMode[0] = + ThresholdSettingsPtr->ThresholdMode[0]; + ThresholdConfigPtr->ThresholdAvgVal[0] = + ThresholdSettingsPtr->ThresholdAvgVal[0]; + ThresholdConfigPtr->ThresholdUnderVal[0] = + ThresholdSettingsPtr->ThresholdUnderVal[0]; + ThresholdConfigPtr->ThresholdOverVal[0] = + ThresholdSettingsPtr->ThresholdOverVal[0]; + } + + /* Update for Threshold1 */ + if ((ThresholdSettingsPtr->UpdateThreshold == + XRFDC_UPDATE_THRESHOLD_1) || + (ThresholdSettingsPtr->UpdateThreshold == + XRFDC_UPDATE_THRESHOLD_BOTH)) { + XRFdc_ClrSetReg(InstancePtr, BaseAddr, + XRFDC_ADC_TRSHD1_CFG_OFFSET, XRFDC_TRSHD1_EN_MOD_MASK, + ThresholdSettingsPtr->ThresholdMode[1]); + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_TRSHD1_AVG_LO_OFFSET, + (u16)ThresholdSettingsPtr->ThresholdAvgVal[1]); + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_TRSHD1_AVG_UP_OFFSET, + (u16)(ThresholdSettingsPtr->ThresholdAvgVal[1] >> + XRFDC_TRSHD1_AVG_UPP_SHIFT)); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, + XRFDC_ADC_TRSHD1_UNDER_OFFSET, XRFDC_TRSHD1_UNDER_MASK, + ThresholdSettingsPtr->ThresholdUnderVal[1]); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, + XRFDC_ADC_TRSHD1_OVER_OFFSET, XRFDC_TRSHD1_OVER_MASK, + ThresholdSettingsPtr->ThresholdOverVal[1]); + + ThresholdConfigPtr->ThresholdMode[1] = + ThresholdSettingsPtr->ThresholdMode[1]; + ThresholdConfigPtr->ThresholdAvgVal[1] = + ThresholdSettingsPtr->ThresholdAvgVal[1]; + ThresholdConfigPtr->ThresholdUnderVal[1] = + ThresholdSettingsPtr->ThresholdUnderVal[1]; + ThresholdConfigPtr->ThresholdOverVal[1] = + ThresholdSettingsPtr->ThresholdOverVal[1]; + } + if ((InstancePtr->ADC_Tile[Tile_Id]. + ADCBlock_Digital_Datapath[Index].MixerInputDataType == + XRFDC_DATA_TYPE_IQ) && (XRFdc_IsHighSpeedADC(InstancePtr, + Tile_Id) == 1)) { + Index += XRFDC_BLK_ID2; + } else { + Index += XRFDC_BLK_ID1; + } + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* Threshold settings are read from the corresponding registers and are passed +* back to the caller. There can be two threshold settings: +* threshold0 and threshold1. Both of them are independent of each other. +* The function returns the requested threshold (which can be threshold0, +* threshold1, or both. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param ThresholdSettingsPtr Pointer through which the register settings +* for thresholds are passed back.. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note Only for ADC blocks +* +******************************************************************************/ +u32 XRFdc_GetThresholdSettings(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, + XRFdc_Threshold_Settings *ThresholdSettingsPtr) +{ + u32 Status; + u32 BaseAddr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(ThresholdSettingsPtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_ADC_TILE, Tile_Id, + Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Block_Id == XRFDC_BLK_ID1) && (InstancePtr->ADC_Tile[Tile_Id]. + ADCBlock_Digital_Datapath[Block_Id].MixerInputDataType != + XRFDC_DATA_TYPE_IQ)) { + Block_Id = XRFDC_BLK_ID2; + } + + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_ADC_TILE, Tile_Id, Block_Id); + + /* Threshold mode */ + ThresholdSettingsPtr->UpdateThreshold = XRFDC_UPDATE_THRESHOLD_BOTH; + ThresholdSettingsPtr->ThresholdMode[0] = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_ADC_TRSHD0_CFG_OFFSET, XRFDC_TRSHD0_EN_MOD_MASK); + ThresholdSettingsPtr->ThresholdMode[1] = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_ADC_TRSHD1_CFG_OFFSET, XRFDC_TRSHD1_EN_MOD_MASK); + + /* Threshold Average Value */ + ThresholdSettingsPtr->ThresholdAvgVal[0] = XRFdc_ReadReg16(InstancePtr, + BaseAddr, XRFDC_ADC_TRSHD0_AVG_LO_OFFSET); + ThresholdSettingsPtr->ThresholdAvgVal[0] |= (XRFdc_ReadReg16(InstancePtr, + BaseAddr, XRFDC_ADC_TRSHD0_AVG_UP_OFFSET) << + XRFDC_TRSHD0_AVG_UPP_SHIFT); + ThresholdSettingsPtr->ThresholdAvgVal[1] = XRFdc_ReadReg16(InstancePtr, + BaseAddr, XRFDC_ADC_TRSHD1_AVG_LO_OFFSET); + ThresholdSettingsPtr->ThresholdAvgVal[1] |= (XRFdc_ReadReg16(InstancePtr, + BaseAddr, XRFDC_ADC_TRSHD1_AVG_UP_OFFSET) << + XRFDC_TRSHD1_AVG_UPP_SHIFT); + + /* Threshold Under Value */ + ThresholdSettingsPtr->ThresholdUnderVal[0] = XRFdc_RDReg(InstancePtr, + BaseAddr, XRFDC_ADC_TRSHD0_UNDER_OFFSET, XRFDC_TRSHD0_UNDER_MASK); + ThresholdSettingsPtr->ThresholdUnderVal[1] = XRFdc_RDReg(InstancePtr, + BaseAddr, XRFDC_ADC_TRSHD1_UNDER_OFFSET, XRFDC_TRSHD1_UNDER_MASK); + + /* Threshold Over Value */ + ThresholdSettingsPtr->ThresholdOverVal[0] = XRFdc_RDReg(InstancePtr, + BaseAddr, XRFDC_ADC_TRSHD0_OVER_OFFSET, XRFDC_TRSHD0_OVER_MASK); + ThresholdSettingsPtr->ThresholdOverVal[1] = XRFdc_RDReg(InstancePtr, + BaseAddr, XRFDC_ADC_TRSHD1_OVER_OFFSET, XRFDC_TRSHD1_OVER_MASK); + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* Decoder mode is updated into the relevant registers. Driver structure is +* updated with the new values. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is DAC block number inside the tile. Valid values +* are 0-3. +* @param DecoderMode Valid values are 1 (Maximum SNR, for non- +* randomized decoder), 2 (Maximum Linearity, for randomized decoder) +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note Only DAC blocks +* +******************************************************************************/ +u32 XRFdc_SetDecoderMode(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, + u32 DecoderMode) +{ + u32 Status; + u32 *DecoderModeConfigPtr; + u32 BaseAddr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_DAC_TILE, Tile_Id, + Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + DecoderModeConfigPtr = &InstancePtr->DAC_Tile[Tile_Id]. + DACBlock_Analog_Datapath[Block_Id].DecoderMode; + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_DAC_TILE, Tile_Id, Block_Id); + + if ((DecoderMode != XRFDC_DECODER_MAX_SNR_MODE) && + (DecoderMode != XRFDC_DECODER_MAX_LINEARITY_MODE)) { + metal_log(METAL_LOG_ERROR, "\n Invalid decoder mode " + "in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_DAC_DECODER_CTRL_OFFSET, + XRFDC_DEC_CTRL_MODE_MASK, DecoderMode); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_DAC_DECODER_CLK_OFFSET, + XRFDC_DEC_CTRL_MODE_MASK, DecoderMode); + *DecoderModeConfigPtr = DecoderMode; + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* Decoder mode is read and returned back. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is DAC block number inside the tile. Valid values +* are 0-3. +* @param DecoderModePtr Valid values are 1 (Maximum SNR, for non-randomized +* decoder), 2 (Maximum Linearity, for randomized decoder) +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note Only for DAC blocks +* +******************************************************************************/ +u32 XRFdc_GetDecoderMode(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, + u32 *DecoderModePtr) +{ + u32 Status; + u32 BaseAddr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(DecoderModePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_DAC_TILE, Tile_Id, + Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_DAC_TILE, Tile_Id, Block_Id); + *DecoderModePtr = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_DAC_DECODER_CTRL_OFFSET, XRFDC_DEC_CTRL_MODE_MASK); + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* Resets the NCO phase of the current block phase accumulator. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note None +* +******************************************************************************/ +u32 XRFdc_ResetNCOPhase(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 Block_Id) +{ + u32 Status; + u32 BaseAddr; + u32 Index; + u32 NoOfBlocks; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckDigitalPathEnabled(InstancePtr, Type, Tile_Id, + Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block digital path not " + "enabled in %s\r\n", __func__); + goto RETURN_PATH; + } + + Index = Block_Id; + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Type == XRFDC_ADC_TILE)) { + NoOfBlocks = XRFDC_NUM_OF_BLKS2; + if (Block_Id == XRFDC_BLK_ID1) { + Index = XRFDC_BLK_ID2; + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + } else { + NoOfBlocks = Block_Id + 1U; + } + + for (; Index < NoOfBlocks; Index++) { + BaseAddr = XRFDC_BLOCK_BASE(Type, Tile_Id, Index); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_NCO_RST_OFFSET, + XRFDC_NCO_PHASE_RST_MASK, XRFDC_NCO_PHASE_RST_MASK); + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; + +} +/*****************************************************************************/ +/** +* +* Enable and Disable the ADC/DAC FIFO. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param Enable valid values are 1 (FIFO enable) and 0 (FIFO Disable) +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Tile not enabled. +* +* @note Common API for ADC/DAC blocks +* +******************************************************************************/ +u32 XRFdc_SetupFIFO(XRFdc *InstancePtr, u32 Type, int Tile_Id, u8 Enable) +{ + u32 Status; + u32 BaseAddr; + u16 NoOfTiles; + u16 Index; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + if ((Enable != 0U) && (Enable != 1U)) { + metal_log(METAL_LOG_ERROR, "\n Invalid enable " + "value in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + /* An input tile if of -1 selects all tiles */ + if (Tile_Id == XRFDC_SELECT_ALL_TILES) { + NoOfTiles = XRFDC_NUM_OF_TILES4; + Index = XRFDC_TILE_ID0; + } else { + NoOfTiles = Tile_Id + 1; + Index = Tile_Id; + } + + for (; Index < NoOfTiles; Index++) { + BaseAddr = XRFDC_CTRL_STS_BASE(Type, Index); + + Status = XRFdc_CheckTileEnabled(InstancePtr, Type, Index); + if ((Status != XRFDC_SUCCESS) && (Tile_Id != XRFDC_SELECT_ALL_TILES)) { + metal_log(METAL_LOG_ERROR, "\n Requested tile%d not " + "available in %s\r\n", Index, __func__); + goto RETURN_PATH; + } else if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_DEBUG, "\n Tile%d not " + "available in %s\r\n", Index, __func__); + continue; + } else { + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_FIFO_ENABLE, + XRFDC_FIFO_EN_MASK, (!Enable)); + } + } + Status = XRFDC_SUCCESS; + +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* Current status of ADC/DAC FIFO. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param EnablePtr valid values are 1 (FIFO enable) and 0 (FIFO Disable) +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Tile not enabled. +* +* @note Common API for ADC/DAC blocks +* +******************************************************************************/ +u32 XRFdc_GetFIFOStatus(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u8 *EnablePtr) +{ + u32 Status; + u32 BaseAddr; + u32 ReadReg; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(EnablePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + 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); + + ReadReg = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_FIFO_ENABLE, XRFDC_FIFO_EN_MASK); + *EnablePtr = (!ReadReg); + + Status = XRFDC_SUCCESS; + +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* Get Output Current for DAC block. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param OutputCurrPtr pointer to return the output current. +* +* @return +* - Return Output Current for DAC block +* +******************************************************************************/ +u32 XRFdc_GetOutputCurr(XRFdc *InstancePtr, u32 Tile_Id, + u32 Block_Id, u32 *OutputCurrPtr) +{ + u32 Status; + u32 BaseAddr; + u16 ReadReg_Cfg2; + u16 ReadReg_Cfg3; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(OutputCurrPtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_DAC_TILE, Tile_Id, + Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_DAC_TILE, Tile_Id, Block_Id); + + ReadReg_Cfg2 = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_ADC_DAC_MC_CFG2_OFFSET, XRFDC_DAC_MC_CFG2_OPCSCAS_MASK); + ReadReg_Cfg3 = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_DAC_MC_CFG3_OFFSET, XRFDC_DAC_MC_CFG3_CSGAIN_MASK); + if ((ReadReg_Cfg2 == XRFDC_DAC_MC_CFG2_OPCSCAS_32MA) && + (ReadReg_Cfg3 == XRFDC_DAC_MC_CFG3_CSGAIN_32MA)) { + *OutputCurrPtr = XRFDC_OUTPUT_CURRENT_32MA; + } else if ((ReadReg_Cfg2 == XRFDC_DAC_MC_CFG2_OPCSCAS_20MA) && + (ReadReg_Cfg3 == XRFDC_DAC_MC_CFG3_CSGAIN_20MA)) { + *OutputCurrPtr = XRFDC_OUTPUT_CURRENT_20MA; + } else if ((ReadReg_Cfg2 == 0x0) && (ReadReg_Cfg3 == 0x0)) { + *OutputCurrPtr = 0x0; + } else { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, "\n Invalid output " + "current value %s\r\n", __func__); + goto RETURN_PATH; + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* Set the Nyquist zone. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param NyquistZone valid values are 1 (Odd),2 (Even). +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Tile not enabled. +* +* @note Common API for ADC/DAC blocks +* +******************************************************************************/ +u32 XRFdc_SetNyquistZone(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 Block_Id, u32 NyquistZone) +{ + u32 Status; + u16 ReadReg; + u32 BaseAddr; + u32 Index; + u32 NoOfBlocks; + u8 CalibrationMode = 0U; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, Type, Tile_Id, Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + if ((NyquistZone != XRFDC_ODD_NYQUIST_ZONE) && + (NyquistZone != XRFDC_EVEN_NYQUIST_ZONE)) { + metal_log(METAL_LOG_ERROR, "\n Invalid NyquistZone " + "value in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + Index = Block_Id; + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Type == XRFDC_ADC_TILE)) { + NoOfBlocks = XRFDC_NUM_OF_BLKS2; + if (Block_Id == XRFDC_BLK_ID1) { + Index = XRFDC_BLK_ID2; + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + } else { + NoOfBlocks = Block_Id + 1U; + } + + for (; Index < NoOfBlocks; Index++) { + BaseAddr = XRFDC_BLOCK_BASE(Type, Tile_Id, Index); + if (Type == XRFDC_ADC_TILE) { + /* Identify calibration mode */ + Status = XRFdc_GetCalibrationMode(InstancePtr, + Tile_Id, Block_Id, &CalibrationMode); + if (Status != XRFDC_SUCCESS) { + return XRFDC_FAILURE; + } + + if (CalibrationMode == XRFDC_CALIB_MODE1) { + if (NyquistZone == + XRFDC_ODD_NYQUIST_ZONE) { + NyquistZone = + XRFDC_EVEN_NYQUIST_ZONE; + } else { + NyquistZone = + XRFDC_ODD_NYQUIST_ZONE; + } + } + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_ADC_TI_TISK_CRL0_OFFSET); + if ((NyquistZone % 2U) == 0U) { + ReadReg |= XRFDC_TI_TISK_ZONE_MASK; + } else { + ReadReg &= ~XRFDC_TI_TISK_ZONE_MASK; + } + + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_TI_TISK_CRL0_OFFSET, ReadReg); + InstancePtr->ADC_Tile[Tile_Id]. + ADCBlock_Analog_Datapath[Index]. + NyquistZone = NyquistZone; + } else { + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_DAC_MC_CFG0_OFFSET); + if ((NyquistZone % 2U) == 0U) { + ReadReg |= XRFDC_MC_CFG0_MIX_MODE_MASK; + } else { + ReadReg &= ~XRFDC_MC_CFG0_MIX_MODE_MASK; + } + + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_DAC_MC_CFG0_OFFSET, ReadReg); + InstancePtr->DAC_Tile[Tile_Id]. + DACBlock_Analog_Datapath[Index]. + NyquistZone = NyquistZone; + } + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* Get the Nyquist zone. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param NyquistZonePtr Pointer to return the Nyquist zone. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Tile not enabled. +* +* @note Common API for ADC/DAC blocks +* +******************************************************************************/ +u32 XRFdc_GetNyquistZone(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 Block_Id, u32 *NyquistZonePtr) +{ + u32 Status; + u16 ReadReg; + u32 BaseAddr; + u32 Block; + u8 CalibrationMode = 0U; + u8 MultibandConfig; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(NyquistZonePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + if (Type == XRFDC_ADC_TILE) { + MultibandConfig = InstancePtr->ADC_Tile[Tile_Id].MultibandConfig; + } else { + MultibandConfig = InstancePtr->DAC_Tile[Tile_Id].MultibandConfig; + } + + if (MultibandConfig != XRFDC_MB_MODE_SB) { + Status = XRFdc_CheckDigitalPathEnabled(InstancePtr, Type, + Tile_Id, Block_Id); + } else { + Status = XRFdc_CheckBlockEnabled(InstancePtr, Type, + Tile_Id, Block_Id); + } + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + Block = Block_Id; + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Block_Id == XRFDC_BLK_ID1) && (Type == XRFDC_ADC_TILE)) { + Block_Id = XRFDC_BLK_ID2; + } + + BaseAddr = XRFDC_BLOCK_BASE(Type, Tile_Id, Block_Id); + + if (Type == XRFDC_ADC_TILE) { + /* Identify calibration mode */ + Status = XRFdc_GetCalibrationMode(InstancePtr, Tile_Id, + Block, &CalibrationMode); + if (Status != XRFDC_SUCCESS) { + return XRFDC_FAILURE; + } + ReadReg = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_ADC_TI_TISK_CRL0_OFFSET, XRFDC_TI_TISK_ZONE_MASK); + *NyquistZonePtr = (ReadReg >> XRFDC_TISK_ZONE_SHIFT); + } else { + ReadReg = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_DAC_MC_CFG0_OFFSET, XRFDC_MC_CFG0_MIX_MODE_MASK); + *NyquistZonePtr = (ReadReg >> XRFDC_MC_CFG0_MIX_MODE_SHIFT); + } + if (*NyquistZonePtr == 0U) { + *NyquistZonePtr = XRFDC_ODD_NYQUIST_ZONE; + } else { + *NyquistZonePtr = XRFDC_EVEN_NYQUIST_ZONE; + } + + if ((Type == XRFDC_ADC_TILE) && + (CalibrationMode == XRFDC_CALIB_MODE1)) { + if (*NyquistZonePtr == XRFDC_EVEN_NYQUIST_ZONE) { + *NyquistZonePtr = XRFDC_ODD_NYQUIST_ZONE; + } else { + *NyquistZonePtr = XRFDC_EVEN_NYQUIST_ZONE; + } + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* This API is to set the DAC Datapath mode. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param Mode valid values are 0-3. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Tile not enabled / out of range. +* +* @note Only for DAC blocks +* +******************************************************************************/ +u32 XRFdc_SetDataPathMode(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, + u32 Mode) +{ + u32 Status = XRFDC_SUCCESS; + u32 BaseAddr; + u32 NyquistZone; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_DAC_TILE, Tile_Id, Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + return Status; + } + + if (Mode > XRFDC_DAC_MODE_MAX) { + metal_log(METAL_LOG_ERROR, "\n Invalid Mode " + "value in %s\r\n", __func__); + Status = XRFDC_FAILURE; + return Status; + } + + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_DAC_TILE, Tile_Id, Block_Id); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_DAC_DATAPATH_OFFSET, + XRFDC_DATAPATH_MODE_MASK, Mode); + + NyquistZone = (Mode == XRFDC_DAC_MODE_7G_NQ2) ? + XRFDC_EVEN_NYQUIST_ZONE : XRFDC_ODD_NYQUIST_ZONE; + XRFdc_SetNyquistZone(InstancePtr, XRFDC_DAC_TILE, Tile_Id, Block_Id, NyquistZone); + return Status; +} + +/*****************************************************************************/ +/** +* +* This API is to get the DAC Datapath mode. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param ModePtr pointer used to return value. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Tile not enabled. +* +* @note Only for DAC blocks +* +******************************************************************************/ +u32 XRFdc_GetDataPathMode(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, + u32 *ModePtr) +{ + u32 Status = XRFDC_SUCCESS; + u32 BaseAddr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + Xil_AssertNonvoid(ModePtr != NULL); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_DAC_TILE, Tile_Id, Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + return Status; + } + + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_DAC_TILE, Tile_Id, Block_Id); + *ModePtr = XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_DAC_DATAPATH_OFFSET, + XRFDC_DATAPATH_MODE_MASK); + return Status; +} + +/*****************************************************************************/ +/** +* +* This API is to set the DAC Image Reject Filter Pass mode. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param Mode valid values are 0 (for low pass) 1 (for high pass). +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Tile not enabled / bad parameter passed +* +* @note Only for DAC blocks +* +******************************************************************************/ +u32 XRFdc_SetIMRPassMode(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, + u32 Mode) +{ + u32 Status = XRFDC_SUCCESS; + u32 BaseAddr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_DAC_TILE, Tile_Id, Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + return Status; + } + + if (Mode > XRFDC_DAC_IMR_MODE_MAX) { + metal_log(METAL_LOG_ERROR, "\n Invalid Mode " + "value in %s\r\n", __func__); + Status = XRFDC_FAILURE; + return Status; + } + + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_DAC_TILE, Tile_Id, Block_Id); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_DAC_DATAPATH_OFFSET, + XRFDC_DATAPATH_IMR_MASK, Mode << 2); + + return Status; +} + +/*****************************************************************************/ +/** +* +* This API is to get the DAC Image Reject Filter Pass mode. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param ModePtr pointer used to return value. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Tile not enabled. +* +* @note Only for DAC blocks +* +******************************************************************************/ +u32 XRFdc_GetIMRPassMode(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, + u32 *ModePtr) +{ + u32 Status = XRFDC_SUCCESS; + u32 BaseAddr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + Xil_AssertNonvoid(ModePtr != NULL); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_DAC_TILE, Tile_Id, Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + return Status; + } + + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_DAC_TILE, Tile_Id, Block_Id); + *ModePtr = (XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_DAC_DATAPATH_OFFSET, + XRFDC_DATAPATH_IMR_MASK)) >> 2; + return Status; +} +/*****************************************************************************/ +/** +* +* This API is to set the Calibration mode. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param CalibrationMode valid values are 1 and 2. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Tile not enabled. +* +* @note Only for ADC blocks +* +******************************************************************************/ +u32 XRFdc_SetCalibrationMode(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, + u8 CalibrationMode) +{ + u32 Status; + u16 ReadReg; + u32 BaseAddr; + u32 Index; + u32 NoOfBlocks; + XRFdc_Mixer_Settings Mixer_Settings = {0}; + u32 NyquistZone = 0U; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + if ((CalibrationMode != XRFDC_CALIB_MODE1) && + (CalibrationMode != XRFDC_CALIB_MODE2)) { + metal_log(METAL_LOG_ERROR, "\n Invalid Calibration mode " + "value in %s\r\n", __func__); + return XRFDC_FAILURE; + } + + Index = Block_Id; + if (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) { + NoOfBlocks = XRFDC_NUM_OF_BLKS2; + if (Block_Id == XRFDC_BLK_ID1) { + Index = XRFDC_BLK_ID2; + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + } else { + NoOfBlocks = Block_Id + 1U; + } + + /* Get Mixer Configurations */ + Status = XRFdc_GetMixerSettings(InstancePtr, XRFDC_ADC_TILE, + Tile_Id, Block_Id, &Mixer_Settings); + if (Status != XRFDC_SUCCESS) { + return XRFDC_FAILURE; + } + + /* Get Nyquist Zone */ + Status = XRFdc_GetNyquistZone(InstancePtr, XRFDC_ADC_TILE, + Tile_Id, Block_Id, &NyquistZone); + if (Status != XRFDC_SUCCESS) { + return XRFDC_FAILURE; + } + + for (; Index < NoOfBlocks; Index++) { + BaseAddr = XRFDC_ADC_TILE_DRP_ADDR(Tile_Id) + + XRFDC_BLOCK_ADDR_OFFSET(Index); + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_ADC_TI_DCB_CRL0_OFFSET); + ReadReg &= ~XRFDC_TI_DCB_MODE_MASK; + if (CalibrationMode == XRFDC_CALIB_MODE1) { + if (((Index % 2U) != 0U) && + (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1)) { + ReadReg |= XRFDC_TI_DCB_MODE1_4GSPS; + } else if (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 0) { + ReadReg |= XRFDC_TI_DCB_MODE1_2GSPS; + } + } + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_TI_DCB_CRL0_OFFSET, ReadReg); + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Analog_Datapath[Index]. + CalibrationMode = CalibrationMode; + } + + /* Set Nyquist Zone */ + Status = XRFdc_SetNyquistZone(InstancePtr, XRFDC_ADC_TILE, + Tile_Id, Block_Id, NyquistZone); + if (Status != XRFDC_SUCCESS) { + return XRFDC_FAILURE; + } + + /* Set Mixer Configurations */ + Status = XRFdc_SetMixerSettings(InstancePtr, XRFDC_ADC_TILE, + Tile_Id, Block_Id, &Mixer_Settings); + if (Status != XRFDC_SUCCESS) { + return XRFDC_FAILURE; + } + + Status = XRFDC_SUCCESS; + + return Status; +} + +/*****************************************************************************/ +/** +* +* This API is to get the Calibration mode. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param CalibrationModePtr pointer to get the calibration mode. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Tile not enabled. +* +* @note Only for ADC blocks +* +******************************************************************************/ +u32 XRFdc_GetCalibrationMode(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, + u8 *CalibrationModePtr) +{ + u32 Status; + u16 ReadReg; + u32 BaseAddr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(CalibrationModePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + if (InstancePtr->ADC_Tile[Tile_Id].MultibandConfig != XRFDC_MB_MODE_SB) { + Status = XRFdc_CheckDigitalPathEnabled(InstancePtr, XRFDC_ADC_TILE, + Tile_Id, Block_Id); + } else { + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_ADC_TILE, + Tile_Id, Block_Id); + } + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + if (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) { + if (Block_Id == XRFDC_BLK_ID1) { + Block_Id = XRFDC_BLK_ID3; + } + if (Block_Id == XRFDC_BLK_ID0) { + Block_Id = XRFDC_BLK_ID1; + } + } + + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_ADC_TILE, Tile_Id, Block_Id); + ReadReg = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_ADC_TI_DCB_CRL0_OFFSET, XRFDC_TI_DCB_MODE_MASK); + if (ReadReg != 0U) { + *CalibrationModePtr = XRFDC_CALIB_MODE1; + } else { + *CalibrationModePtr = XRFDC_CALIB_MODE2; + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* This API is used to set the mode for the Inverse-Sinc filter. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is DAC block number inside the tile. Valid values +* are 0-3. +* @param Mode valid values are 0(disable), 1(1st Nyquist zone) + and 2(2nd Nyquist zone). +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled/invalid mode. +* +* @note Only DAC blocks +* +******************************************************************************/ +u32 XRFdc_SetInvSincFIR(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, + u16 Mode) +{ + u32 Status; + u32 BaseAddr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + if (Mode > ((InstancePtr->RFdc_Config.IPType < 2)?XRFDC_INV_SYNC_EN_MAX:XRFDC_INV_SYNC_MODE_MAX)) { + metal_log(METAL_LOG_ERROR, "\n Invalid mode " + "value in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_DAC_TILE, Tile_Id, + Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_DAC_TILE, Tile_Id, Block_Id); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_DAC_INVSINC_OFFSET, + (InstancePtr->RFdc_Config.IPType < 2)?XRFDC_EN_INVSINC_MASK:XRFDC_MODE_INVSINC_MASK, Mode); + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* This API is used to get the Inverse-Sinc filter mode. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is DAC block number inside the tile. Valid values +* are 0-3. +* @param ModePtr is a pointer to get the inv-sinc status. valid values +* are 0(disable), 1(1st Nyquist zone) and 2(2nd Nyquist zone). +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note Only DAC blocks +* +******************************************************************************/ +u32 XRFdc_GetInvSincFIR(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, + u16 *ModePtr) +{ + u32 Status; + u32 BaseAddr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + Xil_AssertNonvoid(ModePtr != NULL); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_DAC_TILE, Tile_Id, + Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_DAC_TILE, Tile_Id, Block_Id); + *ModePtr = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_DAC_INVSINC_OFFSET, (InstancePtr->RFdc_Config.IPType < 2)?XRFDC_EN_INVSINC_MASK:XRFDC_MODE_INVSINC_MASK); + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* Static API to dump ADC registers. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3, and -1. +* +* @return +* None +* +* @note None +* +******************************************************************************/ +static void XRFdc_DumpADCRegs(XRFdc *InstancePtr, int Tile_Id) +{ + u32 BlockId; + u32 Block; + u32 IsBlockAvail; + u32 Offset; + u32 BaseAddr; + u32 ReadReg = 0U; + + for (BlockId = XRFDC_BLK_ID0; BlockId < XRFDC_BLK_ID4; BlockId++) { + Block = BlockId; + if (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) { + if (BlockId == XRFDC_BLK_ID1) { + Block = XRFDC_BLK_ID0; + } + if ((BlockId == XRFDC_BLK_ID3) || (BlockId == XRFDC_BLK_ID2)) { + Block = XRFDC_BLK_ID1; + } + } + IsBlockAvail = XRFdc_IsADCBlockEnabled(InstancePtr, Tile_Id, + Block); + if (IsBlockAvail == 0U) { + IsBlockAvail = XRFdc_IsADCDigitalPathEnabled(InstancePtr, Tile_Id, + Block); + if (IsBlockAvail == 0U) { + continue; + } + } + metal_log(METAL_LOG_DEBUG, "\n ADC%d%d:: \r\n", Tile_Id, BlockId); + BaseAddr = XRFDC_ADC_TILE_DRP_ADDR(Tile_Id) + + XRFDC_BLOCK_ADDR_OFFSET(BlockId); + for (Offset = 0x0U; Offset <= 0x284U; Offset += 0x4U) { + if ((Offset >= 0x24U && Offset <= 0x2CU) || + (Offset >= 0x48U && Offset <= 0x7CU) || + (Offset >= 0xACU && Offset <= 0xC4U) || + (Offset >= 0x114U && Offset <= 0x13CU) || + (Offset >= 0x188U && Offset <= 0x194U) || + (Offset >= 0x1B8U && Offset <= 0x1BCU) || + (Offset >= 0x1D8U && Offset <= 0x1FCU) || + (Offset >= 0x240U && Offset <= 0x27CU)) { + continue; + } + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, Offset); + metal_log(METAL_LOG_DEBUG, + "\n offset = 0x%x and Value = 0x%x \t", + Offset, ReadReg); + } + } + (void)ReadReg; +} + +/*****************************************************************************/ +/** +* +* Static API to dump DAC registers. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id Valid values are 0-3, and -1. +* +* @return +* None +* +* @note None +* +******************************************************************************/ +static void XRFdc_DumpDACRegs(XRFdc *InstancePtr, int Tile_Id) +{ + u32 BlockId; + u32 IsBlockAvail; + u32 Offset; + u32 BaseAddr; + u32 ReadReg = 0U; + + for (BlockId = XRFDC_BLK_ID0; BlockId < XRFDC_BLK_ID4; BlockId++) { + IsBlockAvail = XRFdc_IsDACBlockEnabled(InstancePtr, Tile_Id, + BlockId); + if (IsBlockAvail == 0U) { + IsBlockAvail = XRFdc_IsDACDigitalPathEnabled(InstancePtr, Tile_Id, + BlockId); + if (IsBlockAvail == 0U) { + continue; + } + } + metal_log(METAL_LOG_DEBUG, "\n DAC%d%d:: \r\n", Tile_Id, BlockId); + BaseAddr = XRFDC_DAC_TILE_DRP_ADDR(Tile_Id) + + XRFDC_BLOCK_ADDR_OFFSET(BlockId); + for (Offset = 0x0U; Offset <= 0x24CU; Offset += 0x4U) { + if ((Offset >= 0x28U && Offset <= 0x34U) || + (Offset >= 0x48U && Offset <= 0x7CU) || + (Offset >= 0xA8U && Offset <= 0xBCU) || + (Offset >= 0xE4U && Offset <= 0xFCU) || + (Offset >= 0x16CU && Offset <= 0x17CU) || + (Offset >= 0x198U && Offset <= 0x1BCU) || + (Offset >= 0x1ECU && Offset <= 0x1FCU) || + (Offset >= 0x204U && Offset <= 0x23CU)) { + continue; + } + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, Offset); + metal_log(METAL_LOG_DEBUG, + "\n offset = 0x%x and Value = 0x%x \t", + Offset, ReadReg); + } + } + (void)ReadReg; +} + +/*****************************************************************************/ +/** +* +* Static API to dump HSCOM registers. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3, and -1. +* +* @return +* None +* +* @note None +* +******************************************************************************/ +static void XRFdc_DumpHSCOMRegs(XRFdc *InstancePtr, u32 Type, int Tile_Id) +{ + u32 Offset; + u32 BaseAddr; + u32 ReadReg = 0U; + + if (Type == XRFDC_ADC_TILE) { + metal_log(METAL_LOG_DEBUG, "\n ADC%d HSCOM:: \r\n", Tile_Id); + BaseAddr = XRFDC_ADC_TILE_DRP_ADDR(Tile_Id) + XRFDC_HSCOM_ADDR; + + } else { + metal_log(METAL_LOG_DEBUG, "\n DAC%d HSCOM:: \r\n", Tile_Id); + BaseAddr = XRFDC_DAC_TILE_DRP_ADDR(Tile_Id) + XRFDC_HSCOM_ADDR; + } + metal_log(METAL_LOG_DEBUG, "\n Offset\tValue \r\n"); + for (Offset = 0x0U; Offset <= 0x148U; Offset += 0x4U) { + if ((Offset >= 0x60U && Offset <= 0x88U) || + (Offset == 0xBCU) || + (Offset >= 0xC4U && Offset <= 0xFCU) || + (Offset >= 0x110U && Offset <= 0x11CU) || + (Offset >= 0x12CU && Offset <= 0x13CU)) { + continue; + } + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, Offset); + metal_log(METAL_LOG_DEBUG, "\n 0x%x \t 0x%x \t", + Offset, ReadReg); + } + (void)ReadReg; +} + +/*****************************************************************************/ +/** +* +* This Prints the offset of the register along with the content. This API is +* meant to be used for debug purposes. It prints to the console the contents +* of registers for the passed Tile_Id. If -1 is passed, it prints the contents +* of the registers for all the tiles for the respective ADC or DAC +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3, and -1. +* +* @return +* None +* +* @note None +* +******************************************************************************/ +void XRFdc_DumpRegs(XRFdc *InstancePtr, u32 Type, int Tile_Id) +{ + u16 NoOfTiles; + u16 Index; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + if (Tile_Id == XRFDC_SELECT_ALL_TILES) { + NoOfTiles = XRFDC_NUM_OF_TILES4; + } else { + NoOfTiles = XRFDC_NUM_OF_TILES1; + } + for (Index = XRFDC_TILE_ID0; Index < NoOfTiles; Index++) { + if (NoOfTiles == XRFDC_NUM_OF_TILES4) { + Tile_Id = Index; + } + if (Type == XRFDC_ADC_TILE) { + XRFdc_DumpADCRegs(InstancePtr, Tile_Id); + } else { + XRFdc_DumpDACRegs(InstancePtr, Tile_Id); + } + XRFdc_DumpHSCOMRegs(InstancePtr, Type, Tile_Id); + } +} + +/*****************************************************************************/ +/** +* +* This is a stub for the status callback. The stub is here in case the upper +* layers forget to set the handler. +* +* @param CallBackRefPtr is a pointer to the upper layer callback reference. +* @param Type indicates ADC/DAC. +* @param Tile_Id indicates Tile number (0-3). +* @param Block_Id indicates Block number (0-3). +* @param StatusEvent indicates one or more interrupt occurred. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void StubHandler(void *CallBackRefPtr, u32 Type, u32 Tile_Id, + u32 Block_Id, u32 StatusEvent) +{ + (void) ((void *)CallBackRefPtr); + (void) Type; + (void) Tile_Id; + (void) Block_Id; + (void) StatusEvent; + + Xil_AssertVoidAlways(); + +} +/*****************************************************************************/ +/** +* +* This function is used to get the Link Coupling mode. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id indicates Tile number (0-3). +* @param Block_Id indicates Block number(0-3 for 2G, 0-1 for 4G). +* @param ModePtr pointer to get link coupling mode. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Tile not enabled. +* +* @note Only for ADC blocks +* +******************************************************************************/ +u32 XRFdc_GetLinkCoupling(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, + u32 *ModePtr) +{ + u32 Status; + u16 ReadReg; + u32 BaseAddr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(ModePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_ADC_TILE, Tile_Id, + Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Block_Id == XRFDC_BLK_ID1)) { + Block_Id = XRFDC_BLK_ID2; + } + + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_ADC_TILE, Tile_Id, Block_Id); + + ReadReg = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_ADC_RXPR_MC_CFG0_OFFSET, XRFDC_RX_MC_CFG0_CM_MASK); + if (ReadReg != 0U) { + *ModePtr = XRFDC_LINK_COUPLING_AC; + } else { + *ModePtr = XRFDC_LINK_COUPLING_DC; + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* This function is used to set the IM3 Dither mode. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id indicates Tile number (0-3). +* @param Block_Id indicates Block number(0-3 for LS, 0-1 for HS). +* @param Mode 0: Disable +* 1: Enable +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Tile not enabled. +* +* @note Only for ADC blocks +* +******************************************************************************/ +u32 XRFdc_SetDither(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, + u32 Mode) +{ + u32 Status; + u32 BaseAddr; + u32 Index; + u32 NoOfBlocks; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_ADC_TILE, Tile_Id, + Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + if (Mode > XRFDC_DITH_ENABLE) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, "\n Invalid Dither Mode " + "in %s\r\n", __func__); + goto RETURN_PATH; + } + Index = Block_Id; + if (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) { + NoOfBlocks = XRFDC_NUM_OF_BLKS2; + if (Block_Id == XRFDC_BLK_ID1) { + Index = XRFDC_BLK_ID2; + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + } else { + NoOfBlocks = Block_Id + 1U; + } + + for (; Index < NoOfBlocks; Index++) { + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_ADC_TILE, Tile_Id, Index); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, + XRFDC_ADC_DAC_MC_CFG0_OFFSET, XRFDC_RX_MC_CFG0_IM3_DITH_MASK, + (Mode << XRFDC_RX_MC_CFG0_IM3_DITH_SHIFT)); + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* This function is used to get the IM3 Dither mode. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id indicates Tile number (0-3). +* @param Block_Id indicates Block number(0-3 for LS, 0-1 for HS). +* @param ModePtr pointer to get link coupling mode. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Tile not enabled. +* +* @note Only for ADC blocks +* +******************************************************************************/ +u32 XRFdc_GetDither(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, + u32 *ModePtr) +{ + u32 Status; + u16 ReadReg; + u32 BaseAddr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(ModePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_ADC_TILE, Tile_Id, + Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Block_Id == XRFDC_BLK_ID1)) { + Block_Id = XRFDC_BLK_ID2; + } + + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_ADC_TILE, Tile_Id, Block_Id); + + ReadReg = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_ADC_DAC_MC_CFG0_OFFSET, XRFDC_RX_MC_CFG0_IM3_DITH_MASK); + if (ReadReg != 0U) { + *ModePtr = XRFDC_DITH_ENABLE; + } else { + *ModePtr = XRFDC_DITH_DISABLE; + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} +/*****************************************************************************/ +/** +* +* This function is used to set the ADC Signal Detector Settings. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id indicates Tile number (0-3). +* @param Block_Id indicates Block number(0-3 for LS, 0-1 for HS). +* @param SettingsPtr pointer to the XRFdc_Signal_Detector_Settings structure +* to set the signal detector configurations +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Tile not enabled, or invaid values. +* +* @note Only for ADC blocks +* +******************************************************************************/ +u32 XRFdc_SetSignalDetector(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, XRFdc_Signal_Detector_Settings *SettingsPtr) +{ + u32 Status; + u32 BaseAddr; + u32 Index; + u32 NoOfBlocks; + u16 SignalDetCtrlReg = 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; + } + + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_ADC_TILE, Tile_Id, Block_Id); + + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, + "\n Requested block not " + "available in %s\r\n", + __func__); + goto RETURN_PATH; + } + if (SettingsPtr->Mode > XRFDC_SIGDET_MODE_RNDM) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, + "\n Invalid Signal Detector " + "Mode in %s\r\n", + __func__); + goto RETURN_PATH; + } + if (SettingsPtr->EnableIntegrator > XRFDC_ENABLED) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, + "\n Invalid Signal Detector " + "Integrator Enable in %s\r\n", + __func__); + goto RETURN_PATH; + } + if (SettingsPtr->HysteresisEnable > XRFDC_ENABLED) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, + "\n Invalid Signal Detector " + "Hysteresis Enable in %s\r\n", + __func__); + goto RETURN_PATH; + } + if (SettingsPtr->Flush > XRFDC_ENABLED) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, + "\n Invalid Signal Detector " + "Flush Option in %s\r\n", + __func__); + goto RETURN_PATH; + } + if (SettingsPtr->TimeConstant > XRFDC_SIGDET_TC_2_18) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, + "\n Invalid Signal Detector " + "Time Constant in %s\r\n", + __func__); + goto RETURN_PATH; + } + SignalDetCtrlReg |= SettingsPtr->EnableIntegrator << XRFDC_ADC_SIG_DETECT_INTG_SHIFT; + SignalDetCtrlReg |= SettingsPtr->Flush << XRFDC_ADC_SIG_DETECT_FLUSH_SHIFT; + SignalDetCtrlReg |= SettingsPtr->TimeConstant << XRFDC_ADC_SIG_DETECT_TCONST_SHIFT; + if (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) { + SignalDetCtrlReg |= ((SettingsPtr->Mode << 1) | 1) << XRFDC_ADC_SIG_DETECT_MODE_WRITE_SHIFT; + } else { + SignalDetCtrlReg |= (SettingsPtr->Mode << 1) << XRFDC_ADC_SIG_DETECT_MODE_WRITE_SHIFT; + } + SignalDetCtrlReg |= SettingsPtr->HysteresisEnable << XRFDC_ADC_SIG_DETECT_HYST_SHIFT; + + Index = Block_Id; + if (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) { + NoOfBlocks = XRFDC_NUM_OF_BLKS2; + if (Block_Id == XRFDC_BLK_ID1) { + Index = XRFDC_BLK_ID2; + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + } else { + NoOfBlocks = Block_Id + 1U; + } + + for (; Index < NoOfBlocks; Index++) { + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_ADC_TILE, Tile_Id, Index); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_SIG_DETECT_CTRL_OFFSET, XRFDC_ADC_SIG_DETECT_MASK, + SignalDetCtrlReg); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_SIG_DETECT_THRESHOLD0_LEVEL_OFFSET, + XRFDC_ADC_SIG_DETECT_THRESH_MASK, SettingsPtr->HighThreshold); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_SIG_DETECT_THRESHOLD1_LEVEL_OFFSET, + XRFDC_ADC_SIG_DETECT_THRESH_MASK, SettingsPtr->LowThreshold); + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* This function is used to get the ADC Signal Detector Settings. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id indicates Tile number (0-3). +* @param Block_Id indicates Block number(0-3 for LS, 0-1 for HS). +* @param SettingsPtr pointer to the XRFdc_Signal_Detector_Settings structure +* to get the signal detector configurations +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Tile not enabled. +* +* @note Only for ADC blocks +* +******************************************************************************/ +u32 XRFdc_GetSignalDetector(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, XRFdc_Signal_Detector_Settings *SettingsPtr) +{ + u32 Status; + u32 BaseAddr; + u16 SignalDetCtrlReg = 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 functionality not " + "available for this IP in %s\r\n", + __func__); + goto RETURN_PATH; + } + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_ADC_TILE, Tile_Id, Block_Id); + + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, + "\n Requested block not " + "available in %s\r\n", + __func__); + goto RETURN_PATH; + } + + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && (Block_Id == XRFDC_BLK_ID1)) { + Block_Id = XRFDC_BLK_ID2; + } + + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_ADC_TILE, Tile_Id, Block_Id); + + SignalDetCtrlReg = + XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_ADC_SIG_DETECT_CTRL_OFFSET, XRFDC_ADC_SIG_DETECT_MASK); + SettingsPtr->EnableIntegrator = + (SignalDetCtrlReg & XRFDC_ADC_SIG_DETECT_INTG_MASK) >> XRFDC_ADC_SIG_DETECT_INTG_SHIFT; + SettingsPtr->Flush = (SignalDetCtrlReg & XRFDC_ADC_SIG_DETECT_FLUSH_MASK) >> XRFDC_ADC_SIG_DETECT_FLUSH_SHIFT; + SettingsPtr->TimeConstant = + (SignalDetCtrlReg & XRFDC_ADC_SIG_DETECT_TCONST_MASK) >> XRFDC_ADC_SIG_DETECT_TCONST_SHIFT; + SettingsPtr->Mode = (SignalDetCtrlReg & XRFDC_ADC_SIG_DETECT_MODE_MASK) >> XRFDC_ADC_SIG_DETECT_MODE_READ_SHIFT; + + SettingsPtr->HysteresisEnable = + (SignalDetCtrlReg & XRFDC_ADC_SIG_DETECT_HYST_MASK) >> XRFDC_ADC_SIG_DETECT_HYST_SHIFT; + SettingsPtr->HighThreshold = XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_ADC_SIG_DETECT_THRESHOLD0_LEVEL_OFFSET, + XRFDC_ADC_SIG_DETECT_THRESH_MASK); + SettingsPtr->LowThreshold = XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_ADC_SIG_DETECT_THRESHOLD1_LEVEL_OFFSET, + XRFDC_ADC_SIG_DETECT_THRESH_MASK); + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} +/*****************************************************************************/ +/** +* +* This function is used to disable Calibration Coefficients override. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id indicates Tile number (0-3). +* @param Block_Id indicates Block number(0-3 for LS, 0-1 for HS). +* @param CalibrationBlock indicates the calibration block. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if error occurs. +* +* @note Only for ADC blocks +* +******************************************************************************/ +u32 XRFdc_DisableCoefficientsOverride(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, u32 CalibrationBlock) +{ + u32 BaseAddr; + u32 Status; + u32 Index; + u32 NoOfBlocks; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_ADC_TILE, Tile_Id, Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, + "\n Requested block not " + "available in %s\r\n", + __func__); + goto RETURN_PATH; + } + + if ((InstancePtr->RFdc_Config.IPType < 2) && (CalibrationBlock == XRFDC_CAL_BLOCK_OCB1)) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, + "\n Requested functionality not " + "available for this IP in %s\r\n", + __func__); + goto RETURN_PATH; + } + + Index = Block_Id; + if (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) { + NoOfBlocks = XRFDC_NUM_OF_BLKS2; + if (Block_Id == XRFDC_BLK_ID1) { + Index = XRFDC_BLK_ID2; + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + } else { + NoOfBlocks = Block_Id + 1U; + } + + for (; Index < NoOfBlocks; Index++) { + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_ADC_TILE, Tile_Id, Index); + switch (CalibrationBlock) { + case XRFDC_CAL_BLOCK_OCB1: + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_TI_DCB_CRL1_OFFSET, XRFDC_CAL_OCB_EN_MASK, + XRFDC_DISABLED); + break; + case XRFDC_CAL_BLOCK_OCB2: + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_TI_DCB_CRL3_OFFSET, XRFDC_CAL_OCB_EN_MASK, + XRFDC_DISABLED); + break; + case XRFDC_CAL_BLOCK_GCB: + if (InstancePtr->RFdc_Config.IPType < 2) { + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_TI_DCB_CRL1_OFFSET, + XRFDC_CAL_GCB_ENFL_MASK, XRFDC_CAL_GCB_ACEN_MASK); + /*Clear IP Override Coeffs*/ + XRFdc_ClrSetReg(InstancePtr, XRFDC_ADC_TILE_CTRL_STATS_ADDR(Tile_Id), + XRFDC_CAL_GCB_COEFF0_FAB(Index), XRFDC_CAL_GCB_MASK, XRFDC_DISABLED); + XRFdc_ClrSetReg(InstancePtr, XRFDC_ADC_TILE_CTRL_STATS_ADDR(Tile_Id), + XRFDC_CAL_GCB_COEFF1_FAB(Index), XRFDC_CAL_GCB_MASK, XRFDC_DISABLED); + XRFdc_ClrSetReg(InstancePtr, XRFDC_ADC_TILE_CTRL_STATS_ADDR(Tile_Id), + XRFDC_CAL_GCB_COEFF2_FAB(Index), XRFDC_CAL_GCB_MASK, XRFDC_DISABLED); + XRFdc_ClrSetReg(InstancePtr, XRFDC_ADC_TILE_CTRL_STATS_ADDR(Tile_Id), + XRFDC_CAL_GCB_COEFF3_FAB(Index), XRFDC_CAL_GCB_MASK, XRFDC_DISABLED); + } else { + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_TI_DCB_CRL2_OFFSET, + XRFDC_CAL_GCB_EN_MASK, XRFDC_DISABLED); + } + break; + case XRFDC_CAL_BLOCK_TSCB: + if (InstancePtr->RFdc_Config.IPType < 2) { + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF0_ALT, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_DISABLED); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF1_ALT, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_DISABLED); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF2_ALT, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_DISABLED); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF3_ALT, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_DISABLED); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF4_ALT, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_DISABLED); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF5_ALT, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_DISABLED); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF6_ALT, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_DISABLED); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF7_ALT, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_DISABLED); + } else { + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF0, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_DISABLED); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF1, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_DISABLED); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF2, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_DISABLED); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF3, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_DISABLED); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF4, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_DISABLED); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF5, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_DISABLED); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF6, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_DISABLED); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF7, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_DISABLED); + } + break; + default: + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, + "\n Invalid Calibration " + "Mode in %s\r\n", + __func__); + goto RETURN_PATH; + } + } + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} +/*****************************************************************************/ +/** +* +* This function is used to set the ADC Calibration Coefficients. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id indicates Tile number (0-3). +* @param Block_Id indicates Block number(0-3 for LS, 0-1 for HS). +* @param CalibrationBlock indicates the block to be written to. +* @param CoeffPtr is pointer to the XRFdc_Calibration_Coefficients structure +* to set the calibration coefficients. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if error occurs. +* +* @note Only for ADC blocks +* +******************************************************************************/ +u32 XRFdc_SetCalCoefficients(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, u32 CalibrationBlock, + XRFdc_Calibration_Coefficients *CoeffPtr) +{ + u32 BaseAddr; + u32 Status; + u32 Index; + u32 NoOfBlocks; + u32 HighSpeed; + u32 Shift; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(CoeffPtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + if ((InstancePtr->RFdc_Config.IPType < 2) && (CalibrationBlock == XRFDC_CAL_BLOCK_OCB1)) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, + "\n Requested functionality not " + "available for this IP in %s\r\n", + __func__); + goto RETURN_PATH; + } + + if (CalibrationBlock == XRFDC_CAL_BLOCK_GCB) { + if ((CoeffPtr->Coeff0 | CoeffPtr->Coeff1 | CoeffPtr->Coeff2 | CoeffPtr->Coeff3) & + ~(XRFDC_CAL_GCB_MASK | (XRFDC_CAL_GCB_MASK << XRFDC_CAL_SLICE_SHIFT))) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, + "\n Bad Coefficient " + "available for this IP in %s\r\n", + __func__); + goto RETURN_PATH; + } + } + + if (CalibrationBlock == XRFDC_CAL_BLOCK_TSCB) { + if ((CoeffPtr->Coeff0 | CoeffPtr->Coeff1 | CoeffPtr->Coeff2 | CoeffPtr->Coeff3 | CoeffPtr->Coeff4 | + CoeffPtr->Coeff5 | CoeffPtr->Coeff6 | CoeffPtr->Coeff7) & + ~(XRFDC_CAL_TSCB_MASK | (XRFDC_CAL_TSCB_MASK << XRFDC_CAL_SLICE_SHIFT))) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, + "\n Bad Coefficient " + "available for this IP in %s\r\n", + __func__); + goto RETURN_PATH; + } + } + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_ADC_TILE, Tile_Id, Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, + "\n Requested block not " + "available in %s\r\n", + __func__); + goto RETURN_PATH; + } + + Index = Block_Id; + HighSpeed = XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id); + if (HighSpeed == XRFDC_ENABLED) { + NoOfBlocks = XRFDC_NUM_OF_BLKS2; + if (Block_Id == XRFDC_BLK_ID1) { + Index = XRFDC_BLK_ID2; + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + } else { + NoOfBlocks = Block_Id + 1U; + } + for (; Index < NoOfBlocks; Index++) { + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_ADC_TILE, Tile_Id, Index); + Shift = HighSpeed ? XRFDC_CAL_SLICE_SHIFT * (Index % 2) : 0; + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_ADC_TILE, Tile_Id, Index); + switch (CalibrationBlock) { + case XRFDC_CAL_BLOCK_OCB1: + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_TI_DCB_CRL1_OFFSET, XRFDC_CAL_OCB_EN_MASK, + XRFDC_ENABLED); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_OCB1_OFFSET_COEFF0, XRFDC_CAL_OCB_MASK, + CoeffPtr->Coeff0 >> Shift); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_OCB1_OFFSET_COEFF1, XRFDC_CAL_OCB_MASK, + CoeffPtr->Coeff1 >> Shift); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_OCB1_OFFSET_COEFF2, XRFDC_CAL_OCB_MASK, + CoeffPtr->Coeff2 >> Shift); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_OCB1_OFFSET_COEFF3, XRFDC_CAL_OCB_MASK, + CoeffPtr->Coeff3 >> Shift); + break; + case XRFDC_CAL_BLOCK_OCB2: + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_TI_DCB_CRL3_OFFSET, XRFDC_CAL_OCB_EN_MASK, + XRFDC_ENABLED); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_OCB2_OFFSET_COEFF0, XRFDC_CAL_OCB_MASK, + CoeffPtr->Coeff0 >> Shift); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_OCB2_OFFSET_COEFF1, XRFDC_CAL_OCB_MASK, + CoeffPtr->Coeff1 >> Shift); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_OCB2_OFFSET_COEFF2, XRFDC_CAL_OCB_MASK, + CoeffPtr->Coeff2 >> Shift); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_OCB2_OFFSET_COEFF3, XRFDC_CAL_OCB_MASK, + CoeffPtr->Coeff3 >> Shift); + break; + case XRFDC_CAL_BLOCK_GCB: + + if (InstancePtr->RFdc_Config.IPType < 2) { + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_TI_DCB_CRL1_OFFSET, + XRFDC_CAL_GCB_ACEN_MASK, XRFDC_DISABLED); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_TI_DCB_CRL1_OFFSET, + XRFDC_CAL_GCB_FLSH_MASK, XRFDC_ENABLED << XRFDC_CAL_GCB_FLSH_SHIFT); + XRFdc_ClrSetReg(InstancePtr, XRFDC_ADC_TILE_CTRL_STATS_ADDR(Tile_Id), + XRFDC_CAL_GCB_COEFF0_FAB(Index), XRFDC_CAL_GCB_MASK, + CoeffPtr->Coeff0 >> Shift); + XRFdc_ClrSetReg(InstancePtr, XRFDC_ADC_TILE_CTRL_STATS_ADDR(Tile_Id), + XRFDC_CAL_GCB_COEFF1_FAB(Index), XRFDC_CAL_GCB_MASK, + CoeffPtr->Coeff1 >> Shift); + XRFdc_ClrSetReg(InstancePtr, XRFDC_ADC_TILE_CTRL_STATS_ADDR(Tile_Id), + XRFDC_CAL_GCB_COEFF2_FAB(Index), XRFDC_CAL_GCB_MASK, + CoeffPtr->Coeff2 >> Shift); + XRFdc_ClrSetReg(InstancePtr, XRFDC_ADC_TILE_CTRL_STATS_ADDR(Tile_Id), + XRFDC_CAL_GCB_COEFF3_FAB(Index), XRFDC_CAL_GCB_MASK, + CoeffPtr->Coeff3 >> Shift); + } else { + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_TI_DCB_CRL2_OFFSET, + XRFDC_CAL_GCB_EN_MASK, XRFDC_ENABLED << XRFDC_CAL_GCB_EN_SHIFT); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_GCB_OFFSET_COEFF0, XRFDC_CAL_GCB_MASK, + CoeffPtr->Coeff0 >> Shift); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_GCB_OFFSET_COEFF1, XRFDC_CAL_GCB_MASK, + CoeffPtr->Coeff1 >> Shift); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_GCB_OFFSET_COEFF2, XRFDC_CAL_GCB_MASK, + CoeffPtr->Coeff2 >> Shift); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_GCB_OFFSET_COEFF3, XRFDC_CAL_GCB_MASK, + CoeffPtr->Coeff3 >> Shift); + } + break; + case XRFDC_CAL_BLOCK_TSCB: + if (InstancePtr->RFdc_Config.IPType < 2) { + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF0_ALT, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_ENABLED << XRFDC_CAL_TSCB_EN_SHIFT); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF1_ALT, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_ENABLED << XRFDC_CAL_TSCB_EN_SHIFT); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF2_ALT, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_ENABLED << XRFDC_CAL_TSCB_EN_SHIFT); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF3_ALT, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_ENABLED << XRFDC_CAL_TSCB_EN_SHIFT); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF4_ALT, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_ENABLED << XRFDC_CAL_TSCB_EN_SHIFT); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF5_ALT, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_ENABLED << XRFDC_CAL_TSCB_EN_SHIFT); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF6_ALT, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_ENABLED << XRFDC_CAL_TSCB_EN_SHIFT); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF7_ALT, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_ENABLED << XRFDC_CAL_TSCB_EN_SHIFT); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF0_ALT, + XRFDC_CAL_TSCB_MASK, CoeffPtr->Coeff0 >> Shift); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF1_ALT, + XRFDC_CAL_TSCB_MASK, CoeffPtr->Coeff1); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF2_ALT, + XRFDC_CAL_TSCB_MASK, CoeffPtr->Coeff2 >> Shift); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF3_ALT, + XRFDC_CAL_TSCB_MASK, CoeffPtr->Coeff3 >> Shift); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF4_ALT, + XRFDC_CAL_TSCB_MASK, CoeffPtr->Coeff4 >> Shift); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF5_ALT, + XRFDC_CAL_TSCB_MASK, CoeffPtr->Coeff5 >> Shift); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF6_ALT, + XRFDC_CAL_TSCB_MASK, CoeffPtr->Coeff6 >> Shift); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF7_ALT, + XRFDC_CAL_TSCB_MASK, CoeffPtr->Coeff7 >> Shift); + } else { + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF0, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_ENABLED << XRFDC_CAL_TSCB_EN_SHIFT); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF1, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_ENABLED << XRFDC_CAL_TSCB_EN_SHIFT); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF2, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_ENABLED << XRFDC_CAL_TSCB_EN_SHIFT); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF3, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_ENABLED << XRFDC_CAL_TSCB_EN_SHIFT); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF4, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_ENABLED << XRFDC_CAL_TSCB_EN_SHIFT); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF5, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_ENABLED << XRFDC_CAL_TSCB_EN_SHIFT); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF6, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_ENABLED << XRFDC_CAL_TSCB_EN_SHIFT); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF7, + XRFDC_CAL_TSCB_EN_MASK, XRFDC_ENABLED << XRFDC_CAL_TSCB_EN_SHIFT); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF0, + XRFDC_CAL_TSCB_MASK, CoeffPtr->Coeff0 >> Shift); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF1, + XRFDC_CAL_TSCB_MASK, CoeffPtr->Coeff1 >> Shift); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF2, + XRFDC_CAL_TSCB_MASK, CoeffPtr->Coeff2 >> Shift); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF3, + XRFDC_CAL_TSCB_MASK, CoeffPtr->Coeff3 >> Shift); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF4, + XRFDC_CAL_TSCB_MASK, CoeffPtr->Coeff4 >> Shift); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF5, + XRFDC_CAL_TSCB_MASK, CoeffPtr->Coeff5 >> Shift); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF6, + XRFDC_CAL_TSCB_MASK, CoeffPtr->Coeff6 >> Shift); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF7, + XRFDC_CAL_TSCB_MASK, CoeffPtr->Coeff7 >> Shift); + } + break; + default: + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, + "\n Invalid Calibration " + "Mode in %s\r\n", + __func__); + goto RETURN_PATH; + } + } + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} +/*****************************************************************************/ +/** +* +* This function is used to get the ADC Calibration Coefficients. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id indicates Tile number (0-3). +* @param Block_Id indicates Block number(0-3 for LS, 0-1 for HS). +* @param CalibrationBlock indicates the block to be read from +* @param CoeffPtr is pointer to the XRFdc_Calibration_Coefficients structure +* to get the calibration coefficients. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if error occurs. +* +* @note Only for ADC blocks +* +******************************************************************************/ +u32 XRFdc_GetCalCoefficients(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, u32 CalibrationBlock, + XRFdc_Calibration_Coefficients *CoeffPtr) +{ + u32 BaseAddr; + u32 Status; + u32 Index; + u32 HighSpeed; + u32 Shift; + u32 NoOfBlocks; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(CoeffPtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_ADC_TILE, Tile_Id, Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, + "\n Requested block not " + "available in %s\r\n", + __func__); + goto RETURN_PATH; + } + + memset(CoeffPtr, 0, sizeof(XRFdc_Calibration_Coefficients)); + Index = Block_Id; + HighSpeed = XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id); + if (HighSpeed == XRFDC_ENABLED) { + NoOfBlocks = XRFDC_NUM_OF_BLKS2; + if (Block_Id == XRFDC_BLK_ID1) { + Index = XRFDC_BLK_ID2; + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + } else { + NoOfBlocks = Block_Id + 1U; + } + for (; Index < NoOfBlocks; Index++) { + BaseAddr = XRFDC_BLOCK_BASE(XRFDC_ADC_TILE, Tile_Id, Index); + Shift = HighSpeed ? XRFDC_CAL_SLICE_SHIFT * (Index % 2) : 0; + switch (CalibrationBlock) { + case XRFDC_CAL_BLOCK_OCB1: + CoeffPtr->Coeff0 |= + XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_OCB1_OFFSET_COEFF0, XRFDC_CAL_OCB_MASK) + << Shift; + CoeffPtr->Coeff1 |= + XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_OCB1_OFFSET_COEFF1, XRFDC_CAL_OCB_MASK) + << Shift; + CoeffPtr->Coeff2 |= + XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_OCB1_OFFSET_COEFF2, XRFDC_CAL_OCB_MASK) + << Shift; + CoeffPtr->Coeff3 |= + XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_OCB1_OFFSET_COEFF3, XRFDC_CAL_OCB_MASK) + << Shift; + break; + case XRFDC_CAL_BLOCK_OCB2: + CoeffPtr->Coeff0 |= + XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_OCB2_OFFSET_COEFF0, XRFDC_CAL_OCB_MASK) + << Shift; + CoeffPtr->Coeff1 |= + XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_OCB2_OFFSET_COEFF1, XRFDC_CAL_OCB_MASK) + << Shift; + CoeffPtr->Coeff2 |= + XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_OCB2_OFFSET_COEFF2, XRFDC_CAL_OCB_MASK) + << Shift; + CoeffPtr->Coeff3 |= + XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_OCB2_OFFSET_COEFF3, XRFDC_CAL_OCB_MASK) + << Shift; + break; + case XRFDC_CAL_BLOCK_GCB: + if (InstancePtr->RFdc_Config.IPType < 2) { + if (XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_ADC_TI_DCB_CRL1_OFFSET, + XRFDC_CAL_GCB_FLSH_MASK) == XRFDC_DISABLED) { + CoeffPtr->Coeff0 |= + (XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_GCB_OFFSET_COEFF0_ALT, + XRFDC_CAL_GCB_FAB_MASK) >> + 4) + << Shift; + CoeffPtr->Coeff1 |= + (XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_GCB_OFFSET_COEFF1_ALT, + XRFDC_CAL_GCB_FAB_MASK) >> + 4) + << Shift; + CoeffPtr->Coeff2 |= + (XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_GCB_OFFSET_COEFF2_ALT, + XRFDC_CAL_GCB_FAB_MASK) >> + 4) + << Shift; + CoeffPtr->Coeff3 |= + (XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_GCB_OFFSET_COEFF3_ALT, + XRFDC_CAL_GCB_FAB_MASK) >> + 4) + << Shift; + } else { + CoeffPtr->Coeff0 |= + XRFdc_RDReg(InstancePtr, XRFDC_ADC_TILE_CTRL_STATS_ADDR(Tile_Id), + XRFDC_CAL_GCB_COEFF0_FAB(Block_Id), XRFDC_CAL_GCB_MASK) + << Shift; + CoeffPtr->Coeff1 |= + XRFdc_RDReg(InstancePtr, XRFDC_ADC_TILE_CTRL_STATS_ADDR(Tile_Id), + XRFDC_CAL_GCB_COEFF1_FAB(Block_Id), XRFDC_CAL_GCB_MASK) + << Shift; + CoeffPtr->Coeff2 |= + XRFdc_RDReg(InstancePtr, XRFDC_ADC_TILE_CTRL_STATS_ADDR(Tile_Id), + XRFDC_CAL_GCB_COEFF2_FAB(Block_Id), XRFDC_CAL_GCB_MASK) + << Shift; + CoeffPtr->Coeff3 |= + XRFdc_RDReg(InstancePtr, XRFDC_ADC_TILE_CTRL_STATS_ADDR(Tile_Id), + XRFDC_CAL_GCB_COEFF3_FAB(Block_Id), XRFDC_CAL_GCB_MASK) + << Shift; + } + } else { + CoeffPtr->Coeff0 |= XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_GCB_OFFSET_COEFF0, + XRFDC_CAL_GCB_MASK) + << Shift; + CoeffPtr->Coeff1 |= XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_GCB_OFFSET_COEFF1, + XRFDC_CAL_GCB_MASK) + << Shift; + CoeffPtr->Coeff2 |= XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_GCB_OFFSET_COEFF2, + XRFDC_CAL_GCB_MASK) + << Shift; + CoeffPtr->Coeff3 |= XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_GCB_OFFSET_COEFF3, + XRFDC_CAL_GCB_MASK) + << Shift; + } + break; + case XRFDC_CAL_BLOCK_TSCB: + if (InstancePtr->RFdc_Config.IPType < 2) { + CoeffPtr->Coeff0 |= XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF0_ALT, + XRFDC_CAL_TSCB_MASK) + << Shift; + CoeffPtr->Coeff1 |= XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF1_ALT, + XRFDC_CAL_TSCB_MASK) + << Shift; + CoeffPtr->Coeff2 |= XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF2_ALT, + XRFDC_CAL_TSCB_MASK) + << Shift; + CoeffPtr->Coeff3 |= XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF3_ALT, + XRFDC_CAL_TSCB_MASK) + << Shift; + CoeffPtr->Coeff4 |= XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF4_ALT, + XRFDC_CAL_TSCB_MASK) + << Shift; + CoeffPtr->Coeff5 |= XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF5_ALT, + XRFDC_CAL_TSCB_MASK) + << Shift; + CoeffPtr->Coeff6 |= XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF6_ALT, + XRFDC_CAL_TSCB_MASK) + << Shift; + CoeffPtr->Coeff7 |= XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF7_ALT, + XRFDC_CAL_TSCB_MASK) + << Shift; + } else { + CoeffPtr->Coeff0 |= XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF0, + XRFDC_CAL_TSCB_MASK) + << Shift; + CoeffPtr->Coeff1 |= XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF1, + XRFDC_CAL_TSCB_MASK) + << Shift; + CoeffPtr->Coeff2 |= XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF2, + XRFDC_CAL_TSCB_MASK) + << Shift; + CoeffPtr->Coeff3 |= XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF3, + XRFDC_CAL_TSCB_MASK) + << Shift; + CoeffPtr->Coeff4 |= XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF4, + XRFDC_CAL_TSCB_MASK) + << Shift; + CoeffPtr->Coeff5 |= XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF5, + XRFDC_CAL_TSCB_MASK) + << Shift; + CoeffPtr->Coeff6 |= XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF6, + XRFDC_CAL_TSCB_MASK) + << Shift; + CoeffPtr->Coeff7 |= XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CAL_TSCB_OFFSET_COEFF7, + XRFDC_CAL_TSCB_MASK) + << Shift; + } + break; + default: + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, + "\n Invalid Calibration " + "Mode in %s\r\n", + __func__); + goto RETURN_PATH; + } + } + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} +/*****************************************************************************/ +/** +* +* This function is used to set calibration freeze settings. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id indicates Tile number (0-3). +* @param Block_Id indicates Block number(0-3 for LS, 0-1 for HS). +* @param CalFreezePtr pointer to the settings to be applied. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if error occurs. +* +* @note Only for ADC blocks +* +******************************************************************************/ +u32 XRFdc_SetCalFreeze(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, XRFdc_Cal_Freeze_Settings *CalFreezePtr) +{ + u32 BaseAddr; + u32 Status; + u32 Index; + u32 NoOfBlocks; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(CalFreezePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + if (CalFreezePtr->FreezeCalibration > XRFDC_CAL_FREEZE_CALIB) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, + "\n Invalid FreezeCalibration " + "option in %s\r\n", + __func__); + goto RETURN_PATH; + } + + if (CalFreezePtr->DisableFreezePin > XRFDC_CAL_FRZ_PIN_DISABLE) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, + "\n Invalid DisableFreezePin " + "option in %s\r\n", + __func__); + goto RETURN_PATH; + } + + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_ADC_TILE, Tile_Id, Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, + "\n Requested block not " + "available in %s\r\n", + __func__); + goto RETURN_PATH; + } + + BaseAddr = XRFDC_ADC_TILE_CTRL_STATS_ADDR(Tile_Id); + + Index = Block_Id; + if (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) { + NoOfBlocks = XRFDC_NUM_OF_BLKS2; + if (Block_Id == XRFDC_BLK_ID1) { + Index = XRFDC_BLK_ID2; + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + } else { + NoOfBlocks = Block_Id + 1U; + } + + for (; Index < NoOfBlocks; Index++) { + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CONV_CAL_STGS(Index), XRFDC_CAL_FREEZE_PIN_MASK, + CalFreezePtr->DisableFreezePin << XRFDC_CAL_FREEZE_PIN_SHIFT); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_CONV_CAL_STGS(Index), XRFDC_CAL_FREEZE_CAL_MASK, + CalFreezePtr->FreezeCalibration << XRFDC_CAL_FREEZE_CAL_SHIFT); + } + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} +/*****************************************************************************/ +/** +* +* This function is used to get calibration freeze settings and status. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Tile_Id indicates Tile number (0-3). +* @param Block_Id indicates Block number(0-3 for LS, 0-1 for HS). +* @param CalFreezePtr pointer to be filled the settings/status. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if error occurs. +* +* @note Only for ADC blocks +* +******************************************************************************/ +u32 XRFdc_GetCalFreeze(XRFdc *InstancePtr, u32 Tile_Id, u32 Block_Id, XRFdc_Cal_Freeze_Settings *CalFreezePtr) +{ + u32 BaseAddr; + u32 Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(CalFreezePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, XRFDC_ADC_TILE, Tile_Id, Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, + "\n Requested block not " + "available in %s\r\n", + __func__); + goto RETURN_PATH; + } + + BaseAddr = XRFDC_ADC_TILE_CTRL_STATS_ADDR(Tile_Id); + + if (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) { + if (Block_Id == XRFDC_BLK_ID1) { + Block_Id = XRFDC_BLK_ID2; + } + } + CalFreezePtr->CalFrozen = + XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CONV_CAL_STGS(Block_Id), XRFDC_CAL_FREEZE_STS_MASK) >> + XRFDC_CAL_FREEZE_STS_SHIFT; + CalFreezePtr->DisableFreezePin = + XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CONV_CAL_STGS(Block_Id), XRFDC_CAL_FREEZE_PIN_MASK) >> + XRFDC_CAL_FREEZE_PIN_SHIFT; + CalFreezePtr->FreezeCalibration = + XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_CONV_CAL_STGS(Block_Id), XRFDC_CAL_FREEZE_CAL_MASK) >> + XRFDC_CAL_FREEZE_CAL_SHIFT; + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} +/** @} */ 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; +} +/** @} */ diff --git a/mpm/lib/rfdc/xrfdc_g.c b/mpm/lib/rfdc/xrfdc_g.c new file mode 100644 index 000000000..857fb1ffd --- /dev/null +++ b/mpm/lib/rfdc/xrfdc_g.c @@ -0,0 +1,619 @@ +/******************************************************************* +* Copyright (C) 2017-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_g.c +* @addtogroup rfdc_v6_0 +* @{ +* +* This file contains a configuration table that specifies the configuration of +* RFdc devices in the system. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- -------- ----------------------------------------------- +* 1.0 sk 05/16/17 Initial release +* 5.1 cog 01/29/19 Added FSMax, NumSlice & IP_Type. +* +* </pre> +* +******************************************************************************/ +#ifdef __BAREMETAL__ +/***************************** Include Files ********************************/ +#include "xparameters.h" +#include "mpm/rfdc/xrfdc.h" +/************************** Constant Definitions ****************************/ + +/**************************** Type Definitions ******************************/ + +/***************** Macros (Inline Functions) Definitions ********************/ + +/************************** Variable Definitions ****************************/ +/** + * The configuration table for devices + */ + +XRFdc_Config XRFdc_ConfigTable[XPAR_XRFDC_NUM_INSTANCES] = +{ + { + XPAR_USP_RF_DATA_CONVERTER_0_DEVICE_ID, + XPAR_USP_RF_DATA_CONVERTER_0_BASEADDR, + XPAR_USP_RF_DATA_CONVERTER_0_HIGH_SPEED_ADC, + XPAR_USP_RF_DATA_CONVERTER_0_SYSREF_MASTER, + XPAR_USP_RF_DATA_CONVERTER_0_SYSREF_MASTER, + XPAR_USP_RF_DATA_CONVERTER_0_SYSREF_SOURCE, + XPAR_USP_RF_DATA_CONVERTER_0_SYSREF_SOURCE, + XPAR_USP_RF_DATA_CONVERTER_0_IP_TYPE, + { + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC0_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC0_PLL_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC0_SAMPLING_RATE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC0_REFCLK_FREQ, + XPAR_USP_RF_DATA_CONVERTER_0_DAC0_FABRIC_FREQ, + XPAR_USP_RF_DATA_CONVERTER_0_DAC0_FBDIV, + XPAR_USP_RF_DATA_CONVERTER_0_DAC0_OUTDIV, + XPAR_USP_RF_DATA_CONVERTER_0_DAC0_REFCLK_DIV, + XPAR_USP_RF_DATA_CONVERTER_0_DAC0_BAND, + XPAR_USP_RF_DATA_CONVERTER_0_DAC0_FS_MAX, + XPAR_USP_RF_DATA_CONVERTER_0_DAC0_SLICES, + { + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_SLICE00_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INVSINC_CTRL00, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_MODE00, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DECODER_MODE00, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_SLICE01_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INVSINC_CTRL01, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_MODE01, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DECODER_MODE01, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_SLICE02_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INVSINC_CTRL02, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_MODE02, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DECODER_MODE02, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_SLICE03_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INVSINC_CTRL03, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_MODE03, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DECODER_MODE03, + }, + }, + { + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_TYPE00, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_WIDTH00, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INTERPOLATION_MODE00, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_FIFO00_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_ADDER00_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_TYPE00, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_TYPE01, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_WIDTH01, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INTERPOLATION_MODE01, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_FIFO01_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_ADDER01_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_TYPE01, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_TYPE02, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_WIDTH02, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INTERPOLATION_MODE02, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_FIFO02_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_ADDER02_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_TYPE02, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_TYPE03, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_WIDTH03, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INTERPOLATION_MODE03, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_FIFO03_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_ADDER03_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_TYPE03, + }, + }, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC1_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC1_PLL_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC1_SAMPLING_RATE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC1_REFCLK_FREQ, + XPAR_USP_RF_DATA_CONVERTER_0_DAC1_FABRIC_FREQ, + XPAR_USP_RF_DATA_CONVERTER_0_DAC1_FBDIV, + XPAR_USP_RF_DATA_CONVERTER_0_DAC1_OUTDIV, + XPAR_USP_RF_DATA_CONVERTER_0_DAC1_REFCLK_DIV, + XPAR_USP_RF_DATA_CONVERTER_0_DAC1_BAND, + XPAR_USP_RF_DATA_CONVERTER_0_DAC1_FS_MAX, + XPAR_USP_RF_DATA_CONVERTER_0_DAC1_SLICES, + { + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_SLICE10_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INVSINC_CTRL10, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_MODE10, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DECODER_MODE10, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_SLICE11_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INVSINC_CTRL11, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_MODE11, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DECODER_MODE11, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_SLICE12_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INVSINC_CTRL12, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_MODE12, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DECODER_MODE12, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_SLICE13_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INVSINC_CTRL13, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_MODE13, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DECODER_MODE13, + }, + }, + { + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_TYPE10, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_WIDTH10, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INTERPOLATION_MODE10, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_FIFO10_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_ADDER10_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_TYPE10, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_TYPE11, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_WIDTH11, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INTERPOLATION_MODE11, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_FIFO11_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_ADDER11_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_TYPE11, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_TYPE12, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_WIDTH12, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INTERPOLATION_MODE12, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_FIFO12_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_ADDER12_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_TYPE12, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_TYPE13, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_WIDTH13, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INTERPOLATION_MODE13, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_FIFO13_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_ADDER13_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_TYPE13, + }, + }, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC2_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC2_PLL_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC2_SAMPLING_RATE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC2_REFCLK_FREQ, + XPAR_USP_RF_DATA_CONVERTER_0_DAC2_FABRIC_FREQ, + XPAR_USP_RF_DATA_CONVERTER_0_DAC2_FBDIV, + XPAR_USP_RF_DATA_CONVERTER_0_DAC2_OUTDIV, + XPAR_USP_RF_DATA_CONVERTER_0_DAC2_REFCLK_DIV, + XPAR_USP_RF_DATA_CONVERTER_0_DAC2_BAND, + XPAR_USP_RF_DATA_CONVERTER_0_DAC2_FS_MAX, + XPAR_USP_RF_DATA_CONVERTER_0_DAC2_SLICES, + { + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_SLICE20_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INVSINC_CTRL20, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_MODE20, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DECODER_MODE20, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_SLICE21_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INVSINC_CTRL21, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_MODE21, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DECODER_MODE21, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_SLICE22_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INVSINC_CTRL22, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_MODE22, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DECODER_MODE22, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_SLICE23_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INVSINC_CTRL23, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_MODE23, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DECODER_MODE23, + }, + }, + { + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_TYPE20, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_WIDTH20, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INTERPOLATION_MODE20, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_FIFO20_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_ADDER20_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_TYPE20, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_TYPE21, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_WIDTH21, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INTERPOLATION_MODE21, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_FIFO21_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_ADDER21_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_TYPE21, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_TYPE22, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_WIDTH22, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INTERPOLATION_MODE22, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_FIFO22_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_ADDER22_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_TYPE22, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_TYPE23, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_WIDTH23, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INTERPOLATION_MODE23, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_FIFO23_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_ADDER23_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_TYPE23, + }, + }, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC3_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC3_PLL_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC3_SAMPLING_RATE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC3_REFCLK_FREQ, + XPAR_USP_RF_DATA_CONVERTER_0_DAC3_FABRIC_FREQ, + XPAR_USP_RF_DATA_CONVERTER_0_DAC3_FBDIV, + XPAR_USP_RF_DATA_CONVERTER_0_DAC3_OUTDIV, + XPAR_USP_RF_DATA_CONVERTER_0_DAC3_REFCLK_DIV, + XPAR_USP_RF_DATA_CONVERTER_0_DAC3_BAND, + XPAR_USP_RF_DATA_CONVERTER_0_DAC3_FS_MAX, + XPAR_USP_RF_DATA_CONVERTER_0_DAC3_SLICES, + { + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_SLICE30_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INVSINC_CTRL30, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_MODE30, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DECODER_MODE30, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_SLICE31_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INVSINC_CTRL31, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_MODE31, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DECODER_MODE31, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_SLICE32_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INVSINC_CTRL32, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_MODE32, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DECODER_MODE32, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_SLICE33_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INVSINC_CTRL33, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_MODE33, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DECODER_MODE33, + }, + }, + { + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_TYPE30, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_WIDTH30, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INTERPOLATION_MODE30, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_FIFO30_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_ADDER30_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_TYPE30, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_TYPE31, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_WIDTH31, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INTERPOLATION_MODE31, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_FIFO31_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_ADDER31_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_TYPE31, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_TYPE32, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_WIDTH32, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INTERPOLATION_MODE32, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_FIFO32_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_ADDER32_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_TYPE32, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_TYPE33, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_DATA_WIDTH33, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_INTERPOLATION_MODE33, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_FIFO33_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_ADDER33_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_DAC_MIXER_TYPE33, + }, + }, + }, + }, + { + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC0_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC0_PLL_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC0_SAMPLING_RATE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC0_REFCLK_FREQ, + XPAR_USP_RF_DATA_CONVERTER_0_ADC0_FABRIC_FREQ, + XPAR_USP_RF_DATA_CONVERTER_0_ADC0_FBDIV, + XPAR_USP_RF_DATA_CONVERTER_0_ADC0_OUTDIV, + XPAR_USP_RF_DATA_CONVERTER_0_ADC0_REFCLK_DIV, + XPAR_USP_RF_DATA_CONVERTER_0_ADC0_BAND, + XPAR_USP_RF_DATA_CONVERTER_0_ADC0_FS_MAX, + XPAR_USP_RF_DATA_CONVERTER_0_ADC0_SLICES, + { + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_SLICE00_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_MODE00, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_SLICE01_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_MODE01, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_SLICE02_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_MODE02, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_SLICE03_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_MODE03, + }, + }, + { + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_TYPE00, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_WIDTH00, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DECIMATION_MODE00, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_FIFO00_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_TYPE00, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_TYPE01, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_WIDTH01, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DECIMATION_MODE01, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_FIFO01_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_TYPE01, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_TYPE02, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_WIDTH02, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DECIMATION_MODE02, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_FIFO02_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_TYPE02, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_TYPE03, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_WIDTH03, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DECIMATION_MODE03, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_FIFO03_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_TYPE03, + }, + }, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC1_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC1_PLL_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC1_SAMPLING_RATE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC1_REFCLK_FREQ, + XPAR_USP_RF_DATA_CONVERTER_0_ADC1_FABRIC_FREQ, + XPAR_USP_RF_DATA_CONVERTER_0_ADC1_FBDIV, + XPAR_USP_RF_DATA_CONVERTER_0_ADC1_OUTDIV, + XPAR_USP_RF_DATA_CONVERTER_0_ADC1_REFCLK_DIV, + XPAR_USP_RF_DATA_CONVERTER_0_ADC1_BAND, + XPAR_USP_RF_DATA_CONVERTER_0_ADC1_FS_MAX, + XPAR_USP_RF_DATA_CONVERTER_0_ADC1_SLICES, + { + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_SLICE10_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_MODE10, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_SLICE11_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_MODE11, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_SLICE12_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_MODE12, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_SLICE13_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_MODE13, + }, + }, + { + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_TYPE10, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_WIDTH10, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DECIMATION_MODE10, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_FIFO10_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_TYPE10, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_TYPE11, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_WIDTH11, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DECIMATION_MODE11, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_FIFO11_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_TYPE11, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_TYPE12, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_WIDTH12, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DECIMATION_MODE12, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_FIFO12_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_TYPE12, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_TYPE13, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_WIDTH13, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DECIMATION_MODE13, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_FIFO13_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_TYPE13, + }, + }, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC2_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC2_PLL_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC2_SAMPLING_RATE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC2_REFCLK_FREQ, + XPAR_USP_RF_DATA_CONVERTER_0_ADC2_FABRIC_FREQ, + XPAR_USP_RF_DATA_CONVERTER_0_ADC2_FBDIV, + XPAR_USP_RF_DATA_CONVERTER_0_ADC2_OUTDIV, + XPAR_USP_RF_DATA_CONVERTER_0_ADC2_REFCLK_DIV, + XPAR_USP_RF_DATA_CONVERTER_0_ADC2_BAND, + XPAR_USP_RF_DATA_CONVERTER_0_ADC2_FS_MAX, + XPAR_USP_RF_DATA_CONVERTER_0_ADC2_SLICES, + { + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_SLICE20_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_MODE20, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_SLICE21_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_MODE21, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_SLICE22_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_MODE22, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_SLICE23_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_MODE23, + }, + }, + { + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_TYPE20, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_WIDTH20, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DECIMATION_MODE20, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_FIFO20_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_TYPE20, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_TYPE21, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_WIDTH21, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DECIMATION_MODE21, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_FIFO21_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_TYPE21, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_TYPE22, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_WIDTH22, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DECIMATION_MODE22, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_FIFO22_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_TYPE22, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_TYPE23, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_WIDTH23, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DECIMATION_MODE23, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_FIFO23_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_TYPE23, + }, + }, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC3_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC3_PLL_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC3_SAMPLING_RATE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC3_REFCLK_FREQ, + XPAR_USP_RF_DATA_CONVERTER_0_ADC3_FABRIC_FREQ, + XPAR_USP_RF_DATA_CONVERTER_0_ADC3_FBDIV, + XPAR_USP_RF_DATA_CONVERTER_0_ADC3_OUTDIV, + XPAR_USP_RF_DATA_CONVERTER_0_ADC3_REFCLK_DIV, + XPAR_USP_RF_DATA_CONVERTER_0_ADC3_BAND, + XPAR_USP_RF_DATA_CONVERTER_0_ADC3_FS_MAX, + XPAR_USP_RF_DATA_CONVERTER_0_ADC3_SLICES, + { + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_SLICE30_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_MODE30, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_SLICE31_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_MODE31, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_SLICE32_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_MODE32, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_SLICE33_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_MODE33, + }, + }, + { + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_TYPE30, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_WIDTH30, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DECIMATION_MODE30, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_FIFO30_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_TYPE30, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_TYPE31, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_WIDTH31, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DECIMATION_MODE31, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_FIFO31_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_TYPE31, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_TYPE32, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_WIDTH32, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DECIMATION_MODE32, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_FIFO32_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_TYPE32, + }, + { + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_TYPE33, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DATA_WIDTH33, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_DECIMATION_MODE33, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_FIFO33_ENABLE, + XPAR_USP_RF_DATA_CONVERTER_0_ADC_MIXER_TYPE33, + }, + }, + }, + } + } +}; +#endif +/** @} */ diff --git a/mpm/lib/rfdc/xrfdc_intr.c b/mpm/lib/rfdc/xrfdc_intr.c new file mode 100644 index 000000000..7b8bd0927 --- /dev/null +++ b/mpm/lib/rfdc/xrfdc_intr.c @@ -0,0 +1,771 @@ +/****************************************************************************** +* +* Copyright (C) 2017-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_intr.c +* @addtogroup rfdc_v6_0 +* @{ +* +* This file contains functions related to RFdc interrupt handling. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ----- -------- ----------------------------------------------- +* 1.0 sk 05/16/17 First release +* 2.1 sk 09/15/17 Remove Libmetal library dependency for MB. +* 09/18/17 Add API to clear the interrupts. +* sk 09/21/17 Add support for Over voltage and Over +* Range interrupts. +* 2.2 sk 10/18/17 Add support for FIFO and DATA overflow interrupt +* 5.0 sk 08/24/18 Reorganize the code to improve readability and +* optimization. +* 5.1 cog 01/29/19 Replace structure reference ADC checks with +* function. +* 6.0 cog 02/20/19 Added handling for new ADC common mode over/under +* voltage interrupts. +* cog 02/20/19 XRFdc_GetIntrStatus now populates a pointer with the +* status and returns an error code. +* cog 02/20/19 XRFdc_IntrClr, XRFdc_IntrDisable and XRFdc_IntrEnable +* now return error codes. +* cog 03/25/19 The new common mode over/under voltage interrupts mask +* bits were clashing with other interrupt bits. +* </pre> +* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "mpm/rfdc/xrfdc.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Variable Definitions *****************************/ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions ****************************/ + +/****************************************************************************/ +/** +* +* This function sets the interrupt mask. +* +* @param InstancePtr is a pointer to the XRFdc instance +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3, and -1. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param IntrMask contains the interrupts to be enabled. +* '1' enables an interrupt, and '0' disables. +* +* @return - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not available. +* +* @note None. +* +*****************************************************************************/ +u32 XRFdc_IntrEnable(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 Block_Id, u32 IntrMask) +{ + u32 BaseAddr; + u32 ReadReg; + u32 Index; + u32 NoOfBlocks; + u32 Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, Type, Tile_Id, Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + Index = Block_Id; + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Type == XRFDC_ADC_TILE)) { + NoOfBlocks = XRFDC_NUM_OF_BLKS2; + if (Block_Id == XRFDC_BLK_ID1) { + Index = XRFDC_BLK_ID2; + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + } else { + NoOfBlocks = Block_Id + 1U; + } + + for (; Index < NoOfBlocks; Index++) { + ReadReg = XRFdc_ReadReg16(InstancePtr, 0x0, + XRFDC_COMMON_INTR_ENABLE); + if (Type == XRFDC_ADC_TILE) { + ReadReg |= (1U << (Tile_Id + 4)); + XRFdc_WriteReg16(InstancePtr, 0x0, + XRFDC_COMMON_INTR_ENABLE, ReadReg); + BaseAddr = XRFDC_ADC_TILE_CTRL_STATS_ADDR(Tile_Id); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_INTR_ENABLE, + (1U << Index), (1U << Index)); + /* Enable Converter interrupts */ + ReadReg = XRFdc_ReadReg(InstancePtr, BaseAddr, + XRFDC_CONV_INTR_EN(Index)); + if ((IntrMask & XRFDC_ADC_OVR_VOLTAGE_MASK) != 0U) { + ReadReg |= (XRFDC_ADC_OVR_VOLTAGE_MASK >> + XRFDC_ADC_OVR_VOL_RANGE_SHIFT); + } + if ((IntrMask & XRFDC_ADC_OVR_RANGE_MASK) != 0U) { + ReadReg |= (XRFDC_ADC_OVR_RANGE_MASK >> + XRFDC_ADC_OVR_VOL_RANGE_SHIFT); + } + if ((IntrMask & XRFDC_ADC_FIFO_OVR_MASK) != 0U) { + ReadReg |= + (XRFDC_ADC_FIFO_OVR_MASK >> XRFDC_ADC_DAT_FIFO_OVR_SHIFT); + } + if ((IntrMask & XRFDC_ADC_DAT_OVR_MASK) != 0U) { + ReadReg |= + (XRFDC_ADC_DAT_OVR_MASK >> XRFDC_ADC_DAT_FIFO_OVR_SHIFT); + } + if ((IntrMask & XRFDC_ADC_CMODE_OVR_MASK) != 0U) { + ReadReg |= + (XRFDC_ADC_CMODE_OVR_MASK >> XRFDC_ADC_CMODE_SHIFT); + } + if ((IntrMask & XRFDC_ADC_CMODE_UNDR_MASK) != 0U) { + ReadReg |= + (XRFDC_ADC_CMODE_UNDR_MASK >> XRFDC_ADC_CMODE_SHIFT); + } + + XRFdc_WriteReg(InstancePtr, BaseAddr, + XRFDC_CONV_INTR_EN(Index), ReadReg); + + BaseAddr = XRFDC_ADC_TILE_DRP_ADDR(Tile_Id) + + XRFDC_BLOCK_ADDR_OFFSET(Index); + + /* Check for FIFO interface interrupts */ + if ((IntrMask & XRFDC_IXR_FIFOUSRDAT_MASK) != 0U) { + ReadReg = (IntrMask & XRFDC_IXR_FIFOUSRDAT_MASK); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_FABRIC_IMR_OFFSET, + XRFDC_IXR_FIFOUSRDAT_MASK, ReadReg); + } + /* Check for SUBADC interrupts */ + if ((IntrMask & XRFDC_SUBADC_IXR_DCDR_MASK) != 0U) { + ReadReg = (IntrMask & XRFDC_SUBADC_IXR_DCDR_MASK) >> + XRFDC_ADC_SUBADC_DCDR_SHIFT; + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_DEC_IMR_OFFSET, + XRFDC_DEC_IMR_MASK, ReadReg); + } + /* Check for DataPath interrupts */ + if ((IntrMask & XRFDC_ADC_IXR_DATAPATH_MASK) != 0U) { + ReadReg = (IntrMask & XRFDC_ADC_IXR_DATAPATH_MASK) >> + XRFDC_DATA_PATH_SHIFT; + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_DATPATH_IMR_OFFSET, + XRFDC_ADC_DAT_IMR_MASK, ReadReg); + } + } else { + ReadReg |= (1U << Tile_Id); + XRFdc_WriteReg16(InstancePtr, 0x0, + XRFDC_COMMON_INTR_ENABLE, ReadReg); + BaseAddr = XRFDC_DAC_TILE_CTRL_STATS_ADDR(Tile_Id); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, + XRFDC_INTR_ENABLE, (1U << Index), (1U << Index)); + BaseAddr = XRFDC_DAC_TILE_DRP_ADDR(Tile_Id) + + XRFDC_BLOCK_ADDR_OFFSET(Index); + /* Check for FIFO interface interrupts */ + if ((IntrMask & XRFDC_IXR_FIFOUSRDAT_MASK) != 0U) { + ReadReg = (IntrMask & XRFDC_IXR_FIFOUSRDAT_MASK); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_DAC_FABRIC_IMR_OFFSET, + XRFDC_IXR_FIFOUSRDAT_MASK, ReadReg); + } + + if ((IntrMask & XRFDC_DAC_IXR_DATAPATH_MASK) != 0U) { + ReadReg = (IntrMask & XRFDC_DAC_IXR_DATAPATH_MASK) >> + XRFDC_DATA_PATH_SHIFT; + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_DATPATH_IMR_OFFSET, + XRFDC_DAC_DAT_IMR_MASK, ReadReg); + } + } + } + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/****************************************************************************/ +/** +* +* This function clears the interrupt mask. +* +* @param InstancePtr is a pointer to the XRFdc instance +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3, and -1. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param IntrMask contains the interrupts to be disabled. +* '1' disables an interrupt, and '0' remains no change. +* +* @return - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not available. +* +* @note None. +* +*****************************************************************************/ +u32 XRFdc_IntrDisable(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 Block_Id, u32 IntrMask) +{ + u32 BaseAddr; + u32 ReadReg; + u32 Status; + u32 Index; + u32 NoOfBlocks; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckBlockEnabled(InstancePtr, Type, Tile_Id, Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + Index = Block_Id; + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Type == XRFDC_ADC_TILE)) { + NoOfBlocks = XRFDC_NUM_OF_BLKS2; + if (Block_Id == XRFDC_BLK_ID1) { + Index = XRFDC_BLK_ID2; + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + } else { + NoOfBlocks = Block_Id + 1U; + } + + for (; Index < NoOfBlocks; Index++) { + if (Type == XRFDC_ADC_TILE) { + BaseAddr = XRFDC_ADC_TILE_CTRL_STATS_ADDR(Tile_Id); + /* Check for Over Voltage and Over Range */ + ReadReg = XRFdc_ReadReg(InstancePtr, BaseAddr, + XRFDC_CONV_INTR_EN(Index)); + if ((IntrMask & XRFDC_ADC_OVR_VOLTAGE_MASK) != 0U) { + ReadReg &= ~(XRFDC_ADC_OVR_VOLTAGE_MASK >> + XRFDC_ADC_OVR_VOL_RANGE_SHIFT); + } + if ((IntrMask & XRFDC_ADC_OVR_RANGE_MASK) != 0U) { + ReadReg &= ~(XRFDC_ADC_OVR_RANGE_MASK >> + XRFDC_ADC_OVR_VOL_RANGE_SHIFT); + } + /* Disable Converter interrupts */ + if ((IntrMask & XRFDC_ADC_FIFO_OVR_MASK) != 0U) { + ReadReg &= + ~(XRFDC_ADC_FIFO_OVR_MASK >> XRFDC_ADC_DAT_FIFO_OVR_SHIFT); + } + if ((IntrMask & XRFDC_ADC_DAT_OVR_MASK) != 0U) { + ReadReg &= + ~(XRFDC_ADC_DAT_OVR_MASK >> XRFDC_ADC_DAT_FIFO_OVR_SHIFT); + } + if ((IntrMask & XRFDC_ADC_CMODE_OVR_MASK) != 0U) { + ReadReg &= + ~(XRFDC_ADC_CMODE_OVR_MASK >> XRFDC_ADC_CMODE_SHIFT); + } + if ((IntrMask & XRFDC_ADC_CMODE_UNDR_MASK) != 0U) { + ReadReg &= + ~(XRFDC_ADC_CMODE_UNDR_MASK >> XRFDC_ADC_CMODE_SHIFT); + } + + XRFdc_WriteReg(InstancePtr, BaseAddr, + XRFDC_CONV_INTR_EN(Index), ReadReg); + BaseAddr = XRFDC_ADC_TILE_DRP_ADDR(Tile_Id) + + XRFDC_BLOCK_ADDR_OFFSET(Index); + /* Check for FIFO interface interrupts */ + if ((IntrMask & XRFDC_IXR_FIFOUSRDAT_MASK) != 0U) { + ReadReg = IntrMask & XRFDC_IXR_FIFOUSRDAT_MASK; + XRFdc_ClrReg(InstancePtr, BaseAddr, XRFDC_ADC_FABRIC_IMR_OFFSET, + ReadReg); + } + /* Check for SUBADC interrupts */ + if ((IntrMask & XRFDC_SUBADC_IXR_DCDR_MASK) != 0U) { + ReadReg = ((IntrMask & XRFDC_SUBADC_IXR_DCDR_MASK) >> + XRFDC_ADC_SUBADC_DCDR_SHIFT); + XRFdc_ClrReg(InstancePtr, BaseAddr, XRFDC_ADC_DEC_IMR_OFFSET, + ReadReg); + } + /* Check for DataPath interrupts */ + if ((IntrMask & XRFDC_ADC_IXR_DATAPATH_MASK) != 0U) { + ReadReg = ((IntrMask & + XRFDC_ADC_IXR_DATAPATH_MASK) >> XRFDC_DATA_PATH_SHIFT); + XRFdc_ClrReg(InstancePtr, BaseAddr, XRFDC_DATPATH_IMR_OFFSET, + ReadReg); + } + } else { + BaseAddr = XRFDC_DAC_TILE_DRP_ADDR(Tile_Id) + + XRFDC_BLOCK_ADDR_OFFSET(Index); + /* Check for FIFO interface interrupts */ + if ((IntrMask & XRFDC_IXR_FIFOUSRDAT_MASK) != 0U) { + ReadReg = (IntrMask & XRFDC_IXR_FIFOUSRDAT_MASK); + XRFdc_ClrReg(InstancePtr, BaseAddr, XRFDC_DAC_FABRIC_IMR_OFFSET, + ReadReg); + } + /* Check for FIFO DataPath interrupts */ + if ((IntrMask & XRFDC_DAC_IXR_DATAPATH_MASK) != 0U) { + ReadReg = ((IntrMask & + XRFDC_DAC_IXR_DATAPATH_MASK) >> XRFDC_DATA_PATH_SHIFT); + XRFdc_ClrReg(InstancePtr, BaseAddr, XRFDC_DATPATH_IMR_OFFSET, + ReadReg); + } + } + } + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/****************************************************************************/ +/** +* +* This function returns the interrupt status read from Interrupt Status +* Register(ISR). +* +* @param InstancePtr is a pointer to the XRFdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3, and -1. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param IntrStsPtr is pointer to a32-bit value representing the contents of +* the Interrupt Status Registers (FIFO interface, Decoder interface, +* Data Path Interface). +* +* @return - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not available. +* +* @note None. +* +*****************************************************************************/ +u32 XRFdc_GetIntrStatus(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 Block_Id, u32 *IntrStsPtr) +{ + u32 BaseAddr; + u32 ReadReg; + u32 Status; + u32 Block; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(IntrStsPtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Block = Block_Id; + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Type == XRFDC_ADC_TILE)) { + if ((Block_Id == XRFDC_BLK_ID2) || (Block_Id == XRFDC_BLK_ID3)) { + Block = XRFDC_BLK_ID1; + } + if (Block_Id == XRFDC_BLK_ID1) { + Block = XRFDC_BLK_ID0; + } + } + Status = XRFdc_CheckBlockEnabled(InstancePtr, Type, Tile_Id, Block); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + *IntrStsPtr = 0; + + if (Type == XRFDC_ADC_TILE) { + BaseAddr = XRFDC_ADC_TILE_CTRL_STATS_ADDR(Tile_Id); + /* Check for Over Voltage and Over Range */ + ReadReg = XRFdc_ReadReg(InstancePtr, BaseAddr, + XRFDC_CONV_INTR_STS(Block_Id)); + *IntrStsPtr |= ((ReadReg & XRFDC_INTR_OVR_VOLTAGE_MASK) << + XRFDC_ADC_OVR_VOL_RANGE_SHIFT); + *IntrStsPtr |= ((ReadReg & XRFDC_INTR_OVR_RANGE_MASK) << + XRFDC_ADC_OVR_VOL_RANGE_SHIFT); + *IntrStsPtr |= ((ReadReg & XRFDC_INTR_FIFO_OVR_MASK) << + XRFDC_ADC_DAT_FIFO_OVR_SHIFT); + *IntrStsPtr |= ((ReadReg & XRFDC_INTR_DAT_OVR_MASK) << + XRFDC_ADC_DAT_FIFO_OVR_SHIFT); + + /* Check for Common Mode Over/Under Voltage */ + *IntrStsPtr |= ((ReadReg & XRFDC_INTR_CMODE_OVR_MASK) << + XRFDC_ADC_CMODE_SHIFT); + *IntrStsPtr |= ((ReadReg & XRFDC_INTR_CMODE_UNDR_MASK) << + XRFDC_ADC_CMODE_SHIFT); + + BaseAddr = XRFDC_ADC_TILE_DRP_ADDR(Tile_Id) + + XRFDC_BLOCK_ADDR_OFFSET(Block_Id); + /* Check for FIFO interface interrupts */ + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_ADC_FABRIC_ISR_OFFSET); + *IntrStsPtr |= (ReadReg & XRFDC_IXR_FIFOUSRDAT_MASK); + /* Check for SUBADC interrupts */ + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_ADC_DEC_ISR_OFFSET); + *IntrStsPtr |= ((ReadReg & XRFDC_DEC_ISR_SUBADC_MASK) << + XRFDC_ADC_SUBADC_DCDR_SHIFT); + /* Check for DataPath interrupts */ + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_DATPATH_ISR_OFFSET); + *IntrStsPtr |= ((ReadReg & XRFDC_ADC_DAT_PATH_ISR_MASK) << + XRFDC_DATA_PATH_SHIFT); + } else { + BaseAddr = XRFDC_DAC_TILE_DRP_ADDR(Tile_Id) + + XRFDC_BLOCK_ADDR_OFFSET(Block_Id); + /* Check for FIFO interface interrupts */ + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_DAC_FABRIC_ISR_OFFSET); + *IntrStsPtr |= (ReadReg & XRFDC_IXR_FIFOUSRDAT_MASK); + /* Check for DataPath interrupts */ + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_DATPATH_ISR_OFFSET); + *IntrStsPtr |= ((ReadReg & XRFDC_DAC_DAT_PATH_ISR_MASK) << + XRFDC_DATA_PATH_SHIFT); + } + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/****************************************************************************/ +/** +* +* This function clear the interrupts. +* +* @param InstancePtr is a pointer to the XRFdc instance +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3, and -1. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param IntrMask contains the interrupts to be cleared. +* +* @return - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not available. +* +* @note None. +* +*****************************************************************************/ +u32 XRFdc_IntrClr(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 Block_Id, u32 IntrMask) +{ + u32 BaseAddr; + u32 Status; + u32 Block; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Block = Block_Id; + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Type == XRFDC_ADC_TILE)) { + if ((Block_Id == XRFDC_BLK_ID2) || (Block_Id == XRFDC_BLK_ID3)) { + Block = XRFDC_BLK_ID1; + } + if (Block_Id == XRFDC_BLK_ID1) { + Block = XRFDC_BLK_ID0; + } + } + Status = XRFdc_CheckBlockEnabled(InstancePtr, Type, Tile_Id, Block); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + + if (Type == XRFDC_ADC_TILE) { + /* ADC */ + BaseAddr = XRFDC_ADC_TILE_CTRL_STATS_ADDR(Tile_Id); + /* Check for Converter interrupts */ + if ((IntrMask & XRFDC_ADC_OVR_VOLTAGE_MASK) != 0U) { + XRFdc_WriteReg(InstancePtr, BaseAddr, + XRFDC_CONV_INTR_STS(Block_Id), (IntrMask & + XRFDC_ADC_OVR_VOLTAGE_MASK) >> XRFDC_ADC_OVR_VOL_RANGE_SHIFT); + } + if ((IntrMask & XRFDC_ADC_OVR_RANGE_MASK) != 0U) { + XRFdc_WriteReg(InstancePtr, BaseAddr, + XRFDC_CONV_INTR_STS(Block_Id), (IntrMask & + XRFDC_ADC_OVR_RANGE_MASK) >> XRFDC_ADC_OVR_VOL_RANGE_SHIFT); + } + if ((IntrMask & XRFDC_ADC_FIFO_OVR_MASK) != 0U) { + XRFdc_WriteReg(InstancePtr, BaseAddr, + XRFDC_CONV_INTR_STS(Block_Id), (IntrMask & + XRFDC_ADC_FIFO_OVR_MASK) >> XRFDC_ADC_DAT_FIFO_OVR_SHIFT); + } + if ((IntrMask & XRFDC_ADC_DAT_OVR_MASK) != 0U) { + XRFdc_WriteReg(InstancePtr, BaseAddr, + XRFDC_CONV_INTR_STS(Block_Id), (IntrMask & + XRFDC_ADC_DAT_OVR_MASK) >> XRFDC_ADC_DAT_FIFO_OVR_SHIFT); + } + if ((IntrMask & XRFDC_ADC_CMODE_OVR_MASK) != 0U) { + XRFdc_WriteReg(InstancePtr, BaseAddr, + XRFDC_CONV_INTR_STS(Block_Id), (IntrMask & + XRFDC_ADC_CMODE_OVR_MASK) >> XRFDC_ADC_CMODE_SHIFT); + } + if ((IntrMask & XRFDC_ADC_CMODE_UNDR_MASK) != 0U) { + XRFdc_WriteReg(InstancePtr, BaseAddr, + XRFDC_CONV_INTR_STS(Block_Id), (IntrMask & + XRFDC_ADC_CMODE_UNDR_MASK) >> XRFDC_ADC_CMODE_SHIFT); + } + BaseAddr = XRFDC_ADC_TILE_DRP_ADDR(Tile_Id) + + XRFDC_BLOCK_ADDR_OFFSET(Block_Id); + /* Check for FIFO interface interrupts */ + if ((IntrMask & XRFDC_IXR_FIFOUSRDAT_MASK) != 0U) { + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_FABRIC_ISR_OFFSET, + (IntrMask & XRFDC_IXR_FIFOUSRDAT_MASK)); + } + /* Check for SUBADC interrupts */ + if ((IntrMask & XRFDC_SUBADC_IXR_DCDR_MASK) != 0U) { + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_DEC_ISR_OFFSET, (u16)((IntrMask & + XRFDC_SUBADC_IXR_DCDR_MASK) >> XRFDC_ADC_SUBADC_DCDR_SHIFT)); + } + /* Check for DataPath interrupts */ + if ((IntrMask & XRFDC_ADC_IXR_DATAPATH_MASK) != 0U) { + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_DATPATH_ISR_OFFSET, (u16)(IntrMask & + XRFDC_ADC_IXR_DATAPATH_MASK) >> XRFDC_DATA_PATH_SHIFT); + } + } else { + /* DAC */ + BaseAddr = XRFDC_DAC_TILE_DRP_ADDR(Tile_Id) + + XRFDC_BLOCK_ADDR_OFFSET(Block_Id); + /* Check for FIFO interface interrupts */ + if ((IntrMask & XRFDC_IXR_FIFOUSRDAT_MASK) != 0U) { + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_DAC_FABRIC_ISR_OFFSET, + (u16)(IntrMask & XRFDC_IXR_FIFOUSRDAT_MASK)); + } + /* Check for DataPath interrupts */ + if ((IntrMask & XRFDC_DAC_IXR_DATAPATH_MASK) != 0U) { + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_DATPATH_ISR_OFFSET, (u16)(IntrMask & + XRFDC_DAC_IXR_DATAPATH_MASK) >> XRFDC_DATA_PATH_SHIFT); + } + } + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} + +/****************************************************************************/ +/** +* +* This function is the interrupt handler for the driver. +* It must be connected to an interrupt system by the application such that it +* can be called when an interrupt occurs. +* +* @param Vector is interrupt vector number. Libmetal status handler +* expects two parameters in the handler prototype, hence +* kept this parameter. This is not used inside +* the interrupt handler API. +* @param XRFdcPtr contains a pointer to the driver instance +* +* @return None. +* +* @note Vector param is not useful inside the interrupt handler, hence +* typecast with void to remove compilation warning. +* +******************************************************************************/ +u32 XRFdc_IntrHandler(u32 Vector, void *XRFdcPtr) +{ + XRFdc *InstancePtr = (XRFdc *)XRFdcPtr; + u32 Intrsts = 0x0U; + u32 Tile_Id = XRFDC_TILE_ID4; + u32 Block_Id = XRFDC_BLK_ID4; + u32 ReadReg; + u16 Type = 0U; + u32 BaseAddr; + u32 IntrMask = 0x0U; + u32 Block; + + Xil_AssertNonvoid(InstancePtr != NULL); + + (void)Vector; + /* + * Read the interrupt ID register to determine which + * interrupt is active + */ + ReadReg = XRFdc_ReadReg16(InstancePtr, 0x0, + XRFDC_COMMON_INTR_STS); + if ((ReadReg & XRFDC_EN_INTR_DAC_TILE0_MASK) != 0U) { + Type = XRFDC_DAC_TILE; + Tile_Id = XRFDC_TILE_ID0; + } else if ((ReadReg & XRFDC_EN_INTR_DAC_TILE1_MASK) != 0U) { + Type = XRFDC_DAC_TILE; + Tile_Id = XRFDC_TILE_ID1; + } else if ((ReadReg & XRFDC_EN_INTR_DAC_TILE2_MASK) != 0U) { + Type = XRFDC_DAC_TILE; + Tile_Id = XRFDC_TILE_ID2; + } else if ((ReadReg & XRFDC_EN_INTR_DAC_TILE3_MASK) != 0U) { + Type = XRFDC_DAC_TILE; + Tile_Id = XRFDC_TILE_ID3; + } else if ((ReadReg & XRFDC_EN_INTR_ADC_TILE0_MASK) != 0U) { + Type = XRFDC_ADC_TILE; + Tile_Id = XRFDC_TILE_ID0; + } else if ((ReadReg & XRFDC_EN_INTR_ADC_TILE1_MASK) != 0U) { + Type = XRFDC_ADC_TILE; + Tile_Id = XRFDC_TILE_ID1; + } else if ((ReadReg & XRFDC_EN_INTR_ADC_TILE2_MASK) != 0U) { + Type = XRFDC_ADC_TILE; + Tile_Id = XRFDC_TILE_ID2; + } else if ((ReadReg & XRFDC_EN_INTR_ADC_TILE3_MASK) != 0U) { + Type = XRFDC_ADC_TILE; + Tile_Id = XRFDC_TILE_ID3; + } else { + metal_log(METAL_LOG_DEBUG, "\n Invalid Tile_Id \r\n"); + } + + BaseAddr = XRFDC_CTRL_STS_BASE(Type, Tile_Id); + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, XRFDC_INTR_STS); + if ((ReadReg & XRFDC_EN_INTR_SLICE0_MASK) != 0U) { + Block_Id = XRFDC_BLK_ID0; + } else if ((ReadReg & XRFDC_EN_INTR_SLICE1_MASK) != 0U) { + Block_Id = XRFDC_BLK_ID1; + } else if ((ReadReg & XRFDC_EN_INTR_SLICE2_MASK) != 0U) { + Block_Id = XRFDC_BLK_ID2; + } else if ((ReadReg & XRFDC_EN_INTR_SLICE3_MASK) != 0U) { + Block_Id = XRFDC_BLK_ID3; + } else { + metal_log(METAL_LOG_DEBUG, "\n Invalid ADC Block_Id \r\n"); + } + (void)XRFdc_GetIntrStatus(InstancePtr, Type, Tile_Id, Block_Id, &Intrsts); + if (Type == XRFDC_ADC_TILE) { + /* ADC */ + if ((Intrsts & XRFDC_ADC_OVR_VOLTAGE_MASK) != 0U) { + IntrMask |= Intrsts & XRFDC_ADC_OVR_VOLTAGE_MASK; + metal_log(METAL_LOG_DEBUG, "\n ADC Over Voltage interrupt \r\n"); + } + if ((Intrsts & XRFDC_ADC_OVR_RANGE_MASK) != 0U) { + IntrMask |= Intrsts & XRFDC_ADC_OVR_RANGE_MASK; + metal_log(METAL_LOG_DEBUG, "\n ADC Over Range interrupt \r\n"); + } + if ((Intrsts & XRFDC_ADC_FIFO_OVR_MASK) != 0U) { + IntrMask |= Intrsts & XRFDC_ADC_FIFO_OVR_MASK; + metal_log(METAL_LOG_DEBUG, "\n ADC FIFO OF interrupt \r\n"); + } + if ((Intrsts & XRFDC_ADC_DAT_OVR_MASK) != 0U) { + IntrMask |= Intrsts & XRFDC_ADC_DAT_OVR_MASK; + metal_log(METAL_LOG_DEBUG, "\n ADC DATA OF interrupt \r\n"); + } + if ((Intrsts & XRFDC_ADC_CMODE_OVR_MASK) != 0U) { + IntrMask |= XRFDC_ADC_CMODE_OVR_MASK; + metal_log(METAL_LOG_DEBUG, "\n ADC CMODE OV interrupt \r\n"); + } + if ((Intrsts & XRFDC_ADC_CMODE_UNDR_MASK) != 0U) { + IntrMask |= XRFDC_ADC_CMODE_UNDR_MASK; + metal_log(METAL_LOG_DEBUG, "\n ADC CMODE UV interrupt \r\n"); + } + if ((Intrsts & XRFDC_IXR_FIFOUSRDAT_MASK) != 0U) { + IntrMask |= Intrsts & XRFDC_IXR_FIFOUSRDAT_MASK; + metal_log(METAL_LOG_DEBUG, "\n ADC FIFO interface interrupt \r\n"); + } + if ((Intrsts & XRFDC_SUBADC_IXR_DCDR_MASK) != 0U) { + IntrMask |= Intrsts & XRFDC_SUBADC_IXR_DCDR_MASK; + metal_log(METAL_LOG_DEBUG, + "\n ADC Decoder interface interrupt \r\n"); + } + if ((Intrsts & XRFDC_ADC_IXR_DATAPATH_MASK) != 0U) { + IntrMask |= Intrsts & XRFDC_ADC_IXR_DATAPATH_MASK; + metal_log(METAL_LOG_DEBUG, + "\n ADC Data Path interface interrupt \r\n"); + } + } else { + /* DAC */ + if ((Intrsts & XRFDC_IXR_FIFOUSRDAT_MASK) != 0U) { + IntrMask |= Intrsts & XRFDC_IXR_FIFOUSRDAT_MASK; + metal_log(METAL_LOG_DEBUG, "\n DAC FIFO interface interrupt \r\n"); + } + if ((Intrsts & XRFDC_DAC_IXR_DATAPATH_MASK) != 0U) { + IntrMask |= Intrsts & XRFDC_DAC_IXR_DATAPATH_MASK; + metal_log(METAL_LOG_DEBUG, "\n DAC Data Path interface interrupt \r\n"); + } + } + Block = Block_Id; + + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Type == XRFDC_ADC_TILE)) { + if ((Block_Id == XRFDC_BLK_ID0) || (Block_Id == XRFDC_BLK_ID1)) { + Block = XRFDC_BLK_ID0; + } else { + Block = XRFDC_BLK_ID1; + } + } + InstancePtr->StatusHandler(InstancePtr->CallBackRef, Type, Tile_Id, + Block, IntrMask); + + /* Clear the interrupt */ + if (Type == XRFDC_ADC_TILE) { + /* ADC */ + XRFdc_IntrClr(InstancePtr, XRFDC_ADC_TILE, Tile_Id, Block_Id, Intrsts); + + } else { + /* DAC */ + XRFdc_IntrClr(InstancePtr, XRFDC_DAC_TILE, Tile_Id, Block_Id, Intrsts); + } + + return (u32)METAL_IRQ_HANDLED; +} + +/*****************************************************************************/ +/** +* +* This function sets the status callback function, the status handler, which the +* driver calls when it encounters conditions that should be reported to the +* higher layer software. The handler executes in an interrupt context, so +* the amount of processing should be minimized +* +* +* @param InstancePtr is a pointer to the XRFdc instance. +* @param CallBackRef is the upper layer callback reference passed back +* when the callback function is invoked. +* @param FunctionPtr is the pointer to the callback function. +* +* @return None. +* +* @note +* +* The handler is called within interrupt context, so it should finish its +* work quickly. +* +******************************************************************************/ +void XRFdc_SetStatusHandler(XRFdc *InstancePtr, void *CallBackRef, + XRFdc_StatusHandler FunctionPtr) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(FunctionPtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == (u32)XRFDC_COMPONENT_IS_READY); + + InstancePtr->StatusHandler = FunctionPtr; + InstancePtr->CallBackRef = CallBackRef; +} + +/** @} */ diff --git a/mpm/lib/rfdc/xrfdc_mb.c b/mpm/lib/rfdc/xrfdc_mb.c new file mode 100644 index 000000000..c7b563d40 --- /dev/null +++ b/mpm/lib/rfdc/xrfdc_mb.c @@ -0,0 +1,786 @@ +/****************************************************************************** +* +* 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_mb.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/18 Initial release/handle alternate bound out. +* +* </pre> +* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include "mpm/rfdc/xrfdc.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ +static void XRFdc_SetSignalFlow(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 Mode, u32 DigitalDataPathId, u32 MixerInOutDataType, + int ConnectIData, int ConnectQData); +static void XRFdc_MB_R2C_C2R(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u8 NoOfDataPaths, u32 MixerInOutDataType, u32 Mode, + u32 DataPathIndex[], u32 BlockIndex[]); +static void XRFdc_MB_C2C(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u8 NoOfDataPaths, u32 MixerInOutDataType, u32 Mode, + u32 DataPathIndex[], u32 BlockIndex[]); +static void XRFdc_SB_R2C_C2R(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 MixerInOutDataType, u32 Mode, u32 DataPathIndex[], u32 BlockIndex[]); +static void XRFdc_SB_C2C(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 MixerInOutDataType, u32 Mode, u32 DataPathIndex[], u32 BlockIndex[]); +/************************** Function Prototypes ******************************/ + +/*****************************************************************************/ +/** +* +* Static API to setup Singleband configuration for C2C MixerInOutDataType +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param MixerInOutDataType is mixer data type, valid values are XRFDC_MB_DATATYPE_* +* @param Mode is connection mode SB/MB_2X/MB_4X. +* @param DataPathIndex is the array that represents the blocks enabled in +* DigitalData Path. +* @param BlockIndex is the array that represents the blocks enabled in +* Analog Path(Data Converters). +* +* @return +* - None +* +* @note Static API for ADC/DAC blocks +* +******************************************************************************/ +static void XRFdc_SB_C2C(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 MixerInOutDataType, u32 Mode, u32 DataPathIndex[], u32 BlockIndex[]) +{ + u32 Block_Id; + + if ((Type == XRFDC_ADC_TILE) && (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1)) { + /* Update ConnectedIData and ConnectedQData for ADC 4GSPS */ + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedQData = BlockIndex[1U]; + Block_Id = (DataPathIndex[0] == 0U ? 1U : 0U); + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[Block_Id]. + ConnectedIData = -1; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[Block_Id]. + ConnectedQData = -1; + + if (DataPathIndex[0] == XRFDC_BLK_ID1) { + DataPathIndex[0] = XRFDC_BLK_ID2; + } + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[0], + MixerInOutDataType, BlockIndex[0U], BlockIndex[0U]+1U); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[0]+1U, + MixerInOutDataType, BlockIndex[1U]+1U, BlockIndex[1U]+2U); + Block_Id = (DataPathIndex[0] == XRFDC_BLK_ID2 ? XRFDC_BLK_ID0 : + XRFDC_BLK_ID2); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, Block_Id, + MixerInOutDataType, -1, -1); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, Block_Id+1U, + MixerInOutDataType, -1, -1); + } else { + DataPathIndex[1] = BlockIndex[0] + BlockIndex[1] - DataPathIndex[0]; + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[0], + MixerInOutDataType, BlockIndex[0], BlockIndex[1]); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[1], + MixerInOutDataType, -1, -1); + + /* Update ConnectedIData and ConnectedQData for DAC and ADC 2GSPS */ + if (Type == XRFDC_ADC_TILE) { + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedIData = BlockIndex[0]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedQData = BlockIndex[1]; + + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedIData = -1; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedQData = -1; + } else { + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedIData = BlockIndex[0]; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedQData = BlockIndex[1]; + + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedIData = -1; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedQData = -1; + } + } +} + +/*****************************************************************************/ +/** +* +* Static API to setup Singleband configuration for C2R and R2C MultiBandDataTypes +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param MixerInOutDataType is mixer data type, valid values are XRFDC_MB_DATATYPE_* +* @param Mode is connection mode SB/MB_2X/MB_4X. +* @param DataPathIndex is the array that represents the blocks enabled in +* DigitalData Path. +* @param BlockIndex is the array that represents the blocks enabled in +* Analog Path(Data Converters). +* +* @return +* - None +* +* @note Static API for ADC/DAC blocks +* +******************************************************************************/ +static void XRFdc_SB_R2C_C2R(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 MixerInOutDataType, u32 Mode, u32 DataPathIndex[], u32 BlockIndex[]) +{ + if (Type == XRFDC_ADC_TILE) { + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedQData = -1; + } else { + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedQData = -1; + } + if ((Type == XRFDC_ADC_TILE) && (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1)) { + if (DataPathIndex[0] == XRFDC_BLK_ID1) { + DataPathIndex[0] = XRFDC_BLK_ID2; + } + if (BlockIndex[0] == XRFDC_BLK_ID1) { + BlockIndex[0] = XRFDC_BLK_ID2; + } + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[0]+1U, + MixerInOutDataType, BlockIndex[0U]+1U, -1); + } + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[0], + MixerInOutDataType, BlockIndex[0U], -1); +} + +/*****************************************************************************/ +/** +* +* Static API to setup Multiband configuration for C2C MixerInOutDataType +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param MixerInOutDataType is mixer data type, valid values are XRFDC_MB_DATATYPE_* +* @param Mode is connection mode SB/MB_2X/MB_4X. +* @param DataPathIndex is the array that represents the blocks enabled in +* DigitalData Path. +* @param BlockIndex is the array that represents the blocks enabled in +* Analog Path(Data Converters). +* +* @return +* - None +* +* @note Static API for ADC/DAC blocks +* +******************************************************************************/ +static void XRFdc_MB_C2C(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u8 NoOfDataPaths, u32 MixerInOutDataType, u32 Mode, + u32 DataPathIndex[], u32 BlockIndex[]) +{ + if ((Type == XRFDC_ADC_TILE) && (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1)) { + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[0], + MixerInOutDataType, BlockIndex[0U], BlockIndex[0U]+1U); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[0]+1U, + MixerInOutDataType, BlockIndex[0U]+2U, BlockIndex[0U]+3U); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[0]+2U, + MixerInOutDataType, BlockIndex[0U], BlockIndex[0U]+1U); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[0]+3U, + MixerInOutDataType, BlockIndex[0U]+2U, BlockIndex[0U]+3U); + + /* Update ConnectedIData and ConnectedQData for ADC 4GSPS */ + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedQData = BlockIndex[1U]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedQData = BlockIndex[1U]; + } else if (NoOfDataPaths == 2U) { + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[0], + MixerInOutDataType, BlockIndex[0U], BlockIndex[1U]); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[1], + MixerInOutDataType, BlockIndex[0U], BlockIndex[1U]); + + /* Update ConnectedIData and ConnectedQData for DAC and ADC 2GSPS */ + if (Type == XRFDC_ADC_TILE) { + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedQData = BlockIndex[1U]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedQData = BlockIndex[1U]; + } else { + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedQData = BlockIndex[1U]; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedQData = BlockIndex[1U]; + } + } + if (NoOfDataPaths == 4U) { + if (Type == XRFDC_ADC_TILE) { + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[0], + MixerInOutDataType, BlockIndex[0U], BlockIndex[1U]); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[1], + MixerInOutDataType, BlockIndex[0U], BlockIndex[1U]); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[2], + MixerInOutDataType, BlockIndex[0U], BlockIndex[1U]); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[3], + MixerInOutDataType, BlockIndex[0U], BlockIndex[1U]); + + /* Update ConnectedIData and ConnectedQData for ADC 4GSPS */ + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedQData = BlockIndex[1U]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedQData = BlockIndex[1U]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[2]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[2]]. + ConnectedQData = BlockIndex[1U]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[3]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[3]]. + ConnectedQData = BlockIndex[1U]; + } else { + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[0], + MixerInOutDataType, DataPathIndex[0], DataPathIndex[1U]); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[1], + MixerInOutDataType, DataPathIndex[0U], DataPathIndex[1U]); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[2], + MixerInOutDataType, DataPathIndex[2U], DataPathIndex[3U]); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[3], + MixerInOutDataType, DataPathIndex[2U], DataPathIndex[3U]); + + /* Update ConnectedIData and ConnectedQData for DAC and ADC 2GSPS */ + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedQData = BlockIndex[1U]; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedQData = BlockIndex[1U]; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[2]]. + ConnectedIData = DataPathIndex[0U]; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[2]]. + ConnectedQData = DataPathIndex[1U]; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[3]]. + ConnectedIData = DataPathIndex[0U]; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[3]]. + ConnectedQData = DataPathIndex[1U]; + } + } +} + +/*****************************************************************************/ +/** +* +* Static API to setup Multiband configuration for C2C MixerInOutDataType +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param MixerInOutDataType is mixer data type, valid values are XRFDC_MB_DATATYPE_* +* @param Mode is connection mode SB/MB_2X/MB_4X. +* @param DataPathIndex is the array that represents the blocks enabled in +* DigitalData Path. +* @param BlockIndex is the array that represents the blocks enabled in +* Analog Path(Data Converters). +* +* @return +* - None +* +* @note Static API for ADC/DAC blocks +* +******************************************************************************/ +static void XRFdc_MB_R2C_C2R(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u8 NoOfDataPaths, u32 MixerInOutDataType, u32 Mode, + u32 DataPathIndex[], u32 BlockIndex[]) +{ + if ((Type == XRFDC_ADC_TILE) && (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1)) { + /* Update ConnectedIData and ConnectedQData */ + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedQData = -1; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedQData = -1; + if (BlockIndex[0] == XRFDC_BLK_ID1) { + BlockIndex[0] = XRFDC_BLK_ID2; + } + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[0], + MixerInOutDataType, BlockIndex[0U], -1); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[1], + MixerInOutDataType, BlockIndex[0U]+1U, -1); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[0]+2U, + MixerInOutDataType, BlockIndex[0U], -1); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[1]+2U, + MixerInOutDataType, BlockIndex[0U]+1U, -1); + } else if (NoOfDataPaths == 2U) { + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[0], + MixerInOutDataType, BlockIndex[0], -1); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[1], + MixerInOutDataType, BlockIndex[0], -1); + + /* Update ConnectedIData and ConnectedQData */ + if (Type == XRFDC_ADC_TILE) { + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedQData = -1; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedQData = -1; + } else { + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedQData = -1; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedQData = -1; + } + + } + if (NoOfDataPaths == 4U) { + if (Type == XRFDC_ADC_TILE) { + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[0], + MixerInOutDataType, BlockIndex[0], -1); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[1], + MixerInOutDataType, BlockIndex[0], -1); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[2], + MixerInOutDataType, BlockIndex[0], -1); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[3], + MixerInOutDataType, BlockIndex[0], -1); + + /* Update ConnectedIData and ConnectedQData */ + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedQData = -1; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedQData = -1; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[2]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[2]]. + ConnectedQData = -1; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[3]]. + ConnectedIData = BlockIndex[0U]; + InstancePtr->ADC_Tile[Tile_Id].ADCBlock_Digital_Datapath[DataPathIndex[3]]. + ConnectedQData = -1; + + } else { + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[0], + MixerInOutDataType, DataPathIndex[0], -1); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[1], + MixerInOutDataType, DataPathIndex[0], -1); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[2], + MixerInOutDataType, DataPathIndex[2], -1); + XRFdc_SetSignalFlow(InstancePtr, Type, Tile_Id, Mode, DataPathIndex[3], + MixerInOutDataType, DataPathIndex[2], -1); + + /* Update ConnectedIData and ConnectedQData */ + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedIData = DataPathIndex[0]; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[0]]. + ConnectedQData = -1; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedIData = DataPathIndex[0]; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[1]]. + ConnectedQData = -1; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[2]]. + ConnectedIData = DataPathIndex[0]; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[2]]. + ConnectedQData = -1; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[3]]. + ConnectedIData = DataPathIndex[0]; + InstancePtr->DAC_Tile[Tile_Id].DACBlock_Digital_Datapath[DataPathIndex[3]]. + ConnectedQData = -1; + } + } +} + +/*****************************************************************************/ +/** +* +* Static API to update mode and MultibandConfig +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param NoOfDataPaths is number of DataPaths enabled. +* @param ModePtr is a pointer to connection mode SB/MB_2X/MB_4X. +* @param DataPathIndex is the array that represents the blocks enabled in +* DigitalData Path. +* +* @return +* - None +* +* @note Static API for ADC/DAC blocks +* +******************************************************************************/ +static u32 XRFdc_UpdateMBConfig(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u8 NoOfDataPaths, u32 *ModePtr, u32 DataPathIndex[]) +{ + u8 MultibandConfig; + u32 Status; + + if (Type == XRFDC_ADC_TILE) { + MultibandConfig = InstancePtr->ADC_Tile[Tile_Id].MultibandConfig; + } else { + MultibandConfig = InstancePtr->DAC_Tile[Tile_Id].MultibandConfig; + } + + if (NoOfDataPaths == 1U) { + *ModePtr = XRFDC_SINGLEBAND_MODE; + if (((DataPathIndex[0] == XRFDC_BLK_ID2) || + (DataPathIndex[0] == XRFDC_BLK_ID3)) && + ((MultibandConfig == XRFDC_MB_MODE_2X_BLK01_BLK23) || + (MultibandConfig == XRFDC_MB_MODE_4X))) { + MultibandConfig = XRFDC_MB_MODE_2X_BLK01; + } else if (((DataPathIndex[0] == XRFDC_BLK_ID0) || + (DataPathIndex[0] == XRFDC_BLK_ID1)) && + ((MultibandConfig == XRFDC_MB_MODE_2X_BLK01_BLK23) || + (MultibandConfig == XRFDC_MB_MODE_4X))) { + MultibandConfig = XRFDC_MB_MODE_2X_BLK23; + } else if ((MultibandConfig == XRFDC_MB_MODE_2X_BLK01) && + ((DataPathIndex[0] == XRFDC_BLK_ID0) || + (DataPathIndex[0] == XRFDC_BLK_ID1))) { + MultibandConfig = XRFDC_MB_MODE_SB; + } else if ((MultibandConfig == XRFDC_MB_MODE_2X_BLK23) && + ((DataPathIndex[0] == XRFDC_BLK_ID2) || + (DataPathIndex[0] == XRFDC_BLK_ID3))) { + MultibandConfig = XRFDC_MB_MODE_SB; + } + } else if (NoOfDataPaths == 2U) { + *ModePtr = XRFDC_MULTIBAND_MODE_2X; + if (((MultibandConfig == XRFDC_MB_MODE_2X_BLK01) && + (DataPathIndex[0] == XRFDC_BLK_ID2) && (DataPathIndex[1] == XRFDC_BLK_ID3)) || + ((MultibandConfig == XRFDC_MB_MODE_2X_BLK23) && (DataPathIndex[0] == XRFDC_BLK_ID0) && + (DataPathIndex[1] == XRFDC_BLK_ID1)) || (MultibandConfig == XRFDC_MB_MODE_4X)) { + MultibandConfig = XRFDC_MB_MODE_2X_BLK01_BLK23; + } else if (((DataPathIndex[0] == XRFDC_BLK_ID2) && (DataPathIndex[1] == XRFDC_BLK_ID3)) && + (MultibandConfig == XRFDC_MB_MODE_SB)) { + MultibandConfig = XRFDC_MB_MODE_2X_BLK23; + } else if (((DataPathIndex[0] == XRFDC_BLK_ID0) && (DataPathIndex[1] == XRFDC_BLK_ID1)) && + (MultibandConfig == XRFDC_MB_MODE_SB)) { + MultibandConfig = XRFDC_MB_MODE_2X_BLK01; + } + } else if (NoOfDataPaths == 4U) { + *ModePtr = XRFDC_MULTIBAND_MODE_4X; + MultibandConfig = XRFDC_MB_MODE_4X; + } else { + metal_log(METAL_LOG_ERROR, "\n Invalid DigitalDataPathMask " + "value in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + /* Update Multiband Config member */ + if (Type == XRFDC_ADC_TILE) { + InstancePtr->ADC_Tile[Tile_Id].MultibandConfig = MultibandConfig; + } else { + InstancePtr->DAC_Tile[Tile_Id].MultibandConfig = MultibandConfig; + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} +/*****************************************************************************/ +/** +* +* User-level API to setup multiband configuration. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param DigitalDataPathMask is the DataPath mask. First 4 bits represent +* 4 data paths, 1 means enabled and 0 means disabled. +* @param MixerInOutDataType is mixer data type, valid values are XRFDC_MB_DATATYPE_* +* @param DataConverterMask is block enabled mask (input/output driving +* blocks). 1 means enabled and 0 means disabled. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note Common API for ADC/DAC blocks +* +******************************************************************************/ +u32 XRFdc_MultiBand(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u8 DigitalDataPathMask, u32 MixerInOutDataType, u32 DataConverterMask) +{ + u32 Status; + u32 Block_Id; + u8 NoOfDataPaths = 0U; + u32 BlockIndex[XRFDC_NUM_OF_BLKS4] = {XRFDC_BLK_ID4}; + u32 DataPathIndex[XRFDC_NUM_OF_BLKS4] = {XRFDC_BLK_ID4}; + u32 NoOfDataConverters = 0U; + u32 Mode = 0x0; + u32 NoOfBlocks = XRFDC_BLK_ID4; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + if ((DigitalDataPathMask == 0U) || (DigitalDataPathMask > 0xFU)) { + metal_log(METAL_LOG_ERROR, "\n Invalid DigitalDataPathMask " + "value in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + if ((DataConverterMask == 0U) || (DataConverterMask > 0xFU)) { + metal_log(METAL_LOG_ERROR, "\n Invalid DataConverterMask " + "value in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + if ((MixerInOutDataType != XRFDC_MB_DATATYPE_C2C) && + (MixerInOutDataType != XRFDC_MB_DATATYPE_R2C) && + (MixerInOutDataType != XRFDC_MB_DATATYPE_C2R)) { + metal_log(METAL_LOG_ERROR, "\n Invalid MixerInOutDataType " + "value in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Type == XRFDC_ADC_TILE)) { + NoOfBlocks = XRFDC_BLK_ID2; + } + /* Identify DataPathIndex and BlockIndex */ + for (Block_Id = XRFDC_BLK_ID0; Block_Id < NoOfBlocks; Block_Id++) { + if ((DataConverterMask & (1U << Block_Id)) != 0U) { + BlockIndex[NoOfDataConverters] = Block_Id; + NoOfDataConverters += 1U; + Status = XRFdc_CheckBlockEnabled(InstancePtr, Type, Tile_Id, + Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block not " + "available in %s\r\n", __func__); + goto RETURN_PATH; + } + } + if ((DigitalDataPathMask & (1U << Block_Id)) != 0U) { + DataPathIndex[NoOfDataPaths] = Block_Id; + NoOfDataPaths += 1U; + Status = XRFdc_CheckDigitalPathEnabled(InstancePtr, Type, Tile_Id, + Block_Id); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Requested block digital path " + "not enabled in %s\r\n", __func__); + goto RETURN_PATH; + } + } + } + + /* rerouting & configuration for alternative bonding. */ + if ((Type == XRFDC_DAC_TILE) && (DataConverterMask & 0x05) && (MixerInOutDataType == XRFDC_MB_DATATYPE_C2C) && + (InstancePtr->RFdc_Config.DACTile_Config[Tile_Id].NumSlices == 2)) { + BlockIndex[XRFDC_BLK_ID1] = XRFDC_BLK_ID1; + XRFdc_ClrSetReg(InstancePtr, XRFDC_BLOCK_BASE(XRFDC_DAC_TILE, Tile_Id, XRFDC_BLK_ID1), + XRFDC_DAC_MB_CFG_OFFSET, XRFDC_ALT_BOND_MASK, XRFDC_ENABLED << XRFDC_ALT_BOND_SHIFT); + XRFdc_ClrSetReg(InstancePtr, XRFDC_BLOCK_BASE(XRFDC_DAC_TILE, Tile_Id, XRFDC_BLK_ID2), + XRFDC_DAC_MB_CFG_OFFSET, XRFDC_ALT_BOND_MASK, XRFDC_ENABLED << XRFDC_ALT_BOND_SHIFT); + } + + if (BlockIndex[0] != DataPathIndex[0]) { + metal_log(METAL_LOG_ERROR, "\n Not a valid MB/SB " + "combination in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + /* UPdate MultibandConfig in driver instance */ + Status = XRFdc_UpdateMBConfig(InstancePtr, Type, Tile_Id, NoOfDataPaths, &Mode, + DataPathIndex); + if (Status != XRFDC_SUCCESS) { + goto RETURN_PATH; + } + + if ((MixerInOutDataType == XRFDC_MB_DATATYPE_C2C) && (Mode == XRFDC_SINGLEBAND_MODE)) { + /* Singleband C2C */ + XRFdc_SB_C2C(InstancePtr, Type, Tile_Id, MixerInOutDataType, Mode, + DataPathIndex, BlockIndex); + } else if (((MixerInOutDataType == XRFDC_MB_DATATYPE_R2C) || + (MixerInOutDataType == XRFDC_MB_DATATYPE_C2R)) && (Mode == XRFDC_SINGLEBAND_MODE)) { + /* Singleband R2C and C2R */ + XRFdc_SB_R2C_C2R(InstancePtr, Type, Tile_Id, MixerInOutDataType, Mode, + DataPathIndex, BlockIndex); + } + if ((MixerInOutDataType == XRFDC_MB_DATATYPE_C2C) && + ((Mode == XRFDC_MULTIBAND_MODE_2X) || (Mode == XRFDC_MULTIBAND_MODE_4X))) { + /* Multiband C2C */ + XRFdc_MB_C2C(InstancePtr, Type, Tile_Id, NoOfDataPaths, MixerInOutDataType, Mode, + DataPathIndex, BlockIndex); + } else if (((MixerInOutDataType == XRFDC_MB_DATATYPE_R2C) || (MixerInOutDataType == XRFDC_MB_DATATYPE_C2R)) && + ((Mode == XRFDC_MULTIBAND_MODE_2X) || (Mode == XRFDC_MULTIBAND_MODE_4X))) { + /* Multiband C2R and R2C */ + XRFdc_MB_R2C_C2R(InstancePtr, Type, Tile_Id, NoOfDataPaths, MixerInOutDataType, + Mode, DataPathIndex, BlockIndex); + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} +/*****************************************************************************/ +/** +* +* Sets up signal flow configuration. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param Mode is connection mode SB/MB_2X/MB_4X. +* @param DigitalDataPathId for the requested I or Q data. +* @param MixerInOutDataType is mixer data type, valid values are XRFDC_MB_DATATYPE_* +* @param ConnectIData is analog blocks that are connected to +* DigitalDataPath I. +* @param ConnectQData is analog blocks that are connected to +* DigitalDataPath Q. +* +* @return None +* +* @note static API used internally. +* +******************************************************************************/ +static void XRFdc_SetSignalFlow(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 Mode, u32 DigitalDataPathId, u32 MixerInOutDataType, + int ConnectIData, int ConnectQData) +{ + u16 ReadReg; + u32 BaseAddr; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + BaseAddr = XRFDC_BLOCK_BASE(Type, Tile_Id, DigitalDataPathId); + if (Type == XRFDC_ADC_TILE) { + /* ADC */ + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_ADC_SWITCH_MATRX_OFFSET); + ReadReg &= ~XRFDC_SWITCH_MTRX_MASK; + if (ConnectIData != -1) { + ReadReg |= ((u16)ConnectIData) << XRFDC_SEL_CB_TO_MIX0_SHIFT; + } + if (ConnectQData != -1) { + ReadReg |= (u16)ConnectQData; + } + if ((MixerInOutDataType == XRFDC_MB_DATATYPE_C2C) && + (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1)) { + ReadReg |= XRFDC_SEL_CB_TO_QMC_MASK; + } + if (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) { + ReadReg |= XRFDC_SEL_CB_TO_DECI_MASK; + } + + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_SWITCH_MATRX_OFFSET, ReadReg); + } else { + /* DAC */ + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_DAC_MB_CFG_OFFSET); + ReadReg &= ~XRFDC_MB_CFG_MASK; + if (Mode == XRFDC_SINGLEBAND_MODE) { + if ((u32)ConnectIData == DigitalDataPathId) { + if (ConnectQData != -1) { + ReadReg |= XRFDC_SB_C2C_BLK0; + } else { + ReadReg |= XRFDC_SB_C2R; + } + } + if ((ConnectIData == -1) && (ConnectQData == -1)) { + ReadReg |= XRFDC_SB_C2C_BLK1; + } + } else { + if (Mode == XRFDC_MULTIBAND_MODE_4X) { + ReadReg |= XRFDC_MB_EN_4X_MASK; + } + if ((u32)ConnectIData == DigitalDataPathId) { + if (ConnectQData != -1) { + ReadReg |= XRFDC_MB_C2C_BLK0; + } else { + ReadReg |= XRFDC_MB_C2R_BLK0; + } + } else { + if (ConnectQData != -1) { + ReadReg |= XRFDC_MB_C2C_BLK1; + } else { + ReadReg |= XRFDC_MB_C2R_BLK1; + } + } + } + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_DAC_MB_CFG_OFFSET, ReadReg); + } +} + +/** @} */
\ No newline at end of file diff --git a/mpm/lib/rfdc/xrfdc_mixer.c b/mpm/lib/rfdc/xrfdc_mixer.c new file mode 100644 index 000000000..747e180a4 --- /dev/null +++ b/mpm/lib/rfdc/xrfdc_mixer.c @@ -0,0 +1,1091 @@ +/****************************************************************************** +* +* Copyright (C) 2018-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_mixer.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 +* ----- --- -------- ----------------------------------------------- +* 5.0 sk 08/06/18 Initial release +* 5.1 cog 01/29/19 Replace structure reference ADC checks with +* function. +* cog 01/29/19 XRFdc_SetCoarseMixer and MixerRangeCheck now need +* Tile_id as a parameter. +* cog 01/29/19 Rename DataType to MixerInputDataType for +* readability. +* </pre> +* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include "mpm/rfdc/xrfdc.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ +static void XRFdc_SetFineMixer(XRFdc *InstancePtr, u32 BaseAddr, + XRFdc_Mixer_Settings *MixerSettingsPtr); +static void XRFdc_SetCoarseMixer(XRFdc *InstancePtr, u32 Type, u32 BaseAddr, + u32 Tile_Id, u32 Block_Id, u32 CoarseMixFreq, XRFdc_Mixer_Settings *MixerSettingsPtr); +static u32 XRFdc_MixerRangeCheck(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + XRFdc_Mixer_Settings *MixerSettingsPtr); + +/************************** Function Prototypes ******************************/ + +/*****************************************************************************/ +/** +* The API is used to update various mixer settings, fine, coarse, NCO etc. +* Mixer/NCO settings passed are used to update the corresponding +* block level registers. Driver structure is updated with the new values. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param MixerSettingsPtr Pointer to the XRFdc_Mixer_Settings structure +* in which the Mixer/NCO settings are passed. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note FineMixerScale in Mixer_Settings structure can have 3 values. +* XRFDC_MIXER_SCALE_* represents the valid values. +* XRFDC_MIXER_SCALE_AUTO - If mixer mode is R2C, Mixer Scale is +* set to 1 and for other modes mixer scale is set to 0.7 +* XRFDC_MIXER_SCALE_1P0 - To set fine mixer scale to 1. +* XRFDC_MIXER_SCALE_0P7 - To set fine mixer scale to 0.7. +* +******************************************************************************/ +u32 XRFdc_SetMixerSettings(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 Block_Id, XRFdc_Mixer_Settings *MixerSettingsPtr) +{ + u32 Status; + u16 ReadReg; + u32 BaseAddr; + double SamplingRate; + s64 Freq; + s32 PhaseOffset; + u32 NoOfBlocks; + u32 Index; + XRFdc_Mixer_Settings *MixerConfigPtr; + u8 CalibrationMode = 0U; + u32 CoarseMixFreq; + double NCOFreq; + u32 NyquistZone = 0U; + u32 Offset; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(MixerSettingsPtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckDigitalPathEnabled(InstancePtr, Type, Tile_Id, Block_Id); + if (Status != XRFDC_SUCCESS) { + goto RETURN_PATH; + } + + Status = XRFdc_MixerRangeCheck(InstancePtr, Type, Tile_Id, MixerSettingsPtr); + if (Status != XRFDC_SUCCESS) { + goto RETURN_PATH; + } + + Index = Block_Id; + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Type == XRFDC_ADC_TILE)) { + NoOfBlocks = XRFDC_NUM_OF_BLKS2; + if (Block_Id == XRFDC_BLK_ID1) { + Index = XRFDC_BLK_ID2; + NoOfBlocks = XRFDC_NUM_OF_BLKS4; + } + } else { + NoOfBlocks = Block_Id + 1U; + } + + for (; Index < NoOfBlocks; Index++) { + if (Type == XRFDC_ADC_TILE) { + /* ADC */ + MixerConfigPtr = &InstancePtr->ADC_Tile[Tile_Id]. + ADCBlock_Digital_Datapath[Index].Mixer_Settings; + SamplingRate = InstancePtr->ADC_Tile[Tile_Id]. + PLL_Settings.SampleRate; + } else { + /* DAC */ + MixerConfigPtr = &InstancePtr->DAC_Tile[Tile_Id]. + DACBlock_Digital_Datapath[Index].Mixer_Settings; + SamplingRate = InstancePtr->DAC_Tile[Tile_Id]. + PLL_Settings.SampleRate; + } + + BaseAddr = XRFDC_BLOCK_BASE(Type, Tile_Id, Index); + + if (SamplingRate <= 0) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, "\n Incorrect Sampling " + "rate in %s\r\n", __func__); + goto RETURN_PATH; + } else { + metal_log(METAL_LOG_DEBUG, "\n Sampling " + "rate is %2.4f in %s\r\n", SamplingRate, __func__); + } + + SamplingRate *= XRFDC_MILLI; + /* Set MixerInputDataType for ADC and DAC */ + if (Type == XRFDC_DAC_TILE) { + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_DAC_ITERP_DATA_OFFSET); + ReadReg &= ~XRFDC_DAC_INTERP_DATA_MASK; + InstancePtr->DAC_Tile[Tile_Id]. + DACBlock_Digital_Datapath[Index].MixerInputDataType = + XRFDC_DATA_TYPE_REAL; + if ((MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_C2C) || + (MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_C2R)) { + ReadReg |= XRFDC_DAC_INTERP_DATA_MASK; + InstancePtr->DAC_Tile[Tile_Id]. + DACBlock_Digital_Datapath[Index]. + MixerInputDataType = XRFDC_DATA_TYPE_IQ; + } + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_DAC_ITERP_DATA_OFFSET, ReadReg); + } else { + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_ADC_DECI_CONFIG_OFFSET); + ReadReg &= ~XRFDC_DEC_CFG_MASK; + if (XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) { + ReadReg |= XRFDC_DEC_CFG_4GSPS_MASK; + } else if ((MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_C2C) || + (MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_R2C)) { + ReadReg |= XRFDC_DEC_CFG_IQ_MASK; + } else { + ReadReg |= XRFDC_DEC_CFG_CHA_MASK; + } + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_DECI_CONFIG_OFFSET, ReadReg); + if (MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_C2C) { + InstancePtr->ADC_Tile[Tile_Id]. + ADCBlock_Digital_Datapath[Index]. + MixerInputDataType = XRFDC_DATA_TYPE_IQ; + } + if ((MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_R2C) || + (MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_R2R)) { + InstancePtr->ADC_Tile[Tile_Id]. + ADCBlock_Digital_Datapath[Index]. + MixerInputDataType = XRFDC_DATA_TYPE_REAL; + } + } + + /* Set NCO Phase Mode */ + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Type == XRFDC_ADC_TILE)) { + if ((Index == XRFDC_BLK_ID0) || (Index == XRFDC_BLK_ID2)) { + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_NCO_PHASE_MOD_OFFSET, + XRFDC_NCO_PHASE_MOD_EVEN); + } else { + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_NCO_PHASE_MOD_OFFSET, + XRFDC_NCO_PHASE_MODE_ODD); + } + } + + /* Update NCO, CoarseMix freq based on calibration mode */ + CoarseMixFreq = MixerSettingsPtr->CoarseMixFreq; + NCOFreq = MixerSettingsPtr->Freq; + if (Type == XRFDC_ADC_TILE) { + Status = XRFdc_GetCalibrationMode(InstancePtr, + Tile_Id, Block_Id, &CalibrationMode); + if (Status != XRFDC_SUCCESS) { + return XRFDC_FAILURE; + } + if (CalibrationMode == XRFDC_CALIB_MODE1) { + switch (CoarseMixFreq) { + case XRFDC_COARSE_MIX_BYPASS: + CoarseMixFreq = + XRFDC_COARSE_MIX_SAMPLE_FREQ_BY_TWO; + break; + case XRFDC_COARSE_MIX_SAMPLE_FREQ_BY_FOUR: + CoarseMixFreq = + XRFDC_COARSE_MIX_MIN_SAMPLE_FREQ_BY_FOUR; + break; + case XRFDC_COARSE_MIX_SAMPLE_FREQ_BY_TWO: + CoarseMixFreq = + XRFDC_COARSE_MIX_BYPASS; + break; + case XRFDC_COARSE_MIX_MIN_SAMPLE_FREQ_BY_FOUR: + CoarseMixFreq = + XRFDC_COARSE_MIX_SAMPLE_FREQ_BY_FOUR; + break; + default: + CoarseMixFreq = + XRFDC_COARSE_MIX_OFF; + break; + } + NCOFreq -= SamplingRate / 2.0; + } + } + + if ((NCOFreq < -(SamplingRate / 2.0)) || + (NCOFreq > (SamplingRate / 2.0))) { + Status = XRFdc_GetNyquistZone(InstancePtr, Type, + Tile_Id, Block_Id, &NyquistZone); + if (Status != XRFDC_SUCCESS) { + return XRFDC_FAILURE; + } + do { + if (NCOFreq < -(SamplingRate / 2.0)) { + NCOFreq += SamplingRate; + } + if (NCOFreq > (SamplingRate / 2.0)) { + NCOFreq -= SamplingRate; + } + } while ((NCOFreq < -(SamplingRate / 2.0)) || + (NCOFreq > (SamplingRate / 2.0))); + + if ((NyquistZone == XRFDC_EVEN_NYQUIST_ZONE) && + (NCOFreq != 0)) { + NCOFreq *= -1; + } + } + + /* NCO Frequency */ + if (NCOFreq < 0) { + Freq = ((NCOFreq * XRFDC_NCO_FREQ_MIN_MULTIPLIER) / + SamplingRate); + } else { + Freq = ((NCOFreq * XRFDC_NCO_FREQ_MULTIPLIER) / + SamplingRate); + } + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_NCO_FQWD_LOW_OFFSET, (u16)Freq); + ReadReg = (Freq >> XRFDC_NCO_FQWD_MID_SHIFT) & XRFDC_NCO_FQWD_MID_MASK; + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_NCO_FQWD_MID_OFFSET, (u16)ReadReg); + ReadReg = (Freq >> XRFDC_NCO_FQWD_UPP_SHIFT) & XRFDC_NCO_FQWD_UPP_MASK; + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_NCO_FQWD_UPP_OFFSET, (u16)ReadReg); + + /* Phase Offset */ + PhaseOffset = ((MixerSettingsPtr->PhaseOffset * + XRFDC_NCO_PHASE_MULTIPLIER) / XRFDC_MIXER_PHASE_OFFSET_UP_LIMIT); + XRFdc_WriteReg16(InstancePtr, BaseAddr, XRFDC_NCO_PHASE_LOW_OFFSET, + (u16)PhaseOffset); + + ReadReg = (PhaseOffset >> XRFDC_NCO_PHASE_UPP_SHIFT) & + XRFDC_NCO_PHASE_UPP_MASK; + XRFdc_WriteReg16(InstancePtr, BaseAddr, XRFDC_NCO_PHASE_UPP_OFFSET, + ReadReg); + + if (MixerSettingsPtr->MixerType == XRFDC_MIXER_TYPE_COARSE) { + XRFdc_SetCoarseMixer(InstancePtr, Type, BaseAddr, Tile_Id, + Index, CoarseMixFreq, MixerSettingsPtr); + } else { + XRFdc_SetFineMixer(InstancePtr, BaseAddr, MixerSettingsPtr); + } + + /* Fine Mixer Scale */ + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_MXR_MODE_OFFSET); + if (MixerSettingsPtr->FineMixerScale == XRFDC_MIXER_SCALE_1P0) { + ReadReg |= XRFDC_FINE_MIX_SCALE_MASK; + InstancePtr->UpdateMixerScale = 0x1U; + } else if (MixerSettingsPtr->FineMixerScale == XRFDC_MIXER_SCALE_0P7) { + ReadReg &= ~XRFDC_FINE_MIX_SCALE_MASK; + InstancePtr->UpdateMixerScale = 0x1U; + } else { + InstancePtr->UpdateMixerScale = 0x0U; + } + XRFdc_WriteReg16(InstancePtr, BaseAddr, XRFDC_MXR_MODE_OFFSET, + ReadReg); + + /* Event Source */ + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_NCO_UPDT_OFFSET, + XRFDC_NCO_UPDT_MODE_MASK, MixerSettingsPtr->EventSource); + if (MixerSettingsPtr->EventSource == XRFDC_EVNT_SRC_IMMEDIATE) { + if (Type == XRFDC_ADC_TILE) { + Offset = XRFDC_ADC_UPDATE_DYN_OFFSET; + } else { + Offset = XRFDC_DAC_UPDATE_DYN_OFFSET; + } + XRFdc_ClrSetReg(InstancePtr, BaseAddr, Offset, + XRFDC_UPDT_EVNT_MASK, XRFDC_UPDT_EVNT_NCO_MASK); + } + + /* Update the instance with new values */ + MixerConfigPtr->EventSource = MixerSettingsPtr->EventSource; + MixerConfigPtr->PhaseOffset = MixerSettingsPtr->PhaseOffset; + MixerConfigPtr->MixerMode = MixerSettingsPtr->MixerMode; + MixerConfigPtr->CoarseMixFreq = MixerSettingsPtr->CoarseMixFreq; + MixerConfigPtr->Freq = MixerSettingsPtr->Freq; + MixerConfigPtr->MixerType = MixerSettingsPtr->MixerType; + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* Static API used to do the Mixer Settings range check. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param MixerSettingsPtr Pointer to the XRFdc_Mixer_Settings structure +* in which the Mixer/NCO settings are passed. +* +* @return +* - XRFDC_SUCCESS if mixer settings are within the range. +* - XRFDC_FAILURE if mixer settings are not in valid range +* +* @note None +* +******************************************************************************/ +static u32 XRFdc_MixerRangeCheck(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + XRFdc_Mixer_Settings *MixerSettingsPtr) +{ + u32 Status; + + if ((MixerSettingsPtr->PhaseOffset >= + XRFDC_MIXER_PHASE_OFFSET_UP_LIMIT) || + (MixerSettingsPtr->PhaseOffset <= + XRFDC_MIXER_PHASE_OFFSET_LOW_LIMIT)) { + metal_log(METAL_LOG_ERROR, "\n Invalid phase offset value " + "in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + if ((MixerSettingsPtr->EventSource > XRFDC_EVNT_SRC_PL) || + ((MixerSettingsPtr->EventSource == XRFDC_EVNT_SRC_MARKER) && + (Type == XRFDC_ADC_TILE))) { + metal_log(METAL_LOG_ERROR, "\n Invalid event source " + "selection in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + if (MixerSettingsPtr->MixerMode > XRFDC_MIXER_MODE_R2R) { + metal_log(METAL_LOG_ERROR, "\n Invalid fine mixer mode " + "in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + if ((MixerSettingsPtr->CoarseMixFreq != XRFDC_COARSE_MIX_OFF) && + (MixerSettingsPtr->CoarseMixFreq != + XRFDC_COARSE_MIX_SAMPLE_FREQ_BY_TWO) && + (MixerSettingsPtr->CoarseMixFreq != + XRFDC_COARSE_MIX_SAMPLE_FREQ_BY_FOUR) && + (MixerSettingsPtr->CoarseMixFreq != + XRFDC_COARSE_MIX_MIN_SAMPLE_FREQ_BY_FOUR) && + (MixerSettingsPtr->CoarseMixFreq != + XRFDC_COARSE_MIX_BYPASS)) { + metal_log(METAL_LOG_ERROR, "\n Invalid coarse mix " + "frequency value in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + if (MixerSettingsPtr->FineMixerScale > XRFDC_MIXER_SCALE_0P7) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, + "\n Invalid Mixer Scale in %s\r\n", __func__); + goto RETURN_PATH; + } + if (((MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_R2C) && + (Type == XRFDC_DAC_TILE)) || + ((MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_C2R) && + (Type == XRFDC_ADC_TILE))) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, + "\n Invalid Mixer mode in %s\r\n", __func__); + goto RETURN_PATH; + } + if ((MixerSettingsPtr->MixerType != XRFDC_MIXER_TYPE_FINE) && + (MixerSettingsPtr->MixerType != XRFDC_MIXER_TYPE_COARSE)) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, + "\n Invalid Mixer Type in %s\r\n", __func__); + goto RETURN_PATH; + } + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Type == XRFDC_ADC_TILE) && + ((MixerSettingsPtr->EventSource == XRFDC_EVNT_SRC_SLICE) || + (MixerSettingsPtr->EventSource == + XRFDC_EVNT_SRC_IMMEDIATE))) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, "\n Invalid Event Source, event " + "source is not supported in 4GSPS ADC %s\r\n", __func__); + goto RETURN_PATH; + } + if (((MixerSettingsPtr->MixerType == XRFDC_MIXER_TYPE_COARSE) && + (MixerSettingsPtr->CoarseMixFreq == XRFDC_COARSE_MIX_OFF)) || + ((MixerSettingsPtr->MixerType == XRFDC_MIXER_TYPE_FINE) && + (MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_OFF))) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, "\n Invalid Combination of " + "Mixer settings in %s\r\n", __func__); + goto RETURN_PATH; + } + if ((MixerSettingsPtr->MixerType == XRFDC_MIXER_TYPE_COARSE) && + (MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_OFF)) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, "\n Invalid Combination of " + "Mixer type and Mixer mode in %s\r\n", __func__); + goto RETURN_PATH; + } + if ((MixerSettingsPtr->MixerType == XRFDC_MIXER_TYPE_FINE) && + (MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_R2R)) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, "\n Invalid Combination of " + "Mixer type and Mixer mode in %s\r\n", __func__); + goto RETURN_PATH; + } + if ((MixerSettingsPtr->MixerType == XRFDC_MIXER_TYPE_COARSE) && + (MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_R2R) && + (MixerSettingsPtr->CoarseMixFreq != XRFDC_COARSE_MIX_BYPASS)) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, "\n Invalid Combination of " + "Mixer type and Mixer mode in %s\r\n", __func__); + goto RETURN_PATH; + } + + Status = XRFDC_SUCCESS; + +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* Static API used to set the Fine Mixer. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param BaseAddr is ADC or DAC base address. +* @param CoarseMixFreq is ADC or DAC Coarse mixer frequency. +* @param MixerSettingsPtr Pointer to the XRFdc_Mixer_Settings structure +* in which the Mixer/NCO settings are passed. +* +* @return +* - None +* +* @note Static API +* +******************************************************************************/ +static void XRFdc_SetFineMixer(XRFdc *InstancePtr, u32 BaseAddr, + XRFdc_Mixer_Settings *MixerSettingsPtr) +{ + + if (MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_C2C) { + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_MXR_MODE_OFFSET, + (XRFDC_SEL_I_IQ_MASK | XRFDC_SEL_Q_IQ_MASK | + XRFDC_EN_I_IQ_MASK | XRFDC_EN_Q_IQ_MASK), + (XRFDC_EN_I_IQ_MASK | XRFDC_EN_Q_IQ_MASK | + XRFDC_I_IQ_COS_MINSIN | XRFDC_Q_IQ_SIN_COS)); + } else if (MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_C2R) { + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_MXR_MODE_OFFSET, + (XRFDC_EN_I_IQ_MASK | XRFDC_SEL_I_IQ_MASK | XRFDC_EN_Q_IQ_MASK), + (XRFDC_EN_I_IQ_MASK | XRFDC_I_IQ_COS_MINSIN)); + } else if (MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_R2C) { + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_MXR_MODE_OFFSET, + (XRFDC_EN_I_IQ_MASK | XRFDC_EN_Q_IQ_MASK | + XRFDC_SEL_I_IQ_MASK | XRFDC_SEL_Q_IQ_MASK | + XRFDC_FINE_MIX_SCALE_MASK), (XRFDC_EN_I_IQ | XRFDC_EN_Q_IQ | + XRFDC_I_IQ_COS_MINSIN | XRFDC_Q_IQ_SIN_COS | + XRFDC_FINE_MIX_SCALE_MASK)); + } else { + /* Fine mixer mode is OFF */ + XRFdc_WriteReg16(InstancePtr, BaseAddr, XRFDC_MXR_MODE_OFFSET, + XRFDC_MIXER_MODE_OFF); + } + + /* Coarse Mixer is OFF */ + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_MXR_CFG0_OFFSET, + XRFDC_MIX_CFG0_MASK, XRFDC_CRSE_MIX_OFF); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_MXR_CFG1_OFFSET, + XRFDC_MIX_CFG1_MASK, XRFDC_CRSE_MIX_OFF); +} + +/*****************************************************************************/ +/** +* Static API used to set the Coarse Mixer. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param BaseAddr is ADC or DAC base address. +* @param Block_Id is ADC/DAC block number inside the tile. +* @param CoarseMixFreq is ADC or DAC Coarse mixer frequency. +* @param MixerSettingsPtr Pointer to the XRFdc_Mixer_Settings structure +* in which the Mixer/NCO settings are passed. +* +* @return +* - None +* +* @note Static API +* +******************************************************************************/ +static void XRFdc_SetCoarseMixer(XRFdc *InstancePtr, u32 Type, u32 BaseAddr, + u32 Tile_Id, u32 Block_Id, u32 CoarseMixFreq, XRFdc_Mixer_Settings *MixerSettingsPtr) +{ + u16 ReadReg; + + if (CoarseMixFreq == XRFDC_COARSE_MIX_BYPASS) { + /* Coarse Mix BYPASS */ + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_MXR_CFG0_OFFSET, + XRFDC_MIX_CFG0_MASK, XRFDC_CRSE_MIX_BYPASS); + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_ADC_MXR_CFG1_OFFSET); + ReadReg &= ~XRFDC_MIX_CFG1_MASK; + if ((MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_C2C) || + (MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_C2R)) { + ReadReg |= XRFDC_CRSE_MIX_BYPASS; + } else { + ReadReg |= XRFDC_CRSE_MIX_OFF; + } + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_MXR_CFG1_OFFSET, (u16)ReadReg); + } else if (CoarseMixFreq == XRFDC_COARSE_MIX_SAMPLE_FREQ_BY_TWO) { + /* Coarse Mix freq Fs/2 */ + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_ADC_MXR_CFG0_OFFSET); + ReadReg &= ~XRFDC_MIX_CFG0_MASK; + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 0) || + (Type == XRFDC_DAC_TILE)) { + ReadReg |= XRFDC_CRSE_MIX_I_Q_FSBYTWO; + } else { + if ((Block_Id % 2U) == 0U) { + ReadReg |= XRFDC_CRSE_MIX_BYPASS; + } else { + ReadReg |= XRFDC_CRSE_4GSPS_ODD_FSBYTWO; + } + } + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_MXR_CFG0_OFFSET, (u16)ReadReg); + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_ADC_MXR_CFG1_OFFSET); + ReadReg &= ~XRFDC_MIX_CFG1_MASK; + if ((MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_C2C) || + (MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_C2R)) { + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 0) || + (Type == XRFDC_DAC_TILE)) { + ReadReg |= XRFDC_CRSE_MIX_I_Q_FSBYTWO; + } else { + ReadReg |= ((Block_Id % 2U) == 0U) ? + XRFDC_CRSE_MIX_BYPASS : + XRFDC_CRSE_4GSPS_ODD_FSBYTWO; + } + } else { + ReadReg |= XRFDC_CRSE_MIX_OFF; + } + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_MXR_CFG1_OFFSET, (u16)ReadReg); + } else if (CoarseMixFreq == XRFDC_COARSE_MIX_SAMPLE_FREQ_BY_FOUR) { + /* Coarse Mix freq Fs/4 */ + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_ADC_MXR_CFG0_OFFSET); + ReadReg &= ~XRFDC_MIX_CFG0_MASK; + if ((MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_C2C) || + (MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_C2R)) { + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 0) || + (Type == XRFDC_DAC_TILE)) { + ReadReg |= XRFDC_CRSE_MIX_I_FSBYFOUR; + } else { + ReadReg |= ((Block_Id % 2U) == 0U) ? + XRFDC_CRSE_MIX_I_Q_FSBYTWO : + XRFDC_CRSE_MIX_I_ODD_FSBYFOUR; + } + } else { + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 0) || + (Type == XRFDC_DAC_TILE)) { + ReadReg |= XRFDC_CRSE_MIX_R_I_FSBYFOUR; + } else { + ReadReg |= ((Block_Id % 2U) == 0U) ? + XRFDC_CRSE_MIX_I_Q_FSBYTWO : + XRFDC_CRSE_MIX_OFF; + } + } + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_MXR_CFG0_OFFSET, (u16)ReadReg); + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_ADC_MXR_CFG1_OFFSET); + ReadReg &= ~XRFDC_MIX_CFG1_MASK; + if ((MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_C2C) || + (MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_C2R)) { + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 0) || + (Type == XRFDC_DAC_TILE)) { + ReadReg |= XRFDC_CRSE_MIX_Q_FSBYFOUR; + } else { + ReadReg |= ((Block_Id % 2U) == 0U) ? + XRFDC_CRSE_MIX_I_Q_FSBYTWO : + XRFDC_CRSE_MIX_Q_ODD_FSBYFOUR; + } + } else { + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 0) || + (Type == XRFDC_DAC_TILE)) { + ReadReg |= XRFDC_CRSE_MIX_R_Q_FSBYFOUR; + } else { + ReadReg |= ((Block_Id % 2U) == 0U) ? + XRFDC_CRSE_MIX_OFF : + XRFDC_CRSE_MIX_Q_ODD_FSBYFOUR; + } + } + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_MXR_CFG1_OFFSET, (u16)ReadReg); + } else if (CoarseMixFreq == XRFDC_COARSE_MIX_MIN_SAMPLE_FREQ_BY_FOUR) { + /* Coarse Mix freq -Fs/4 */ + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_ADC_MXR_CFG0_OFFSET); + ReadReg &= ~XRFDC_MIX_CFG0_MASK; + if ((MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_C2C) || + (MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_C2R)) { + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 0) || + (Type == XRFDC_DAC_TILE)) { + ReadReg |= XRFDC_CRSE_MIX_I_MINFSBYFOUR; + } else { + ReadReg |= ((Block_Id % 2U) == 0U) ? + XRFDC_CRSE_MIX_I_Q_FSBYTWO : + XRFDC_CRSE_MIX_Q_ODD_FSBYFOUR; + } + } else { + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 0) || + (Type == XRFDC_DAC_TILE)) { + ReadReg |= XRFDC_CRSE_MIX_R_I_MINFSBYFOUR; + } else { + ReadReg |= ((Block_Id % 2U) == 0U) ? + XRFDC_CRSE_MIX_I_Q_FSBYTWO : + XRFDC_CRSE_MIX_OFF; + } + } + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_MXR_CFG0_OFFSET, (u16)ReadReg); + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_ADC_MXR_CFG1_OFFSET); + ReadReg &= ~XRFDC_MIX_CFG1_MASK; + if ((MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_C2C) || + (MixerSettingsPtr->MixerMode == XRFDC_MIXER_MODE_C2R)) { + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 0) || + (Type == XRFDC_DAC_TILE)) { + ReadReg |= XRFDC_CRSE_MIX_Q_MINFSBYFOUR; + } else { + ReadReg |= ((Block_Id % 2U) == 0U) ? + XRFDC_CRSE_MIX_I_Q_FSBYTWO : + XRFDC_CRSE_MIX_I_ODD_FSBYFOUR; + } + } else { + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 0) || + (Type == XRFDC_DAC_TILE)) { + ReadReg |= XRFDC_CRSE_MIX_R_Q_MINFSBYFOUR; + } else { + ReadReg |= ((Block_Id % 2U) == 0U) ? + XRFDC_CRSE_MIX_OFF : + XRFDC_CRSE_MIX_I_ODD_FSBYFOUR; + } + } + XRFdc_WriteReg16(InstancePtr, BaseAddr, + XRFDC_ADC_MXR_CFG1_OFFSET, (u16)ReadReg); + } else if (CoarseMixFreq == XRFDC_COARSE_MIX_OFF) { + /* Coarse Mix OFF */ + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_MXR_CFG0_OFFSET, + XRFDC_MIX_CFG0_MASK, XRFDC_CRSE_MIX_OFF); + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_ADC_MXR_CFG1_OFFSET, + XRFDC_MIX_CFG1_MASK, XRFDC_CRSE_MIX_OFF); + } else { + metal_log(METAL_LOG_ERROR, "\n Invalid Coarse " + "Mixer frequency in %s\r\n", __func__); + } + + /* Fine mixer mode is OFF */ + XRFdc_WriteReg16(InstancePtr, BaseAddr, XRFDC_MXR_MODE_OFFSET, + XRFDC_MIXER_MODE_OFF); +} + +/*****************************************************************************/ +/** +* +* The API returns back Mixer/NCO settings to the caller. +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param Block_Id is ADC/DAC block number inside the tile. Valid values +* are 0-3. +* @param MixerSettingsPtr Pointer to the XRFdc_Mixer_Settings structure +* in which the Mixer/NCO settings are passed. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_FAILURE if Block not enabled. +* +* @note FineMixerScale in Mixer_Settings structure can have 3 values. +* XRFDC_MIXER_SCALE_* represents the valid values. +* XRFDC_MIXER_SCALE_AUTO - If mixer mode is R2C, Mixer Scale is +* set to 1 and for other modes mixer scale is set to 0.7 +* XRFDC_MIXER_SCALE_1P0 - To set fine mixer scale to 1. +* XRFDC_MIXER_SCALE_0P7 - To set fine mixer scale to 0.7. +* +******************************************************************************/ +u32 XRFdc_GetMixerSettings(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 Block_Id, XRFdc_Mixer_Settings *MixerSettingsPtr) +{ + u32 Status; + u32 BaseAddr; + u64 ReadReg; + u64 ReadReg_Mix1; + double SamplingRate; + s64 Freq; + s32 PhaseOffset; + u32 Block; + u8 CalibrationMode = 0U; + XRFdc_Mixer_Settings *MixerConfigPtr; + u32 NyquistZone = 0U; + double NCOFreq; + u32 FineMixerMode; + u32 CoarseMixerMode = 0x0; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(MixerSettingsPtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + Status = XRFdc_CheckDigitalPathEnabled(InstancePtr, Type, Tile_Id, Block_Id); + if (Status != XRFDC_SUCCESS) { + goto RETURN_PATH; + } + + Block = Block_Id; + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 1) && + (Type == XRFDC_ADC_TILE)) { + if (Block_Id == XRFDC_BLK_ID1) { + Block_Id = XRFDC_BLK_ID3; + } + if (Block_Id == XRFDC_BLK_ID0) { + Block_Id = XRFDC_BLK_ID1; + } + } + + if (Type == XRFDC_ADC_TILE) { + /* ADC */ + SamplingRate = InstancePtr->ADC_Tile[Tile_Id].PLL_Settings. + SampleRate; + MixerConfigPtr = &InstancePtr->ADC_Tile[Tile_Id]. + ADCBlock_Digital_Datapath[Block_Id].Mixer_Settings; + } else { + /* DAC */ + SamplingRate = InstancePtr->DAC_Tile[Tile_Id].PLL_Settings. + SampleRate; + MixerConfigPtr = &InstancePtr->DAC_Tile[Tile_Id]. + DACBlock_Digital_Datapath[Block_Id].Mixer_Settings; + } + + if (SamplingRate <= 0) { + Status = XRFDC_FAILURE; + metal_log(METAL_LOG_ERROR, "\n Incorrect Sampling rate " + "in %s\r\n", __func__); + goto RETURN_PATH; + } + + BaseAddr = XRFDC_BLOCK_BASE(Type, Tile_Id, Block_Id); + SamplingRate *= XRFDC_MILLI; + ReadReg = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_ADC_MXR_CFG0_OFFSET, XRFDC_MIX_CFG0_MASK); + ReadReg_Mix1 = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_ADC_MXR_CFG1_OFFSET, XRFDC_MIX_CFG1_MASK); + MixerSettingsPtr->CoarseMixFreq = 0x20; + + /* Identify CoarseMixFreq and CoarseMixerMode */ + if (ReadReg == XRFDC_CRSE_MIX_BYPASS) { + if (ReadReg_Mix1 == XRFDC_CRSE_MIX_BYPASS) { + MixerSettingsPtr->CoarseMixFreq = + XRFDC_COARSE_MIX_BYPASS; + CoarseMixerMode = XRFDC_MIXER_MODE_C2C; + } else if (ReadReg_Mix1 == XRFDC_CRSE_MIX_OFF) { + MixerSettingsPtr->CoarseMixFreq = + XRFDC_COARSE_MIX_BYPASS; + CoarseMixerMode = XRFDC_MIXER_MODE_R2R; + if (MixerConfigPtr->MixerMode == XRFDC_MIXER_MODE_R2C) { + CoarseMixerMode = XRFDC_MIXER_MODE_R2C; + } + } + } + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 0) || + (Type == XRFDC_DAC_TILE)) { + if ((ReadReg_Mix1 == XRFDC_CRSE_MIX_I_Q_FSBYTWO) && + (ReadReg == XRFDC_CRSE_MIX_I_Q_FSBYTWO)) { + MixerSettingsPtr->CoarseMixFreq = + XRFDC_COARSE_MIX_SAMPLE_FREQ_BY_TWO; + CoarseMixerMode = XRFDC_MIXER_MODE_C2C; + } else if ((ReadReg_Mix1 == XRFDC_CRSE_MIX_OFF) && + (ReadReg == XRFDC_CRSE_MIX_I_Q_FSBYTWO)) { + MixerSettingsPtr->CoarseMixFreq = + XRFDC_COARSE_MIX_SAMPLE_FREQ_BY_TWO; + CoarseMixerMode = XRFDC_MIXER_MODE_R2C; + } + } else { + if (ReadReg == XRFDC_CRSE_4GSPS_ODD_FSBYTWO) { + if (ReadReg_Mix1 == XRFDC_CRSE_4GSPS_ODD_FSBYTWO) { + MixerSettingsPtr->CoarseMixFreq = + XRFDC_COARSE_MIX_SAMPLE_FREQ_BY_TWO; + CoarseMixerMode = XRFDC_MIXER_MODE_C2C; + } else if (ReadReg_Mix1 == XRFDC_CRSE_MIX_OFF) { + MixerSettingsPtr->CoarseMixFreq = + XRFDC_COARSE_MIX_SAMPLE_FREQ_BY_TWO; + CoarseMixerMode = XRFDC_MIXER_MODE_R2C; + } + } + } + + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 0) || + (Type == XRFDC_DAC_TILE)) { + if ((ReadReg_Mix1 == XRFDC_CRSE_MIX_Q_FSBYFOUR) && + (ReadReg == XRFDC_CRSE_MIX_I_FSBYFOUR)) { + MixerSettingsPtr->CoarseMixFreq = + XRFDC_COARSE_MIX_SAMPLE_FREQ_BY_FOUR; + CoarseMixerMode = XRFDC_MIXER_MODE_C2C; + } else if ((ReadReg_Mix1 == + XRFDC_CRSE_MIX_R_Q_FSBYFOUR) && + (ReadReg == XRFDC_CRSE_MIX_R_I_MINFSBYFOUR)) { + MixerSettingsPtr->CoarseMixFreq = + XRFDC_COARSE_MIX_SAMPLE_FREQ_BY_FOUR; + CoarseMixerMode = XRFDC_MIXER_MODE_R2C; + } + } else { + if ((ReadReg == XRFDC_CRSE_MIX_I_ODD_FSBYFOUR) && + (ReadReg_Mix1 == XRFDC_CRSE_MIX_Q_ODD_FSBYFOUR)) { + MixerSettingsPtr->CoarseMixFreq = + XRFDC_COARSE_MIX_SAMPLE_FREQ_BY_FOUR; + CoarseMixerMode = XRFDC_MIXER_MODE_C2C; + } else if ((ReadReg == XRFDC_CRSE_MIX_OFF) && + (ReadReg_Mix1 == XRFDC_CRSE_MIX_Q_ODD_FSBYFOUR)) { + MixerSettingsPtr->CoarseMixFreq = + XRFDC_COARSE_MIX_SAMPLE_FREQ_BY_FOUR; + CoarseMixerMode = XRFDC_MIXER_MODE_R2C; + } + + } + + if ((XRFdc_IsHighSpeedADC(InstancePtr, Tile_Id) == 0) || + (Type == XRFDC_DAC_TILE)) { + if ((ReadReg_Mix1 == XRFDC_CRSE_MIX_I_FSBYFOUR) && + (ReadReg == XRFDC_CRSE_MIX_Q_FSBYFOUR)) { + MixerSettingsPtr->CoarseMixFreq = + XRFDC_COARSE_MIX_MIN_SAMPLE_FREQ_BY_FOUR; + CoarseMixerMode = XRFDC_MIXER_MODE_C2C; + } else if ((ReadReg_Mix1 == XRFDC_CRSE_MIX_R_Q_MINFSBYFOUR) && + (ReadReg == XRFDC_CRSE_MIX_R_I_MINFSBYFOUR)) { + MixerSettingsPtr->CoarseMixFreq = + XRFDC_COARSE_MIX_MIN_SAMPLE_FREQ_BY_FOUR; + CoarseMixerMode = XRFDC_MIXER_MODE_R2C; + } + } else { + if ((ReadReg == XRFDC_CRSE_MIX_Q_ODD_FSBYFOUR) && + (ReadReg_Mix1 == XRFDC_CRSE_MIX_I_ODD_FSBYFOUR)) { + MixerSettingsPtr->CoarseMixFreq = + XRFDC_COARSE_MIX_MIN_SAMPLE_FREQ_BY_FOUR; + CoarseMixerMode = XRFDC_MIXER_MODE_C2C; + } else if ((ReadReg == XRFDC_CRSE_MIX_OFF) && + (ReadReg_Mix1 == XRFDC_CRSE_MIX_I_ODD_FSBYFOUR)) { + MixerSettingsPtr->CoarseMixFreq = + XRFDC_COARSE_MIX_MIN_SAMPLE_FREQ_BY_FOUR; + CoarseMixerMode = XRFDC_MIXER_MODE_R2C; + } + + } + + if ((ReadReg == XRFDC_CRSE_MIX_OFF) && (ReadReg_Mix1 == + XRFDC_CRSE_MIX_OFF)) { + MixerSettingsPtr->CoarseMixFreq = XRFDC_COARSE_MIX_OFF; + CoarseMixerMode = XRFDC_MIXER_MODE_C2C; + } + if (MixerSettingsPtr->CoarseMixFreq == 0x20U) { + metal_log(METAL_LOG_ERROR, + "\n Coarse mixer settings not match any of the modes %s\r\n", + __func__); + } + if ((MixerConfigPtr->MixerMode == XRFDC_MIXER_MODE_C2R) && + (CoarseMixerMode == XRFDC_MIXER_MODE_C2C)) { + CoarseMixerMode = XRFDC_MIXER_MODE_C2R; + } + + /* Identify FineMixerMode */ + ReadReg = XRFdc_RDReg(InstancePtr, BaseAddr, XRFDC_MXR_MODE_OFFSET, + (XRFDC_EN_I_IQ_MASK | XRFDC_EN_Q_IQ_MASK)); + if (ReadReg == 0xFU) { + FineMixerMode = XRFDC_MIXER_MODE_C2C; + } else if (ReadReg == 0x3U) { + FineMixerMode = XRFDC_MIXER_MODE_C2R; + } else if (ReadReg == 0x5U) { + FineMixerMode = XRFDC_MIXER_MODE_R2C; + } else { + FineMixerMode = XRFDC_MIXER_MODE_OFF; + } + + if (FineMixerMode == XRFDC_MIXER_MODE_OFF) { + MixerSettingsPtr->MixerType = XRFDC_MIXER_TYPE_COARSE; + MixerSettingsPtr->MixerMode = CoarseMixerMode; + } else { + MixerSettingsPtr->MixerType = XRFDC_MIXER_TYPE_FINE; + MixerSettingsPtr->MixerMode = FineMixerMode; + } + + /* Identify Fine Mixer Scale */ + ReadReg = XRFdc_RDReg(InstancePtr, BaseAddr, + XRFDC_MXR_MODE_OFFSET, XRFDC_FINE_MIX_SCALE_MASK); + if (InstancePtr->UpdateMixerScale == 0x0U) { + MixerSettingsPtr->FineMixerScale = + XRFDC_MIXER_SCALE_AUTO; + } else if ((ReadReg != 0U) && + (InstancePtr->UpdateMixerScale == 0x1U)) { + MixerSettingsPtr->FineMixerScale = + XRFDC_MIXER_SCALE_1P0; + } else if (InstancePtr->UpdateMixerScale == 0x1U) { + MixerSettingsPtr->FineMixerScale = + XRFDC_MIXER_SCALE_0P7; + } else { + metal_log(METAL_LOG_ERROR, + "\n Invalid Fine mixer scale in %s\r\n", __func__); + Status = XRFDC_FAILURE; + goto RETURN_PATH; + } + + /* Phase Offset */ + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_NCO_PHASE_UPP_OFFSET); + PhaseOffset = ReadReg << XRFDC_NCO_PHASE_UPP_SHIFT; + PhaseOffset |= XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_NCO_PHASE_LOW_OFFSET); + PhaseOffset &= XRFDC_NCO_PHASE_MASK; + PhaseOffset = ((PhaseOffset << 14) >> 14); + MixerSettingsPtr->PhaseOffset = ((PhaseOffset * 180.0) / + XRFDC_NCO_PHASE_MULTIPLIER); + + /* NCO Frequency */ + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_ADC_NCO_FQWD_UPP_OFFSET); + Freq = ReadReg << XRFDC_NCO_FQWD_UPP_SHIFT; + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_ADC_NCO_FQWD_MID_OFFSET); + Freq |= ReadReg << XRFDC_NCO_FQWD_MID_SHIFT; + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_ADC_NCO_FQWD_LOW_OFFSET); + Freq |= ReadReg; + Freq &= XRFDC_NCO_FQWD_MASK; + Freq = (Freq << 16) >> 16; + if (Freq < 0) { + MixerSettingsPtr->Freq = ((Freq * SamplingRate) / + XRFDC_NCO_FREQ_MIN_MULTIPLIER); + } else { + MixerSettingsPtr->Freq = ((Freq * SamplingRate) / + XRFDC_NCO_FREQ_MULTIPLIER); + } + + /* Event Source */ + ReadReg = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_NCO_UPDT_OFFSET); + MixerSettingsPtr->EventSource = ReadReg & XRFDC_NCO_UPDT_MODE_MASK; + + /* Update NCO, CoarseMix freq based on calibration mode */ + NCOFreq = MixerConfigPtr->Freq; + if (Type == XRFDC_ADC_TILE) { + Status = XRFdc_GetCalibrationMode(InstancePtr, Tile_Id, + Block, &CalibrationMode); + if (Status != XRFDC_SUCCESS) { + return XRFDC_FAILURE; + } + + if (CalibrationMode == XRFDC_CALIB_MODE1) { + switch (MixerSettingsPtr->CoarseMixFreq) { + case XRFDC_COARSE_MIX_BYPASS: + MixerSettingsPtr->CoarseMixFreq = + XRFDC_COARSE_MIX_SAMPLE_FREQ_BY_TWO; + break; + case XRFDC_COARSE_MIX_SAMPLE_FREQ_BY_FOUR: + MixerSettingsPtr->CoarseMixFreq = + XRFDC_COARSE_MIX_MIN_SAMPLE_FREQ_BY_FOUR; + break; + case XRFDC_COARSE_MIX_SAMPLE_FREQ_BY_TWO: + MixerSettingsPtr->CoarseMixFreq = + XRFDC_COARSE_MIX_BYPASS; + break; + case XRFDC_COARSE_MIX_MIN_SAMPLE_FREQ_BY_FOUR: + MixerSettingsPtr->CoarseMixFreq = + XRFDC_COARSE_MIX_SAMPLE_FREQ_BY_FOUR; + break; + default: + MixerSettingsPtr->CoarseMixFreq = + XRFDC_COARSE_MIX_OFF; + break; + } + NCOFreq = (MixerConfigPtr->Freq - + (SamplingRate / 2.0)); + } + } + + if ((NCOFreq > (SamplingRate / 2.0)) || + (NCOFreq < -(SamplingRate / 2.0))) { + Status = XRFdc_GetNyquistZone(InstancePtr, + Type, Tile_Id, Block, &NyquistZone); + if (Status != XRFDC_SUCCESS) { + return XRFDC_FAILURE; + } + + if ((NyquistZone == XRFDC_EVEN_NYQUIST_ZONE) && + (MixerSettingsPtr->Freq != 0)) { + MixerSettingsPtr->Freq *= -1; + } + + do { + if (NCOFreq < -(SamplingRate / 2.0)) { + NCOFreq += SamplingRate; + MixerSettingsPtr->Freq -= SamplingRate; + } + if (NCOFreq > (SamplingRate / 2.0)) { + NCOFreq -= SamplingRate; + MixerSettingsPtr->Freq += SamplingRate; + } + } while ((NCOFreq > (SamplingRate / 2.0)) || + (NCOFreq < -(SamplingRate / 2.0))); + } + if ((Type == XRFDC_ADC_TILE) && + (CalibrationMode == XRFDC_CALIB_MODE1)) { + MixerSettingsPtr->Freq += (SamplingRate / 2.0); + } + + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; + +} + +/** @} */ diff --git a/mpm/lib/rfdc/xrfdc_mts.c b/mpm/lib/rfdc/xrfdc_mts.c new file mode 100644 index 000000000..00a1abc85 --- /dev/null +++ b/mpm/lib/rfdc/xrfdc_mts.c @@ -0,0 +1,1308 @@ +/****************************************************************************** +* +* Copyright (C) 2018-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_mts.c +* @addtogroup xrfdc_v6_0 +* @{ +* +* Contains the multi tile sync functions of the XRFdc driver. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- -------- ----------------------------------------------- +* 3.1 jm 01/24/18 Initial release +* 3.2 jm 03/12/18 Fixed DAC latency calculation. +* jm 03/12/18 Added support for reloading DTC scans. +* jm 03/12/18 Add option to configure sysref capture after MTS. +* 4.0 sk 04/09/18 Added API to enable/disable the sysref. +* rk 04/17/18 Adjust calculated latency by sysref period, where doing +* so results in closer alignment to the target latency. +* 5.0 sk 08/03/18 Fixed MISRAC warnings. +* sk 08/03/18 Check for Block0 enable for tiles participating in MTS. +* sk 08/24/18 Reorganize the code to improve readability and +* optimization. +* 5.1 cog 01/29/19 Replace structure reference ADC checks with +* function. +* 6.0 cog 02/17/19 Added XRFdc_GetMTSEnable API. +* +* </pre> +* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include "mpm/rfdc/xrfdc_mts.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +static void XRFdc_MTS_Sysref_TRx(XRFdc *InstancePtr, u32 Enable); +static void XRFdc_MTS_Sysref_Ctrl(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 Is_PLL, u32 Enable_Cap, u32 Enable_Div_Reset); +static u32 XRFdc_MTS_Sysref_Dist(XRFdc *InstancePtr, int Num_DAC); +static u32 XRFdc_MTS_Sysref_Count(XRFdc *InstancePtr, u32 Type, u32 Count_Val); +static u32 XRFdc_MTS_Dtc_Scan(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + XRFdc_MTS_DTC_Settings *SettingsPtr); +static u32 XRFdc_MTS_Dtc_Code(XRFdc *InstancePtr, u32 Type, u32 BaseAddr, + u32 SRCtrlAddr, u32 DTCAddr, u16 SRctl, u16 SRclr_m, u32 Code); +static u32 XRFdc_MTS_Dtc_Calc(u32 Type, u32 Tile_Id, + XRFdc_MTS_DTC_Settings *SettingsPtr, u8 *FlagsPtr); +static void XRFdc_MTS_Dtc_Flag_Debug(u8 *FlagsPtr, u32 Type, u32 Tile_Id, + u32 Target, u32 Picked); +static void XRFdc_MTS_FIFOCtrl(XRFdc *InstancePtr, u32 Type, u32 FIFO_Mode, + u32 Tiles_To_Clear); +static u32 XRFdc_MTS_GetMarker(XRFdc *InstancePtr, u32 Type, u32 Tiles, + XRFdc_MTS_Marker *MarkersPtr, int Marker_Delay); +static void XRFdc_MTS_Marker_Read(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 FIFO_Id, u32 *CountPtr, u32 *LocPtr, u32 *DonePtr); +static u32 XRFdc_MTS_Latency(XRFdc *InstancePtr, u32 Type, + XRFdc_MultiConverter_Sync_Config *ConfigPtr, XRFdc_MTS_Marker *MarkersPtr); + +/*****************************************************************************/ +/** +* +* This API enables the master tile sysref Tx/Rx +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Enable the master tile sysref for Tx/Rx, valid values are 0 and 1. +* +* @return +* - None. +* +* @note None +* +******************************************************************************/ +static void XRFdc_MTS_Sysref_TRx(XRFdc *InstancePtr, u32 Enable) +{ + u32 BaseAddr; + u32 Data; + + BaseAddr = XRFDC_DRP_BASE(XRFDC_DAC_TILE, 0) + XRFDC_HSCOM_ADDR; + Data = (Enable != 0U) ? 0xFFFFU : 0U; + + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_MTS_SRCAP_T1, + XRFDC_MTS_SRCAP_EN_TRX_M, Data); +} + +/*****************************************************************************/ +/** +* +* This API Control SysRef Capture Settings +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param Is_PLL Valid values are 0 and 1. +* @param Enable_Cap Valid values are 0 and 1. +* @param Enable_Div_Reset Valid values are 0 and 1. +* +* @return +* - None. +* +* @note None +* +******************************************************************************/ +static void XRFdc_MTS_Sysref_Ctrl(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 Is_PLL, u32 Enable_Cap, u32 Enable_Div_Reset) +{ + u32 BaseAddr; + u16 RegData; + + RegData = 0U; + BaseAddr = XRFDC_DRP_BASE(Type, Tile_Id) + XRFDC_HSCOM_ADDR; + + /* Write some bits to ensure sysref is in the right mode */ + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_MTS_SRCAP_T1, + XRFDC_MTS_SRCAP_INIT_M, 0U); + + if (Is_PLL != 0U) { + /* PLL Cap */ + RegData = (Enable_Cap != 0U) ? XRFDC_MTS_SRCAP_PLL_M : 0U; + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_MTS_SRCAP_PLL, + XRFDC_MTS_SRCAP_PLL_M, RegData); + } else { + /* Analog Cap disable */ + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_MTS_SRCAP_T1, + XRFDC_MTS_SRCAP_T1_EN, 0U); + + /* Analog Divider */ + RegData = (Enable_Div_Reset != 0U) ? 0U : XRFDC_MTS_SRCAP_T1_RST; + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_MTS_SRCAP_T1, + XRFDC_MTS_SRCAP_T1_RST, RegData); + + /* Digital Divider */ + RegData = (Enable_Div_Reset != 0U) ? 0U : XRFDC_MTS_SRCAP_DIG_M; + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_MTS_SRCAP_DIG, + XRFDC_MTS_SRCAP_DIG_M, RegData); + + /* Set SysRef Cap Clear */ + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_MTS_SRCAP_T1, + XRFDC_MTS_SRCLR_T1_M, XRFDC_MTS_SRCLR_T1_M); + + /* Analog Cap enable */ + RegData = (Enable_Cap != 0U) ? XRFDC_MTS_SRCAP_T1_EN : 0U; + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_MTS_SRCAP_T1, + XRFDC_MTS_SRCAP_T1_EN, RegData); + + /* Unset SysRef Cap Clear */ + XRFdc_ClrSetReg(InstancePtr, BaseAddr, XRFDC_MTS_SRCAP_T1, + XRFDC_MTS_SRCLR_T1_M, 0U); + } +} + +/*****************************************************************************/ +/** +* +* This API Update SysRef Distribution between tiles +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Num_DAC is number of DAC tiles +* +* @return +* - XRFDC_MTS_OK if successful. +* - XRFDC_MTS_NOT_SUPPORTED +* +* @note None +* +******************************************************************************/ +static u32 XRFdc_MTS_Sysref_Dist(XRFdc *InstancePtr, int Num_DAC) +{ + + if (Num_DAC < 0) { + /* Auto-detect. Only 2 types Supported - 2GSPS ADCs, 4GSPS ADCs */ + if (XRFdc_IsHighSpeedADC(InstancePtr,0) != 0U) { + Num_DAC = 2; + } else { + Num_DAC = 4; + } + } + + if (Num_DAC == XRFDC_NUM_OF_TILES2) { + /* 2 DACs, 4ADCs */ + XRFdc_WriteReg16(InstancePtr, XRFDC_DAC_TILE_DRP_ADDR(0U), + XRFDC_MTS_SRDIST, 0xC980U); + XRFdc_WriteReg16(InstancePtr, XRFDC_DAC_TILE_DRP_ADDR(1U), + XRFDC_MTS_SRDIST, 0x0100U); + XRFdc_WriteReg16(InstancePtr, XRFDC_ADC_TILE_DRP_ADDR(3U), + XRFDC_MTS_SRDIST, 0x1700U); + } else if (Num_DAC == XRFDC_NUM_OF_TILES4) { + /* 4 DACs, 4ADCs */ + XRFdc_WriteReg16(InstancePtr, XRFDC_DAC_TILE_DRP_ADDR(0U), + XRFDC_MTS_SRDIST, 0xCA80U); + XRFdc_WriteReg16(InstancePtr, XRFDC_DAC_TILE_DRP_ADDR(1U), + XRFDC_MTS_SRDIST, 0x2400U); + XRFdc_WriteReg16(InstancePtr, XRFDC_DAC_TILE_DRP_ADDR(2U), + XRFDC_MTS_SRDIST, 0x0980U); + XRFdc_WriteReg16(InstancePtr, XRFDC_DAC_TILE_DRP_ADDR(3U), + XRFDC_MTS_SRDIST, 0x0100U); + XRFdc_WriteReg16(InstancePtr, XRFDC_ADC_TILE_DRP_ADDR(3U), + XRFDC_MTS_SRDIST, 0x0700U); + } else { + return XRFDC_MTS_NOT_SUPPORTED; + } + + XRFdc_WriteReg16(InstancePtr, XRFDC_ADC_TILE_DRP_ADDR(0U), + XRFDC_MTS_SRDIST, 0x0280U); + XRFdc_WriteReg16(InstancePtr, XRFDC_ADC_TILE_DRP_ADDR(1U), + XRFDC_MTS_SRDIST, 0x0600U); + XRFdc_WriteReg16(InstancePtr, XRFDC_ADC_TILE_DRP_ADDR(2U), + XRFDC_MTS_SRDIST, 0x8880U); + + return XRFDC_MTS_OK; +} + +/*****************************************************************************/ +/** +* +* This API Wait for a number of sysref's to be captured +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Count_Val to wait for a number of sysref's to be captured. +* +* @return +* - XRFDC_MTS_OK if successful. +* - XRFDC_MTS_TIMEOUT if timeout occurs. +* +* @note None +* +******************************************************************************/ +static u32 XRFdc_MTS_Sysref_Count(XRFdc *InstancePtr, u32 Type, u32 Count_Val) +{ + u32 RegData; + u32 Timeout; + u32 Shift; + + RegData = (Type == XRFDC_DAC_TILE) ? 0x2U : 0x1U; + Shift = (Type == XRFDC_DAC_TILE) ? 8U : 0U; + + /* Start counter */ + XRFdc_WriteReg(InstancePtr, 0U, XRFDC_MTS_SRCOUNT_CTRL, RegData); + + /* Check counter with timeout in case sysref is not active */ + Timeout = 0U; + while (Timeout < XRFDC_MTS_SRCOUNT_TIMEOUT) { + RegData = XRFdc_ReadReg(InstancePtr, 0U, XRFDC_MTS_SRCOUNT_VAL); + RegData = ((RegData >> Shift) & XRFDC_MTS_SRCOUNT_M); + if (RegData >= Count_Val) { + break; + } + Timeout++; + } + + if (Timeout >= XRFDC_MTS_SRCOUNT_TIMEOUT) { + metal_log(METAL_LOG_ERROR, + "PL SysRef Timeout - PL SysRef not active: %d\n in %s\n", + Timeout, __func__); + return XRFDC_MTS_TIMEOUT; + } + + return XRFDC_MTS_OK; +} + +/*****************************************************************************/ +/** +* +* This API print the DTC scan results +* +* +* @param FlagsPtr is for internal usage. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param Target is for internal usage. +* @param Picked is for internal usage. +* +* @return None +* +* @note None +* +******************************************************************************/ +static void XRFdc_MTS_Dtc_Flag_Debug(u8 *FlagsPtr, u32 Type, u32 Tile_Id, + u32 Target, u32 Picked) +{ + u32 Index; + char buf[XRFDC_MTS_NUM_DTC+1]; + + for (Index = 0U; Index < XRFDC_MTS_NUM_DTC; Index++) { + if (Index == Picked) { + buf[Index] = '*'; + } else if (Index == Target) { + buf[Index] = '#'; + } else { + buf[Index] = '0' + FlagsPtr[Index]; + } + } + buf[XRFDC_MTS_NUM_DTC] = '\0'; + metal_log(METAL_LOG_INFO, "%s%d: %s\n", + (Type == XRFDC_DAC_TILE) ? "DAC" : "ADC", Tile_Id, buf); + + (void)buf; + (void)Type; + (void)Tile_Id; + +} + +/*****************************************************************************/ +/** +* +* This API Calculate the best DTC code to use +* +* +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param SettingsPtr dtc settings structure. +* @param FlagsPtr is for internal usage. +* +* @return +* - XRFDC_MTS_OK if successful. +* - XRFDC_MTS_NOT_SUPPORTED if MTS is not supported. +* +* @note None +* +******************************************************************************/ +static u32 XRFdc_MTS_Dtc_Calc(u32 Type, u32 Tile_Id, + XRFdc_MTS_DTC_Settings *SettingsPtr, u8 *FlagsPtr) +{ + u32 Index, Status, Num_Found; + int Last, Current_Gap, Max_Overlap, Overlap_Cnt; + int Min_Gap, Max_Gap, Diff, Min_Diff, Min_Range, Val, Target; + u8 Min_Gap_Allowed; + int Codes[XRFDC_MTS_MAX_CODE] = {0}; + + Min_Gap_Allowed = (SettingsPtr->IsPLL != 0U) ? XRFDC_MTS_MIN_GAP_PLL : + XRFDC_MTS_MIN_GAP_T1; + Status = XRFDC_MTS_OK; + + /* Scan the flags and find candidate DTC codes */ + Num_Found = 0U; + Max_Gap = 0; + Min_Gap = XRFDC_MTS_NUM_DTC; + Max_Overlap = 0; + Overlap_Cnt = 0; + Last = -1; + FlagsPtr[XRFDC_MTS_NUM_DTC] = 1; + for (Index = 0U; Index <= XRFDC_MTS_NUM_DTC; Index++) { + Current_Gap = Index-Last; + if (FlagsPtr[Index] != 0) { + if (Current_Gap > Min_Gap_Allowed) { + Codes[Num_Found] = Last + (Current_Gap / 2); + Num_Found++; + /* Record max/min gaps */ + Current_Gap--; + if (Current_Gap > Max_Gap) { + Max_Gap = Current_Gap; + } + if (Current_Gap < Min_Gap) { + Min_Gap = Current_Gap; + } + } + Last = Index; + } + /* check for the longest run of overlapping codes */ + if (FlagsPtr[Index] == 3U) { + Overlap_Cnt++; + if (Overlap_Cnt > Max_Overlap) { + Max_Overlap = Overlap_Cnt; + } + } else { + Overlap_Cnt = 0; + } + } + + /* Record some stats */ + SettingsPtr->Num_Windows[Tile_Id] = Num_Found; + SettingsPtr->Max_Gap[Tile_Id] = Max_Gap; + SettingsPtr->Min_Gap[Tile_Id] = Min_Gap; + SettingsPtr->Max_Overlap[Tile_Id] = Max_Overlap; + + /* Calculate the best code */ + if (SettingsPtr->Scan_Mode == XRFDC_MTS_SCAN_INIT) { + /* Initial scan */ + if (Tile_Id == SettingsPtr->RefTile) { + /* RefTile: Get the code closest to the target */ + Target = XRFDC_MTS_REF_TARGET; + SettingsPtr->Target[Tile_Id] = XRFDC_MTS_REF_TARGET; + Min_Diff = XRFDC_MTS_NUM_DTC; + /* scan all codes to find the closest */ + for (Index = 0U; Index < Num_Found; Index++) { + Diff = abs(Target - Codes[Index]); + if (Diff < Min_Diff) { + Min_Diff = Diff; + SettingsPtr->DTC_Code[Tile_Id] = Codes[Index]; + } + metal_log(METAL_LOG_DEBUG, + "Target %d, DTC Code %d, Diff %d, Min %d\n", Target, + Codes[Index], Diff, Min_Diff); + } + /* set the reference code as the target for the other tiles */ + for (Index = 0U; Index < 4U; Index++) { + if (Index != Tile_Id) { + SettingsPtr->Target[Index] = SettingsPtr->DTC_Code[Tile_Id]; + } + } + metal_log(METAL_LOG_DEBUG, + "RefTile (%d): DTC Code Target %d, Picked %d\n", Tile_Id, + Target, SettingsPtr->DTC_Code[Tile_Id]); + + } else { + /* + * Other Tiles: Get the code that minimises the total range of codes + * compute the range of the existing dtc codes + */ + Max_Gap = 0; + Min_Gap = XRFDC_MTS_NUM_DTC; + for (Index = XRFDC_TILE_ID0; Index < XRFDC_TILE_ID4; Index++) { + Val = SettingsPtr->DTC_Code[Index]; + if ((Val != -1) && (Val > Max_Gap)) { + Max_Gap = Val; + } + if ((Val != -1) && (Val < Min_Gap)) { + Min_Gap = Val; + } + } + metal_log(METAL_LOG_DEBUG, + "Tile (%d): Max/Min %d/%d, Range %d\n", Tile_Id, Max_Gap, + Min_Gap, Max_Gap-Min_Gap); + Min_Range = XRFDC_MTS_NUM_DTC; + for (Index = 0U; Index < Num_Found; Index++) { + Val = Codes[Index]; + Diff = Max_Gap - Min_Gap; + if (Val < Min_Gap) { + Diff = Max_Gap - Val; + } + if (Val > Max_Gap) { + Diff = Val - Min_Gap; + } + if (Diff <= Min_Range) { + Min_Range = Diff; + SettingsPtr->DTC_Code[Tile_Id] = Val; + } + metal_log(METAL_LOG_DEBUG, + "Tile (%d): Code %d, New-Range: %d, Min-Range: %d\n", + Tile_Id, Val, Diff, Min_Range); + } + metal_log(METAL_LOG_DEBUG, + "Tile (%d): Code %d, Range Prev %d, New %d\n", Tile_Id, + SettingsPtr->DTC_Code[Tile_Id], Max_Gap-Min_Gap, Min_Range); + } + } else { + /* Reload the results of an initial scan to seed a new scan */ + if (Tile_Id == SettingsPtr->RefTile) { + /* RefTile: Get code closest to the target */ + Target = SettingsPtr->Target[Tile_Id]; + } else { + Target = SettingsPtr->DTC_Code[SettingsPtr->RefTile] + + SettingsPtr->Target[Tile_Id] - SettingsPtr->Target[SettingsPtr->RefTile]; + } + Min_Diff = XRFDC_MTS_NUM_DTC; + /* scan all codes to find the closest */ + for (Index = 0U; Index < Num_Found; Index++) { + Diff = abs(Target - Codes[Index]); + if (Diff < Min_Diff) { + Min_Diff = Diff; + SettingsPtr->DTC_Code[Tile_Id] = Codes[Index]; + } + metal_log(METAL_LOG_DEBUG, + "Reload Target %d, DTC Code %d, Diff %d, Min %d\n", Target, + Codes[Index], Diff, Min_Diff); + } + } + + /* Print some debug info */ + XRFdc_MTS_Dtc_Flag_Debug(FlagsPtr, Type, Tile_Id, SettingsPtr->Target[Tile_Id], + SettingsPtr->DTC_Code[Tile_Id]); + + return Status; +} + +/*****************************************************************************/ +/** +* +* This API Set a DTC code and wait for it to be updated. Return early/late +* flags, if set +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param BaseAddr is for internal usage. +* @param SRCtrlAddr is for internal usage. +* @param DTCAddr is for internal usage. +* @param SRctl is for internal usage. +* @param SRclr_m is for internal usage. +* @param Code is for internal usage. +* +* @return +* - XRFDC_MTS_OK if successful. +* - XRFDC_MTS_TIMEOUT if timeout occurs. +* +* @note None +* +******************************************************************************/ +static u32 XRFdc_MTS_Dtc_Code(XRFdc *InstancePtr, u32 Type, u32 BaseAddr, + u32 SRCtrlAddr, u32 DTCAddr, u16 SRctl, u16 SRclr_m, u32 Code) +{ + u32 Status; + + /* set the DTC code */ + XRFdc_WriteReg16(InstancePtr, BaseAddr, DTCAddr, Code); + + /* set sysref cap clear */ + XRFdc_WriteReg16(InstancePtr, BaseAddr, SRCtrlAddr, SRctl | SRclr_m); + + /* unset sysref cap clear */ + XRFdc_WriteReg16(InstancePtr, BaseAddr, SRCtrlAddr, SRctl); + + Status = XRFdc_MTS_Sysref_Count(InstancePtr, Type, XRFDC_MTS_DTC_COUNT); + + return Status; +} + +/*****************************************************************************/ +/** +* +* This API Scan the DTC codes and determine the optimal capture code for +* both PLL and T1 cases +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param SettingsPtr dtc settings structure. +* +* @return +* - XRFDC_MTS_OK if successful. +* - XRFDC_MTS_TIMEOUT if timeout occurs. +* +* @note None +* +******************************************************************************/ +static u32 XRFdc_MTS_Dtc_Scan (XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + XRFdc_MTS_DTC_Settings *SettingsPtr) +{ + u32 Status; + u32 BaseAddr; + u32 SRCtrlAddr; + u32 DTCAddr; + u8 Flags[XRFDC_MTS_NUM_DTC+1]; + u16 SRctl; + u16 SRclr_m; + u16 Flag_s; + u32 Index; + + BaseAddr = XRFDC_DRP_BASE(Type, Tile_Id) + XRFDC_HSCOM_ADDR; + Status = XRFDC_MTS_OK; + + /* Enable SysRef Capture and Disable Divide Reset */ + XRFdc_MTS_Sysref_Ctrl(InstancePtr, Type, Tile_Id, SettingsPtr->IsPLL, 1, 0); + SRCtrlAddr = (SettingsPtr->IsPLL != 0U) ? XRFDC_MTS_SRCAP_PLL : XRFDC_MTS_SRCAP_T1; + DTCAddr = (SettingsPtr->IsPLL != 0U) ? XRFDC_MTS_SRDTC_PLL : XRFDC_MTS_SRDTC_T1; + SRclr_m = (SettingsPtr->IsPLL != 0U) ? XRFDC_MTS_SRCLR_PLL_M : XRFDC_MTS_SRCLR_T1_M; + Flag_s = (SettingsPtr->IsPLL != 0U) ? XRFDC_MTS_SRFLAG_PLL : XRFDC_MTS_SRFLAG_T1; + + SRctl = XRFdc_ReadReg16(InstancePtr, BaseAddr, SRCtrlAddr) & ~SRclr_m; + + for (Index = 0U; Index < XRFDC_MTS_NUM_DTC; Index++) { + Flags[Index] = 0U; + } + for (Index = 0U; (Index < XRFDC_MTS_NUM_DTC) && (Status == XRFDC_MTS_OK); Index++) { + Status |= XRFdc_MTS_Dtc_Code(InstancePtr, Type, BaseAddr, + SRCtrlAddr, DTCAddr, SRctl, SRclr_m, Index); + Flags[Index] = (XRFdc_ReadReg16(InstancePtr, BaseAddr, XRFDC_MTS_SRFLAG) >> + Flag_s) & 0x3U; + } + + /* Calculate the best DTC code */ + (void)XRFdc_MTS_Dtc_Calc(Type, Tile_Id, SettingsPtr, Flags); + + /* Program the calculated code */ + if (SettingsPtr->DTC_Code[Tile_Id] == -1) { + metal_log(METAL_LOG_ERROR, + "Unable to capture analog SysRef safely on %s tile %d\n" + , (Type == XRFDC_ADC_TILE) ? "ADC" : "DAC", Tile_Id); + Status |= XRFDC_MTS_DTC_INVALID; + } else { + (void)XRFdc_MTS_Dtc_Code(InstancePtr, Type, BaseAddr, SRCtrlAddr, DTCAddr, + SRctl, SRclr_m, SettingsPtr->DTC_Code[Tile_Id]); + } + + if (SettingsPtr->IsPLL != 0U) { + /* PLL - Disable SysRef Capture */ + XRFdc_MTS_Sysref_Ctrl(InstancePtr, Type, Tile_Id, 1, 0, 0); + } else { + /* T1 - Reset Dividers */ + XRFdc_MTS_Sysref_Ctrl(InstancePtr, Type, Tile_Id, 0, 1, 1); + Status |= XRFdc_MTS_Sysref_Count(InstancePtr, Type, + XRFDC_MTS_DTC_COUNT); + XRFdc_MTS_Sysref_Ctrl(InstancePtr, Type, Tile_Id, 0, 1, 0); + } + + return Status; +} + +/*****************************************************************************/ +/** +* +* This API Control the FIFO enable for the group. If Tiles_to_clear has bits +* set, the FIFOs of those tiles will have their FIFO flags cleared. +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param FIFO_Mode is fifo mode. +* @param Tiles_To_Clear bits set, FIFO flags will be cleared for those tiles. +* +* @return None +* +* @note None +* +******************************************************************************/ +static void XRFdc_MTS_FIFOCtrl (XRFdc *InstancePtr, u32 Type, u32 FIFO_Mode, + u32 Tiles_To_Clear) +{ + u32 RegAddr; + u32 BaseAddr; + u32 Tile_Id; + u32 Block_Id; + + /* Clear the FIFO Flags */ + RegAddr = (Type == XRFDC_ADC_TILE) ? XRFDC_ADC_FABRIC_ISR_OFFSET : + XRFDC_DAC_FABRIC_ISR_OFFSET; + for (Tile_Id = XRFDC_TILE_ID0; Tile_Id < XRFDC_TILE_ID4; Tile_Id++) { + if (((1U << Tile_Id) & Tiles_To_Clear) != 0U) { + for (Block_Id = XRFDC_BLK_ID0; Block_Id < XRFDC_BLK_ID4; Block_Id++) { + BaseAddr = XRFDC_DRP_BASE(Type, Tile_Id) + + XRFDC_BLOCK_ADDR_OFFSET(Block_Id); + XRFdc_WriteReg16(InstancePtr, BaseAddr, RegAddr, + XRFDC_IXR_FIFOUSRDAT_MASK); + } + } + } + + /* Enable the FIFOs */ + RegAddr = (Type == XRFDC_ADC_TILE) ? XRFDC_MTS_FIFO_CTRL_ADC : + XRFDC_MTS_FIFO_CTRL_DAC; + XRFdc_WriteReg(InstancePtr, 0, RegAddr, FIFO_Mode); +} + +/*****************************************************************************/ +/** +* +* This API Read-back the marker data for an ADC or DAC +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tile_Id Valid values are 0-3. +* @param FIFO_Id is FIFO number. +* @param Count is for internal usage. +* @param Loc is for internal usage. +* @param Done is for internal usage. +* +* @return +* - None. +* +* @note None +* +******************************************************************************/ +static void XRFdc_MTS_Marker_Read(XRFdc *InstancePtr, u32 Type, u32 Tile_Id, + u32 FIFO_Id, u32 *CountPtr, u32 *LocPtr, u32 *DonePtr) +{ + u32 BaseAddr; + u32 RegData = 0x0; + + if (Type == XRFDC_ADC_TILE) { + BaseAddr = XRFDC_DRP_BASE(Type, Tile_Id) - 0x2000; + RegData = XRFdc_ReadReg(InstancePtr, BaseAddr, + XRFDC_MTS_ADC_MARKER_CNT+(FIFO_Id << 2)); + *CountPtr = XRFDC_MTS_FIELD(RegData, XRFDC_MTS_AMARK_CNT_M, 0); + *LocPtr = XRFDC_MTS_FIELD(RegData, XRFDC_MTS_AMARK_LOC_M, + XRFDC_MTS_AMARK_LOC_S); + *DonePtr = XRFDC_MTS_FIELD(RegData, XRFDC_MTS_AMARK_DONE_M, + XRFDC_MTS_AMARK_DONE_S); + } else { + BaseAddr = XRFDC_DRP_BASE(Type, Tile_Id) + + XRFDC_BLOCK_ADDR_OFFSET(FIFO_Id); + *CountPtr = XRFdc_ReadReg(InstancePtr, BaseAddr, + XRFDC_MTS_DAC_MARKER_CNT); + *LocPtr = XRFdc_ReadReg(InstancePtr, BaseAddr, + XRFDC_MTS_DAC_MARKER_LOC); + *DonePtr = 1; + } + metal_log(METAL_LOG_DEBUG, + "Marker Read Tile %d, FIFO %d - %08X = %04X: count=%d, loc=%d," + "done=%d\n", Tile_Id, FIFO_Id, BaseAddr, RegData, *CountPtr, + *LocPtr, *DonePtr); +} + +/*****************************************************************************/ +/** +* +* This API Run the marker counter and read the results +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param Tiles is tiles to get marker +* @param MarkersPtr mts marker structure. +* @param Marker_Delay is marker delay. +* +* @return +* - XRFDC_MTS_OK if successful. +* - XRFDC_MTS_TIMEOUT if timeout occurs. +* - XRFDC_MTS_MARKER_RUN +* - XRFDC_MTS_MARKER_MISM +* - +* +* @note None +* +******************************************************************************/ +static u32 XRFdc_MTS_GetMarker(XRFdc *InstancePtr, u32 Type, u32 Tiles, + XRFdc_MTS_Marker *MarkersPtr, int Marker_Delay) +{ + u32 Done; + u32 Count; + u32 Loc; + u32 Tile_Id; + u32 Block_Id; + u32 Status; + + Status = XRFDC_MTS_OK; + if (Type == XRFDC_ADC_TILE) { + /* Reset marker counter */ + XRFdc_WriteReg(InstancePtr, 0, XRFDC_MTS_ADC_MARKER, 1); + XRFdc_WriteReg(InstancePtr, 0, XRFDC_MTS_ADC_MARKER, 0); + } else { + /* + * SysRef Capture should be still active from the DTC Scan + * but set it anyway to be sure + */ + for (Tile_Id = XRFDC_TILE_ID0; Tile_Id < XRFDC_TILE_ID4; Tile_Id++) { + if (((1U << Tile_Id) & Tiles) != 0U) { + XRFdc_MTS_Sysref_Ctrl(InstancePtr, XRFDC_DAC_TILE, + Tile_Id, 0, 1, 0); + } + } + + /* Set marker delay */ + XRFdc_WriteReg(InstancePtr, 0, XRFDC_MTS_DAC_MARKER_CTRL, + Marker_Delay); + } + + /* Allow the marker counter to run */ + Status |= XRFdc_MTS_Sysref_Count(InstancePtr, Type, + XRFDC_MTS_MARKER_COUNT); + + /* Read master FIFO (FIFO0 in each Tile) */ + for (Tile_Id = XRFDC_TILE_ID0; Tile_Id < XRFDC_TILE_ID4; Tile_Id++) { + if (((1U << Tile_Id) & Tiles) != 0U) { + if (Type == XRFDC_DAC_TILE) { + /* Disable SysRef Capture before reading it */ + XRFdc_MTS_Sysref_Ctrl(InstancePtr, XRFDC_DAC_TILE, + Tile_Id, 0, 0, 0); + Status |= XRFdc_MTS_Sysref_Count(InstancePtr, Type, + XRFDC_MTS_MARKER_COUNT); + } + + XRFdc_MTS_Marker_Read(InstancePtr, Type, Tile_Id, 0, &Count, + &Loc, &Done); + MarkersPtr->Count[Tile_Id] = Count; + MarkersPtr->Loc[Tile_Id] = Loc; + metal_log(METAL_LOG_INFO, + "%s%d: Marker: - %d, %d\n", (Type == XRFDC_DAC_TILE) ? + "DAC":"ADC", Tile_Id, MarkersPtr->Count[Tile_Id], MarkersPtr->Loc[Tile_Id]); + + if ((!Done) != 0U) { + metal_log(METAL_LOG_ERROR, "Analog SysRef timeout," + "SysRef not detected on %s tile %d\n", + (Type == XRFDC_ADC_TILE) ? "ADC" : "DAC", Tile_Id); + Status |= XRFDC_MTS_MARKER_RUN; + } + + /* + * Check all enabled FIFOs agree with the master FIFO. + * This is optional. + */ + for (Block_Id = XRFDC_BLK_ID0; Block_Id < XRFDC_BLK_ID4; Block_Id++) { + if (XRFdc_IsFifoEnabled(InstancePtr, Type, Tile_Id, Block_Id) != 0U) { + XRFdc_MTS_Marker_Read(InstancePtr, Type, Tile_Id, Block_Id, + &Count, &Loc, &Done); + if ((MarkersPtr->Count[Tile_Id] != Count) || + (MarkersPtr->Loc[Tile_Id] != Loc)) { + metal_log(METAL_LOG_DEBUG, + "Tile %d, FIFO %d Marker != Expected: %d, %d vs" + "%d, %d\n", Tile_Id, Block_Id, MarkersPtr->Count[Tile_Id], + MarkersPtr->Loc[Tile_Id], Count, Loc); + metal_log(METAL_LOG_ERROR, + "SysRef capture mismatch on %s tile %d," + " PL SysRef may not have been" + " captured synchronously\n", + (Type == XRFDC_ADC_TILE) ? "ADC" : "DAC", Block_Id); + Status |= XRFDC_MTS_MARKER_MISM; + + } + } + } + } + } + + return Status; +} + +/*****************************************************************************/ +/** +* +* This API Calculate the absoulte/relative latencies +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param ConfigPtr is mts config structure. +* @param MarkersPtr is mts marker structure. +* +* @return +* - XRFDC_MTS_OK if successful. +* - XRFDC_MTS_DELAY_OVER +* - XRFDC_MTS_TARGET_LOW +* - +* +* @note Latency calculation will use Sysref frequency counters +* logic which will work with IP version 2.0.1 and above. +* +******************************************************************************/ +static u32 XRFdc_MTS_Latency(XRFdc *InstancePtr, u32 Type, + XRFdc_MultiConverter_Sync_Config *ConfigPtr, XRFdc_MTS_Marker *MarkersPtr) +{ + u32 Status, Fifo, Index, BaseAddr, RegAddr; + int Count_W, Loc_W, Latency, Offset, Max_Latency, Target, Delta; + int I_Part, F_Part, SysRefT1Period, LatencyDiff, LatencyOffset; + u32 RegData, SysRefFreqCntrDone; + int Target_Latency = -1; + int LatencyOffsetDiff; + u32 Factor = 1U; + u32 Write_Words = 0U; + u32 Read_Words = 1U; + + Status = XRFDC_MTS_OK; + if (Type == XRFDC_ADC_TILE) { + (void)XRFdc_GetDecimationFactor(InstancePtr, ConfigPtr->RefTile, 0, &Factor); + } else { + (void)XRFdc_GetInterpolationFactor(InstancePtr, ConfigPtr->RefTile, 0, &Factor); + (void)XRFdc_GetFabWrVldWords(InstancePtr, Type, ConfigPtr->RefTile, 0, &Write_Words); + } + (void)XRFdc_GetFabRdVldWords(InstancePtr, Type, ConfigPtr->RefTile, 0, &Read_Words); + Count_W = Read_Words * Factor; + Loc_W = Factor; + + metal_log(METAL_LOG_DEBUG, + "Count_W %d, loc_W %d\n", Count_W, Loc_W); + + /* Find the individual latencies */ + Max_Latency = 0; + + /* Determine relative SysRef frequency */ + RegData = XRFdc_ReadReg(InstancePtr, 0, XRFDC_MTS_SRFREQ_VAL); + if (Type == XRFDC_ADC_TILE) { + /* ADC SysRef frequency information contained in lower 16 bits */ + RegData = RegData & 0XFFFFU; + } else { + /* DAC SysRef frequency information contained in upper 16 bits */ + RegData = (RegData >> 16U) & 0XFFFFU; + } + + /* + * Ensure SysRef frequency counter has completed. + * Sysref frequency counters logic will work with IP version + * 2.0.1 and above. + */ + SysRefFreqCntrDone = RegData & 0x1U; + if (SysRefFreqCntrDone == 0U) { + metal_log(METAL_LOG_ERROR, "Error : %s SysRef frequency counter not yet done\n", + (Type == XRFDC_ADC_TILE) ? "ADC" : "DAC"); + Status |= XRFDC_MTS_SYSREF_FREQ_NDONE; + /* Set SysRef period in terms of T1's will not be used */ + SysRefT1Period = 0; + } else { + SysRefT1Period = (RegData >> 1) * Count_W; + if (Type == XRFDC_DAC_TILE) { + /* + * DAC marker counter is on the tile clock domain so need + * to update SysRef period accordingly + */ + SysRefT1Period = (SysRefT1Period * Write_Words) / Read_Words; + } + metal_log(METAL_LOG_INFO, "SysRef period in terms of %s T1s = %d\n", + (Type == XRFDC_ADC_TILE) ? "ADC" : "DAC", SysRefT1Period); + } + + /* Work out the latencies */ + for (Index = XRFDC_TILE_ID0; Index < XRFDC_TILE_ID4; Index++) { + if (((1U << Index) & ConfigPtr->Tiles) != 0U) { + Latency = (MarkersPtr->Count[Index] * Count_W) + (MarkersPtr->Loc[Index] * Loc_W); + /* Set marker counter target on first tile */ + if (Target_Latency < 0) { + Target_Latency = ConfigPtr->Target_Latency; + if (Target_Latency < 0) { + Target_Latency = Latency; + } + metal_log(METAL_LOG_INFO, "%s target latency = %d\n", + (Type == XRFDC_ADC_TILE) ? "ADC" : "DAC", Target_Latency); + } + + /* + * Adjust reported counter values if offsetting by a SysRef + * period reduces distance between current and target latencies + */ + LatencyDiff = Target_Latency - Latency; + LatencyOffset = (LatencyDiff > 0) ? (Latency + SysRefT1Period) : + (Latency - SysRefT1Period); + LatencyOffsetDiff = Target_Latency - LatencyOffset; + if (abs(LatencyDiff) > abs(LatencyOffsetDiff)) { + Latency = LatencyOffset; + metal_log(METAL_LOG_INFO, "%s%d latency offset by a SysRef period to %d\n", + (Type == XRFDC_ADC_TILE) ? "ADC" : "DAC", Index, Latency); + } + ConfigPtr->Latency[Index] = Latency; + if (Latency > Max_Latency) { + Max_Latency = Latency; + } + metal_log(METAL_LOG_DEBUG, "Tile %d, latency %d, max %d\n", + Index, Latency, Max_Latency); + } + } + + /* + * Adjust the latencies to meet the target. Choose max, if it + * is not supplied by the user. + */ + Target = (ConfigPtr->Target_Latency < 0) ? Max_Latency : + ConfigPtr->Target_Latency; + + if (Target < Max_Latency) { + /* Cannot correct for -ve latencies, so default to aligning */ + Target = Max_Latency; + metal_log(METAL_LOG_ERROR, "Error : %s alignment target latency of %d < minimum possible %d\n", + (Type == XRFDC_ADC_TILE) ? "ADC" : "DAC", Target, Max_Latency); + Status |= XRFDC_MTS_TARGET_LOW; + } + + for (Index = XRFDC_TILE_ID0; Index < XRFDC_TILE_ID4; Index++) { + if (((1U << Index) & ConfigPtr->Tiles) != 0U) { + Delta = Target - ConfigPtr->Latency[Index]; + if (Delta < 0) { + Delta = 0; + } + I_Part = Delta / Factor; + F_Part = Delta % Factor; + Offset = I_Part; + if (F_Part > (int)(Factor / 2U)) { + Offset++; + } + metal_log(METAL_LOG_DEBUG, + "Target %d, Tile %d, delta %d, i/f_part %d/%d, offset %d\n", + Target, Index, Delta, I_Part, F_Part, Offset * Factor); + + /* check for excessive delay correction values */ + if (Offset > (int)XRFDC_MTS_DELAY_MAX) { + Offset = (int)XRFDC_MTS_DELAY_MAX; + metal_log(METAL_LOG_ERROR, + "Alignment correction delay %d" + " required exceeds maximum for %s Tile %d\n", + Offset, (Type == XRFDC_ADC_TILE) ? "ADC" : "DAC", + XRFDC_MTS_DELAY_MAX, Index); + Status |= XRFDC_MTS_DELAY_OVER; + } + + /* Adjust the latency, write the same value to each FIFO */ + BaseAddr = XRFDC_DRP_BASE(Type, Index) - 0x2000; + for (Fifo = XRFDC_BLK_ID0; Fifo < XRFDC_BLK_ID4; Fifo++) { + RegAddr = XRFDC_MTS_DELAY_CTRL + (Fifo << 2); + RegData = XRFdc_ReadReg(InstancePtr, BaseAddr, RegAddr); + RegData = XRFDC_MTS_RMW(RegData, XRFDC_MTS_DELAY_VAL_M, + Offset); + XRFdc_WriteReg(InstancePtr, BaseAddr, RegAddr, RegData); + } + + /* Report the total latency for this tile */ + ConfigPtr->Latency[Index] = ConfigPtr->Latency[Index] + (Offset * Factor); + ConfigPtr->Offset[Index] = Offset; + + /* Set the Final SysRef Capture Enable state */ + XRFdc_MTS_Sysref_Ctrl(InstancePtr, Type, Index, 0, ConfigPtr->SysRef_Enable, 0); + } + } + + return Status; +} + +/*****************************************************************************/ +/** +* +* This API is used to enable/disable the sysref. +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param DACSyncConfigPtr is pointer to DAC Multi-Tile Sync config structure. +* @param ADCSyncConfigPtr is pointer to ADC Multi-Tile Sync config structure. +* @param SysRefEnable valid values are 0(disable) and 1(enable). +* +* @return +* - XRFDC_MTS_OK if successful. +* +* @note None +* +******************************************************************************/ +u32 XRFdc_MTS_Sysref_Config(XRFdc *InstancePtr, + XRFdc_MultiConverter_Sync_Config *DACSyncConfigPtr, + XRFdc_MultiConverter_Sync_Config *ADCSyncConfigPtr, u32 SysRefEnable) +{ + u32 Tile; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(DACSyncConfigPtr != NULL); + Xil_AssertNonvoid(ADCSyncConfigPtr != NULL); + + /* Enable/disable SysRef Capture on all DACs participating in MTS */ + for (Tile = XRFDC_TILE_ID0; Tile < XRFDC_TILE_ID4; Tile++) { + if (((1U << Tile) & DACSyncConfigPtr->Tiles) != 0U) { + XRFdc_MTS_Sysref_Ctrl(InstancePtr, + XRFDC_DAC_TILE, Tile, 0, SysRefEnable, 0); + } + } + + /* Enable/Disable SysRef Capture on all ADCs participating in MTS */ + for (Tile = XRFDC_TILE_ID0; Tile < XRFDC_TILE_ID4; Tile++) { + if (((1U << Tile) & ADCSyncConfigPtr->Tiles) != 0U) { + XRFdc_MTS_Sysref_Ctrl(InstancePtr, + XRFDC_ADC_TILE, Tile, 0, SysRefEnable, 0); + } + } + + /* Enable/Disable SysRef TRX */ + XRFdc_MTS_Sysref_TRx(InstancePtr, SysRefEnable); + + return XRFDC_MTS_OK; +} + +/*****************************************************************************/ +/** +* +* This API Initializes the multi-tile sync config structures. +* Optionally allows target codes to be provided for the Pll/T1 +* analog sysref capture +* +* @param ConfigPtr pointer to Multi-tile sync config structure. +* @param PLL_CodesPtr pointer to PLL analog sysref capture. +* @param T1_CodesPtr pointer to T1 analog sysref capture. +* +* @return None +* +* @note None +* +******************************************************************************/ +void XRFdc_MultiConverter_Init(XRFdc_MultiConverter_Sync_Config *ConfigPtr, + int *PLL_CodesPtr, int *T1_CodesPtr) +{ + u32 Index; + + Xil_AssertVoid(ConfigPtr != NULL); + + ConfigPtr->RefTile = 0U; + ConfigPtr->DTC_Set_PLL.Scan_Mode = (PLL_CodesPtr == NULL) ? + XRFDC_MTS_SCAN_INIT : XRFDC_MTS_SCAN_RELOAD; + ConfigPtr->DTC_Set_T1.Scan_Mode = (T1_CodesPtr == NULL) ? + XRFDC_MTS_SCAN_INIT : XRFDC_MTS_SCAN_RELOAD; + ConfigPtr->DTC_Set_PLL.IsPLL = 1U; + ConfigPtr->DTC_Set_T1.IsPLL = 0U; + ConfigPtr->Target_Latency = -1; + ConfigPtr->Marker_Delay = 15; + ConfigPtr->SysRef_Enable = 1; /* By default enable Sysref capture after MTS */ + + /* Initialize variables per tile */ + for (Index = XRFDC_TILE_ID0; Index < XRFDC_TILE_ID4; Index++) { + if (PLL_CodesPtr != NULL) { + ConfigPtr->DTC_Set_PLL.Target[Index] = PLL_CodesPtr[Index]; + } else { + ConfigPtr->DTC_Set_PLL.Target[Index] = 0; + } + if (T1_CodesPtr != NULL) { + ConfigPtr->DTC_Set_T1.Target[Index] = T1_CodesPtr[Index]; + } else { + ConfigPtr->DTC_Set_T1.Target[Index] = 0; + } + + ConfigPtr->DTC_Set_PLL.DTC_Code[Index] = -1; + ConfigPtr->DTC_Set_T1.DTC_Code[Index] = -1; + } + +} + +/*****************************************************************************/ +/** +* +* This is the top level API which will be used for Multi-tile +* Synchronization. +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC +* @param ConfigPtr Multi-tile sync config structure. +* +* @return +* - XRFDC_MTS_OK if successful. +* - XRFDC_MTS_TIMEOUT if timeout occurs. +* - XRFDC_MTS_MARKER_RUN +* - XRFDC_MTS_MARKER_MISM +* - XRFDC_MTS_NOT_SUPPORTED if MTS is not supported. +* +* @note None +* +******************************************************************************/ +u32 XRFdc_MultiConverter_Sync(XRFdc *InstancePtr, u32 Type, + XRFdc_MultiConverter_Sync_Config *ConfigPtr) +{ + u32 Status; + u32 Index; + u32 RegData; + XRFdc_IPStatus IPStatus = {0}; + XRFdc_MTS_Marker Markers = {0U}; + u32 BaseAddr; + u32 TileState; + u32 BlockStatus; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(ConfigPtr != NULL); + + Status = XRFDC_MTS_OK; + + (void)XRFdc_GetIPStatus(InstancePtr, &IPStatus); + for (Index = XRFDC_TILE_ID0; Index < XRFDC_TILE_ID4; Index++) { + if ((ConfigPtr->Tiles & (1U << Index)) != 0U) { + TileState = (Type == XRFDC_DAC_TILE) ? + IPStatus.DACTileStatus[Index].TileState : + IPStatus.ADCTileStatus[Index].TileState ; + if (TileState != 0xFU) { + metal_log(METAL_LOG_ERROR, + "%s tile %d in Multi-Tile group not started\n", + (Type == XRFDC_ADC_TILE) ? "ADC" : "DAC", Index); + + Status |= XRFDC_MTS_IP_NOT_READY; + } + BaseAddr = XRFDC_DRP_BASE(Type, Index) - XRFDC_TILE_DRP_OFFSET; + RegData = XRFdc_ReadReg(InstancePtr, BaseAddr, XRFDC_MTS_DLY_ALIGNER); + if (RegData == 0U) { + metal_log(METAL_LOG_ERROR, "%s tile %d is not enabled for MTS, check IP configuration\n", + (Type == XRFDC_ADC_TILE) ? "ADC" : "DAC", Index); + Status |= XRFDC_MTS_NOT_ENABLED; + } + + BlockStatus = XRFdc_CheckBlockEnabled(InstancePtr, Type, Index, 0x0U); + if (BlockStatus != 0U) { + metal_log(METAL_LOG_ERROR, "%s%d block0 is not enabled, check IP configuration\n", + (Type == XRFDC_ADC_TILE) ? "ADC" : "DAC", Index); + Status |= XRFDC_MTS_NOT_SUPPORTED; + } + } + } + + if (Status != XRFDC_MTS_OK) { + return Status; + } + + /* Disable the FIFOs */ + XRFdc_MTS_FIFOCtrl(InstancePtr, Type, XRFDC_MTS_FIFO_DISABLE, 0); + + /* Enable SysRef Rx */ + XRFdc_MTS_Sysref_TRx(InstancePtr, 1); + + /* Update distribution */ + Status |= XRFdc_MTS_Sysref_Dist(InstancePtr, -1); + + /* Scan DTCs for each tile */ + for (Index = XRFDC_TILE_ID0; Index < XRFDC_TILE_ID4; Index++) { + if ((ConfigPtr->Tiles & (1U << Index)) != 0U) { + /* Run DTC Scan for T1/PLL */ + BaseAddr = XRFDC_DRP_BASE(Type, Index) + XRFDC_HSCOM_ADDR; + RegData = XRFdc_ReadReg16(InstancePtr, BaseAddr, + XRFDC_MTS_CLKSTAT); + if ((RegData & XRFDC_MTS_PLLEN_M) != 0U) { + /* DTC Scan PLL */ + if (Index == 0U) { + metal_log(METAL_LOG_INFO, "\nDTC Scan PLL\n", 0); + } + ConfigPtr->DTC_Set_PLL.RefTile = ConfigPtr->RefTile; + Status |= XRFdc_MTS_Dtc_Scan(InstancePtr, Type, Index, + &ConfigPtr->DTC_Set_PLL); + } + } + } + + /* Scan DTCs for each tile T1 */ + metal_log(METAL_LOG_INFO, "\nDTC Scan T1\n", 0); + for (Index = XRFDC_TILE_ID0; Index < XRFDC_TILE_ID4; Index++) { + if ((ConfigPtr->Tiles & (1U << Index)) != 0U) { + ConfigPtr->DTC_Set_T1 .RefTile = ConfigPtr->RefTile; + Status |= XRFdc_MTS_Dtc_Scan(InstancePtr, Type, Index, + &ConfigPtr->DTC_Set_T1); + } + } + + /* Enable FIFOs */ + XRFdc_MTS_FIFOCtrl(InstancePtr, Type, XRFDC_MTS_FIFO_ENABLE, + ConfigPtr->Tiles); + + /* Measure latency */ + Status |= XRFdc_MTS_GetMarker(InstancePtr, Type, ConfigPtr->Tiles, + &Markers, ConfigPtr->Marker_Delay); + + /* Calculate latency difference and adjust for it */ + Status |= XRFdc_MTS_Latency(InstancePtr, Type, ConfigPtr, &Markers); + + return Status; +} +/*****************************************************************************/ +/** +* +* This is the top level API which will be used to check if Multi-tile +* is enabled. +* +* +* @param InstancePtr is a pointer to the XRfdc instance. +* @param Type is ADC or DAC. 0 for ADC and 1 for DAC. +* @param Tile_Id indicates Tile number (0-3). +* @param EnablePtr to be filled with the enable state. +* +* @return +* - XRFDC_SUCCESS if successful. +* - XRFDC_SUCCESS if error occurs. +* +* @note None +* +******************************************************************************/ +u32 XRFdc_GetMTSEnable(XRFdc *InstancePtr, u32 Type,u32 Tile_Id, u32 *EnablePtr) +{ + u32 RegData; + u32 BaseAddr; + u32 Status; + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(EnablePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XRFDC_COMPONENT_IS_READY); + + 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_TILE_DRP_OFFSET; + RegData = XRFdc_ReadReg(InstancePtr, BaseAddr, XRFDC_MTS_DLY_ALIGNER); + if (RegData == 0) { + *EnablePtr = 0; + } else { + *EnablePtr = 1; + } + Status = XRFDC_SUCCESS; +RETURN_PATH: + return Status; +} +/** @} */ diff --git a/mpm/lib/rfdc/xrfdc_sinit.c b/mpm/lib/rfdc/xrfdc_sinit.c new file mode 100644 index 000000000..0fb907859 --- /dev/null +++ b/mpm/lib/rfdc/xrfdc_sinit.c @@ -0,0 +1,272 @@ +/****************************************************************************** +* +* Copyright (C) 2017-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_sinit.c +* @addtogroup rfdc_v6_0 +* @{ +* +* The implementation of the XRFdc component's static initialization +* functionality. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- -------- ----------------------------------------------- +* 1.0 sk 05/16/17 Initial release +* 5.0 mus 08/17/18 Updated XRFdc_LookupConfig to make use of device +* tree instead of xrfdc_g.c, to obtain +* XRFdc_Config for provided device id.It is being +* achieved through "param-list" property in RFDC +* device node, it will be having 1:1 mapping with +* the XRFdc_Config structure. Said changes +* have been done, to remove the xparameters.h +* dependency from RFDC Linux user space driver. +* +* </pre> +* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#define METAL_INTERNAL +#include "mpm/rfdc/xrfdc.h" +#ifdef __BAREMETAL__ +#include "xparameters.h" +#else +#include <dirent.h> +#include <arpa/inet.h> +#endif +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ +#ifdef __BAREMETAL__ +extern XRFdc_Config XRFdc_ConfigTable[]; +#else +static XRFdc_Config *XRFdc_ConfigTablePtr=NULL; +#endif + +#ifndef __BAREMETAL__ +/*****************************************************************************/ +/** +* +* Compare two strings in the reversed order.This function compares only +* the last "Count" number of characters of Str1Ptr and Str2Ptr. +* +* @param Str1Ptr is base address of first string +* @param Str2Ptr is base address of second string +* @param Count is number of last characters to be compared between +* Str1Ptr and Str2Ptr +* +* @return +* 0 if last "Count" number of bytes matches between Str1Ptr and +* Str2Ptr, else differnce in unmatched character. +* +*@note None. +* +******************************************************************************/ +static s32 XRFdc_Strrncmp(const char *Str1Ptr, const char *Str2Ptr, size_t Count) +{ + u16 Len1 = strlen(Str1Ptr); + u16 Len2 = strlen(Str2Ptr); + u8 Diff; + + for (; Len1 && Len2; Len1--, Len2--) { + if ((Diff = Str1Ptr[Len1 - 1] - Str2Ptr[Len2 - 1]) != 0) { + return Diff; + } + if (--Count == 0) { + return 0; + } + } + + return (Len1 - Len2); +} + +/*****************************************************************************/ +/** +* +* Traverse "/sys/bus/platform/device" directory, to find RFDC device entry, +* corresponding to provided device id. If device entry corresponding to said +* device id is found, store it in output buffer DevNamePtr. +* +* @param DevNamePtr is base address of char array, where device name +* will be stored +* @param DevId contains the ID of the device to look up the +* RFDC device name entry in "/sys/bus/platform/device" +* +* @return + * - XRFDC_SUCCESS if successful. + * - XRFDC_FAILURE if device entry not found for given device id. + * + *@note None. +* +******************************************************************************/ +s32 XRFdc_GetDeviceNameByDeviceId(char *DevNamePtr, u16 DevId) +{ + s32 Status = XRFDC_FAILURE; + u32 Data = 0; + char CompatibleString[NAME_MAX]; + struct metal_device *DevicePtr; + DIR *DirPtr; + struct dirent *DirentPtr; + char Len = strlen(XRFDC_COMPATIBLE_STRING); + char SignLen = strlen(XRFDC_SIGNATURE); + + DirPtr = opendir(XRFDC_PLATFORM_DEVICE_DIR); + if (DirPtr) { + while ((DirentPtr = readdir(DirPtr)) != NULL) { + if (XRFdc_Strrncmp(DirentPtr->d_name, + XRFDC_SIGNATURE, SignLen) == 0) { + Status = metal_device_open("platform",DirentPtr->d_name, + &DevicePtr); + if (Status) { + metal_log(METAL_LOG_ERROR, + "\n Failed to open device %s", DirentPtr->d_name); + continue; + } + Status = metal_linux_get_device_property(DevicePtr, + XRFDC_COMPATIBLE_PROPERTY, CompatibleString , + Len); + if (Status < 0) { + metal_log(METAL_LOG_ERROR, + "\n Failed to read device tree property"); + } else if (strncmp(CompatibleString, \ + XRFDC_COMPATIBLE_STRING, Len) == 0) { + Status = metal_linux_get_device_property(DevicePtr, + XRFDC_CONFIG_DATA_PROPERTY, + &Data, XRFDC_DEVICE_ID_SIZE); + if (Status < 0) { + metal_log(METAL_LOG_ERROR, + "\n Failed to read device tree property"); + } else if ( Data == DevId ) { + strcpy(DevNamePtr, DirentPtr->d_name); + Status = XRFDC_SUCCESS; + metal_device_close(DevicePtr); + break; + } + } + metal_device_close(DevicePtr); + } + } + closedir(DirPtr); + } + return Status; +} +#endif +/*****************************************************************************/ +/** +* +* Looks up the device configuration based on the unique device ID. A table +* contains the configuration info for each device in the system. +* +* @param DeviceId contains the ID of the device to look up the +* configuration for. +* +* @return +* +* A pointer to the configuration found or NULL if the specified device ID was +* not found. See xrfdc.h for the definition of XRFdc_Config. +* +* @note None. +* +******************************************************************************/ +XRFdc_Config *XRFdc_LookupConfig(u16 DeviceId) +{ + XRFdc_Config *CfgPtr = NULL; +#ifndef __BAREMETAL__ + s32 Status=0; + u32 NumInstances; + struct metal_device *Deviceptr; + char DeviceName[NAME_MAX]; + + Status = XRFdc_GetDeviceNameByDeviceId(DeviceName, DeviceId); + if (Status != XRFDC_SUCCESS) { + metal_log(METAL_LOG_ERROR, "\n Invalid device id %d", DeviceId); + goto RETURN_PATH2; + } + + Status = metal_device_open(XRFDC_BUS_NAME, DeviceName, &Deviceptr); + if (Status) { + metal_log(METAL_LOG_ERROR, "\n Failed to open device %s", DeviceName); + goto RETURN_PATH2; + } + + if (XRFdc_ConfigTablePtr == NULL) { + Status = metal_linux_get_device_property(Deviceptr, + XRFDC_NUM_INSTANCES_PROPERTY, + &NumInstances, XRFDC_NUM_INST_SIZE); + if (Status < 0) { + metal_log(METAL_LOG_ERROR, + "\n Failed to read device tree property %s", + XRFDC_NUM_INSTANCES_PROPERTY); + goto RETURN_PATH1; + } + XRFdc_ConfigTablePtr = (XRFdc_Config*) malloc(ntohl(NumInstances) * \ + XRFDC_CONFIG_DATA_SIZE); + if (XRFdc_ConfigTablePtr == NULL) { + metal_log(METAL_LOG_ERROR, + "\n Failed to allocate memory for XRFdc_ConfigTablePtr"); + goto RETURN_PATH1; + } + } + Status = metal_linux_get_device_property(Deviceptr, + XRFDC_CONFIG_DATA_PROPERTY, + &XRFdc_ConfigTablePtr[DeviceId], + XRFDC_CONFIG_DATA_SIZE); + if (Status == XRFDC_SUCCESS) { + CfgPtr = &XRFdc_ConfigTablePtr[DeviceId]; + } else { + metal_log(METAL_LOG_ERROR, + "\n Failed to read device tree property %s", + XRFDC_CONFIG_DATA_PROPERTY); + + } +RETURN_PATH1: + metal_device_close(Deviceptr); +RETURN_PATH2: +#else + u32 Index; + + for (Index = 0U; Index < (u32)XPAR_XRFDC_NUM_INSTANCES; Index++) { + if (XRFdc_ConfigTable[Index].DeviceId == DeviceId) { + CfgPtr = &XRFdc_ConfigTable[Index]; + break; + } + } +#endif + return (XRFdc_Config *)CfgPtr; +} +/** @} */ |