From c26de63a6481970cbc4c84b110df72e29c46ee3d Mon Sep 17 00:00:00 2001
From: Mark Meserve <mark.meserve@ni.com>
Date: Mon, 19 Nov 2018 13:50:18 -0600
Subject: rh: add support for atr frontend control

---
 host/lib/usrp/dboard/rhodium/rhodium_constants.hpp | 11 +++
 .../dboard/rhodium/rhodium_radio_ctrl_cpld.cpp     | 82 +---------------------
 .../dboard/rhodium/rhodium_radio_ctrl_impl.cpp     | 74 ++++++++++++++++++-
 .../dboard/rhodium/rhodium_radio_ctrl_impl.hpp     | 16 ++---
 .../dboard/rhodium/rhodium_radio_ctrl_init.cpp     | 12 +++-
 5 files changed, 103 insertions(+), 92 deletions(-)

(limited to 'host/lib/usrp/dboard/rhodium')

diff --git a/host/lib/usrp/dboard/rhodium/rhodium_constants.hpp b/host/lib/usrp/dboard/rhodium/rhodium_constants.hpp
index dd703a612..d21804f50 100644
--- a/host/lib/usrp/dboard/rhodium/rhodium_constants.hpp
+++ b/host/lib/usrp/dboard/rhodium/rhodium_constants.hpp
@@ -56,7 +56,18 @@ static const std::vector<std::string> RHODIUM_TX_ANTENNAS = {
 static constexpr char SPUR_DODGING_ARG_NAME[] = "spur_dodging";
 static constexpr char SPUR_DODGING_THRESHOLD_ARG_NAME[] = "spur_dodging_threshold";
 
+static constexpr uint32_t RHODIUM_GPIO_MASK = 0x1F;
 static constexpr uint32_t SW10_GPIO_MASK = 0x3;
+static constexpr uint32_t LED_GPIO_MASK = 0x1C;
+
+static constexpr uint32_t SW10_FROMTXLOWBAND = 0x0;
+static constexpr uint32_t SW10_FROMTXHIGHBAND = 0x1;
+static constexpr uint32_t SW10_ISOLATION = 0x2;
+static constexpr uint32_t SW10_TORX = 0x3;
+
+static constexpr uint32_t LED_RX  = 0x04;
+static constexpr uint32_t LED_RX2 = 0x08;
+static constexpr uint32_t LED_TX  = 0x10;
 
 //! Main LO
 static constexpr char RHODIUM_LO1[] = "lo1";
diff --git a/host/lib/usrp/dboard/rhodium/rhodium_radio_ctrl_cpld.cpp b/host/lib/usrp/dboard/rhodium/rhodium_radio_ctrl_cpld.cpp
index 68efe0f83..846a4eac6 100644
--- a/host/lib/usrp/dboard/rhodium/rhodium_radio_ctrl_cpld.cpp
+++ b/host/lib/usrp/dboard/rhodium/rhodium_radio_ctrl_cpld.cpp
@@ -223,9 +223,6 @@ void rhodium_radio_ctrl_impl::_update_tx_freq_switches(
         tx_sw5,
         tx_hb_lb_sel
     );
-
-    // If TX lowband/highband changes, SW10 needs to be updated
-    _update_tx_output_switches(get_tx_antenna(0));
 }
 
 void rhodium_radio_ctrl_impl::_update_rx_input_switches(
@@ -234,9 +231,6 @@ void rhodium_radio_ctrl_impl::_update_rx_input_switches(
     UHD_LOG_TRACE(unique_id(),
         "Update all RX input related switches. input=" << input
     );
-    const sw10_t sw10 = (input == "TX/RX") ?
-        SW10_TORX :
-        SW10_ISOLATION;
     const rhodium_cpld_ctrl::cal_iso_sw_t cal_iso = (input == "CAL") ?
         rhodium_cpld_ctrl::CAL_ISO_CALLOOPBACK :
         rhodium_cpld_ctrl::CAL_ISO_ISOLATION;
@@ -261,42 +255,9 @@ void rhodium_radio_ctrl_impl::_update_rx_input_switches(
 
     UHD_LOG_TRACE(unique_id(),
         "Selected switch values:"
-        " sw10=" << sw10 <<
         " sw1=" << sw1 <<
         " cal_iso=" << cal_iso
     );
-
-    // the TX path may be using TX/RX already, in which case only override sw10 if
-    // we are attempting to use TX/RX
-    if (get_tx_antenna(0) == "TX/RX")
-    {
-        if (input == "TX/RX")
-        {
-            UHD_LOG_TRACE(unique_id(),
-                "Overriding TX antenna to TERM"
-            );
-            // TODO: setting antenna here could cause race conditions
-            set_tx_antenna("TERM", 0);
-
-            UHD_LOG_TRACE(unique_id(),
-                "Setting switch values: sw10=" << sw10
-            );
-            _gpio->set_gpio_out(sw10, SW10_GPIO_MASK);
-        }
-        else {
-            // skip setting sw10, allowing TX to continue using TX/RX
-            UHD_LOG_TRACE(unique_id(),
-                "sw10 setting was not applied because TX antenna is set to TX/RX"
-            );
-        }
-    }
-    else {
-        // TX/RX is not in use, fire away
-        UHD_LOG_TRACE(unique_id(),
-            "Setting switch values: sw10=" << sw10
-        );
-        _gpio->set_gpio_out(sw10, SW10_GPIO_MASK);
-    }
     _cpld->set_rx_input_switches(sw1, cal_iso);
 }
 
@@ -306,69 +267,32 @@ void rhodium_radio_ctrl_impl::_update_tx_output_switches(
     UHD_LOG_TRACE(unique_id(),
         "Update all TX output related switches. output=" << output
     );
-    sw10_t sw10;
     rhodium_cpld_ctrl::tx_sw1_t sw1;
 
     if (output == "TX/RX")
     {
-        //Both sw1 and sw10 need to select low/high band
-        if (_map_freq_to_tx_band(get_tx_frequency(0)) == tx_band::TX_BAND_0)
+        //SW1 needs to select low/high band
+        if (_is_tx_lowband(get_tx_frequency(0)))
         {
             sw1 = rhodium_cpld_ctrl::TX_SW1_TOLOWBAND;
-            sw10 = SW10_FROMTXLOWBAND;
         }
         else {
             sw1 = rhodium_cpld_ctrl::TX_SW1_TOSWITCH2;
-            sw10 = SW10_FROMTXHIGHBAND;
         }
     }
     else if (output == "CAL") {
         sw1 = rhodium_cpld_ctrl::TX_SW1_TOCALLOOPBACK;
-        sw10 = SW10_ISOLATION;
     }
     else if (output == "TERM") {
         sw1 = rhodium_cpld_ctrl::TX_SW1_ISOLATION;
-        sw10 = SW10_ISOLATION;
     }
     else {
         throw uhd::runtime_error("Invalid antenna in _update_tx_output_switches: " + output);
     }
 
     UHD_LOG_TRACE(unique_id(),
-        "Selected switch values: sw1=" << sw1 << " sw10=" << sw10
+        "Selected switch values: sw1=" << sw1
     );
 
-    // If RX is on TX/RX, only set sw10 if TX is requesting TX/RX
-    // and override the RX antenna value
-    if (get_rx_antenna(0) == "TX/RX")
-    {
-        if (output == "TX/RX")
-        {
-            UHD_LOG_TRACE(unique_id(),
-                "Overriding RX antenna to TERM"
-            );
-            // TODO: setting antenna here could cause race conditions
-            set_rx_antenna("TERM", 0);
-
-            UHD_LOG_TRACE(unique_id(),
-                "Setting switch values: sw10=" << sw10
-            );
-            _gpio->set_gpio_out(sw10, SW10_GPIO_MASK);
-        }
-        else {
-            // skip setting sw10, allowing RX to continue using TX/RX
-            UHD_LOG_TRACE(unique_id(),
-                "sw10 setting was not applied because RX antenna is set to TX/RX"
-            );
-        }
-    }
-    // If RX is on any other setting, set sw10 normally
-    else {
-        UHD_LOG_TRACE(unique_id(),
-            "Setting switch values: sw10=" << sw10
-        );
-        _gpio->set_gpio_out(sw10, SW10_GPIO_MASK);
-    }
-
     _cpld->set_tx_output_switches(sw1);
 }
diff --git a/host/lib/usrp/dboard/rhodium/rhodium_radio_ctrl_impl.cpp b/host/lib/usrp/dboard/rhodium/rhodium_radio_ctrl_impl.cpp
index 01f467476..3de3f36f1 100644
--- a/host/lib/usrp/dboard/rhodium/rhodium_radio_ctrl_impl.cpp
+++ b/host/lib/usrp/dboard/rhodium/rhodium_radio_ctrl_impl.cpp
@@ -93,8 +93,10 @@ void rhodium_radio_ctrl_impl::set_tx_antenna(
         ));
     }
 
