host: SPI: Read number of supported SPI slaves from device

Add support for reading the number of supported SPI slaves from
the device. This has become necessary because we may have bitfiles
with different capabilities and we want to report this back correctly.
This commit is contained in:
Martin Anderseck 2022-03-17 13:34:15 +01:00 committed by Aaron Rossetto
parent af9e13f4dc
commit bc8713e7af
6 changed files with 63 additions and 28 deletions

View file

@ -68,8 +68,7 @@ int UHD_SAFE_MAIN(int argc, char* argv[])
// create a usrp device
std::cout << std::endl;
std::cout << "Creating the usrp device with: " << args << "..."
<< std::endl;
std::cout << "Creating the usrp device with: " << args << "..." << std::endl;
auto usrp = uhd::usrp::multi_usrp::make(args);
if (vm.count("list-banks")) {
@ -80,7 +79,12 @@ int UHD_SAFE_MAIN(int argc, char* argv[])
}
}
// Get the SPI getter interface from where we'll get
// Get the SPI getter interface from where we'll get the SPI interface itself
if (!usrp->get_radio_control().has_feature<uhd::features::spi_getter_iface>()) {
std::cout << "Error: Could not find SPI_Getter_Iface. Please check if your FPGA "
"image is up to date.\n";
return EXIT_FAILURE;
}
auto& spi_getter_iface =
usrp->get_radio_control().get_feature<uhd::features::spi_getter_iface>();

View file

@ -35,6 +35,7 @@ public:
const size_t spi_transaction_cfg,
const size_t spi_transaction_go,
const size_t spi_status,
const size_t spi_controller_info,
const mapper_sptr port_mapper);
//! Configures the SPI transaction. The vector index refers to the slave number.
@ -43,4 +44,3 @@ public:
};
}} // namespace uhd::cores

View file

@ -25,6 +25,7 @@ public:
const size_t spi_transaction_cfg,
const size_t spi_transaction_go,
const size_t spi_status,
const size_t spi_controller_info,
const mapper_sptr port_mapper)
: _poke32(std::move(poke32_fn))
, _peek32(std::move(peek32_fn))
@ -32,6 +33,7 @@ public:
, _spi_transaction_cfg(spi_transaction_cfg)
, _spi_transaction_go(spi_transaction_go)
, _spi_status(spi_status)
, _spi_ctrl_info(spi_controller_info)
, _port_mapper(port_mapper)
{
}
@ -39,12 +41,17 @@ public:
void set_spi_slave_config(
const std::vector<uhd::features::spi_slave_config_t>& ssc) override
{
if (ssc.size() > 4) {
throw uhd::value_error(
"Passed more than 4 SPI slaves. Maximum number of SPI slaves is 4.");
const size_t num_slaves_allowed = _peek32(_spi_ctrl_info) & 0xF;
if (ssc.size() > num_slaves_allowed) {
throw uhd::value_error("Number of configurations passed ("
+ std::to_string(ssc.size())
+ ") exceeds the maximum number allowed by "
"the bitfile per radio block. Maximum number: "
+ std::to_string(num_slaves_allowed));
}
_spi_slave_config = ssc;
_slave_ctrl_cache.assign(_spi_slave_config.size(), 0);
}
uint32_t transact_spi(const int which_slave,
@ -135,8 +142,9 @@ private:
const size_t _spi_transaction_cfg;
const size_t _spi_transaction_go;
const size_t _spi_status;
const size_t _spi_ctrl_info;
const mapper_sptr _port_mapper;
std::vector<uint32_t> _slave_ctrl_cache{0, 0, 0, 0};
std::vector<uint32_t> _slave_ctrl_cache;
uint32_t _transaction_cfg_cache = 0;
std::mutex _mutex;
std::vector<uhd::features::spi_slave_config_t> _spi_slave_config;
@ -161,6 +169,7 @@ spi_core_4000::sptr spi_core_4000::make(spi_core_4000::poke32_fn_t&& poke32_fn,
const size_t spi_transaction_cfg,
const size_t spi_transaction_go,
const size_t spi_status,
const size_t spi_controller_info,
const mapper_sptr port_mapper)
{
return std::make_shared<spi_core_4000_impl>(std::move(poke32_fn),
@ -169,6 +178,7 @@ spi_core_4000::sptr spi_core_4000::make(spi_core_4000::poke32_fn_t&& poke32_fn,
spi_transaction_cfg,
spi_transaction_go,
spi_status,
spi_controller_info,
port_mapper);
}

View file

@ -191,20 +191,32 @@ x400_radio_control_impl::x400_radio_control_impl(make_args_ptr make_args)
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);
// Check if SPI is available as GPIO source, otherwise don't register
// SPI_GETTER_IFace
auto gpio_srcs = _mb_control->get_gpio_srcs("GPIO0");
if (std::count(gpio_srcs.begin(), gpio_srcs.end(), "DB0_SPI") > 0) {
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,
x400_regs::SPI_CONTROLLER_INFO_REG,
gpio_port_mapper);
_spi_getter_iface = std::make_shared<x400_spi_getter>(spicore);
register_feature(_spi_getter_iface);
} else {
UHD_LOG_INFO("x400_radio_control",
"SPI functionality not available in this FPGA image. Please update to at "
"least version 7.7 to use SPI.");
}
}
}
@ -816,5 +828,4 @@ std::string x400_radio_control_impl::get_dboard_fe_from_chan(
UHD_RFNOC_BLOCK_REGISTER_FOR_DEVICE_DIRECT(
x400_radio_control, RADIO_BLOCK, X400, "Radio", true, "radio_clk", "ctrl_clk")
}} // namespace uhd::rfnoc

