aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fpga/usrp3/top/x300/bus_int.v13
-rw-r--r--fpga/usrp3/top/x300/x300_core.v39
-rw-r--r--host/examples/gpio.cpp48
-rw-r--r--host/lib/usrp/multi_usrp_python.hpp3
-rw-r--r--host/lib/usrp/x300/x300_mb_controller.cpp105
-rw-r--r--host/lib/usrp/x300/x300_mb_controller.hpp4
-rw-r--r--host/lib/usrp/x300/x300_radio_control.cpp47
-rw-r--r--host/lib/usrp/x300/x300_regs.hpp4
8 files changed, 209 insertions, 54 deletions
diff --git a/fpga/usrp3/top/x300/bus_int.v b/fpga/usrp3/top/x300/bus_int.v
index faf4f8d82..92bea5d84 100644
--- a/fpga/usrp3/top/x300/bus_int.v
+++ b/fpga/usrp3/top/x300/bus_int.v
@@ -45,6 +45,8 @@ module bus_int #(
input SFPP0_ModAbs, input SFPP0_TxFault, input SFPP0_RxLOS, inout SFPP0_RS0, inout SFPP0_RS1,
// SFP+ 1
input SFPP1_ModAbs, input SFPP1_TxFault, input SFPP1_RxLOS, inout SFPP1_RS0, inout SFPP1_RS1,
+ // Front-panel GPIO source
+ output [23:0] fp_gpio_src,
// Clock control and status
input [7:0] clock_status, output [7:0] clock_control, output [31:0] ref_freq, output ref_freq_changed,
// SFP+ 0 data stream
@@ -153,7 +155,7 @@ module bus_int #(
localparam SR_SPI = 8'd32;
localparam SR_ETHINT0 = 8'd40;
localparam SR_ETHINT1 = 8'd56;
- //localparam SR_NEXT_ADDR = 8'd72;
+ localparam SR_FP_GPIO_SRC = 8'd72;
localparam SR_BASE_TIME = 8'd100;
localparam RB_COUNTER = 8'd00;
@@ -169,6 +171,7 @@ module bus_int #(
localparam RB_GIT_HASH = 8'd10;
localparam RB_XADC_VALS = 8'd11;
localparam RB_NUM_TIMEKEEPERS = 8'd12;
+ localparam RB_FP_GPIO_SRC = 8'd13;
localparam COMPAT_MAJOR = 16'h0026;
localparam COMPAT_MINOR = 16'h0000;
@@ -433,6 +436,7 @@ module bus_int #(
`endif
RB_GIT_HASH: rb_data = `GIT_HASH;
RB_XADC_VALS: rb_data = xadc_readback;
+ RB_FP_GPIO_SRC: rb_data = fp_gpio_src;
SR_BASE_TIME: begin
rb_data = radio_time[31:0];
radio_time_hi_ld = 1'b1;
@@ -604,6 +608,13 @@ module bus_int #(
assign SFPP1_RS0 = sfpp1_ctrl[0] ? 1'b0 : 1'bz;
assign SFPP1_RS1 = sfpp1_ctrl[1] ? 1'b0 : 1'bz;
+
+ // Front-panel GPIO source - Each pin is allocated 2 bits
+ setting_reg #(.my_addr(SR_FP_GPIO_SRC), .awidth(SR_AWIDTH), .width(24)) set_fp_gpio_src
+ (.clk(clk), .rst(reset),
+ .strobe(set_stb), .addr(set_addr), .in(set_data),
+ .out(fp_gpio_src));
+
// ////////////////////////////////////////////////////////////////
// ETH interfaces
diff --git a/fpga/usrp3/top/x300/x300_core.v b/fpga/usrp3/top/x300/x300_core.v
index 0a721e06b..5665c397f 100644
--- a/fpga/usrp3/top/x300/x300_core.v
+++ b/fpga/usrp3/top/x300/x300_core.v
@@ -1,6 +1,7 @@
//
// Copyright 2014 Ettus Research LLC
// Copyright 2017 Ettus Research, a National Instruments Company
+// Copyright 2020 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
@@ -21,7 +22,7 @@ module x300_core #(
// Radio 0
input [31:0] rx0, output [31:0] tx0,
input [31:0] db0_gpio_in, output [31:0] db0_gpio_out, output [31:0] db0_gpio_ddr,
- input [31:0] fp_gpio_in, output [31:0] fp_gpio_out, output [31:0] fp_gpio_ddr,
+ input [31:0] fp_gpio_in, output reg [31:0] fp_gpio_out, output reg [31:0] fp_gpio_ddr,
output [7:0] sen0, output sclk0, output mosi0, input miso0,
output [2:0] radio_led0,
output reg [31:0] radio0_misc_out, input [31:0] radio0_misc_in,
@@ -311,6 +312,8 @@ module x300_core #(
// SFP 1
.SFPP1_ModAbs(SFPP1_ModAbs),.SFPP1_TxFault(SFPP1_TxFault),.SFPP1_RxLOS(SFPP1_RxLOS),
.SFPP1_RS0(SFPP1_RS0), .SFPP1_RS1(SFPP1_RS1),
+ // Front-panel GPIO source
+ .fp_gpio_src(sr_fp_gpio_src),
//clocky locky misc
.clock_status({misc_clock_status, pps_detect, LMK_Holdover, LMK_Lock, LMK_Status}),
.clock_control({1'b0, clock_misc_opt[1:0], pps_out_enb, pps_select[1:0], clock_ref_sel[1:0]}),
@@ -528,6 +531,7 @@ module x300_core #(
wire [31:0] db_gpio_in[0:NUM_DBOARDS-1], db_gpio_out[0:NUM_DBOARDS-1], db_gpio_ddr[0:NUM_DBOARDS-1];
wire [31:0] misc_outs[0:NUM_DBOARDS-1];
reg [31:0] misc_ins[0:NUM_DBOARDS-1];
+ wire [24:0] sr_fp_gpio_src, fp_gpio_src;
wire [7:0] sen[0:NUM_DBOARDS-1];
wire sclk[0:NUM_DBOARDS-1], mosi[0:NUM_DBOARDS-1], miso[0:NUM_DBOARDS-1];
wire rx_running[0:NUM_CHANNELS-1], tx_running[0:NUM_CHANNELS-1];
@@ -602,6 +606,34 @@ module x300_core #(
endgenerate
//------------------------------------
+ // Front-Panel GPIO Source Mux
+ //------------------------------------
+ // Number of FP GPIO Pins
+ localparam FP_GPIO_WIDTH = 12;
+
+ // Bring FP GPIO controls into radio clk domain
+ synchronizer #(.WIDTH(24)) fp_gpio_sync (
+ .clk(radio_clk), .rst(radio_rst), .in(sr_fp_gpio_src), .out(fp_gpio_src)
+ );
+
+ // For each bit in the front-panel GPIO, mux the output and the direction
+ // control bit based on the fp_gpio_src register. The fp_gpio_src register
+ // holds 2 bits per GPIO pin, which selects which source to use for GPIO
+ // control. Currently, only daughter board 0 and daughter board 1 are
+ // supported.
+ for (i=0; i<FP_GPIO_WIDTH; i=i+1) begin : gen_fp_gpio_mux
+ always @(posedge radio_clk) begin
+ fp_gpio_out[i] <= fp_gpio_r_out[fp_gpio_src[2*i +: 2] == 0 ? 0 : 1][i];
+ fp_gpio_ddr[i] <= fp_gpio_r_ddr[fp_gpio_src[2*i +: 2] == 0 ? 0 : 1][i];
+ end
+ end
+
+ // Front-panel GPIO inputs are routed to all daughter boards
+ for (i=0; i<NUM_DBOARDS; i=i+1) begin : gen_fp_gpio_inputs
+ assign fp_gpio_r_in[i] = fp_gpio_in;
+ end
+
+ //------------------------------------
// Radio to ADC,DAC and IO Mapping
//------------------------------------
@@ -653,11 +685,6 @@ module x300_core #(
assign db0_gpio_ddr = db_gpio_ddr[0];
assign db1_gpio_ddr = db_gpio_ddr[1];
- //Front-panel board GPIO
- assign {fp_gpio_r_in[1], fp_gpio_r_in[0]} = {32'b0, fp_gpio_in};
- assign fp_gpio_out = fp_gpio_r_out[0]; //fp_gpio_r_out[1] unused
- assign fp_gpio_ddr = fp_gpio_r_ddr[0]; //fp_gpio_ddr[1] unused
-
//SPI
assign {sen0, sclk0, mosi0} = {sen[0], sclk[0], mosi[0]};
assign miso[0] = miso0;
diff --git a/host/examples/gpio.cpp b/host/examples/gpio.cpp
index fdd65349e..779fc1fa0 100644
--- a/host/examples/gpio.cpp
+++ b/host/examples/gpio.cpp
@@ -1,6 +1,7 @@
//
// Copyright 2014-15 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
+// Copyright 2020 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
@@ -48,8 +49,11 @@
// ATR_TX - Output values to be set when transmitting
// ATR_XX - Output values to be set when operating in full duplex
// This code below contains examples of setting all these registers. On
-// devices with multiple radios, the ATR for the front panel GPIO is driven
-// by the state of the first radio (0 or A).
+// devices with multiple radios, the ATR driver for the front panel GPIO
+// defaults to the state of the first radio (0 or A). This can be changed
+// on a bit-by-bit basis by writing to the register:
+// The ATR source can also be controlled, ie. drive from Radio0 or Radio1.
+// SRC - Source (RFA=Radio0, RFB=Radio1, etc.)
//
// The UHD API
// The multi_usrp::set_gpio_attr() method is the UHD API for configuring and
@@ -57,8 +61,9 @@
// bank - the name of the GPIO bank (typically "FP0" for front panel GPIO,
// "TX<n>" for TX daughter card GPIO, or
// "RX<n>" for RX daughter card GPIO)
-// attr - attribute (register) to change ("DDR", "OUT", "CTRL", "ATR_0X",
-// "ATR_RX", "ATR_TX", "ATR_XX")
+// attr - attribute (register) to change ("SRC", "DDR", "OUT", "CTRL",
+// "ATR_0X", "ATR_RX", "ATR_TX",
+// "ATR_XX")
// value - the value to be set
// mask - a mask indicating which bits in the specified attribute register are
// to be changed (default is all bits).
@@ -71,6 +76,7 @@
#include <stdlib.h>
#include <boost/format.hpp>
#include <boost/program_options.hpp>
+#include <boost/tokenizer.hpp>
#include <chrono>
#include <csignal>
#include <iostream>
@@ -127,6 +133,13 @@ void output_reg_values(const std::string bank,
% to_bit_string(gpio_bits, num_bits))
<< std::endl;
}
+ // GPIO Src
+ const auto gpio_src = usrp->get_gpio_src(bank);
+ std::cout << boost::format("%10s:") % "SRC: ";
+ for (auto src : gpio_src) {
+ std::cout << " " << src;
+ }
+ std::cout << std::endl;
}
int UHD_SAFE_MAIN(int argc, char* argv[])
@@ -137,9 +150,12 @@ int UHD_SAFE_MAIN(int argc, char* argv[])
double rx_rate, tx_rate, dwell;
std::string gpio;
size_t num_bits;
+ std::string src_str;
std::string ctrl_str;
std::string ddr_str;
std::string out_str;
+ std::string tx_subdev_spec;
+ std::string rx_subdev_spec;
// setup the program options
po::options_description desc("Allowed options");
@@ -147,6 +163,8 @@ int UHD_SAFE_MAIN(int argc, char* argv[])
desc.add_options()
("help", "help message")
("args", po::value<std::string>(&args)->default_value(""), "multi uhd device address args")
+ ("tx_subdev_spec", po::value<std::string>(&tx_subdev_spec)->default_value(""), "A:0, B:0, or A:0 B:0")
+ ("rx_subdev_spec", po::value<std::string>(&rx_subdev_spec)->default_value(""), "A:0, B:0, or A:0 B:0")
("repeat", "repeat loop until Ctrl-C is pressed")
("list-banks", "print list of banks before running tests")
("cpu", po::value<std::string>(&cpu)->default_value(GPIO_DEFAULT_CPU_FORMAT), "cpu data format")
@@ -157,6 +175,7 @@ int UHD_SAFE_MAIN(int argc, char* argv[])
("bank", po::value<std::string>(&gpio)->default_value(GPIO_DEFAULT_GPIO), "name of gpio bank")
("bits", po::value<size_t>(&num_bits)->default_value(GPIO_DEFAULT_NUM_BITS), "number of bits in gpio bank")
("bitbang", "single test case where user sets values for CTRL, DDR, and OUT registers")
+ ("src", po::value<std::string>(&src_str), "GPIO SRC reg value")
("ddr", po::value<std::string>(&ddr_str)->default_value(GPIO_DEFAULT_DDR), "GPIO DDR reg value")
("out", po::value<std::string>(&out_str)->default_value(GPIO_DEFAULT_OUT), "GPIO OUT reg value")
;
@@ -187,6 +206,18 @@ int UHD_SAFE_MAIN(int argc, char* argv[])
}
std::cout << "Using GPIO bank: " << gpio << std::endl;
+ // subdev spec
+ if (tx_subdev_spec != "")
+ usrp->set_tx_subdev_spec(tx_subdev_spec);
+ if (rx_subdev_spec != "")
+ usrp->set_rx_subdev_spec(rx_subdev_spec);
+ std::cout << boost::format(" rx_subdev_spec: %s")
+ % usrp->get_rx_subdev_spec(0).to_string()
+ << std::endl;
+ std::cout << boost::format(" tx_subdev_spec: %s")
+ % usrp->get_tx_subdev_spec(0).to_string()
+ << std::endl;
+
// print out initial unconfigured state of FP GPIO
std::cout << "Initial GPIO values:" << std::endl;
output_reg_values(gpio, usrp, num_bits);
@@ -227,6 +258,15 @@ int UHD_SAFE_MAIN(int argc, char* argv[])
ddr |= GPIO_BIT(4);
}
+ // set GPIO driver source
+ if (vm.count("src")) {
+ std::vector<std::string> gpio_src;
+ typedef boost::char_separator<char> separator;
+ boost::tokenizer<separator> tokens(src_str, separator(" "));
+ std::copy(tokens.begin(), tokens.end(), std::back_inserter(gpio_src));
+ usrp->set_gpio_src(gpio, gpio_src);
+ }
+
// set data direction register (DDR)
usrp->set_gpio_attr(gpio, "DDR", ddr, mask);
diff --git a/host/lib/usrp/multi_usrp_python.hpp b/host/lib/usrp/multi_usrp_python.hpp
index c9d89888b..8d25e26d4 100644
--- a/host/lib/usrp/multi_usrp_python.hpp
+++ b/host/lib/usrp/multi_usrp_python.hpp
@@ -24,6 +24,7 @@ void export_multi_usrp(py::module& m)
// Factory
.def(py::init(&multi_usrp::make))
+ // clang-format off
// General USRP methods
.def("get_rx_freq" , &multi_usrp::get_rx_freq, py::arg("chan") = 0)
.def("get_rx_num_channels" , &multi_usrp::get_rx_num_channels)
@@ -170,6 +171,7 @@ void export_multi_usrp(py::module& m)
.def("get_gpio_srcs" , &multi_usrp::get_gpio_srcs, py::arg("bank"), py::arg("mboard") = 0)
.def("get_gpio_src" , &multi_usrp::get_gpio_src, py::arg("bank"), py::arg("mboard") = 0)
.def("set_gpio_src" , &multi_usrp::set_gpio_src, py::arg("bank"), py::arg("src"), py::arg("mboard") = 0)
+ .def("get_gpio_src_banks" , &multi_usrp::get_gpio_src_banks, py::arg("mboard") = 0)
// Filter API methods
.def("get_rx_filter_names" , &multi_usrp::get_rx_filter_names)
@@ -178,6 +180,7 @@ void export_multi_usrp(py::module& m)
.def("get_tx_filter_names" , &multi_usrp::get_tx_filter_names)
.def("get_tx_filter" , &multi_usrp::get_tx_filter)
.def("set_tx_filter" , &multi_usrp::set_tx_filter)
+ // clang-format off
;
}
diff --git a/host/lib/usrp/x300/x300_mb_controller.cpp b/host/lib/usrp/x300/x300_mb_controller.cpp
index fd70526ab..28567e62e 100644
--- a/host/lib/usrp/x300/x300_mb_controller.cpp
+++ b/host/lib/usrp/x300/x300_mb_controller.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2019 Ettus Research, a National Instruments Brand
+// Copyright 2019-2020 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
@@ -26,7 +26,7 @@ constexpr uint32_t ADC_SELF_TEST_DURATION = 100; // ms
// When these regs are fixed, there is another fixme below to actually init the
// timekeepers
-constexpr uint32_t TK_NUM_TIMEKEEPERS = 12; //Read-only
+constexpr uint32_t TK_NUM_TIMEKEEPERS = 12; // Read-only
constexpr uint32_t TK_REG_BASE = 100;
constexpr uint32_t TK_REG_OFFSET = 48;
constexpr uint32_t TK_REG_TICKS_NOW_LO = 0x00; // Read-only
@@ -41,6 +41,11 @@ constexpr uint32_t TK_REG_TICKS_PERIOD_HI = 0x20; // Read-Write
constexpr char LOG_ID[] = "X300::MB_CTRL";
+constexpr char GPIO_SRC_BANK[] = "FP0";
+constexpr char GPIO_SRC_RFA[] = "RFA";
+constexpr char GPIO_SRC_RFB[] = "RFB";
+constexpr size_t GPIO_SRC_NUM_PINS = 12;
+
} // namespace
@@ -75,7 +80,9 @@ x300_mb_controller::x300_mb_controller(const size_t hw_rev,
const size_t num_tks = _zpu_ctrl->peek32(SR_ADDR(SET0_BASE, TK_NUM_TIMEKEEPERS));
for (size_t i = 0; i < num_tks; i++) {
- register_timekeeper(i, std::make_shared<x300_timekeeper>(i, _zpu_ctrl, clock_ctrl->get_master_clock_rate()));
+ register_timekeeper(i,
+ std::make_shared<x300_timekeeper>(
+ i, _zpu_ctrl, clock_ctrl->get_master_clock_rate()));
}
init_gps();
@@ -107,8 +114,7 @@ void x300_mb_controller::x300_timekeeper::set_ticks_now(const uint64_t ticks)
get_tk_addr(TK_REG_TICKS_EVENT_LO), narrow_cast<uint32_t>(ticks & 0xFFFFFFFF));
_zpu_ctrl->poke32(
get_tk_addr(TK_REG_TICKS_EVENT_HI), narrow_cast<uint32_t>(ticks >> 32));
- _zpu_ctrl->poke32(
- get_tk_addr(TK_REG_TICKS_CTRL), narrow_cast<uint32_t>(0x1));
+ _zpu_ctrl->poke32(get_tk_addr(TK_REG_TICKS_CTRL), narrow_cast<uint32_t>(0x1));
}
void x300_mb_controller::x300_timekeeper::set_ticks_next_pps(const uint64_t ticks)
@@ -117,16 +123,15 @@ void x300_mb_controller::x300_timekeeper::set_ticks_next_pps(const uint64_t tick
get_tk_addr(TK_REG_TICKS_EVENT_LO), narrow_cast<uint32_t>(ticks & 0xFFFFFFFF));
_zpu_ctrl->poke32(
get_tk_addr(TK_REG_TICKS_EVENT_HI), narrow_cast<uint32_t>(ticks >> 32));
- _zpu_ctrl->poke32(
- get_tk_addr(TK_REG_TICKS_CTRL), narrow_cast<uint32_t>(0x2));
+ _zpu_ctrl->poke32(get_tk_addr(TK_REG_TICKS_CTRL), narrow_cast<uint32_t>(0x2));
}
void x300_mb_controller::x300_timekeeper::set_period(const uint64_t period_ns)
{
_zpu_ctrl->poke32(get_tk_addr(TK_REG_TICKS_PERIOD_LO),
narrow_cast<uint32_t>(period_ns & 0xFFFFFFFF));
- _zpu_ctrl->poke32(get_tk_addr(TK_REG_TICKS_PERIOD_HI),
- narrow_cast<uint32_t>(period_ns >> 32));
+ _zpu_ctrl->poke32(
+ get_tk_addr(TK_REG_TICKS_PERIOD_HI), narrow_cast<uint32_t>(period_ns >> 32));
}
uint32_t x300_mb_controller::x300_timekeeper::get_tk_addr(const uint32_t tk_addr)
@@ -247,8 +252,8 @@ void x300_mb_controller::set_clock_source(const std::string& source)
.str());
} else {
// TODO: Re-enable this warning when we figure out a reliable lock time
- // UHD_LOGGER_WARNING("X300::MB_CTRL") << "Reference clock failed to lock to " +
- // source + " during device initialization. " <<
+ // UHD_LOGGER_WARNING("X300::MB_CTRL") << "Reference clock failed to lock
+ // to " + source + " during device initialization. " <<
// "Check for the lock before operation or ignore this warning if using
// another clock source." ;
}
@@ -311,7 +316,8 @@ void x300_mb_controller::set_sync_source(
set_sync_source(sync_args);
}
-void x300_mb_controller::set_sync_source(const device_addr_t& sync_source) {
+void x300_mb_controller::set_sync_source(const device_addr_t& sync_source)
+{
if (sync_source.has_key("clock_source")) {
set_clock_source(sync_source["clock_source"]);
}
@@ -338,8 +344,7 @@ std::vector<device_addr_t> x300_mb_controller::get_sync_sources()
{"external", "internal"},
{"external", "external"},
{"gpsdo", "gpsdo"},
- {"gpsdo", "internal"}
- };
+ {"gpsdo", "internal"}};
// Now convert to vector of device_addr_t
std::vector<device_addr_t> sync_sources;
@@ -484,6 +489,78 @@ bool x300_mb_controller::synchronize(std::vector<mb_controller::sptr>& mb_contro
throw uhd::runtime_error(err_str);
}
+std::vector<std::string> x300_mb_controller::get_gpio_banks() const
+{
+ return {GPIO_SRC_BANK};
+}
+
+std::vector<std::string> x300_mb_controller::get_gpio_srcs(const std::string& bank) const
+{
+ if (bank != GPIO_SRC_BANK) {
+ UHD_LOG_ERROR(LOG_ID,
+ "Invalid GPIO source bank: " << bank << ". Only supported bank is "
+ << GPIO_SRC_BANK);
+ throw uhd::runtime_error(
+ std::string("Invalid GPIO source bank: ") + GPIO_SRC_BANK);
+ }
+ return {GPIO_SRC_RFA, GPIO_SRC_RFB};
+}
+
+std::vector<std::string> x300_mb_controller::get_gpio_src(const std::string& bank)
+{
+ if (bank != GPIO_SRC_BANK) {
+ UHD_LOG_ERROR(LOG_ID,
+ "Invalid GPIO source bank: " << bank << ". Only supported bank is "
+ << GPIO_SRC_BANK);
+ throw uhd::runtime_error(
+ std::string("Invalid GPIO source bank: ") + GPIO_SRC_BANK);
+ }
+ uint32_t fp_gpio_src = _zpu_ctrl->peek32(SR_ADDR(SET0_BASE, ZPU_RB_FP_GPIO_SRC));
+ const auto gpio_srcs = get_gpio_srcs(bank);
+ std::vector<std::string> gpio_src;
+ for (size_t ii = 0; ii < GPIO_SRC_NUM_PINS; ++ii) {
+ const uint32_t this_src = (fp_gpio_src >> (2 * ii)) & 0x3;
+ if (this_src > 1) {
+ UHD_LOG_WARNING(LOG_ID,
+ "get_gpio_src() read back invalid GPIO source index: "
+ << this_src << ". Falling back to " << (this_src & 0x1));
+ }
+ gpio_src.push_back(gpio_srcs[this_src & 0x1]);
+ }
+ return gpio_src;
+}
+
+void x300_mb_controller::set_gpio_src(
+ const std::string& bank, const std::vector<std::string>& srcs)
+{
+ if (srcs.size() > GPIO_SRC_NUM_PINS) {
+ UHD_LOG_WARNING(LOG_ID, "set_gpio_src(): Provided more sources than pins!");
+ }
+ uint32_t fp_gpio_src = _zpu_ctrl->peek32(SR_ADDR(SET0_BASE, ZPU_RB_FP_GPIO_SRC));
+ size_t pins_configured = 0;
+
+ const auto gpio_srcs = get_gpio_srcs(bank);
+ for (auto src : srcs) {
+ const uint32_t pins = [src]() {
+ if (src == GPIO_SRC_RFA) {
+ return 0;
+ }
+ if (src == GPIO_SRC_RFB) {
+ return 1;
+ }
+ UHD_LOG_ERROR(LOG_ID, "Invalid GPIO source provided: " << src);
+ throw uhd::runtime_error("Invalid GPIO source provided!");
+ }();
+ uint32_t pin_mask = ~(uint32_t(0x3) << (2 * pins_configured));
+ fp_gpio_src = (fp_gpio_src & pin_mask) | (pins << 2 * pins_configured);
+ pins_configured++;
+ if (pins_configured > GPIO_SRC_NUM_PINS) {
+ break;
+ }
+ }
+ _zpu_ctrl->poke32(SR_ADDR(SET0_BASE, ZPU_SR_FP_GPIO_SRC), fp_gpio_src);
+}
+
/******************************************************************************
* Private Methods
*****************************************************************************/
diff --git a/host/lib/usrp/x300/x300_mb_controller.hpp b/host/lib/usrp/x300/x300_mb_controller.hpp
index 53f166a0e..92844f1b9 100644
--- a/host/lib/usrp/x300/x300_mb_controller.hpp
+++ b/host/lib/usrp/x300/x300_mb_controller.hpp
@@ -120,6 +120,10 @@ public:
bool synchronize(std::vector<mb_controller::sptr>& mb_controllers,
const uhd::time_spec_t& time_spec = uhd::time_spec_t(0.0),
const bool quiet = false);
+ std::vector<std::string> get_gpio_banks() const;
+ std::vector<std::string> get_gpio_srcs(const std::string&) const;
+ std::vector<std::string> get_gpio_src(const std::string&);
+ void set_gpio_src(const std::string&, const std::vector<std::string>&);
private:
//! Return a string X300::MB_CTRL#N
diff --git a/host/lib/usrp/x300/x300_radio_control.cpp b/host/lib/usrp/x300/x300_radio_control.cpp
index c41a19401..48b484467 100644
--- a/host/lib/usrp/x300/x300_radio_control.cpp
+++ b/host/lib/usrp/x300/x300_radio_control.cpp
@@ -147,27 +147,24 @@ public:
_init_codecs();
_x300_mb_control->register_reset_codec_cb([this]() { this->reset_codec(); });
// FP-GPIO
- if (_radio_type == PRIMARY) {
- RFNOC_LOG_TRACE("Creating FP-GPIO interface...");
- _fp_gpio = gpio_atr::gpio_atr_3000::make(_wb_iface,
- x300_regs::SR_FP_GPIO,
- x300_regs::RB_FP_GPIO,
- x300_regs::PERIPH_REG_OFFSET);
- // Create the GPIO banks and attributes, and populate them with some default
- // values
- // TODO: Do we need this section? Since the _fp_gpio handles state now, we
- // don't need to stash values here. We only need this if we want to set
- // anything to a default value.
- for (const gpio_atr::gpio_attr_map_t::value_type attr :
- gpio_atr::gpio_attr_map) {
- // TODO: Default values?
- if (attr.first == usrp::gpio_atr::GPIO_SRC) {
- // Don't set the SRC
- // TODO: Remove from the map??
- continue;
- }
- set_gpio_attr("FP0", usrp::gpio_atr::gpio_attr_map.at(attr.first), 0);
+ RFNOC_LOG_TRACE("Creating FP-GPIO interface...");
+ _fp_gpio = gpio_atr::gpio_atr_3000::make(_wb_iface,
+ x300_regs::SR_FP_GPIO,
+ x300_regs::RB_FP_GPIO,
+ x300_regs::PERIPH_REG_OFFSET);
+ // Create the GPIO banks and attributes, and populate them with some default
+ // values
+ // TODO: Do we need this section? Since the _fp_gpio handles state now, we
+ // don't need to stash values here. We only need this if we want to set
+ // anything to a default value.
+ for (const gpio_atr::gpio_attr_map_t::value_type attr : gpio_atr::gpio_attr_map) {
+ // TODO: Default values?
+ if (attr.first == usrp::gpio_atr::GPIO_SRC) {
+ // Don't set the SRC
+ // TODO: Remove from the map??
+ continue;
}
+ set_gpio_attr("FP0", usrp::gpio_atr::gpio_attr_map.at(attr.first), 0);
}
// DB Initialization
_init_db(); // This does not init the dboards themselves!
@@ -855,17 +852,13 @@ public:
/*** GPIO API ************************************************************/
std::vector<std::string> get_gpio_banks() const
{
- std::vector<std::string> banks{"RX", "TX"};
- if (_fp_gpio) {
- banks.push_back("FP0");
- }
- return banks;
+ return {"RX", "TX", "FP0"};
}
void set_gpio_attr(
const std::string& bank, const std::string& attr, const uint32_t value)
{
- if (bank == "FP0" and _fp_gpio) {
+ if (bank == "FP0") {
_fp_gpio->set_gpio_attr(usrp::gpio_atr::gpio_attr_rev_map.at(attr), value);
return;
}
@@ -909,7 +902,7 @@ public:
uint32_t get_gpio_attr(const std::string& bank, const std::string& attr)
{
- if (bank == "FP0" and _fp_gpio) {
+ if (bank == "FP0") {
return _fp_gpio->get_attr_reg(usrp::gpio_atr::gpio_attr_rev_map.at(attr));
}
if (bank.size() >= 2 and bank[1] == 'X') {
diff --git a/host/lib/usrp/x300/x300_regs.hpp b/host/lib/usrp/x300/x300_regs.hpp
index 64ff63d77..86ffd46c4 100644
--- a/host/lib/usrp/x300/x300_regs.hpp
+++ b/host/lib/usrp/x300/x300_regs.hpp
@@ -35,8 +35,7 @@ static const int ZPU_SR_REF_FREQ = 04;
static const int ZPU_SR_SPI = 32;
static const int ZPU_SR_ETHINT0 = 40;
static const int ZPU_SR_ETHINT1 = 56;
-static const int ZPU_SR_DRAM_FIFO0 = 72;
-static const int ZPU_SR_DRAM_FIFO1 = 80;
+static const int ZPU_SR_FP_GPIO_SRC = 72;
// reset bits
#define ZPU_SR_SW_RST_ETH_PHY (1 << 0)
@@ -51,6 +50,7 @@ static const int ZPU_RB_NUM_CE = 7;
static const int ZPU_RB_GIT_HASH = 10;
static const int ZPU_RB_SFP0_TYPE = 4;
static const int ZPU_RB_SFP1_TYPE = 5;
+static const int ZPU_RB_FP_GPIO_SRC = 13;
static const uint32_t RB_SFP_1G_ETH = 0;
static const uint32_t RB_SFP_10G_ETH = 1;