diff options
Diffstat (limited to 'host')
-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); |