aboutsummaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
Diffstat (limited to 'host')
-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);