View file

@ -54,6 +54,9 @@ 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;
//! Base address for SPI_CONTROLLER_INFO Register
constexpr uint32_t SPI_CONTROLLER_INFO_REG = SPI_SLAVE_CFG + 0x001C;
} // namespace x400_regs
class x400_radio_control_impl : public radio_control_impl

View file

@ -147,6 +147,7 @@ class DioControl:
FPGA_DIO_SW_DIO_CONTROL_REGISTER = FPGA_DIO_REGISTER_BASE + 0x20
FULL_DIO_FPGA_COMPAT = (7, 5)
FULL_SPI_FPGA_COMPAT = (7, 7)
# DIO registers addresses in CPLD
CPLD_DIO_DIRECTION_REGISTER = 0x30
@ -157,9 +158,10 @@ class DioControl:
X4XX_GPIO_SRC_MPM = "MPM"
X4XX_GPIO_SRC_USER_APP = "USER_APP"
X4XX_GPIO_SRC_RADIO = [
["DB0_RF0", "DB0_RF1", "DB0_SPI"],
["DB1_RF0", "DB1_RF1", "DB1_SPI"]
["DB0_RF0", "DB0_RF1"],
["DB1_RF0", "DB1_RF1"]
]
X4XX_GPIO_SPI_SRC_RADIO = [["DB0_SPI"], ["DB1_SPI"]]
X4XX_GPIO_WIDTH = 12
# pylint: enable=bad-whitespace
@ -227,6 +229,8 @@ class DioControl:
self.mboard_cpld = mboard_cpld
if self.mboard_regs.get_compat_number() < self.FULL_DIO_FPGA_COMPAT:
self.log.warning("DIO board does not support the full feature set.")
if self.mboard_regs.get_compat_number() < self.FULL_SPI_FPGA_COMPAT:
self.log.warning("DIO board does not support SPI.")
# initialize port mapping for HDMI and DIO
self.port_mappings = {}
self.mapping = None
@ -263,6 +267,9 @@ class DioControl:
]
for dboard in dboards:
gpio_srcs.extend(self.X4XX_GPIO_SRC_RADIO[dboard.slot_idx])
# Only add SPI if FPGA version is high enough
if self.mboard_regs.get_compat_number() >= self.FULL_SPI_FPGA_COMPAT:
gpio_srcs.extend(self.X4XX_GPIO_SPI_SRC_RADIO[dboard.slot_idx])
self._gpio_srcs = {
gpio_bank : gpio_srcs for gpio_bank in self.X4XX_GPIO_BANKS
@ -895,10 +902,10 @@ class DioControl:
:return: board status
"""
result = "\n" \
+ self._format_row(["%s mapping" % self.mapping.name, self.DIO_PORTS[0], self.DIO_PORTS[1]]) \
+ self._format_row(["", "", ""], "-", "+") \
+ self._format_row(["voltage"] + self._get_voltage()) \
+ self._format_row(["", "", ""], "-", "+")
+ self._format_row(["%s mapping" % self.mapping.name, self.DIO_PORTS[0], self.DIO_PORTS[1]]) \
+ self._format_row(["", "", ""], "-", "+") \
+ self._format_row(["voltage"] + self._get_voltage()) \
+ self._format_row(["", "", ""], "-", "+")
register = self.mboard_regs.peek32(self.FPGA_DIO_MASTER_REGISTER)
result += self._format_row(["master"] + self._format_registers(register))