diff options
author | Lane Kolbly <lane.kolbly@ni.com> | 2022-03-18 15:42:03 -0500 |
---|---|---|
committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2022-03-23 16:14:07 -0500 |
commit | 48b76f49bc7e5498df4fba9274063913d7f31cfb (patch) | |
tree | d17d2ea71a3f302ccf9016b961f9eca1909cd763 | |
parent | 1ba8c2517d7162e0a5df1006abffcfc0ca910394 (diff) | |
download | uhd-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.cpp | 80 | ||||
-rw-r--r-- | host/lib/usrp/x400/x400_gpio_control.hpp | 14 | ||||
-rw-r--r-- | host/lib/usrp/x400/x400_radio_control.cpp | 2 |
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); |