// // Copyright 2011,2014 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 . // #include "gpio_core_200.hpp" #include #define REG_GPIO_IDLE _base + 0 #define REG_GPIO_RX_ONLY _base + 4 #define REG_GPIO_TX_ONLY _base + 8 #define REG_GPIO_BOTH _base + 12 #define REG_GPIO_DDR _base + 16 using namespace uhd; using namespace usrp; template static void shadow_it(T &shadow, const T &value, const T &mask){ shadow = (shadow & ~mask) | (value & mask); } gpio_core_200::~gpio_core_200(void){ /* NOP */ } class gpio_core_200_impl : public gpio_core_200{ public: gpio_core_200_impl(wb_iface::sptr iface, const size_t base, const size_t rb_addr): _iface(iface), _base(base), _rb_addr(rb_addr), _first_atr(true) { /* NOP */ } void set_pin_ctrl(const unit_t unit, const uint16_t value, const uint16_t mask){ if (unit == dboard_iface::UNIT_BOTH) throw uhd::runtime_error("UNIT_BOTH not supported in gpio_core_200"); shadow_it(_pin_ctrl[unit], value, mask); update(); //full update } uint16_t get_pin_ctrl(unit_t unit){ if (unit == dboard_iface::UNIT_BOTH) throw uhd::runtime_error("UNIT_BOTH not supported in gpio_core_200"); return _pin_ctrl[unit]; } void set_atr_reg(const unit_t unit, const atr_reg_t atr, const uint16_t value, const uint16_t mask){ if (unit == dboard_iface::UNIT_BOTH) throw uhd::runtime_error("UNIT_BOTH not supported in gpio_core_200"); shadow_it(_atr_regs[unit][atr], value, mask); if (_first_atr) { // To preserve legacy behavior, update all registers the first time update(); _first_atr = false; } else update(atr); } uint16_t get_atr_reg(unit_t unit, atr_reg_t reg){ if (unit == dboard_iface::UNIT_BOTH) throw uhd::runtime_error("UNIT_BOTH not supported in gpio_core_200"); return _atr_regs[unit][reg]; } void set_gpio_ddr(const unit_t unit, const uint16_t value, const uint16_t mask){ if (unit == dboard_iface::UNIT_BOTH) throw uhd::runtime_error("UNIT_BOTH not supported in gpio_core_200"); shadow_it(_gpio_ddr[unit], value, mask); _iface->poke32(REG_GPIO_DDR, //update the 32 bit register (uint32_t(_gpio_ddr[dboard_iface::UNIT_RX]) << shift_by_unit(dboard_iface::UNIT_RX)) | (uint32_t(_gpio_ddr[dboard_iface::UNIT_TX]) << shift_by_unit(dboard_iface::UNIT_TX)) ); } uint16_t get_gpio_ddr(unit_t unit){ if (unit == dboard_iface::UNIT_BOTH) throw uhd::runtime_error("UNIT_BOTH not supported in gpio_core_200"); return _gpio_ddr[unit]; } void set_gpio_out(const unit_t unit, const uint16_t value, const uint16_t mask){ if (unit == dboard_iface::UNIT_BOTH) throw uhd::runtime_error("UNIT_BOTH not supported in gpio_core_200"); shadow_it(_gpio_out[unit], value, mask); this->update(); //full update } uint16_t get_gpio_out(unit_t unit){ if (unit == dboard_iface::UNIT_BOTH) throw uhd::runtime_error("UNIT_BOTH not supported in gpio_core_200"); return _gpio_out[unit]; } uint16_t read_gpio(const unit_t unit){ if (unit == dboard_iface::UNIT_BOTH) throw uhd::runtime_error("UNIT_BOTH not supported in gpio_core_200"); return uint16_t(_iface->peek32(_rb_addr) >> shift_by_unit(unit)); } private: wb_iface::sptr _iface; const size_t _base; const size_t _rb_addr; bool _first_atr; uhd::dict _update_cache; uhd::dict _pin_ctrl, _gpio_out, _gpio_ddr; uhd::dict > _atr_regs; unsigned shift_by_unit(const unit_t unit){ return (unit == dboard_iface::UNIT_RX)? 0 : 16; } void update(void){ update(gpio_atr::ATR_REG_IDLE); update(gpio_atr::ATR_REG_TX_ONLY); update(gpio_atr::ATR_REG_RX_ONLY); update(gpio_atr::ATR_REG_FULL_DUPLEX); } void update(const atr_reg_t atr){ size_t addr; switch (atr) { case gpio_atr::ATR_REG_IDLE: addr = REG_GPIO_IDLE; break; case gpio_atr::ATR_REG_TX_ONLY: addr = REG_GPIO_TX_ONLY; break; case gpio_atr::ATR_REG_RX_ONLY: addr = REG_GPIO_RX_ONLY; break; case gpio_atr::ATR_REG_FULL_DUPLEX: addr = REG_GPIO_BOTH; break; default: UHD_THROW_INVALID_CODE_PATH(); } const uint32_t atr_val = (uint32_t(_atr_regs[dboard_iface::UNIT_RX][atr]) << shift_by_unit(dboard_iface::UNIT_RX)) | (uint32_t(_atr_regs[dboard_iface::UNIT_TX][atr]) << shift_by_unit(dboard_iface::UNIT_TX)); const uint32_t gpio_val = (uint32_t(_gpio_out[dboard_iface::UNIT_RX]) << shift_by_unit(dboard_iface::UNIT_RX)) | (uint32_t(_gpio_out[dboard_iface::UNIT_TX]) << shift_by_unit(dboard_iface::UNIT_TX)); const uint32_t ctrl = (uint32_t(_pin_ctrl[dboard_iface::UNIT_RX]) << shift_by_unit(dboard_iface::UNIT_RX)) | (uint32_t(_pin_ctrl[dboard_iface::UNIT_TX]) << shift_by_unit(dboard_iface::UNIT_TX)); const uint32_t val = (ctrl & atr_val) | ((~ctrl) & gpio_val); if (not _update_cache.has_key(addr) or _update_cache[addr] != val) { _iface->poke32(addr, val); } _update_cache[addr] = val; } }; gpio_core_200::sptr gpio_core_200::make(wb_iface::sptr iface, const size_t base, const size_t rb_addr){ return sptr(new gpio_core_200_impl(iface, base, rb_addr)); } gpio_core_200_32wo::~gpio_core_200_32wo(void){ /* NOP */ } class gpio_core_200_32wo_impl : public gpio_core_200_32wo{ public: gpio_core_200_32wo_impl(wb_iface::sptr iface, const size_t base): _iface(iface), _base(base) { set_ddr_reg(); } void set_ddr_reg(){ _iface->poke32(REG_GPIO_DDR, 0xffffffff); } void set_atr_reg(const atr_reg_t atr, const uint32_t value){ if (atr == gpio_atr::ATR_REG_IDLE) _iface->poke32(REG_GPIO_IDLE, value); else if (atr == gpio_atr::ATR_REG_TX_ONLY) _iface->poke32(REG_GPIO_TX_ONLY, value); else if (atr == gpio_atr::ATR_REG_RX_ONLY) _iface->poke32(REG_GPIO_RX_ONLY, value); else if (atr == gpio_atr::ATR_REG_FULL_DUPLEX) _iface->poke32(REG_GPIO_BOTH, value); else UHD_THROW_INVALID_CODE_PATH(); } void set_all_regs(const uint32_t value){ set_atr_reg(gpio_atr::ATR_REG_IDLE, value); set_atr_reg(gpio_atr::ATR_REG_TX_ONLY, value); set_atr_reg(gpio_atr::ATR_REG_RX_ONLY, value); set_atr_reg(gpio_atr::ATR_REG_FULL_DUPLEX, value); } private: wb_iface::sptr _iface; const size_t _base; }; gpio_core_200_32wo::sptr gpio_core_200_32wo::make(wb_iface::sptr iface, const size_t base){ return sptr(new gpio_core_200_32wo_impl(iface, base)); }