aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/x400
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp/x400')
-rw-r--r--host/lib/usrp/x400/x400_gpio_control.cpp37
-rw-r--r--host/lib/usrp/x400/x400_gpio_control.hpp17
-rw-r--r--host/lib/usrp/x400/x400_radio_control.cpp30
-rw-r--r--host/lib/usrp/x400/x400_radio_control.hpp49
4 files changed, 118 insertions, 15 deletions
diff --git a/host/lib/usrp/x400/x400_gpio_control.cpp b/host/lib/usrp/x400/x400_gpio_control.cpp
index 3213f6e64..18599eb88 100644
--- a/host/lib/usrp/x400/x400_gpio_control.cpp
+++ b/host/lib/usrp/x400/x400_gpio_control.cpp
@@ -6,6 +6,7 @@
#include "x400_gpio_control.hpp"
+
using namespace uhd::rfnoc::x400;
namespace {
@@ -33,6 +34,9 @@ constexpr uint32_t DIO_DIRECTION_REG = 0x4;
// There are two ports, each with 12 pins
constexpr size_t NUM_PINS_PER_PORT = 12;
+// Start of Port B pin numbers relative to Port A:
+constexpr size_t PORT_NUMBER_OFFSET = 16;
+
// These values should match the values in MPM's x4xx_periphs.py "DIO_PORT_MAP"
constexpr uint32_t PORTA_MAPPING[12] = {1, 0, 2, 3, 5, 4, 6, 7, 9, 8, 10, 11};
constexpr uint32_t PORTB_MAPPING[12] = {10, 11, 9, 8, 6, 7, 5, 4, 2, 3, 1, 0};
@@ -40,7 +44,8 @@ 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)
+gpio_control::gpio_control(
+ uhd::usrp::x400_rpc_iface::sptr rpcc, uhd::wb_iface::sptr iface)
: _rpcc(rpcc), _regs(iface)
{
_rpcc->dio_set_port_mapping("DIO");
@@ -87,8 +92,10 @@ void gpio_control::set_gpio_attr(
bool gpio_control::is_atr_attr(const uhd::usrp::gpio_atr::gpio_attr_t attr)
{
- return attr == uhd::usrp::gpio_atr::GPIO_ATR_0X || attr == uhd::usrp::gpio_atr::GPIO_ATR_RX
- || attr == uhd::usrp::gpio_atr::GPIO_ATR_TX || attr == uhd::usrp::gpio_atr::GPIO_ATR_XX;
+ return attr == uhd::usrp::gpio_atr::GPIO_ATR_0X
+ || attr == uhd::usrp::gpio_atr::GPIO_ATR_RX
+ || attr == uhd::usrp::gpio_atr::GPIO_ATR_TX
+ || attr == uhd::usrp::gpio_atr::GPIO_ATR_XX;
}
uint32_t gpio_control::internalize_value(const uint32_t value)
@@ -125,3 +132,27 @@ uint32_t gpio_control::get_gpio_attr(const uhd::usrp::gpio_atr::gpio_attr_t attr
return publicize_value(_gpios[0]->get_attr_reg(attr));
}
+
+uint32_t uhd::rfnoc::x400::x400_gpio_port_mapping::map_value(const uint32_t& value)
+{
+ const uint32_t bank = value >= NUM_PINS_PER_PORT ? 1 : 0;
+ uint32_t pin_intern = value % NUM_PINS_PER_PORT;
+ const uint32_t* const mapping = bank == 1 ? PORTB_MAPPING : PORTA_MAPPING;
+ for (size_t i = 0; i < NUM_PINS_PER_PORT; i++) {
+ if (mapping[i] == pin_intern) {
+ return i + (bank * PORT_NUMBER_OFFSET);
+ }
+ }
+ throw uhd::lookup_error(
+ "Could not find corresponding GPIO pin number for given SPI pin " + value);
+ return 0;
+}
+
+uint32_t uhd::rfnoc::x400::x400_gpio_port_mapping::unmap_value(const uint32_t& value)
+{
+ const uint32_t bank = value >= PORT_NUMBER_OFFSET ? 1 : 0;
+ uint32_t pin_number = value % PORT_NUMBER_OFFSET;
+ const uint32_t* const mapping = bank == 1 ? PORTB_MAPPING : PORTA_MAPPING;
+ UHD_ASSERT_THROW(pin_number < NUM_PINS_PER_PORT);
+ return mapping[pin_number] + (bank * NUM_PINS_PER_PORT);
+} \ No newline at end of file
diff --git a/host/lib/usrp/x400/x400_gpio_control.hpp b/host/lib/usrp/x400/x400_gpio_control.hpp
index a0c0593ec..01cfc134e 100644
--- a/host/lib/usrp/x400/x400_gpio_control.hpp
+++ b/host/lib/usrp/x400/x400_gpio_control.hpp
@@ -6,8 +6,9 @@
#pragma once
-#include <uhdlib/usrp/cores/gpio_atr_3000.hpp>
#include <uhdlib/usrp/common/rpc.hpp>
+#include <uhdlib/usrp/cores/gpio_atr_3000.hpp>
+#include <uhdlib/usrp/cores/gpio_port_mapper.hpp>
#include <vector>
namespace uhd { namespace rfnoc { namespace x400 {
@@ -32,7 +33,8 @@ extern const char* GPIO_BANK_NAME;
* internal radio control registers, as well as in MPM to configure the DIO
* board.
*/
-class gpio_control {
+class gpio_control
+{
public:
using sptr = std::shared_ptr<gpio_control>;
@@ -79,4 +81,13 @@ private:
std::vector<usrp::gpio_atr::gpio_atr_3000::sptr> _gpios;
};
-}}} // namespace uhd::rfnoc::x400
+class x400_gpio_port_mapping : public uhd::mapper::gpio_port_mapper
+{
+public:
+ x400_gpio_port_mapping(){};
+
+ uint32_t map_value(const uint32_t& value) override;
+
+ uint32_t unmap_value(const uint32_t& value) override;
+};
+}}} // namespace uhd::rfnoc::x400 \ No newline at end of file
diff --git a/host/lib/usrp/x400/x400_radio_control.cpp b/host/lib/usrp/x400/x400_radio_control.cpp
index a58f522bf..75719f6a2 100644
--- a/host/lib/usrp/x400/x400_radio_control.cpp
+++ b/host/lib/usrp/x400/x400_radio_control.cpp
@@ -5,14 +5,17 @@
//
#include "x400_radio_control.hpp"
+#include "x400_gpio_control.hpp"
#include <uhd/rfnoc/registry.hpp>
+#include <uhd/types/serial.hpp>
#include <uhd/utils/log.hpp>
#include <uhd/utils/math.hpp>
+#include <uhdlib/rfnoc/reg_iface_adapter.hpp>
#include <uhdlib/usrp/common/x400_rfdc_control.hpp>
+#include <uhdlib/usrp/cores/spi_core_4000.hpp>
#include <uhdlib/usrp/dboard/debug_dboard.hpp>
#include <uhdlib/usrp/dboard/null_dboard.hpp>
#include <uhdlib/usrp/dboard/zbx/zbx_dboard.hpp>
-#include <uhdlib/rfnoc/reg_iface_adapter.hpp>
namespace uhd { namespace rfnoc {
@@ -182,8 +185,25 @@ 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));
+ _gpios = std::make_shared<x400::gpio_control>(
+ _rpcc, 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);
+ auto spicore = uhd::cores::spi_core_4000::make(
+ [this](const uint32_t addr, const uint32_t data) {
+ regs().poke32(addr, data, get_command_time(0));
+ },
+ [this](
+ const uint32_t addr) { return regs().peek32(addr, get_command_time(0)); },
+ x400_regs::SPI_SLAVE_CFG,
+ x400_regs::SPI_TRANSACTION_CFG_REG,
+ x400_regs::SPI_TRANSACTION_GO_REG,
+ x400_regs::SPI_STATUS_REG,
+ gpio_port_mapper);
+
+ _spi_getter_iface = std::make_shared<x400_spi_getter>(spicore);
+ register_feature(_spi_getter_iface);
}
}
@@ -328,8 +348,8 @@ double x400_radio_control_impl::set_rate(const double rate)
// X400 does not support runtime rate changes
if (!uhd::math::frequencies_are_equal(rate, get_rate())) {
RFNOC_LOG_WARNING("Requesting invalid sampling rate from device: "
- << (rate / 1e6) << " MHz. Actual rate is: "
- << (get_rate() / 1e6) << " MHz.");
+ << (rate / 1e6)
+ << " MHz. Actual rate is: " << (get_rate() / 1e6) << " MHz.");
}
return get_rate();
}
diff --git a/host/lib/usrp/x400/x400_radio_control.hpp b/host/lib/usrp/x400/x400_radio_control.hpp
index 8848926c7..cd45291bc 100644
--- a/host/lib/usrp/x400/x400_radio_control.hpp
+++ b/host/lib/usrp/x400/x400_radio_control.hpp
@@ -7,24 +7,28 @@
#pragma once
#include "adc_self_calibration.hpp"
+#include "x400_gpio_control.hpp"
+#include <uhd/features/spi_getter_iface.hpp>
#include <uhd/rfnoc/noc_block_base.hpp>
#include <uhd/types/device_addr.hpp>
#include <uhd/types/direction.hpp>
#include <uhd/types/ranges.hpp>
#include <uhdlib/features/fpga_load_notification_iface.hpp>
#include <uhdlib/rfnoc/radio_control_impl.hpp>
+#include <uhdlib/rfnoc/reg_iface_adapter.hpp>
#include <uhdlib/rfnoc/rf_control/dboard_iface.hpp>
#include <uhdlib/usrp/common/mpmd_mb_controller.hpp>
#include <uhdlib/usrp/common/rpc.hpp>
#include <uhdlib/usrp/common/x400_rfdc_control.hpp>
+#include <uhdlib/usrp/cores/gpio_atr_3000.hpp>
+#include <uhdlib/usrp/cores/spi_core_4000.hpp>
#include <uhdlib/utils/rpc.hpp>
#include <stddef.h>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
-#include <uhdlib/usrp/cores/gpio_atr_3000.hpp>
-#include "x400_gpio_control.hpp"
+
namespace uhd { namespace rfnoc {
@@ -34,6 +38,22 @@ namespace x400_regs {
// other things in the RFDC.
constexpr uint32_t RFDC_CTRL_BASE = radio_control_impl::regmap::PERIPH_BASE + 0x8000;
+constexpr uint32_t DIO_REGMAP_OFFSET = 0x2000;
+constexpr uint32_t DIO_WINDOW_OFFSET = 0xC000;
+
+// SPI control registers
+constexpr uint32_t SPI_SLAVE_CFG =
+ DIO_REGMAP_OFFSET + DIO_WINDOW_OFFSET + radio_control_impl::regmap::PERIPH_BASE;
+
+//! Base address for SPI_TRANSACTION_CONFIG Register
+constexpr uint32_t SPI_TRANSACTION_CFG_REG = SPI_SLAVE_CFG + 0x0010;
+
+//! Base address for SPI_TRANSACTION_GO Register
+constexpr uint32_t SPI_TRANSACTION_GO_REG = SPI_SLAVE_CFG + 0x0014;
+
+//! Base address for SPI_STATUS Register
+constexpr uint32_t SPI_STATUS_REG = SPI_SLAVE_CFG + 0x0018;
+
} // namespace x400_regs
class x400_radio_control_impl : public radio_control_impl
@@ -116,8 +136,7 @@ public:
const std::string& name, const size_t chan) override;
void set_rx_lo_export_enabled(
bool enabled, const std::string& name, const size_t chan) override;
- bool get_rx_lo_export_enabled(
- const std::string& name, const size_t chan) override;
+ bool get_rx_lo_export_enabled(const std::string& name, const size_t chan) override;
double set_rx_lo_freq(
double freq, const std::string& name, const size_t chan) override;
double get_rx_lo_freq(const std::string& name, const size_t chan) override;
@@ -179,6 +198,8 @@ private:
uhd::features::adc_self_calibration_iface::sptr _adc_self_calibration;
+ uhd::features::spi_getter_iface::sptr _spi_getter_iface;
+
x400::gpio_control::sptr _gpios;
class fpga_onload : public uhd::features::fpga_load_notification_iface
@@ -203,6 +224,26 @@ private:
};
fpga_onload::sptr _fpga_onload;
+
+ class x400_spi_getter : public uhd::features::spi_getter_iface
+ {
+ public:
+ using sptr = std::shared_ptr<spi_getter_iface>;
+
+ x400_spi_getter(uhd::cores::spi_core_4000::sptr _spi) : _spicore(_spi) {}
+
+ uhd::spi_iface::sptr get_spi_ref(
+ const std::vector<uhd::features::spi_slave_config_t>& spi_slave_config)
+ const override
+ {
+ _spicore->set_spi_slave_config(spi_slave_config);
+ return _spicore;
+ }
+
+ private:
+ uhd::cores::spi_core_4000::sptr _spicore;
+ };
};
+
}} // namespace uhd::rfnoc