aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLane Kolbly <lane.kolbly@ni.com>2022-03-18 15:42:03 -0500
committerAaron Rossetto <aaron.rossetto@ni.com>2022-03-23 16:14:07 -0500
commit48b76f49bc7e5498df4fba9274063913d7f31cfb (patch)
treed17d2ea71a3f302ccf9016b961f9eca1909cd763
parent1ba8c2517d7162e0a5df1006abffcfc0ca910394 (diff)
downloaduhd-48b76f49bc7e5498df4fba9274063913d7f31cfb.tar.gz
uhd-48b76f49bc7e5498df4fba9274063913d7f31cfb.tar.bz2
uhd-48b76f49bc7e5498df4fba9274063913d7f31cfb.zip
host: x410: Emulate GPIO classic ATR mode using new mode
This fixes an issue with setting the active channel source in MPM, and additionally allows opening up the more flexible API in the future without requiring a filesystem update.
-rw-r--r--host/lib/usrp/x400/x400_gpio_control.cpp80
-rw-r--r--host/lib/usrp/x400/x400_gpio_control.hpp14
-rw-r--r--host/lib/usrp/x400/x400_radio_control.cpp2
3 files changed, 83 insertions, 13 deletions
diff --git a/host/lib/usrp/x400/x400_gpio_control.cpp b/host/lib/usrp/x400/x400_gpio_control.cpp
index b0eb4f27e..94b61f8c1 100644
--- a/host/lib/usrp/x400/x400_gpio_control.cpp
+++ b/host/lib/usrp/x400/x400_gpio_control.cpp
@@ -32,7 +32,7 @@ constexpr uint32_t DIO_DIRECTION_REG = 0x4;
} // namespace gpio_regmap
// There are two ports, each with 12 pins
-constexpr size_t NUM_PORTS = 2;
+constexpr size_t NUM_PORTS = 2;
constexpr size_t NUM_PINS_PER_PORT = 12;
// Start of Port B pin numbers relative to Port A:
@@ -45,22 +45,24 @@ constexpr uint32_t PORTB_MAPPING[12] = {10, 11, 9, 8, 6, 7, 5, 4, 2, 3, 1, 0};
const char* uhd::rfnoc::x400::GPIO_BANK_NAME = "GPIO";
-gpio_control::gpio_control(
- uhd::usrp::x400_rpc_iface::sptr rpcc, uhd::wb_iface::sptr iface)
- : _rpcc(rpcc), _regs(iface)
+gpio_control::gpio_control(uhd::usrp::x400_rpc_iface::sptr rpcc,
+ uhd::rfnoc::mpmd_mb_controller::sptr mb_control,
+ uhd::wb_iface::sptr iface)
+ : _rpcc(rpcc), _mb_control(mb_control), _regs(iface)
{
_rpcc->dio_set_port_mapping("DIO");
_rpcc->dio_set_voltage_level("PORTA", "3V3");
_rpcc->dio_set_voltage_level("PORTB", "3V3");
- // Hardcode classic ATR (channels operate independently)
- _regs->poke32(gpio_regmap::CLASSIC_MODE_OFFSET, 0x1);
+ // Hardcode new ATR (channel ATRs are combined into 4-bit index)
+ // Note that we emulate classic ATR
+ _regs->poke32(gpio_regmap::CLASSIC_MODE_OFFSET, 0x0);
// Initialize everything as inputs
_rpcc->dio_set_pin_directions("PORTA", 0x0);
_rpcc->dio_set_pin_directions("PORTB", 0x0);
- for (size_t bank = 0; bank < 2; bank++) {
+ for (size_t bank = 0; bank < 4; bank++) {
const wb_iface::wb_addr_type atr_base = bank * gpio_regmap::ATR_STRIDE;
usrp::gpio_atr::gpio_atr_offsets regmap{
atr_base + gpio_regmap::ATR_IDLE_OFFSET,
@@ -85,13 +87,58 @@ void gpio_control::set_gpio_attr(
_rpcc->dio_set_pin_directions("PORTB", value >> 12);
}
- const uint32_t internal_value = map_dio(value);
- _gpios[0]->set_gpio_attr(attr, internal_value);
if (is_atr_attr(attr)) {
- _gpios[1]->set_gpio_attr(attr, internal_value);
+ const uint32_t rf1_mask = build_rf1_mask();
+
+ for (size_t i = 0; i < 4; i++) {
+ const uint32_t previous_value = unmap_dio(_gpios[i]->get_attr_reg(attr));
+ const uint32_t new_value = (previous_value & rf1_mask) | (value & ~rf1_mask);
+ _gpios[i]->set_gpio_attr(attr, map_dio(new_value));
+ }
+
+ // Set the RF1 settings
+ for (const auto subattr : {uhd::usrp::gpio_atr::GPIO_ATR_0X,
+ uhd::usrp::gpio_atr::GPIO_ATR_RX,
+ uhd::usrp::gpio_atr::GPIO_ATR_TX,
+ uhd::usrp::gpio_atr::GPIO_ATR_XX}) {
+ const uint32_t previous_value =
+ unmap_dio(_gpios[atr_attr_index(attr)]->get_attr_reg(subattr));
+ const uint32_t new_value = (previous_value & ~rf1_mask) | (value & rf1_mask);
+ _gpios[atr_attr_index(attr)]->set_gpio_attr(subattr, map_dio(new_value));
+ }
+ } else {
+ const uint32_t internal_value = map_dio(value);
+ _gpios[0]->set_gpio_attr(attr, internal_value);
}
}
+uint32_t gpio_control::build_rf1_mask()
+{
+ auto porta_sources = _mb_control->get_gpio_src("GPIO0");
+ auto portb_sources = _mb_control->get_gpio_src("GPIO1");
+
+ uint32_t rf1_mask = 0;
+ for (size_t i = 0; i < 12; i++) {
+ if (porta_sources[i].find("RF1") != std::string::npos) {
+ rf1_mask |= 1 << i;
+ }
+ if (portb_sources[i].find("RF1") != std::string::npos) {
+ rf1_mask |= 1 << (i + 12);
+ }
+ }
+
+ return rf1_mask;
+}
+
+size_t gpio_control::atr_attr_index(const uhd::usrp::gpio_atr::gpio_attr_t attr)
+{
+ return attr == uhd::usrp::gpio_atr::GPIO_ATR_0X ? 0
+ : attr == uhd::usrp::gpio_atr::GPIO_ATR_RX ? 1
+ : attr == uhd::usrp::gpio_atr::GPIO_ATR_TX ? 2
+ : attr == uhd::usrp::gpio_atr::GPIO_ATR_XX ? 3
+ : 0;
+}
+
bool gpio_control::is_atr_attr(const uhd::usrp::gpio_atr::gpio_attr_t attr)
{
return attr == uhd::usrp::gpio_atr::GPIO_ATR_0X
@@ -136,6 +183,16 @@ uint32_t gpio_control::get_gpio_attr(const uhd::usrp::gpio_atr::gpio_attr_t attr
return unmap_dio(raw_value);
}
+ if (is_atr_attr(attr)) {
+ const uint32_t rf1_mask = build_rf1_mask();
+
+ // Grab the values for each channel
+ const uint32_t rf0_atr = unmap_dio(_gpios[0]->get_attr_reg(attr));
+ const uint32_t rf1_atr = unmap_dio(
+ _gpios[atr_attr_index(attr)]->get_attr_reg(uhd::usrp::gpio_atr::GPIO_ATR_0X));
+ return (rf0_atr & ~rf1_mask) | (rf1_atr & rf1_mask);
+ }
+
const uint32_t raw_value = _gpios[0]->get_attr_reg(attr);
return unmap_dio(raw_value);
}
@@ -151,7 +208,8 @@ uint32_t uhd::rfnoc::x400::x400_gpio_port_mapping::map_value(const uint32_t& val
}
}
throw uhd::lookup_error(
- std::string("Could not find corresponding GPIO pin number for given SPI pin ") + std::to_string(value));
+ std::string("Could not find corresponding GPIO pin number for given SPI pin ")
+ + std::to_string(value));
}
uint32_t uhd::rfnoc::x400::x400_gpio_port_mapping::unmap_value(const uint32_t& value)
diff --git a/host/lib/usrp/x400/x400_gpio_control.hpp b/host/lib/usrp/x400/x400_gpio_control.hpp
index 492413685..fdaa671ec 100644
--- a/host/lib/usrp/x400/x400_gpio_control.hpp
+++ b/host/lib/usrp/x400/x400_gpio_control.hpp
@@ -6,6 +6,7 @@
#pragma once
+#include <uhdlib/usrp/common/mpmd_mb_controller.hpp>
#include <uhdlib/usrp/common/rpc.hpp>
#include <uhdlib/usrp/cores/gpio_atr_3000.hpp>
#include <uhdlib/usrp/cores/gpio_port_mapper.hpp>
@@ -56,7 +57,7 @@ public:
* \param rpcc RPC object to talk to MPM
* \param iface wb_iface to talk to the radio registers
*/
- gpio_control(uhd::usrp::x400_rpc_iface::sptr rpcc, wb_iface::sptr iface);
+ gpio_control(uhd::usrp::x400_rpc_iface::sptr rpcc, uhd::rfnoc::mpmd_mb_controller::sptr mb_control, wb_iface::sptr iface);
/*! Set the given GPIO attribute. See gpio_atr_3000 for details.
*/
@@ -77,11 +78,22 @@ private:
*/
uint32_t map_dio(const uint32_t user_form);
+ /*! Builds the mask of which pins are currently assigned to the DBx_RF1
+ * source. Returns the pins in "unmapped" form.
+ */
+ uint32_t build_rf1_mask();
+
+ /*! Returns the numeric index of the given ATR attribute in the array of
+ * ATR value registers.
+ */
+ static size_t atr_attr_index(const uhd::usrp::gpio_atr::gpio_attr_t attr);
+
/*! Returns whether the given attribute is setting one of the ATR entries.
*/
static bool is_atr_attr(const usrp::gpio_atr::gpio_attr_t attr);
uhd::usrp::x400_rpc_iface::sptr _rpcc;
+ uhd::rfnoc::mpmd_mb_controller::sptr _mb_control;
wb_iface::sptr _regs;
// There are two GPIOs, one for each channel. These two are set in unison.
diff --git a/host/lib/usrp/x400/x400_radio_control.cpp b/host/lib/usrp/x400/x400_radio_control.cpp
index 528330101..ef2d6bd21 100644
--- a/host/lib/usrp/x400/x400_radio_control.cpp
+++ b/host/lib/usrp/x400/x400_radio_control.cpp
@@ -187,7 +187,7 @@ x400_radio_control_impl::x400_radio_control_impl(make_args_ptr make_args)
auto mpm_rpc = _mb_control->dynamic_cast_rpc_as<uhd::usrp::mpmd_rpc_iface>();
if (mpm_rpc->get_gpio_banks().size() > 0) {
_gpios = std::make_shared<x400::gpio_control>(
- _rpcc, RFNOC_MAKE_WB_IFACE(regmap::PERIPH_BASE + 0xC000, 0));
+ _rpcc, _mb_control, RFNOC_MAKE_WB_IFACE(regmap::PERIPH_BASE + 0xC000, 0));
auto gpio_port_mapper = std::shared_ptr<uhd::mapper::gpio_port_mapper>(
new uhd::rfnoc::x400::x400_gpio_port_mapping);