-    radio_ctrl_impl::set_tx_antenna(ant, chan);
     _update_tx_output_switches(ant);
+    // _update_atr will set the cached antenna value, so no need to do
+    // it here. See comments in _update_antenna for more info.
+    _update_atr(ant, TX_DIRECTION);
 }
 
 void rhodium_radio_ctrl_impl::set_rx_antenna(
@@ -112,8 +114,10 @@ void rhodium_radio_ctrl_impl::set_rx_antenna(
         ));
     }
 
-    radio_ctrl_impl::set_rx_antenna(ant, chan);
     _update_rx_input_switches(ant);
+    // _update_atr will set the cached antenna value, so no need to do
+    // it here. See comments in _update_antenna for more info.
+    _update_atr(ant, RX_DIRECTION);
 }
 
 void rhodium_radio_ctrl_impl::_set_tx_fe_connection(const std::string &conn)
@@ -180,6 +184,9 @@ double rhodium_radio_ctrl_impl::set_tx_frequency(
     set_tx_gain(get_tx_gain(chan), 0);
     radio_ctrl_impl::set_tx_frequency(coerced_freq, chan);
     _update_tx_freq_switches(coerced_freq);
+    // if TX lowband/highband changed and antenna is TX/RX,
+    // the ATR needs to be updated
+    _update_atr(get_tx_antenna(0), TX_DIRECTION);
 
     return coerced_freq;
 }
