From 83dde40090e0bbd91c304602cc0e3c365f7878bb Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Tue, 26 Sep 2017 18:22:25 -0700 Subject: uhd: Changed mboard_eeprom_t interface, refactored MB EEPROM code - uhd::usrp::mboard_eeprom_t is now simply a map. Its commit() method has no utility being a public API call, because the user never gets access to the appropriate I2C object (Minor API breakage) - The central mboard_eeprom.cpp file was broken up and put into many smaller compilation units in every device's implementation folder. - Renamed some of the constants (e.g. B000_* -> USRP1_*, N100_* -> N200_*) - Removed the N000_* EEPROM code, because, well, you know, there's no such device --- host/lib/usrp/x300/CMakeLists.txt | 1 + host/lib/usrp/x300/x300_impl.cpp | 32 +-- host/lib/usrp/x300/x300_impl.hpp | 9 +- host/lib/usrp/x300/x300_mb_eeprom.cpp | 338 ++++++++++++++-------------- host/lib/usrp/x300/x300_mb_eeprom.hpp | 37 --- host/lib/usrp/x300/x300_mb_eeprom_iface.cpp | 190 ++++++++++++++++ host/lib/usrp/x300/x300_mb_eeprom_iface.hpp | 37 +++ 7 files changed, 425 insertions(+), 219 deletions(-) delete mode 100644 host/lib/usrp/x300/x300_mb_eeprom.hpp create mode 100644 host/lib/usrp/x300/x300_mb_eeprom_iface.cpp create mode 100644 host/lib/usrp/x300/x300_mb_eeprom_iface.hpp (limited to 'host/lib/usrp/x300') diff --git a/host/lib/usrp/x300/CMakeLists.txt b/host/lib/usrp/x300/CMakeLists.txt index 5f8e83e1c..3a48c9900 100644 --- a/host/lib/usrp/x300/CMakeLists.txt +++ b/host/lib/usrp/x300/CMakeLists.txt @@ -34,6 +34,7 @@ IF(ENABLE_X300) ${CMAKE_CURRENT_SOURCE_DIR}/x300_dboard_iface.cpp ${CMAKE_CURRENT_SOURCE_DIR}/x300_clock_ctrl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/x300_image_loader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/x300_mb_eeprom_iface.cpp ${CMAKE_CURRENT_SOURCE_DIR}/x300_mb_eeprom.cpp ${CMAKE_CURRENT_SOURCE_DIR}/cdecode.c ) diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index 1e22f7fb7..f98bdb5b1 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -18,7 +18,7 @@ #include "x300_impl.hpp" #include "x300_lvbitx.hpp" #include "x310_lvbitx.hpp" -#include "x300_mb_eeprom.hpp" +#include "x300_mb_eeprom_iface.hpp" #include "apply_corrections.hpp" #include #include @@ -125,7 +125,8 @@ static device_addrs_t x300_find_with_addr(const device_addr_t &hint) i2c_core_100_wb32::sptr zpu_i2c = i2c_core_100_wb32::make(zpu_ctrl, I2C1_BASE); x300_mb_eeprom_iface::sptr eeprom_iface = x300_mb_eeprom_iface::make(zpu_ctrl, zpu_i2c); - const mboard_eeprom_t mb_eeprom(*eeprom_iface, "X300"); + const mboard_eeprom_t mb_eeprom = + x300_impl::get_mb_eeprom(eeprom_iface); if (mb_eeprom.size() == 0 or x300_impl::claim_status(zpu_ctrl) == x300_impl::CLAIMED_BY_OTHER) { // Skip device claimed by another process @@ -233,7 +234,8 @@ static device_addrs_t x300_find_pcie(const device_addr_t &hint, bool explicit_qu i2c_core_100_wb32::sptr zpu_i2c = i2c_core_100_wb32::make(zpu_ctrl, I2C1_BASE); x300_mb_eeprom_iface::sptr eeprom_iface = x300_mb_eeprom_iface::make(zpu_ctrl, zpu_i2c); - const mboard_eeprom_t mb_eeprom(*eeprom_iface, "X300"); + const mboard_eeprom_t mb_eeprom = + x300_impl::get_mb_eeprom(eeprom_iface); if (mb_eeprom.size() == 0 or x300_impl::claim_status(zpu_ctrl) == x300_impl::CLAIMED_BY_OTHER) { // Skip device claimed by another process @@ -783,13 +785,21 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) x300_mb_eeprom_iface::sptr eeprom16 = x300_mb_eeprom_iface::make(mb.zpu_ctrl, mb.zpu_i2c); if (dev_addr.has_key("blank_eeprom")) { - UHD_LOGGER_WARNING("X300") << "Obliterating the motherboard EEPROM..." ; + UHD_LOGGER_WARNING("X300") << "Obliterating the motherboard EEPROM..."; eeprom16->write_eeprom(0x50, 0, byte_vector_t(256, 0xff)); } - const mboard_eeprom_t mb_eeprom(*eeprom16, "X300"); + + const mboard_eeprom_t mb_eeprom = get_mb_eeprom(eeprom16); _tree->create(mb_path / "eeprom") + // Initialize the property with a current copy of the EEPROM contents .set(mb_eeprom) - .add_coerced_subscriber(boost::bind(&x300_impl::set_mb_eeprom, this, mb.zpu_i2c, _1)); + // Whenever this property is written, update the chip + .add_coerced_subscriber( + [this, eeprom16](const mboard_eeprom_t &mb_eeprom){ + this->set_mb_eeprom(eeprom16, mb_eeprom); + } + ) + ; bool recover_mb_eeprom = dev_addr.has_key("recover_mb_eeprom"); if (recover_mb_eeprom) { @@ -1523,16 +1533,6 @@ bool x300_impl::is_pps_present(mboard_members_t& mb) return false; } -/*********************************************************************** - * eeprom - **********************************************************************/ - -void x300_impl::set_mb_eeprom(i2c_iface::sptr i2c, const mboard_eeprom_t &mb_eeprom) -{ - i2c_iface::sptr eeprom16 = i2c->eeprom16(); - mb_eeprom.commit(*eeprom16, "X300"); -} - /*********************************************************************** * claimer logic **********************************************************************/ diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp index 7186e5f4f..a1ff65a5c 100644 --- a/host/lib/usrp/x300/x300_impl.hpp +++ b/host/lib/usrp/x300/x300_impl.hpp @@ -147,6 +147,9 @@ public: static x300_mboard_t get_mb_type_from_pcie(const std::string& resource, const std::string& rpc_port); static x300_mboard_t get_mb_type_from_eeprom(const uhd::usrp::mboard_eeprom_t& mb_eeprom); + //! Read out the on-board EEPROM, convert to dict, and return + static uhd::usrp::mboard_eeprom_t get_mb_eeprom(uhd::i2c_iface::sptr i2c); + protected: void subdev_to_blockid( const uhd::usrp::subdev_spec_pair_t &spec, const size_t mb_i, @@ -287,7 +290,11 @@ private: bool wait_for_clk_locked(mboard_members_t& mb, uint32_t which, double timeout); bool is_pps_present(mboard_members_t& mb); - void set_mb_eeprom(uhd::i2c_iface::sptr i2c, const uhd::usrp::mboard_eeprom_t &); + //! Write the contents of an EEPROM dict to the on-board EEPROM + void set_mb_eeprom( + uhd::i2c_iface::sptr i2c, + const uhd::usrp::mboard_eeprom_t & + ); void check_fw_compat(const uhd::fs_path &mb_path, uhd::wb_iface::sptr iface); void check_fpga_compat(const uhd::fs_path &mb_path, const mboard_members_t &members); diff --git a/host/lib/usrp/x300/x300_mb_eeprom.cpp b/host/lib/usrp/x300/x300_mb_eeprom.cpp index 084685991..da4cf6021 100644 --- a/host/lib/usrp/x300/x300_mb_eeprom.cpp +++ b/host/lib/usrp/x300/x300_mb_eeprom.cpp @@ -1,190 +1,198 @@ // -// Copyright 2013-2016 Ettus Research LLC +// Copyright 2017 Ettus Research (National Instruments Corp.) // -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// SPDX-License-Identifier: GPL-3.0 // -/* - * x300_mb_eeprom_iface - * This interface was created to prevent MB EEPROM corruption while reading - * data during discovery. For devices with firmware version newer than 5.0, - * the EEPROM data is read into firmware memory and available without - * claiming the device. For devices with firmware versions 5.0 and older, - * the code makes sure to claim the device before driving the I2C bus. This - * has the unfortunate side effect of preventing multiple processes from - * discovering the device simultaneously, but is far better than having EEPROM - * corruption. - */ - -#include "x300_mb_eeprom.hpp" -#include "x300_fw_common.h" -#include "x300_regs.hpp" #include "x300_impl.hpp" -#include -#include -#include -#include -#include +#include "eeprom_utils.hpp" +#include +#include -using namespace uhd; +namespace { + const uint8_t X300_EEPROM_ADDR = 0x50; + + struct x300_eeprom_map + { + //identifying numbers + unsigned char revision[2]; + unsigned char product[2]; + unsigned char revision_compat[2]; + uint8_t _pad0[2]; + + //all the mac addrs + uint8_t mac_addr0[6]; + uint8_t _pad1[2]; + uint8_t mac_addr1[6]; + uint8_t _pad2[2]; + + //all the IP addrs + uint32_t gateway; + uint32_t subnet[4]; + uint32_t ip_addr[4]; + uint8_t _pad3[16]; + + //names and serials + unsigned char name[NAME_MAX_LEN]; + unsigned char serial[SERIAL_LEN]; + }; +} -static const uint32_t X300_FW_SHMEM_IDENT_MIN_VERSION = 0x50001; +using namespace uhd; +using uhd::usrp::mboard_eeprom_t; -class x300_mb_eeprom_iface_impl : public x300_mb_eeprom_iface +mboard_eeprom_t x300_impl::get_mb_eeprom(uhd::i2c_iface::sptr iface) { -public: + byte_vector_t bytes = + iface->read_eeprom(X300_EEPROM_ADDR, 0, sizeof(struct x300_eeprom_map)); - x300_mb_eeprom_iface_impl(wb_iface::sptr wb, i2c_iface::sptr i2c) : _wb(wb), _i2c(i2c) - { - _compat_num = _wb->peek32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_COMPAT_NUM)); + mboard_eeprom_t mb_eeprom; + if (bytes.empty()) { + return mb_eeprom; } - ~x300_mb_eeprom_iface_impl() + //extract the revision number + mb_eeprom["revision"] = uint16_bytes_to_string( + byte_vector_t( + bytes.begin() + offsetof(x300_eeprom_map, revision), + bytes.begin() + (offsetof(x300_eeprom_map, revision)+2)) + ); + + //extract the revision compat number + mb_eeprom["revision_compat"] = uint16_bytes_to_string( + byte_vector_t( + bytes.begin() + offsetof(x300_eeprom_map, revision_compat), + bytes.begin() + (offsetof(x300_eeprom_map, revision_compat)+2)) + ); + + //extract the product code + mb_eeprom["product"] = uint16_bytes_to_string( + byte_vector_t( + bytes.begin() + offsetof(x300_eeprom_map, product), + bytes.begin() + (offsetof(x300_eeprom_map, product)+2)) + ); + + //extract the mac addresses + mb_eeprom["mac-addr0"] = mac_addr_t::from_bytes( + byte_vector_t( + bytes.begin() + offsetof(x300_eeprom_map, mac_addr0), + bytes.begin() + (offsetof(x300_eeprom_map, mac_addr0)+6)) + ).to_string(); + mb_eeprom["mac-addr1"] = mac_addr_t::from_bytes( + byte_vector_t( + bytes.begin() + offsetof(x300_eeprom_map, mac_addr1), + bytes.begin() + (offsetof(x300_eeprom_map, mac_addr1)+6)) + ).to_string(); + + //extract the ip addresses + boost::asio::ip::address_v4::bytes_type ip_addr_bytes; + byte_copy( + byte_vector_t( + bytes.begin() + offsetof(x300_eeprom_map, gateway), + bytes.begin() + (offsetof(x300_eeprom_map, gateway)+4)), + ip_addr_bytes + ); + mb_eeprom["gateway"] = boost::asio::ip::address_v4(ip_addr_bytes).to_string(); + for (size_t i = 0; i < 4; i++) { - /* NOP */ + const std::string n(1, i+'0'); + byte_copy( + byte_vector_t( + bytes.begin() + (offsetof(x300_eeprom_map, ip_addr)+(i*4)), + bytes.begin() + (offsetof(x300_eeprom_map, ip_addr)+(i*4)+4)), + ip_addr_bytes + ); + mb_eeprom["ip-addr"+n] = boost::asio::ip::address_v4(ip_addr_bytes).to_string(); + + byte_copy( + byte_vector_t( + bytes.begin() + (offsetof(x300_eeprom_map, subnet)+(i*4)), + bytes.begin() + (offsetof(x300_eeprom_map, subnet)+(i*4)+4)), + ip_addr_bytes + ); + mb_eeprom["subnet"+n] = boost::asio::ip::address_v4(ip_addr_bytes).to_string(); } - /*! - * Write bytes over the i2c. - * \param addr the address - * \param buf the vector of bytes - */ - void write_i2c( - uint16_t addr, - const byte_vector_t &buf - ) - { - UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR); - if (x300_impl::claim_status(_wb) != x300_impl::CLAIMED_BY_US) - { - throw uhd::io_error("Attempted to write MB EEPROM without claim to device."); - } - _i2c->write_i2c(addr, buf); - } + //extract the serial + mb_eeprom["serial"] = bytes_to_string( + byte_vector_t( + bytes.begin() + offsetof(x300_eeprom_map, serial), + bytes.begin() + (offsetof(x300_eeprom_map, serial)+SERIAL_LEN)) + ); + + //extract the name + mb_eeprom["name"] = bytes_to_string( + byte_vector_t( + bytes.begin() + offsetof(x300_eeprom_map, name), + bytes.begin() + (offsetof(x300_eeprom_map, name)+NAME_MAX_LEN)) + ); + + return mb_eeprom; +} - /*! - * Read bytes over the i2c. - * \param addr the address - * \param num_bytes number of bytes to read - * \return a vector of bytes - */ - byte_vector_t read_i2c( - uint16_t addr, - size_t num_bytes - ) - { - UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR); - byte_vector_t bytes; - if (_compat_num > X300_FW_SHMEM_IDENT_MIN_VERSION) - { - bytes = read_eeprom(addr, 0, num_bytes); - } else { - x300_impl::claim_status_t status = x300_impl::claim_status(_wb); - // Claim device before driving the I2C bus - if (status == x300_impl::CLAIMED_BY_US or x300_impl::try_to_claim(_wb)) - { - bytes = _i2c->read_i2c(addr, num_bytes); - if (status != x300_impl::CLAIMED_BY_US) - { - // We didn't originally have the claim, so give it up - x300_impl::release(_wb); - } - } - } - return bytes; - } - /*! - * Write bytes to an eeprom. - * \param addr the address - * \param offset byte offset - * \param buf the vector of bytes - */ - void write_eeprom( - uint16_t addr, - uint16_t offset, - const byte_vector_t &buf - ) +void x300_impl::set_mb_eeprom( + i2c_iface::sptr iface, + const mboard_eeprom_t &mb_eeprom +) { + //parse the revision number + if (mb_eeprom.has_key("revision")) iface->write_eeprom( + X300_EEPROM_ADDR, offsetof(x300_eeprom_map, revision), + string_to_uint16_bytes(mb_eeprom["revision"]) + ); + + //parse the revision compat number + if (mb_eeprom.has_key("revision_compat")) iface->write_eeprom( + X300_EEPROM_ADDR, offsetof(x300_eeprom_map, revision_compat), + string_to_uint16_bytes(mb_eeprom["revision_compat"]) + ); + + //parse the product code + if (mb_eeprom.has_key("product")) iface->write_eeprom( + X300_EEPROM_ADDR, offsetof(x300_eeprom_map, product), + string_to_uint16_bytes(mb_eeprom["product"]) + ); + + //store the mac addresses + if (mb_eeprom.has_key("mac-addr0")) iface->write_eeprom( + X300_EEPROM_ADDR, offsetof(x300_eeprom_map, mac_addr0), + mac_addr_t::from_string(mb_eeprom["mac-addr0"]).to_bytes() + ); + if (mb_eeprom.has_key("mac-addr1")) iface->write_eeprom( + X300_EEPROM_ADDR, offsetof(x300_eeprom_map, mac_addr1), + mac_addr_t::from_string(mb_eeprom["mac-addr1"]).to_bytes() + ); + + //store the ip addresses + byte_vector_t ip_addr_bytes(4); + if (mb_eeprom.has_key("gateway")){ + byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["gateway"]).to_bytes(), ip_addr_bytes); + iface->write_eeprom(X300_EEPROM_ADDR, offsetof(x300_eeprom_map, gateway), ip_addr_bytes); + } + for (size_t i = 0; i < 4; i++) { - UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR); - if (x300_impl::claim_status(_wb) != x300_impl::CLAIMED_BY_US) - { - throw uhd::io_error("Attempted to write MB EEPROM without claim to device."); + const std::string n(1, i+'0'); + if (mb_eeprom.has_key("ip-addr"+n)){ + byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["ip-addr"+n]).to_bytes(), ip_addr_bytes); + iface->write_eeprom(X300_EEPROM_ADDR, offsetof(x300_eeprom_map, ip_addr)+(i*4), ip_addr_bytes); } - _i2c->write_eeprom(addr, offset, buf); - } - /*! - * Read bytes from an eeprom. - * \param addr the address - * \param offset byte offset - * \param num_bytes number of bytes to read - * \return a vector of bytes - */ - byte_vector_t read_eeprom( - uint16_t addr, - uint16_t offset, - size_t num_bytes - ) - { - UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR); - byte_vector_t bytes; - x300_impl::claim_status_t status = x300_impl::claim_status(_wb); - if (_compat_num >= X300_FW_SHMEM_IDENT_MIN_VERSION) - { - // Get MB EEPROM data from firmware memory - if (num_bytes == 0) return bytes; - - size_t bytes_read = 0; - for (size_t word = offset / 4; bytes_read < num_bytes; word++) - { - uint32_t value = byteswap(_wb->peek32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_IDENT + word))); - for (size_t byte = offset % 4; byte < 4 and bytes_read < num_bytes; byte++) - { - bytes.push_back(uint8_t((value >> (byte * 8)) & 0xff)); - bytes_read++; - } - } - } else { - // Claim device before driving the I2C bus - if (status == x300_impl::CLAIMED_BY_US or x300_impl::try_to_claim(_wb)) - { - bytes = _i2c->read_eeprom(addr, offset, num_bytes); - if (status != x300_impl::CLAIMED_BY_US) - { - // We didn't originally have the claim, so give it up - x300_impl::release(_wb); - } - } + if (mb_eeprom.has_key("subnet"+n)){ + byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["subnet"+n]).to_bytes(), ip_addr_bytes); + iface->write_eeprom(X300_EEPROM_ADDR, offsetof(x300_eeprom_map, subnet)+(i*4), ip_addr_bytes); } - return bytes; } - -private: - wb_iface::sptr _wb; - i2c_iface::sptr _i2c; - uint32_t _compat_num; -}; - -x300_mb_eeprom_iface::~x300_mb_eeprom_iface(void) -{ - /* NOP */ -} - -x300_mb_eeprom_iface::sptr x300_mb_eeprom_iface::make(wb_iface::sptr wb, i2c_iface::sptr i2c) -{ - return boost::make_shared(wb, i2c->eeprom16()); + //store the serial + if (mb_eeprom.has_key("serial")) iface->write_eeprom( + X300_EEPROM_ADDR, offsetof(x300_eeprom_map, serial), + string_to_bytes(mb_eeprom["serial"], SERIAL_LEN) + ); + + //store the name + if (mb_eeprom.has_key("name")) iface->write_eeprom( + X300_EEPROM_ADDR, offsetof(x300_eeprom_map, name), + string_to_bytes(mb_eeprom["name"], NAME_MAX_LEN) + ); } diff --git a/host/lib/usrp/x300/x300_mb_eeprom.hpp b/host/lib/usrp/x300/x300_mb_eeprom.hpp deleted file mode 100644 index 0649855c6..000000000 --- a/host/lib/usrp/x300/x300_mb_eeprom.hpp +++ /dev/null @@ -1,37 +0,0 @@ -// -// Copyright 2016 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#ifndef INCLUDED_X300_MB_EEPROM_HPP -#define INCLUDED_X300_MB_EEPROM_HPP - -#include -#include -#include -#include -#include - -class x300_mb_eeprom_iface : public uhd::i2c_iface -{ -public: - typedef boost::shared_ptr sptr; - - virtual ~x300_mb_eeprom_iface(void) = 0; - - static sptr make(uhd::wb_iface::sptr wb, uhd::i2c_iface::sptr i2c); -}; - -#endif /* INCLUDED_X300_MB_EEPROM_HPP */ diff --git a/host/lib/usrp/x300/x300_mb_eeprom_iface.cpp b/host/lib/usrp/x300/x300_mb_eeprom_iface.cpp new file mode 100644 index 000000000..adc766c39 --- /dev/null +++ b/host/lib/usrp/x300/x300_mb_eeprom_iface.cpp @@ -0,0 +1,190 @@ +// +// Copyright 2013-2016 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +/* + * x300_mb_eeprom_iface + * This interface was created to prevent MB EEPROM corruption while reading + * data during discovery. For devices with firmware version newer than 5.0, + * the EEPROM data is read into firmware memory and available without + * claiming the device. For devices with firmware versions 5.0 and older, + * the code makes sure to claim the device before driving the I2C bus. This + * has the unfortunate side effect of preventing multiple processes from + * discovering the device simultaneously, but is far better than having EEPROM + * corruption. + */ + +#include "x300_mb_eeprom_iface.hpp" +#include "x300_fw_common.h" +#include "x300_regs.hpp" +#include "x300_impl.hpp" +#include +#include +#include +#include +#include + +using namespace uhd; + +static const uint32_t X300_FW_SHMEM_IDENT_MIN_VERSION = 0x50001; + +class x300_mb_eeprom_iface_impl : public x300_mb_eeprom_iface +{ +public: + + x300_mb_eeprom_iface_impl(wb_iface::sptr wb, i2c_iface::sptr i2c) : _wb(wb), _i2c(i2c) + { + _compat_num = _wb->peek32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_COMPAT_NUM)); + } + + ~x300_mb_eeprom_iface_impl() + { + /* NOP */ + } + + /*! + * Write bytes over the i2c. + * \param addr the address + * \param buf the vector of bytes + */ + void write_i2c( + uint16_t addr, + const byte_vector_t &buf + ) + { + UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR); + if (x300_impl::claim_status(_wb) != x300_impl::CLAIMED_BY_US) + { + throw uhd::io_error("Attempted to write MB EEPROM without claim to device."); + } + _i2c->write_i2c(addr, buf); + } + + /*! + * Read bytes over the i2c. + * \param addr the address + * \param num_bytes number of bytes to read + * \return a vector of bytes + */ + byte_vector_t read_i2c( + uint16_t addr, + size_t num_bytes + ) + { + UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR); + byte_vector_t bytes; + if (_compat_num > X300_FW_SHMEM_IDENT_MIN_VERSION) + { + bytes = read_eeprom(addr, 0, num_bytes); + } else { + x300_impl::claim_status_t status = x300_impl::claim_status(_wb); + // Claim device before driving the I2C bus + if (status == x300_impl::CLAIMED_BY_US or x300_impl::try_to_claim(_wb)) + { + bytes = _i2c->read_i2c(addr, num_bytes); + if (status != x300_impl::CLAIMED_BY_US) + { + // We didn't originally have the claim, so give it up + x300_impl::release(_wb); + } + } + } + return bytes; + } + + /*! + * Write bytes to an eeprom. + * \param addr the address + * \param offset byte offset + * \param buf the vector of bytes + */ + void write_eeprom( + uint16_t addr, + uint16_t offset, + const byte_vector_t &buf + ) + { + UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR); + if (x300_impl::claim_status(_wb) != x300_impl::CLAIMED_BY_US) + { + throw uhd::io_error("Attempted to write MB EEPROM without claim to device."); + } + _i2c->write_eeprom(addr, offset, buf); + } + + /*! + * Read bytes from an eeprom. + * \param addr the address + * \param offset byte offset + * \param num_bytes number of bytes to read + * \return a vector of bytes + */ + byte_vector_t read_eeprom( + uint16_t addr, + uint16_t offset, + size_t num_bytes + ) + { + UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR); + byte_vector_t bytes; + x300_impl::claim_status_t status = x300_impl::claim_status(_wb); + if (_compat_num >= X300_FW_SHMEM_IDENT_MIN_VERSION) + { + // Get MB EEPROM data from firmware memory + if (num_bytes == 0) return bytes; + + size_t bytes_read = 0; + for (size_t word = offset / 4; bytes_read < num_bytes; word++) + { + uint32_t value = byteswap(_wb->peek32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_IDENT + word))); + for (size_t byte = offset % 4; byte < 4 and bytes_read < num_bytes; byte++) + { + bytes.push_back(uint8_t((value >> (byte * 8)) & 0xff)); + bytes_read++; + } + } + } else { + // Claim device before driving the I2C bus + if (status == x300_impl::CLAIMED_BY_US or x300_impl::try_to_claim(_wb)) + { + bytes = _i2c->read_eeprom(addr, offset, num_bytes); + if (status != x300_impl::CLAIMED_BY_US) + { + // We didn't originally have the claim, so give it up + x300_impl::release(_wb); + } + } + } + return bytes; + } + + +private: + wb_iface::sptr _wb; + i2c_iface::sptr _i2c; + uint32_t _compat_num; +}; + +x300_mb_eeprom_iface::~x300_mb_eeprom_iface(void) +{ + /* NOP */ +} + +x300_mb_eeprom_iface::sptr x300_mb_eeprom_iface::make(wb_iface::sptr wb, i2c_iface::sptr i2c) +{ + return boost::make_shared(wb, i2c->eeprom16()); +} + diff --git a/host/lib/usrp/x300/x300_mb_eeprom_iface.hpp b/host/lib/usrp/x300/x300_mb_eeprom_iface.hpp new file mode 100644 index 000000000..0649855c6 --- /dev/null +++ b/host/lib/usrp/x300/x300_mb_eeprom_iface.hpp @@ -0,0 +1,37 @@ +// +// Copyright 2016 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#ifndef INCLUDED_X300_MB_EEPROM_HPP +#define INCLUDED_X300_MB_EEPROM_HPP + +#include +#include +#include +#include +#include + +class x300_mb_eeprom_iface : public uhd::i2c_iface +{ +public: + typedef boost::shared_ptr sptr; + + virtual ~x300_mb_eeprom_iface(void) = 0; + + static sptr make(uhd::wb_iface::sptr wb, uhd::i2c_iface::sptr i2c); +}; + +#endif /* INCLUDED_X300_MB_EEPROM_HPP */ -- cgit v1.2.3