@@ -296,6 +303,69 @@ double rhodium_radio_ctrl_impl::set_rx_gain(
     return index;
 }
 
+void rhodium_radio_ctrl_impl::_update_atr(
+    const std::string& ant,
+    const direction_t dir
+) {
+    // This function updates sw10 based on the value of both antennas, so we
+    // use a mutex to prevent other calls in this class instance from running
+    // at the same time.
+    std::lock_guard<std::mutex> lock(_ant_mutex);
+
+    UHD_LOG_TRACE(unique_id(),
+        "Updating ATRs for " << ((dir == RX_DIRECTION) ? "RX" : "TX") << " to " << ant);
+
+    const auto rx_ant  = (dir == RX_DIRECTION) ? ant : get_rx_antenna(0);
+    const auto tx_ant  = (dir == TX_DIRECTION) ? ant : get_tx_antenna(0);
+    const auto sw10_tx = _is_tx_lowband(get_tx_frequency(0)) ?
+        SW10_FROMTXLOWBAND : SW10_FROMTXHIGHBAND;
+
+
+    const uint32_t atr_idle = SW10_ISOLATION;
+
+    const uint32_t atr_rx = [rx_ant]{
+        if (rx_ant == "TX/RX") {
+            return SW10_TORX | LED_RX;
+        } else if (rx_ant == "RX2") {
+            return SW10_ISOLATION | LED_RX2;
+        } else {
+            return SW10_ISOLATION;
+        }
+    }();
+
+    const uint32_t atr_tx = (tx_ant == "TX/RX") ?
+        (sw10_tx | LED_TX) : SW10_ISOLATION;
+
+    const uint32_t atr_dx = [tx_ant, rx_ant, sw10_tx] {
+        uint32_t sw10_return;
+        if (tx_ant == "TX/RX") {
+            // if both channels are set to TX/RX, TX will override
+            sw10_return = sw10_tx | LED_TX;
+        } else if (rx_ant == "TX/RX") {
+            sw10_return = SW10_TORX | LED_RX;
+        } else {
+            sw10_return = SW10_ISOLATION;
+        }
+        sw10_return |= (rx_ant == "RX2") ? LED_RX2 : 0;
+        return sw10_return;
+    }();
+
+    _gpio->set_atr_reg(gpio_atr::ATR_REG_IDLE, atr_idle, RHODIUM_GPIO_MASK);
+    _gpio->set_atr_reg(gpio_atr::ATR_REG_RX_ONLY, atr_rx, RHODIUM_GPIO_MASK);
+    _gpio->set_atr_reg(gpio_atr::ATR_REG_TX_ONLY, atr_tx, RHODIUM_GPIO_MASK);
+    _gpio->set_atr_reg(gpio_atr::ATR_REG_FULL_DUPLEX, atr_dx, RHODIUM_GPIO_MASK);
+
+    UHD_LOG_TRACE(unique_id(),
+        str(boost::format("Wrote ATR registers i:0x%02X, r:0x%02X, t:0x%02X, d:0x%02X")
+            % atr_idle % atr_rx % atr_tx % atr_dx));
+
+    if (dir == RX_DIRECTION) {
+        radio_ctrl_impl::set_rx_antenna(ant, 0);
+    } else {
+        radio_ctrl_impl::set_tx_antenna(ant, 0);
+    }
+}
+
 uhd::gain_range_t rhodium_radio_ctrl_impl::_get_gain_range(direction_t dir)
 {
     if (dir == RX_DIRECTION) {
diff --git a/host/lib/usrp/dboard/rhodium/rhodium_radio_ctrl_impl.hpp b/host/lib/usrp/dboard/rhodium/rhodium_radio_ctrl_impl.hpp
index af6322655..ac2311a24 100644
--- a/host/lib/usrp/dboard/rhodium/rhodium_radio_ctrl_impl.hpp
+++ b/host/lib/usrp/dboard/rhodium/rhodium_radio_ctrl_impl.hpp
@@ -56,13 +56,6 @@ public:
         TX_BAND_7
     };
 
-    enum sw10_t {
-        SW10_FROMTXLOWBAND = 0,
-        SW10_FROMTXHIGHBAND = 1,
-        SW10_ISOLATION = 2,
-        SW10_TORX = 3
-    };
-
     /************************************************************************
      * Structors
      ***********************************************************************/
@@ -217,6 +210,11 @@ private:
         const direction_t dir
     );
 
+    //! Configure ATR registers and update the cached antenna value from the
+    //  new antenna value.
+    //  ATR registers control SW10 and the frontend LEDs.
+    void _update_atr(const std::string& ant, const direction_t dir);
+
     //! Map a frequency in Hz to an rx_band value. Will return
     //  rx_band::INVALID_BAND if the frequency is out of range.
     static rx_band _map_freq_to_rx_band(const double freq);
@@ -285,8 +283,8 @@ private:
     /**************************************************************************
      * Private attributes
      *************************************************************************/
-    //! Locks access to setter APIs
-    std::mutex _set_lock;
+    //! Locks access to the antenna cached values
+    std::mutex _ant_mutex;
 
     //! Letter representation of the radio we're currently running
     std::string _radio_slot;
diff --git a/host/lib/usrp/dboard/rhodium/rhodium_radio_ctrl_init.cpp b/host/lib/usrp/dboard/rhodium/rhodium_radio_ctrl_init.cpp
index 600758efa..28e5eb3a6 100644
--- a/host/lib/usrp/dboard/rhodium/rhodium_radio_ctrl_init.cpp
+++ b/host/lib/usrp/dboard/rhodium/rhodium_radio_ctrl_init.cpp
@@ -191,14 +191,22 @@ void rhodium_radio_ctrl_impl::_init_peripherals()
             regs::rb_addr(regs::RB_DB_GPIO)
         );
     _gpio->set_atr_mode(
-        usrp::gpio_atr::MODE_GPIO, // Disable ATR mode
-        usrp::gpio_atr::gpio_atr_3000::MASK_SET_ALL
+        usrp::gpio_atr::MODE_ATR, // Enable ATR mode for Rhodium bits
+        RHODIUM_GPIO_MASK
+    );
+    _gpio->set_atr_mode(
+        usrp::gpio_atr::MODE_GPIO, // Disable ATR mode for unused bits
+        ~RHODIUM_GPIO_MASK
     );
     _gpio->set_gpio_ddr(
         usrp::gpio_atr::DDR_OUTPUT, // Make all GPIOs outputs
         usrp::gpio_atr::gpio_atr_3000::MASK_SET_ALL
     );
 
+    UHD_LOG_TRACE(unique_id(), "Set initial ATR values...");
+    _update_atr(RHODIUM_DEFAULT_TX_ANTENNA, TX_DIRECTION);
+    _update_atr(RHODIUM_DEFAULT_RX_ANTENNA, RX_DIRECTION);
+
     // Updating the TX frequency path may include an update to SW10, which is
     // GPIO controlled, so this must follow CPLD and GPIO initialization
     UHD_LOG_TRACE(unique_id(), "Writing initial switch values...");
-- 
cgit v1.2.3