diff options
Diffstat (limited to 'firmware/zpu/lib')
63 files changed, 5024 insertions, 0 deletions
diff --git a/firmware/zpu/lib/CMakeLists.txt b/firmware/zpu/lib/CMakeLists.txt new file mode 100644 index 000000000..ce6b7fa44 --- /dev/null +++ b/firmware/zpu/lib/CMakeLists.txt @@ -0,0 +1,48 @@ +# +# Copyright 2010 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 <http://www.gnu.org/licenses/>. +# + +######################################################################## +SET(COMMON_SRCS + ${CMAKE_SOURCE_DIR}/lib/u2_init.c + ${CMAKE_SOURCE_DIR}/lib/abort.c + ${CMAKE_SOURCE_DIR}/lib/ad9510.c + ${CMAKE_SOURCE_DIR}/lib/clocks.c + ${CMAKE_SOURCE_DIR}/lib/eeprom.c + ${CMAKE_SOURCE_DIR}/lib/eth_addrs.c + ${CMAKE_SOURCE_DIR}/lib/eth_mac.c + ${CMAKE_SOURCE_DIR}/lib/_exit.c + ${CMAKE_SOURCE_DIR}/lib/exit.c + ${CMAKE_SOURCE_DIR}/lib/hal_io.c + ${CMAKE_SOURCE_DIR}/lib/hal_uart.c + ${CMAKE_SOURCE_DIR}/lib/i2c.c + ${CMAKE_SOURCE_DIR}/lib/mdelay.c + ${CMAKE_SOURCE_DIR}/lib/memcpy_wa.c + ${CMAKE_SOURCE_DIR}/lib/memset_wa.c + ${CMAKE_SOURCE_DIR}/lib/nonstdio.c + ${CMAKE_SOURCE_DIR}/lib/pic.c + ${CMAKE_SOURCE_DIR}/lib/pkt_ctrl.c + ${CMAKE_SOURCE_DIR}/lib/print_addrs.c + ${CMAKE_SOURCE_DIR}/lib/print_rmon_regs.c + ${CMAKE_SOURCE_DIR}/lib/print_buffer.c + ${CMAKE_SOURCE_DIR}/lib/printf.c + ${CMAKE_SOURCE_DIR}/lib/ihex.c + ${CMAKE_SOURCE_DIR}/lib/spi.c + ${CMAKE_SOURCE_DIR}/lib/net_common.c + ${CMAKE_SOURCE_DIR}/lib/arp_cache.c + ${CMAKE_SOURCE_DIR}/lib/banal.c + ${CMAKE_SOURCE_DIR}/lib/udp_uart.c +) diff --git a/firmware/zpu/lib/_exit.c b/firmware/zpu/lib/_exit.c new file mode 100644 index 000000000..9b40ab2ee --- /dev/null +++ b/firmware/zpu/lib/_exit.c @@ -0,0 +1,27 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +/* + * Stub so we can compile using 3.4 based mb-gcc + */ +void +_exit(int status) +{ + while (1) + ; +} diff --git a/firmware/zpu/lib/abort.c b/firmware/zpu/lib/abort.c new file mode 100644 index 000000000..d1d709392 --- /dev/null +++ b/firmware/zpu/lib/abort.c @@ -0,0 +1,32 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <nonstdio.h> + +extern void _exit(int status); + +void +abort(void) +{ + putstr("\n\nabort\n"); + // FIXME loop blinking leds + _exit(-1); +} diff --git a/firmware/zpu/lib/ad9510.c b/firmware/zpu/lib/ad9510.c new file mode 100644 index 000000000..4021a9bf7 --- /dev/null +++ b/firmware/zpu/lib/ad9510.c @@ -0,0 +1,42 @@ +/* + * Copyright 2012 Ettus Research LLC + * Copyright 2008 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "ad9510.h" +#include "spi.h" +#include <memory_map.h> + +#define RD (1 << 15) +#define WR (0 << 15) + +void +ad9510_write_reg(int regno, uint8_t value) +{ + uint32_t inst = WR | (regno & 0xff); + uint32_t v = (inst << 8) | (value & 0xff); + spi_transact(SPI_TXONLY, SPI_SS_AD9510, v, 24, SPI_PUSH_FALL); +} + +int +ad9510_read_reg(int regno) +{ + uint32_t inst = RD | (regno & 0xff); + uint32_t v = (inst << 8) | 0; + uint32_t r = spi_transact(SPI_TXRX, SPI_SS_AD9510, v, 24, + SPI_PUSH_FALL | SPI_LATCH_FALL); + return r & 0xff; +} diff --git a/firmware/zpu/lib/ad9510.h b/firmware/zpu/lib/ad9510.h new file mode 100644 index 000000000..a395e5223 --- /dev/null +++ b/firmware/zpu/lib/ad9510.h @@ -0,0 +1,30 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ +#ifndef INCLUDED_AD9510_H +#define INCLUDED_AD9510_H + +#include <stdint.h> + +/* + * Analog Device AD9510 1.2 GHz Clock Distribution IC w/ PLL + */ + +void ad9510_write_reg(int regno, uint8_t value); +int ad9510_read_reg(int regno); + +#endif /* INCLUDED_AD9510_H */ diff --git a/firmware/zpu/lib/arp_cache.c b/firmware/zpu/lib/arp_cache.c new file mode 100644 index 000000000..8e14d8f17 --- /dev/null +++ b/firmware/zpu/lib/arp_cache.c @@ -0,0 +1,90 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009-2011 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 <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include "arp_cache.h" +#include <stddef.h> + +typedef struct { + struct ip_addr ip; + eth_mac_addr_t mac; +} arp_cache_t; + +#define NENTRIES 8 // power-of-2 + +static size_t nentries; +static size_t victim; +static arp_cache_t cache[NENTRIES]; + +void +arp_cache_init(void) +{ + nentries = 0; + victim = 0; +} + +// returns non-negative index if found, else -1 +static int +arp_cache_lookup(const struct ip_addr *ip) +{ + int i; + for (i = 0; i < nentries; i++) + if (cache[i].ip.addr == ip->addr) + return i; + + return -1; +} + +static int +arp_cache_alloc(void) +{ + if (nentries < NENTRIES) + return nentries++; + + int i = victim; + victim = (victim + 1) % NENTRIES; + return i; +} + +void +arp_cache_update(const struct ip_addr *ip, + const eth_mac_addr_t *mac) +{ + int i = arp_cache_lookup(ip); + if (i < 0){ + i = arp_cache_alloc(); + cache[i].ip = *ip; + cache[i].mac = *mac; + } + else { + cache[i].mac = *mac; + } +} + +bool +arp_cache_lookup_mac(const struct ip_addr *ip, + eth_mac_addr_t *mac) +{ + int i = arp_cache_lookup(ip); + if (i < 0) + return false; + + *mac = cache[i].mac; + return true; +} diff --git a/firmware/zpu/lib/arp_cache.h b/firmware/zpu/lib/arp_cache.h new file mode 100644 index 000000000..e0e125d89 --- /dev/null +++ b/firmware/zpu/lib/arp_cache.h @@ -0,0 +1,33 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009-2011 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 <http://www.gnu.org/licenses/>. + */ +#ifndef INCLUDED_ARP_CACHE_H +#define INCLUDED_ARP_CACHE_H + +#include <lwip/ip_addr.h> +#include <net/eth_mac_addr.h> +#include <stdbool.h> + +void arp_cache_init(void); + +void arp_cache_update(const struct ip_addr *ip, + const eth_mac_addr_t *mac); + +bool arp_cache_lookup_mac(const struct ip_addr *ip, + eth_mac_addr_t *mac); + +#endif /* INCLUDED_ARP_CACHE_H */ diff --git a/firmware/zpu/lib/banal.c b/firmware/zpu/lib/banal.c new file mode 100644 index 000000000..dfb8df355 --- /dev/null +++ b/firmware/zpu/lib/banal.c @@ -0,0 +1,31 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009-2011 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 <http://www.gnu.org/licenses/>. + */ + +#include <banal.h> + +uint32_t +get_uint32(const unsigned char *s) +{ + return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]; +} + +uint64_t +get_uint64(const unsigned char *s) +{ + return (((uint64_t)get_uint32(s)) << 32) | get_uint32(s+4); +} diff --git a/firmware/zpu/lib/banal.h b/firmware/zpu/lib/banal.h new file mode 100644 index 000000000..e9e55bca5 --- /dev/null +++ b/firmware/zpu/lib/banal.h @@ -0,0 +1,71 @@ +/* -*- c -*- */ +/* + * Copyright 2009-2011 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 <http://www.gnu.org/licenses/>. + */ +#ifndef INCLUDED_BANAL_H +#define INCLUDED_BANAL_H + +#include <stdint.h> + +#define dimof(x) (sizeof(x)/sizeof(x[0])) + +//-------------- unsigned get_int 8, 16, 32, 64 --------------// + +static inline uint8_t +get_uint8(const unsigned char *s) +{ + return s[0]; +} + +static inline uint16_t +get_uint16(const unsigned char *s) +{ + return (s[0] << 8) | s[1]; +} + +uint32_t +get_uint32(const unsigned char *s); + +uint64_t +get_uint64(const unsigned char *s); + +//--------------- signed get_int 8, 16, 32, 64 --------------// + +static inline int8_t +get_int8(const unsigned char *s) +{ + return get_uint8(s); +} + +static inline int16_t +get_int16(const unsigned char *s) +{ + return get_uint16(s); +} + +static inline int32_t +get_int32(const unsigned char *s) +{ + return get_uint32(s); +} + +static inline int64_t +get_int64(const unsigned char *s) +{ + return get_uint64(s); +} + +#endif /* INCLUDED_BANAL_H */ diff --git a/firmware/zpu/lib/clocks.c b/firmware/zpu/lib/clocks.c new file mode 100644 index 000000000..bc1954e13 --- /dev/null +++ b/firmware/zpu/lib/clocks.c @@ -0,0 +1,121 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <clocks.h> +#include <stdbool.h> +#include "memory_map.h" +#include "ad9510.h" +#include "spi.h" + +/*! + * \brief Lock Detect -- Return True if our PLL is locked + */ +bool clocks_lock_detect(); + +/*! + * \brief Enable or disable fpga clock. Disabling would wedge and require a power cycle. + */ +void clocks_enable_fpga_clk(bool enable, int divisor); + +void +clocks_init(void) +{ + // Set up basic clocking functions in AD9510 + ad9510_write_reg(0x45, 0x01); + + //enable the 100MHz clock output to the FPGA for 50MHz CPU clock + clocks_enable_fpga_clk(true, 1); + + //! Cannot SPI wait since SPI is on DSP clock + //! because DSP clock goes away until DCM reset. + //! However, spi is quick, the cpu is slow, its already ready... + //spi_wait(); + + //wait for the clock to stabilize + while(!clocks_lock_detect()); + + //issue a reset to the DCM so it locks up to the new freq + output_regs->clk_ctrl |= CLK_RESET; +} + +bool +clocks_lock_detect() +{ + return (pic_regs->pending & PIC_CLKSTATUS); +} + +int inline +clocks_gen_div(int divisor) +{ + int L,H; + L = (divisor>>1)-1; + H = divisor-L-2; + return (L<<4)|H; +} + +#define CLOCK_OUT_EN 0x08 +#define CLOCK_OUT_DIS_CMOS 0x01 +#define CLOCK_OUT_DIS_PECL 0x02 +#define CLOCK_DIV_DIS 0x80 +#define CLOCK_DIV_EN 0x00 + +#define CLOCK_MODE_PECL 1 +#define CLOCK_MODE_LVDS 2 +#define CLOCK_MODE_CMOS 3 + +//CHANGED: set to PECL for default behavior +void +clocks_enable_XXX_clk(bool enable, int divisor, int reg_en, int reg_div, int mode) +{ + int enable_word, div_word, div_en_word; + + switch(mode) { + case CLOCK_MODE_LVDS : + enable_word = enable ? 0x02 : 0x03; + break; + case CLOCK_MODE_CMOS : + enable_word = enable ? 0x08 : 0x09; + break; + case CLOCK_MODE_PECL : + default: + enable_word = enable ? 0x08 : 0x0A; + break; + } + if(enable && (divisor>1)) { + div_word = clocks_gen_div(divisor); + div_en_word = CLOCK_DIV_EN; + } + else { + div_word = 0; + div_en_word = CLOCK_DIV_DIS; + } + + ad9510_write_reg(reg_en,enable_word); // Output en/dis + ad9510_write_reg(reg_div,div_word); // Set divisor + ad9510_write_reg(reg_div+1,div_en_word); // Enable or Bypass Divider + ad9510_write_reg(0x5A, 0x01); // Update Regs +} + +// Clock 1 +void +clocks_enable_fpga_clk(bool enable, int divisor) +{ + clocks_enable_XXX_clk(enable,divisor,0x3D,0x4A,CLOCK_MODE_PECL); +} diff --git a/firmware/zpu/lib/clocks.h b/firmware/zpu/lib/clocks.h new file mode 100644 index 000000000..7bc7a3cda --- /dev/null +++ b/firmware/zpu/lib/clocks.h @@ -0,0 +1,30 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_CLOCKS_H +#define INCLUDED_CLOCKS_H + +/*! + * One time call to initialize the master clock to a reasonable state. + * We come out of here using our free running 100MHz oscillator. + */ +void clocks_init(void); + +#endif /* INCLUDED_CLOCKS_H */ diff --git a/firmware/zpu/lib/compiler.h b/firmware/zpu/lib/compiler.h new file mode 100644 index 000000000..f677bdc3b --- /dev/null +++ b/firmware/zpu/lib/compiler.h @@ -0,0 +1,26 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009, 2010 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 <http://www.gnu.org/licenses/>. + */ +#ifndef INCLUDED_COMPILER_H +#define INCLUDED_COMPILER_H + +// FIXME gcc specific. +#define _AL4 __attribute__((aligned (4))) + +#define FORCE_INLINE inline __attribute__((always_inline)) + +#endif /* INCLUDED_COMPILER_H */ diff --git a/firmware/zpu/lib/eeprom.c b/firmware/zpu/lib/eeprom.c new file mode 100644 index 000000000..d4e170046 --- /dev/null +++ b/firmware/zpu/lib/eeprom.c @@ -0,0 +1,81 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "i2c.h" +#include "mdelay.h" +#include "usrp2/fw_common.h" + +static const int EEPROM_PAGESIZE = 16; + +bool find_safe_booted_flag(void) { + unsigned char flag_byte; + eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_BOOTLOADER_FLAGS, &flag_byte, 1); + return (flag_byte == 0x5E); +} + +void set_safe_booted_flag(bool flag) { + unsigned char flag_byte = flag ? 0x5E : 0xDC; + eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_BOOTLOADER_FLAGS, &flag_byte, 1); +} + +bool +eeprom_write (int i2c_addr, int eeprom_offset, const void *buf, int len) +{ + unsigned char cmd[2]; + const unsigned char *p = (unsigned char *) buf; + + // The simplest thing that could possibly work: + // all writes are single byte writes. + // + // We could speed this up using the page write feature, + // but we write so infrequently, why bother... + + while (len-- > 0){ + cmd[0] = eeprom_offset++; + cmd[1] = *p++; + bool r = i2c_write (i2c_addr, cmd, sizeof (cmd)); + mdelay (10); // delay 10ms worst case write time + if (!r) + return false; + } + return true; +} + +bool +eeprom_read (int i2c_addr, int eeprom_offset, void *buf, int len) +{ + unsigned char *p = (unsigned char *) buf; + + // We setup a random read by first doing a "zero byte write". + // Writes carry an address. Reads use an implicit address. + + unsigned char cmd[1]; + cmd[0] = eeprom_offset; + if (!i2c_write (i2c_addr, cmd, sizeof (cmd))) + return false; + + while (len > 0){ + // int n = std::min (len, MAX_EP0_PKTSIZE); + int n = len; + if (!i2c_read (i2c_addr, p, n)) + return false; + len -= n; + p += n; + } + return true; +} + diff --git a/firmware/zpu/lib/eth_addrs.c b/firmware/zpu/lib/eth_addrs.c new file mode 100644 index 000000000..6d3347cf3 --- /dev/null +++ b/firmware/zpu/lib/eth_addrs.c @@ -0,0 +1,106 @@ +/* + * Copyright 2010-2012 Ettus Research LLC + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "ethernet.h" +#include "memory_map.h" +#include "nonstdio.h" +#include <stdbool.h> +#include <string.h> +#include "i2c.h" +#include "usrp2/fw_common.h" + +static bool +unprogrammed(const void *t, size_t len) +{ + int i; + uint8_t *p = (uint8_t *)t; + bool all_zeros = true; + bool all_ones = true; + for (i = 0; i < len; i++){ + all_zeros &= p[i] == 0x00; + all_ones &= p[i] == 0xff; + } + return all_ones | all_zeros; +} + +typedef struct{ + eth_mac_addr_t mac_addr; + struct ip_addr ip_addr; + struct ip_addr gateway; + struct ip_addr subnet; +} eth_addrs_t; + +static bool eth_addrs_initialized = false; + +static const eth_addrs_t default_eth_addrs = { + .mac_addr = {{0x00, 0x50, 0xC2, 0x85, 0x3f, 0xff}}, + .ip_addr = {(192 << 24 | 168 << 16 | 10 << 8 | 2 << 0)}, + .gateway = {(192 << 24 | 168 << 16 | 10 << 8 | 1 << 0)}, + .subnet = {(255 << 24 | 255 << 16 | 255 << 8 | 0 << 0)}, +}; + +static eth_addrs_t current_eth_addrs; + +static void eth_addrs_init(void){ + if (eth_addrs_initialized) return; + eth_addrs_initialized = true; + + #define eth_addrs_init_x(addr, x){ \ + const bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, addr, ¤t_eth_addrs.x, sizeof(current_eth_addrs.x)); \ + if (!ok || unprogrammed(¤t_eth_addrs.x, sizeof(current_eth_addrs.x))){ \ + memcpy(¤t_eth_addrs.x, &default_eth_addrs.x, sizeof(current_eth_addrs.x)); \ + } \ + } + + eth_addrs_init_x(USRP2_EE_MBOARD_MAC_ADDR, mac_addr); + eth_addrs_init_x(USRP2_EE_MBOARD_IP_ADDR, ip_addr); + eth_addrs_init_x(USRP2_EE_MBOARD_GATEWAY, gateway); + eth_addrs_init_x(USRP2_EE_MBOARD_SUBNET, subnet); + +} + +const eth_mac_addr_t *ethernet_mac_addr(void){ + eth_addrs_init(); + return ¤t_eth_addrs.mac_addr; +} + +const struct ip_addr *get_ip_addr(void){ + eth_addrs_init(); + return ¤t_eth_addrs.ip_addr; +} + +const struct ip_addr *get_subnet(void){ + eth_addrs_init(); + return ¤t_eth_addrs.subnet; +} + +const struct ip_addr *get_gateway(void){ + eth_addrs_init(); + return ¤t_eth_addrs.gateway; +} + +bool set_ip_addr(const struct ip_addr *t){ + const bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, t, sizeof(struct ip_addr)); + if (ok) current_eth_addrs.ip_addr = *t; + return ok; +} + +void eth_addrs_set_default(void){ + eth_addrs_initialized = true; + memcpy(¤t_eth_addrs, &default_eth_addrs, sizeof(default_eth_addrs)); +} diff --git a/firmware/zpu/lib/eth_mac.c b/firmware/zpu/lib/eth_mac.c new file mode 100644 index 000000000..581a5c69f --- /dev/null +++ b/firmware/zpu/lib/eth_mac.c @@ -0,0 +1,121 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "eth_mac.h" +#include "memory_map.h" +#include <stdbool.h> +#include "eth_phy.h" // for simulation constants +#include "mdelay.h" +#include "stdio.h" + +#define PHY_ADDR 1 + +void +eth_mac_set_addr(const eth_mac_addr_t *src) +{ + /* disable because MAC_SET_PASS_ALL is set below + eth_mac->ucast_hi = + (((unsigned int)src->addr[0])<<8) + + ((unsigned int)src->addr[1]); + eth_mac->ucast_lo = + (((unsigned int)src->addr[2])<<24) + + (((unsigned int)src->addr[3])<<16) + + (((unsigned int)src->addr[4])<<8) + + (((unsigned int)src->addr[5])); +*/ +} + + +void +eth_mac_init(const eth_mac_addr_t *src) +{ + eth_mac->miimoder = 25; // divider from CPU clock (50MHz/25 = 2MHz) + + eth_mac_set_addr(src); + eth_mac->settings = MAC_SET_PAUSE_EN | MAC_SET_PASS_BCAST | MAC_SET_PASS_UCAST | MAC_SET_PAUSE_SEND_EN | MAC_SET_PASS_ALL; + + eth_mac->pause_time = 38; + eth_mac->pause_thresh = 1200; + + // set rx flow control high and low water marks + // unsigned int lwmark = (2*2048 + 64)/4; // 2 * 2048-byte frames + 1 * 64-byte pause frame + // eth_mac->fc_hwmark = lwmark + 2048/4; // plus a 2048-byte frame + + // eth_mac->fc_lwmark = 600; // there are currently 2047 lines in the fifo + // eth_mac->fc_hwmark = 1200; + //eth_mac->fc_padtime = 1700; // how long before flow control runs out do we + // request a re-pause. Units of 8ns (bytes) + + //eth_mac->tx_pause_en = 0; // pay attn to pause frames sent to us + //eth_mac->pause_quanta_set = 38; // a bit more than 1 max frame 16kb/512 + fudge + //eth_mac->pause_frame_send_en = 0; // enable sending pause frames +} + +int +eth_mac_read_rmon(int addr) +{ + int t = 0; + /* + eth_mac->rmon_rd_addr = addr; + eth_mac->rmon_rd_apply = 1; + while(eth_mac->rmon_rd_grant == 0) + ; + + t = eth_mac->rmon_rd_dout; + eth_mac->rmon_rd_apply = 0; + */ + return t; +} + +int +eth_mac_miim_read(int addr) +{ + + int phy_addr = PHY_ADDR; + eth_mac->miiaddress = ((addr & 0x1f) << 8) | phy_addr; + eth_mac->miicommand = MIIC_RSTAT; + + while((eth_mac->miistatus & MIIS_BUSY) != 0) + ; + + int r = eth_mac->miirx_data; + //printf("MIIM-READ ADDR 0x%x DATA 0x%x\n",addr, r); + return r; +} + +void +eth_mac_miim_write(int addr, int value) +{ + int phy_addr = PHY_ADDR; + eth_mac->miiaddress = ((addr & 0x1f) << 8) | phy_addr; + eth_mac->miitx_data = value; + eth_mac->miicommand = MIIC_WCTRLDATA; + +// printf("MIIM-WRITE ADDR 0x%x VAL 0x%x\n",addr,value); + while((eth_mac->miistatus & MIIS_BUSY) != 0) + ; +} + +int +eth_mac_miim_read_status(void) +{ + if (hwconfig_simulation_p()) + return 0; + + return eth_mac->miistatus; +} diff --git a/firmware/zpu/lib/eth_mac.h b/firmware/zpu/lib/eth_mac.h new file mode 100644 index 000000000..73feec955 --- /dev/null +++ b/firmware/zpu/lib/eth_mac.h @@ -0,0 +1,32 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_ETH_MAC_H +#define INCLUDED_ETH_MAC_H + +#include <net/eth_mac_addr.h> + +void eth_mac_init(const eth_mac_addr_t *src); + +void eth_mac_set_addr(const eth_mac_addr_t *src); +int eth_mac_read_rmon(int addr); +int eth_mac_miim_read(int addr); +void eth_mac_miim_write(int addr, int value); +int eth_mac_miim_read_status(void); + +#endif /* INCLUDED_ETH_MAC_H */ diff --git a/firmware/zpu/lib/ethernet.h b/firmware/zpu/lib/ethernet.h new file mode 100644 index 000000000..b5b08cb8c --- /dev/null +++ b/firmware/zpu/lib/ethernet.h @@ -0,0 +1,100 @@ +/* + * Copyright 2010-2012 Ettus Research LLC + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_ETHERNET_H +#define INCLUDED_ETHERNET_H + +#include <net/eth_mac_addr.h> +#include <lwip/ip_addr.h> +#include <stdbool.h> + +typedef void (*ethernet_link_changed_callback_t)(int speed); + + +/*! + * \brief one time call to initialize ethernet + */ +void ethernet_init(void); + +/*! + * \brief Specify the function to call on link state changes. + * + * When the link comes up, speed is the link speed in Mbit/s. + * When the link goes down, speed is 0. + */ +void ethernet_register_link_changed_callback(ethernet_link_changed_callback_t cb); + +/*! + * \returns ethernet MAC address + */ +const eth_mac_addr_t *ethernet_mac_addr(void); + +/*! + * \returns IP address + */ +const struct ip_addr *get_ip_addr(void); + +/*! + * \returns gateway address + */ +const struct ip_addr *get_gateway(void); + +/*! + * \returns subnet address + */ +const struct ip_addr *get_subnet(void); + +/*! + * \brief write ip address to eeprom and begin using it + */ +bool set_ip_addr(const struct ip_addr *t); + +//! Apply default settings to eth addrs +void eth_addrs_set_default(void); + +/* + * \brief read RMON regs and return error mask + */ +int ethernet_check_errors(void); + +#define RME_RX_CRC 0x0001 +#define RME_RX_FIFO_FULL 0x0002 +#define RME_RX_2SHORT_2LONG 0x0004 + +#define RME_TX_JAM_DROP 0x0010 +#define RME_TX_FIFO_UNDER 0x0020 +#define RME_TX_FIFO_OVER 0x0040 + + +typedef enum { LS_UNKNOWN, LS_DOWN, LS_UP } eth_link_state_t; + +// flow control bitmasks +#define FC_NONE 0x0 +#define FC_WE_TX 0x1 // we send PAUSE frames +#define FC_WE_RX 0x2 // we honor received PAUSE frames +#define FC_SYMM (FC_WE_TX | FC_WE_RX) + +#define S_UNKNOWN (-1) // unknown link speed + +typedef struct { + eth_link_state_t link_state; + int link_speed; // in Mb/s + int flow_control; +} ethernet_t; + +#endif /* INCLUDED_ETHERNET_H */ diff --git a/firmware/zpu/lib/ethertype.h b/firmware/zpu/lib/ethertype.h new file mode 100644 index 000000000..235981193 --- /dev/null +++ b/firmware/zpu/lib/ethertype.h @@ -0,0 +1,27 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009-2011 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 <http://www.gnu.org/licenses/>. + */ +#ifndef INCLUDED_ETHERTYPE_H +#define INCLUDED_ETHERTYPE_H + +// all we care about + +#define ETHERTYPE_IPV4 0x0800 +#define ETHERTYPE_ARP 0x0806 + + +#endif /* INCLUDED_ETHERTYPE_H */ diff --git a/firmware/zpu/lib/exit.c b/firmware/zpu/lib/exit.c new file mode 100644 index 000000000..95a3bf4de --- /dev/null +++ b/firmware/zpu/lib/exit.c @@ -0,0 +1,28 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +extern void _exit(int status); + +void +exit(int status) +{ + _exit(status); +} diff --git a/firmware/zpu/lib/hal_io.c b/firmware/zpu/lib/hal_io.c new file mode 100644 index 000000000..d4be324f5 --- /dev/null +++ b/firmware/zpu/lib/hal_io.c @@ -0,0 +1,274 @@ +/* -*- c -*- */ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +// conditionalized on HAL_IO_USES_DBOARD_PINS && HAL_IO_USES_UART + +#include "memory_map.h" +#include "hal_uart.h" +#include "hal_io.h" +#include <stdbool.h> +#include <stdio.h> +#include <string.h> + +/* + * ======================================================================== + * leds + * ======================================================================== + */ + +static unsigned long leds_shadow = 0; +static unsigned long led_src_shadow = 0; + +void +hal_set_leds(int value, int mask) +{ + int ei = hal_disable_ints(); + leds_shadow = (leds_shadow & ~mask) | (value & mask); + output_regs->leds = leds_shadow; + hal_restore_ints(ei); +} + +// Allow hardware control over leds. 1 = hardware, 0 = software +void +hal_set_led_src(int value, int mask) +{ + int ei = hal_disable_ints(); + led_src_shadow = (led_src_shadow & ~mask) | (value & mask); + output_regs->led_src = led_src_shadow; + hal_restore_ints(ei); +} + +void +hal_toggle_leds(int mask) +{ + int ei = hal_disable_ints(); + leds_shadow ^= mask; + output_regs->leds = leds_shadow; + hal_restore_ints(ei); +} + + +// ================================================================ +// primitives +// ================================================================ + +#if defined(HAL_IO_USES_DBOARD_PINS) +// +// Does i/o using high 9-bits of rx daughterboard pins. +// +// 1 1 1 1 1 1 +// 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | char |W| | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// +// Asserts W when writing char +// + +#define W 0x0080 + +void +hal_io_init(void) +{ + // make high 9 bits of tx daughterboard outputs + hal_gpio_set_rx_mode(15, 7, GPIOM_OUTPUT); + + // and set them to zero + hal_gpio_set_rx(0x0000, 0xff80); +} + +void +hal_finish(void) +{ + volatile unsigned long *p = (unsigned long *) 0xC2F0; + *p = 0; +} + +// %c +inline int +putchar(int ch) +{ + hal_gpio_set_rx((s << 8) | W, 0xff80); + hal_gpio_set_rx(0, 0xff80); + return ch; +} + +#elif defined(HAL_IO_USES_UART) + +void +hal_io_init(void) +{ + hal_uart_init(); +} + +void +hal_finish(void) +{ +} + +// %c +inline int +fputchar(hal_uart_name_t u, int ch) +{ + hal_uart_putc(u, ch); + return ch; +} + +inline int +putchar(int ch) +{ + hal_uart_putc(DEFAULT_UART, ch); + return ch; +} + +int +fgetchar(hal_uart_name_t u) +{ + return hal_uart_getc(u); +} + +int +getchar(void) +{ + return fgetchar(DEFAULT_UART); +} + +#else // nop all i/o + +void +hal_io_init(void) +{ +} + +void +hal_finish(void) +{ +} + +// %c +inline int +putchar(int ch) +{ + return ch; +} + +int +getchar(void) +{ + return EOF; +} + +#endif + +// ================================================================ +// (slightly) higher level functions +// +// These are here so we can inline the calls to putchar. +// The rest of the stuff was moved to nonstdio.c +// ================================================================ + +// \n +inline void +fnewline(hal_uart_name_t u) +{ + fputchar(u, '\n'); +} + +inline void +newline(void) +{ + fnewline(DEFAULT_UART); +} + +int +fputstr(hal_uart_name_t u, const char *s) +{ + while (*s) + fputchar(u, *s++); + + return 0; +} + +int +fnputstr(hal_uart_name_t u, const char *s, int len) +{ + int x = 0; + while (*s && (len > x++)) + fputchar(u, *s++); + + return x; +} + +int +putstr(const char *s) +{ + return fputstr(DEFAULT_UART, s); +} + +int +fputs(hal_uart_name_t u, const char *s) +{ + fputstr(u, s); + fputchar(u, '\n'); + return 0; +} + +int puts(const char *s) +{ + return fputs(DEFAULT_UART, s); +} + +char * +fgets(hal_uart_name_t u, char * const s) +{ + char *x = s; + while((*x=(char)hal_uart_getc(u)) != '\n') x++; + *x = 0; + return s; +} + +int +fngets(hal_uart_name_t u, char * const s, int len) +{ + char *x = s; + while(((*x=(char)hal_uart_getc(u)) != '\n') && ((x-s) < len)) x++; + *x = 0; + return (x-s); +} + +int +fngets_noblock(hal_uart_name_t u, char * const s, int len) +{ + int i; + for(i=0; i < len; i++) { + int ret = hal_uart_getc_noblock(u); + s[i] = (char) ret; + if((ret == -1) || (s[i] == '\n')) break; + } + s[i] = 0; + + return i; +} + +char * +gets(char * const s) +{ + return fgets(DEFAULT_UART, s); +} + diff --git a/firmware/zpu/lib/hal_io.h b/firmware/zpu/lib/hal_io.h new file mode 100644 index 000000000..7a617685c --- /dev/null +++ b/firmware/zpu/lib/hal_io.h @@ -0,0 +1,96 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_HAL_IO_H +#define INCLUDED_HAL_IO_H + +#include "memory_map.h" +#include "hal_uart.h" + +void hal_io_init(void); +void hal_finish(); +char *gets(char * const s); +int fputstr(hal_uart_name_t u, const char *s); +int fnputstr(hal_uart_name_t u, const char *s, int len); +int fngets(hal_uart_name_t u, char * const s, int len); +int fngets_noblock(hal_uart_name_t u, char * const s, int len); + +/* + * ------------------------------------------------------------------------ + * control the leds + * + * Low 4-bits are the general purpose leds on the board + * The next bit is the led on the ethernet connector + * ------------------------------------------------------------------------ + */ + +void hal_set_leds(int value, int mask); +void hal_set_led_src(int value, int mask); +void hal_toggle_leds(int mask); + +/* + * ------------------------------------------------------------------------ + * simple timeouts + * ------------------------------------------------------------------------ + */ + + + +static inline void +hal_set_timeout(int delta_ticks) +{ + sr_simple_timer->onetime = delta_ticks; +} + +/* + * ------------------------------------------------------------------------ + * interrupt enable/disable + * ------------------------------------------------------------------------ + */ + +/*! + * \brief Disable interrupts and return previous interrupt enable state. + * [Microblaze specific] + */ +static inline int +hal_disable_ints(void) +{ + return 0; /* NOP */ +} + +/*! + * \brief Enable interrupts and return previous interrupt enable state. + * [Microblaze specific] + */ +static inline int +hal_enable_ints(void) +{ + return 0; /* NOP */ +} + +/*! + * \brief Set interrupt enable state to \p prev_state. + * [Microblaze specific] + */ +static inline void +hal_restore_ints(int prev_state) +{ + /* NOP */ +} + +#endif /* INCLUDED_HAL_IO_H */ diff --git a/firmware/zpu/lib/hal_uart.c b/firmware/zpu/lib/hal_uart.c new file mode 100644 index 000000000..af60bed6a --- /dev/null +++ b/firmware/zpu/lib/hal_uart.c @@ -0,0 +1,121 @@ +/* -*- c -*- */ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "memory_map.h" +#include "hal_uart.h" +#include "hal_io.h" +#include "mdelay.h" + +//just to save you from going insane, note that firmware/FPGA UARTs [0-2] correspond to serial ports [1-3]. +//so in software, we refer to UART_DEBUG as UART0, but it transmits on pin TXD<1>. see the UART assignments in hal_uart.h. + +#define NSPEEDS 6 +#define MAX_WB_DIV 4 + +//if you're going to recalculate the divisors, it's just uart_clock_rate / baud_rate. +//uart_clock_rate is 50MHz for USRP2. +static const uint16_t +divisor_table[NSPEEDS] = { + 5208, // 9600 + 2604, // 19200 + 1302, // 38400 + 868, // 57600 + 434, // 115200 + 217 // 230400 +}; + +static char uart_mode[4] = { + [UART_DEBUG] = UART_MODE_ONLCR, + [UART_EXP] = UART_MODE_ONLCR, + [UART_GPS] = UART_MODE_ONLCR +}; + +static char uart_speeds[4] = { + [UART_DEBUG] = US_230400, + [UART_EXP] = US_230400, + [UART_GPS] = US_115200 +}; + +void +hal_uart_set_mode(hal_uart_name_t uart, int mode) +{ + uart_mode[uart] = mode; +} + +void hal_uart_set_speed(hal_uart_name_t uart, hal_uart_speed_t speed) +{ + uart_regs[uart].clkdiv = divisor_table[speed]; +} + +void +hal_uart_init(void) +{ + for(int i = 0; i < 3; i++) { + hal_uart_set_mode(i, uart_mode[i]); + hal_uart_set_speed(i, uart_speeds[i]); + } +} + +void +hal_uart_putc(hal_uart_name_t u, int ch) +{ + if ((ch == '\n') && (uart_mode[u] == UART_MODE_ONLCR)) //map \n->\r\n if necessary + hal_uart_putc(u, '\r'); + + while (uart_regs[u].txlevel == 0) // wait for fifo to have space + ; + + uart_regs[u].txchar = ch; +} + +void +hal_uart_putc_nowait(hal_uart_name_t u, int ch) +{ + if ((ch == '\n') && (uart_mode[u] == UART_MODE_ONLCR)) //map \n->\r\n if necessary + hal_uart_putc(u, '\r'); + + if(uart_regs[u].txlevel) // If fifo has space + uart_regs[u].txchar = ch; +} + +int +hal_uart_getc(hal_uart_name_t u) +{ + while ((uart_regs[u].rxlevel) == 0) // wait for data to be ready + ; + + return uart_regs[u].rxchar; +} + +int +hal_uart_getc_noblock(hal_uart_name_t u) +{ +// int timeout = 0; +// while (((uart_regs[u].rxlevel) == 0) && (timeout++ < HAL_UART_TIMEOUT_MS)) +// mdelay(1); + if(uart_regs[u].rxlevel == 0) return -1; + return uart_regs[u].rxchar; +} + +int hal_uart_rx_flush(hal_uart_name_t u) +{ + char x = 0; + while(uart_regs[u].rxlevel) x = uart_regs[u].rxchar; + return x; +} + diff --git a/firmware/zpu/lib/hal_uart.h b/firmware/zpu/lib/hal_uart.h new file mode 100644 index 000000000..793aface0 --- /dev/null +++ b/firmware/zpu/lib/hal_uart.h @@ -0,0 +1,92 @@ +/* -*- c -*- */ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_HAL_UART_H +#define INCLUDED_HAL_UART_H + +/*! + * \brief uart mode flags + */ +#define UART_MODE_RAW 0x0000 // no mapping on input or output +#define UART_MODE_ONLCR 0x0001 // map \n to \r\n on output (default) + +#define DEFAULT_UART UART_DEBUG //which UART printf, gets, etc. use + +typedef enum { + US_9600 = 0, + US_19200 = 1, + US_38400 = 2, + US_57600 = 3, + US_115200 = 4, + US_230400 = 5 +} hal_uart_speed_t; + +typedef struct { + hal_uart_speed_t speed; +} hal_uart_config_t; + +typedef enum { + UART_DEBUG = 0, + UART_EXP = 1, + UART_GPS = 2 +} hal_uart_name_t; + +/* + * \brief Set uart mode + */ +void hal_uart_set_mode(hal_uart_name_t uart, int flags); + +/*! + * \brief one-time call to init + */ +void hal_uart_init(void); + +/*! + * \brief Set uart parameters + * Default is 115,200 bps, 8N1. + */ +void hal_uart_set_config(const hal_uart_config_t *c); + +/*! + * \brief Get uart configuation. + */ +void hal_uart_get_config(hal_uart_config_t *c); + +/*! + * \brief Enqueue \p ch for output over serial port + */ +void hal_uart_putc(hal_uart_name_t u, int ch); + +/*! + * \brief Enqueue \p ch for output over serial port, silent fail if queue is full + */ +void hal_uart_putc_nowait(hal_uart_name_t u, int ch); + +/* + * \brief Blocking read of next char from serial port + */ +int hal_uart_getc(hal_uart_name_t u); + +/* + * \brief Non-blocking read of next char from serial port, return -1 if nothing available + */ +int hal_uart_getc_noblock(hal_uart_name_t u); + +int hal_uart_rx_flush(hal_uart_name_t u); + +#endif /* INCLUDED_HAL_UART_H */ diff --git a/firmware/zpu/lib/i2c.c b/firmware/zpu/lib/i2c.c new file mode 100644 index 000000000..d230f462c --- /dev/null +++ b/firmware/zpu/lib/i2c.c @@ -0,0 +1,129 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "i2c.h" +#include "memory_map.h" +#include "stdint.h" +#include <string.h> +#include "nonstdio.h" + +#define MAX_WB_DIV 4 // maximum wishbone divisor (from 100 MHz MASTER_CLK) + +// prescaler divisor values for 100 kHz I2C [uses 5 * SCLK internally] + +#define PRESCALER(wb_div) (((MASTER_CLK_RATE/(wb_div)) / (5 * 400000)) - 1) + +static uint16_t prescaler_values[MAX_WB_DIV+1] = { + 0xffff, // 0: can't happen + PRESCALER(1), // 1: 100 MHz + PRESCALER(2), // 2: 50 MHz + PRESCALER(3), // 3: 33.333 MHz + PRESCALER(4), // 4: 25 MHz +}; + +void +i2c_init(void) +{ + i2c_regs->ctrl = 0; // disable core + + // setup prescaler depending on wishbone divisor + int wb_div = hwconfig_wishbone_divisor(); + if (wb_div > MAX_WB_DIV) + wb_div = MAX_WB_DIV; + + i2c_regs->prescaler_lo = prescaler_values[wb_div] & 0xff; + i2c_regs->prescaler_hi = (prescaler_values[wb_div] >> 8) & 0xff; + + i2c_regs->ctrl = I2C_CTRL_EN; //| I2C_CTRL_IE; // enable core + + //now this is done separately to maintain common code for async and sync + //pic_register_handler(IRQ_I2C, i2c_irq_handler); +} + +static inline void +wait_for_xfer(void) +{ + while (i2c_regs->cmd_status & I2C_ST_TIP) // wait for xfer to complete + ; +} + +static inline bool +wait_chk_ack(void) +{ + wait_for_xfer(); + + if ((i2c_regs->cmd_status & I2C_ST_RXACK) != 0){ // target NAK'd + return false; + } + return true; +} + +bool +i2c_read (unsigned char i2c_addr, unsigned char *buf, unsigned int len) +{ + if (len == 0) // reading zero bytes always works + return true; + + while (i2c_regs->cmd_status & I2C_ST_BUSY) + ; + + i2c_regs->data = (i2c_addr << 1) | 1; // 7 bit address and read bit (1) + // generate START and write addr + i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START; + if (!wait_chk_ack()) + goto fail; + + for (; len > 0; buf++, len--){ + i2c_regs->cmd_status = I2C_CMD_RD | (len == 1 ? (I2C_CMD_NACK | I2C_CMD_STOP) : 0); + wait_for_xfer(); + *buf = i2c_regs->data; + } + return true; + + fail: + i2c_regs->cmd_status = I2C_CMD_STOP; // generate STOP + return false; +} + + +bool +i2c_write(unsigned char i2c_addr, const unsigned char *buf, unsigned int len) +{ + while (i2c_regs->cmd_status & I2C_ST_BUSY) + ; + + i2c_regs->data = (i2c_addr << 1) | 0; // 7 bit address and write bit (0) + + // generate START and write addr (and maybe STOP) + i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START | (len == 0 ? I2C_CMD_STOP : 0); + if (!wait_chk_ack()) + goto fail; + + for (; len > 0; buf++, len--){ + i2c_regs->data = *buf; + i2c_regs->cmd_status = I2C_CMD_WR | (len == 1 ? I2C_CMD_STOP : 0); + if (!wait_chk_ack()) + goto fail; + } + return true; + + fail: + i2c_regs->cmd_status = I2C_CMD_STOP; // generate STOP + return false; +} + diff --git a/firmware/zpu/lib/i2c.h b/firmware/zpu/lib/i2c.h new file mode 100644 index 000000000..1af4d72df --- /dev/null +++ b/firmware/zpu/lib/i2c.h @@ -0,0 +1,39 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_I2C_H +#define INCLUDED_I2C_H + +#include <stdbool.h> +#include "stdint.h" + +void i2c_init(void); +bool i2c_read (unsigned char i2c_addr, unsigned char *buf, unsigned int len); +bool i2c_write(unsigned char i2c_addr, const unsigned char *buf, unsigned int len); + +bool eeprom_write (int i2c_addr, int eeprom_offset, const void *buf, int len); + +// Read 24LC024 / 24LC025 EEPROM on motherboard or daughterboard. +// Which EEPROM is determined by i2c_addr. See i2c_addr.h + +bool eeprom_read (int i2c_addr, int eeprom_offset, void *buf, int len); + +bool find_safe_booted_flag(void); +void set_safe_booted_flag(bool flag); + +#endif /* INCLUDED_I2C_H */ diff --git a/firmware/zpu/lib/i2c_async.c b/firmware/zpu/lib/i2c_async.c new file mode 100644 index 000000000..05c4c3a09 --- /dev/null +++ b/firmware/zpu/lib/i2c_async.c @@ -0,0 +1,206 @@ +// +// Copyright 2010 Ettus Research LLC +// +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + + //i2c_async.c: asynchronous (interrupt-driven) routines for I2C. + //separated out here so we can have a small I2C lib for bootloader and + //retain interrupt-driven I2C for the main app. + +#include "memory_map.h" +#include "stdint.h" +#include <string.h> +#include "pic.h" +#include "nonstdio.h" +#include "i2c_async.h" + + //asynchronous (interrupt-driven) i2c state variables +volatile uint8_t i2c_buf[17]; //tx/rx data transfer buffer +volatile uint8_t *volatile i2c_bufptr = i2c_buf; //ptr to current position +volatile uint8_t i2c_len = 0; //length remaining in current transfer +volatile i2c_state_t i2c_state = I2C_STATE_IDLE; //current I2C transfer state +i2c_dir_t i2c_dir; //I2C transfer direction + +void (*volatile i2c_callback)(void); //function pointer to i2c callback to be called when transaction is complete +static void i2c_irq_handler(unsigned irq); +inline void i2c_async_err(void); + +void i2c_register_handler(void) { + pic_register_handler(IRQ_I2C, i2c_irq_handler); +} + + +static void i2c_irq_handler(unsigned irq) { +//i2c state machine. + + //printf("I2C irq handler\n"); + //first let's make sure nothing is f'ed up + //TODO: uncomment this error checking when we have some way to handle errors +// if(((i2c_regs->cmd_status & I2C_ST_RXACK) != 0) && i2c_dir == I2C_DIR_WRITE) { //we got a NACK and we didn't send it +// printf("\tNACK received\n"); +// i2c_async_err(); +// return; +// }// else printf("\tACK received, proceeding\n"); + + if(i2c_regs->cmd_status & I2C_ST_AL) { + printf("\tArbitration lost!\n"); + i2c_async_err(); + return; + } + + if(i2c_regs->cmd_status & I2C_ST_TIP) { + //printf("\tI2C still busy in interrupt\n"); + return; + } + + //now decide what to do + switch(i2c_state) { + + case I2C_STATE_IDLE: + //this is an error. in idle state, we shouldn't be transferring data, and the fact that the IRQ fired is terrible bad. + printf("AAAAAHHHHH INTERRUPT IN THE IDLE STATE AAAHHHHHHHHH\n"); + i2c_async_err(); + break; + + case I2C_STATE_CONTROL_BYTE_SENT: //here we've sent the control byte, and we're either clocking data in or out now, but we haven't received a byte yet. + case I2C_STATE_DATA: //here we're sending/receiving data and if we're receiving there's data in the data reg + + //if(i2c_state == I2C_STATE_DATA) printf("\tI2C in state DATA with dir=%d and len=%d\n", i2c_dir, i2c_len); + //else printf("\tI2C in state CONTROL_BYTE_SENT with dir=%d and len=%d\n", i2c_dir, i2c_len); + + if(i2c_dir == I2C_DIR_READ) { + if(i2c_state == I2C_STATE_DATA) *(i2c_bufptr++) = i2c_regs->data; + //printf("\tRead %x\n", *(i2c_bufptr-1)); + //set up another data byte + if(i2c_len > 1) //only one more byte to transfer + i2c_regs->cmd_status = I2C_CMD_RD; + else + i2c_regs->cmd_status = I2C_CMD_RD | I2C_CMD_NACK | I2C_CMD_STOP; + } + else if(i2c_dir == I2C_DIR_WRITE) { + //write a byte + //printf("\tWriting %x\n", *i2c_bufptr); + i2c_regs->data = *(i2c_bufptr++); + if(i2c_len > 1) + i2c_regs->cmd_status = I2C_CMD_WR; + else { + //printf("\tGenerating STOP\n"); + i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_STOP; + } + }; + i2c_len--; + if(i2c_len == 0) i2c_state = I2C_STATE_LAST_BYTE; + else i2c_state = I2C_STATE_DATA; //takes care of the addr_sent->data transition + break; + + + case I2C_STATE_LAST_BYTE: //here we've already sent the last read request and the last data is waiting for us. + //printf("\tI2C in state LAST BYTE\n"); + + if(i2c_dir == I2C_DIR_READ) { + *(i2c_bufptr++) = i2c_regs->data; + //printf("\tRead %x\n", *(i2c_bufptr-1)); + i2c_state = I2C_STATE_DATA_READY; + } else { + i2c_state = I2C_STATE_IDLE; + } + i2c_regs->ctrl &= ~I2C_CTRL_IE; //disable interrupts until next time + + if(i2c_callback) { + i2c_callback(); //if we registered a callback, call it! + } + + break; + + + default: //terrible things have happened. + break; + } + +} + +void i2c_register_callback(void (*volatile callback)(void)) { + i2c_callback = callback; +} + +inline void i2c_async_err(void) { + i2c_state = I2C_STATE_IDLE; + i2c_regs->ctrl &= ~I2C_CTRL_IE; + printf("I2C error\n"); +//TODO: set an error flag instead of just dropping things on the floor + i2c_regs->cmd_status = I2C_CMD_STOP; +} + +bool i2c_async_read(uint8_t addr, unsigned int len) { + //printf("Starting async read\n"); + if(i2c_state != I2C_STATE_IDLE) return false; //sorry mario but your i2c is in another castle + if(len == 0) return true; //just idiot-proofing + if(len > sizeof(i2c_buf)) return false; + + //disable I2C interrupts and clear pending interrupts on the I2C device + i2c_regs->ctrl &= ~I2C_CTRL_IE; + i2c_regs->cmd_status |= I2C_CMD_IACK; + + i2c_len = len; + i2c_dir = I2C_DIR_READ; + i2c_bufptr = i2c_buf; + //then set up the transfer by issuing the control byte + i2c_regs->ctrl |= I2C_CTRL_IE; + i2c_regs->data = (addr << 1) | 0x01; //7 bit addr and read bit + i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START; //generate start & start writing addr + //update the state so the irq handler knows what's going on + i2c_state = I2C_STATE_CONTROL_BYTE_SENT; + return true; +} + +bool i2c_async_write(uint8_t addr, const uint8_t *buf, unsigned int len) { + //printf("Starting async write\n"); + if(i2c_state != I2C_STATE_IDLE) return false; //sorry mario but your i2c is in another castle + if(len > sizeof(i2c_buf)) return false; + + //disable I2C interrupts and clear pending interrupts on the I2C device + i2c_regs->ctrl &= ~I2C_CTRL_IE; + i2c_regs->cmd_status |= I2C_CMD_IACK; + + //copy the buffer into our own if writing + memcpy((void *)i2c_buf, buf, len); + + i2c_len = len; + i2c_dir = I2C_DIR_WRITE; + i2c_bufptr = i2c_buf; + //then set up the transfer by issuing the control byte + i2c_regs->ctrl |= I2C_CTRL_IE; + i2c_regs->data = (addr << 1) | 0x00; //7 bit addr and read bit + i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START; //generate start & start writing addr + //update the state so the irq handler knows what's going on + i2c_state = I2C_STATE_CONTROL_BYTE_SENT; + + return true; +} + +//TODO: determine if it's better to read sequentially into the user's buffer, copy on transfer complete, or copy on request (shown below). probably best to copy on request. +bool i2c_async_data_ready(void *buf) { + if(i2c_state == I2C_STATE_DATA_READY) { + i2c_state = I2C_STATE_IDLE; + memcpy(buf, (void *)i2c_buf, (i2c_bufptr - i2c_buf)); //TODO: not really comfortable with this + //printf("Copying %d bytes to user buffer\n", i2c_bufptr-i2c_buf); + return true; + } + return false; +} + diff --git a/firmware/zpu/lib/i2c_async.h b/firmware/zpu/lib/i2c_async.h new file mode 100644 index 000000000..e6095fca6 --- /dev/null +++ b/firmware/zpu/lib/i2c_async.h @@ -0,0 +1,50 @@ +// +// Copyright 2010 Ettus Research LLC +// +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_I2C_ASYNC_H +#define INCLUDED_I2C_ASYNC_H + +#include <stdbool.h> +#include "stdint.h" + +typedef enum { I2C_STATE_IDLE, + I2C_STATE_CONTROL_BYTE_SENT, + I2C_STATE_DATA, + I2C_STATE_LAST_BYTE, + I2C_STATE_DATA_READY, + I2C_STATE_ERROR + } i2c_state_t; + +typedef enum { I2C_DIR_WRITE=0, I2C_DIR_READ=1 } i2c_dir_t; + +bool i2c_async_read(uint8_t addr, unsigned int len); +bool i2c_async_write(uint8_t addr, const uint8_t *buf, unsigned int len); +bool i2c_async_data_ready(void *); +//static void i2c_irq_handler(unsigned irq); +void i2c_register_callback(void (*callback)(void)); +void i2c_register_handler(void); + +// Write 24LC024 / 24LC025 EEPROM on motherboard or daughterboard. +// Which EEPROM is determined by i2c_addr. See i2c_addr.h + +bool eeprom_write_async (int i2c_addr, int eeprom_offset, const void *buf, int len, void (*callback)(void)); +bool eeprom_read_async(int i2c_addr, int eeprom_offset, void *buf, int len, void (*callback)(void)); + +#endif /* INCLUDED_I2C_ASYNC_H */ diff --git a/firmware/zpu/lib/if_arp.h b/firmware/zpu/lib/if_arp.h new file mode 100644 index 000000000..63519c4be --- /dev/null +++ b/firmware/zpu/lib/if_arp.h @@ -0,0 +1,153 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Global definitions for the ARP (RFC 826) protocol. + * + * Version: @(#)if_arp.h 1.0.1 04/16/93 + * + * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988 + * Portions taken from the KA9Q/NOS (v2.00m PA0GRI) source. + * Ross Biro + * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> + * Florian La Roche, + * Jonathan Layes <layes@loran.com> + * Arnaldo Carvalho de Melo <acme@conectiva.com.br> ARPHRD_HWX25 + * + * 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 + * 2 of the License, or (at your option) any later version. + */ +#ifndef _LINUX_IF_ARP_H +#define _LINUX_IF_ARP_H + +/* ARP protocol HARDWARE identifiers. */ +#define ARPHRD_NETROM 0 /* from KA9Q: NET/ROM pseudo */ +#define ARPHRD_ETHER 1 /* Ethernet 10Mbps */ +#define ARPHRD_EETHER 2 /* Experimental Ethernet */ +#define ARPHRD_AX25 3 /* AX.25 Level 2 */ +#define ARPHRD_PRONET 4 /* PROnet token ring */ +#define ARPHRD_CHAOS 5 /* Chaosnet */ +#define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet/TR/TB */ +#define ARPHRD_ARCNET 7 /* ARCnet */ +#define ARPHRD_APPLETLK 8 /* APPLEtalk */ +#define ARPHRD_DLCI 15 /* Frame Relay DLCI */ +#define ARPHRD_ATM 19 /* ATM */ +#define ARPHRD_METRICOM 23 /* Metricom STRIP (new IANA id) */ +#define ARPHRD_IEEE1394 24 /* IEEE 1394 IPv4 - RFC 2734 */ +#define ARPHRD_EUI64 27 /* EUI-64 */ +#define ARPHRD_INFINIBAND 32 /* InfiniBand */ + +/* Dummy types for non ARP hardware */ +#define ARPHRD_SLIP 256 +#define ARPHRD_CSLIP 257 +#define ARPHRD_SLIP6 258 +#define ARPHRD_CSLIP6 259 +#define ARPHRD_RSRVD 260 /* Notional KISS type */ +#define ARPHRD_ADAPT 264 +#define ARPHRD_ROSE 270 +#define ARPHRD_X25 271 /* CCITT X.25 */ +#define ARPHRD_HWX25 272 /* Boards with X.25 in firmware */ +#define ARPHRD_CAN 280 /* Controller Area Network */ +#define ARPHRD_PPP 512 +#define ARPHRD_CISCO 513 /* Cisco HDLC */ +#define ARPHRD_HDLC ARPHRD_CISCO +#define ARPHRD_LAPB 516 /* LAPB */ +#define ARPHRD_DDCMP 517 /* Digital's DDCMP protocol */ +#define ARPHRD_RAWHDLC 518 /* Raw HDLC */ + +#define ARPHRD_TUNNEL 768 /* IPIP tunnel */ +#define ARPHRD_TUNNEL6 769 /* IP6IP6 tunnel */ +#define ARPHRD_FRAD 770 /* Frame Relay Access Device */ +#define ARPHRD_SKIP 771 /* SKIP vif */ +#define ARPHRD_LOOPBACK 772 /* Loopback device */ +#define ARPHRD_LOCALTLK 773 /* Localtalk device */ +#define ARPHRD_FDDI 774 /* Fiber Distributed Data Interface */ +#define ARPHRD_BIF 775 /* AP1000 BIF */ +#define ARPHRD_SIT 776 /* sit0 device - IPv6-in-IPv4 */ +#define ARPHRD_IPDDP 777 /* IP over DDP tunneller */ +#define ARPHRD_IPGRE 778 /* GRE over IP */ +#define ARPHRD_PIMREG 779 /* PIMSM register interface */ +#define ARPHRD_HIPPI 780 /* High Performance Parallel Interface */ +#define ARPHRD_ASH 781 /* Nexus 64Mbps Ash */ +#define ARPHRD_ECONET 782 /* Acorn Econet */ +#define ARPHRD_IRDA 783 /* Linux-IrDA */ +/* ARP works differently on different FC media .. so */ +#define ARPHRD_FCPP 784 /* Point to point fibrechannel */ +#define ARPHRD_FCAL 785 /* Fibrechannel arbitrated loop */ +#define ARPHRD_FCPL 786 /* Fibrechannel public loop */ +#define ARPHRD_FCFABRIC 787 /* Fibrechannel fabric */ + /* 787->799 reserved for fibrechannel media types */ +#define ARPHRD_IEEE802_TR 800 /* Magic type ident for TR */ +#define ARPHRD_IEEE80211 801 /* IEEE 802.11 */ +#define ARPHRD_IEEE80211_PRISM 802 /* IEEE 802.11 + Prism2 header */ +#define ARPHRD_IEEE80211_RADIOTAP 803 /* IEEE 802.11 + radiotap header */ + +#define ARPHRD_VOID 0xFFFF /* Void type, nothing is known */ +#define ARPHRD_NONE 0xFFFE /* zero header length */ + +/* ARP protocol opcodes. */ +#define ARPOP_REQUEST 1 /* ARP request */ +#define ARPOP_REPLY 2 /* ARP reply */ +#define ARPOP_RREQUEST 3 /* RARP request */ +#define ARPOP_RREPLY 4 /* RARP reply */ +#define ARPOP_InREQUEST 8 /* InARP request */ +#define ARPOP_InREPLY 9 /* InARP reply */ +#define ARPOP_NAK 10 /* (ATM)ARP NAK */ + + +/* ARP Flag values. */ +#define ATF_COM 0x02 /* completed entry (ha valid) */ +#define ATF_PERM 0x04 /* permanent entry */ +#define ATF_PUBL 0x08 /* publish entry */ +#define ATF_USETRAILERS 0x10 /* has requested trailers */ +#define ATF_NETMASK 0x20 /* want to use a netmask (only + for proxy entries) */ +#define ATF_DONTPUB 0x40 /* don't answer this addresses */ + +typedef unsigned short __be16; + +/* + * This structure defines an ethernet arp header. + */ +struct arphdr +{ + __be16 ar_hrd; /* format of hardware address */ + __be16 ar_pro; /* format of protocol address */ + unsigned char ar_hln; /* length of hardware address */ + unsigned char ar_pln; /* length of protocol address */ + __be16 ar_op; /* ARP opcode (command) */ + +#if 0 + /* + * Ethernet looks like this : This bit is variable sized however... + */ + unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ + unsigned char ar_sip[4]; /* sender IP address */ + unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ + unsigned char ar_tip[4]; /* target IP address */ +#endif + +}; + +/* + * This structure defines an ethernet arp header. + */ +struct arp_eth_ipv4 +{ + __be16 ar_hrd; /* format of hardware address */ + __be16 ar_pro; /* format of protocol address */ + unsigned char ar_hln; /* length of hardware address */ + unsigned char ar_pln; /* length of protocol address */ + __be16 ar_op; /* ARP opcode (command) */ + + unsigned char ar_sha[6]; /* sender hardware address */ + unsigned char ar_sip[4]; /* sender IP address */ + unsigned char ar_tha[6]; /* target hardware address */ + unsigned char ar_tip[4]; /* target IP address */ +}; + + +#endif /* _LINUX_IF_ARP_H */ diff --git a/firmware/zpu/lib/ihex.c b/firmware/zpu/lib/ihex.c new file mode 100644 index 000000000..97ecf73b6 --- /dev/null +++ b/firmware/zpu/lib/ihex.c @@ -0,0 +1,57 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + */ + +#include "ihex.h" +#include <ctype.h> //man that pulls in a lot of shit + +//this is not safe and you should run isxdigit beforehand +uint8_t asc2nibble(char input) { + if(input > 'Z') return input - 'W'; + else if(input > '9') return input - '7'; + else return input - '0'; +} + +int ihex_parse(char input[], ihex_record_t *record) { + //given a NULL-TERMINATED input string (use gets()) in I16HEX format, write the binary record in record. return 0 on success. + + uint8_t inputlen; + uint8_t t, i, checksum_calc=0, checksum_read; + + //first check for ":" leading character + if(input[0] != ':') return -1; + + //then check the string for only valid ASCII ['0'-'F'] + inputlen=1; + while(input[inputlen]) { + if( !isxdigit(input[inputlen++]) ) return -2; + } + + //then read the length. + record->length = (asc2nibble(input[1]) << 4) + asc2nibble(input[2]); + if(input[(record->length<<1) + 11] != 0) return -3; //if we're missing a null terminator in the right place + + //then read the address. + record->addr = (asc2nibble(input[3]) << 12) + (asc2nibble(input[4]) << 8) + (asc2nibble(input[5]) << 4) + asc2nibble(input[6]); + + //then read the record type. + record->type = (asc2nibble(input[7]) << 4) + asc2nibble(input[8]); +// if(record->type > 4) return -4; + + //then read the data, which goes from input[9] to input[9+length*2]. + for(i=0; i < record->length; i++) { + t = 9 + (i<<1); + record->data[i] = (asc2nibble(input[t]) << 4) + (asc2nibble(input[t + 1])); + checksum_calc += record->data[i]; //might as well keep a running checksum as we read + } + checksum_calc += record->length + record->type + (record->addr >> 8) + (record->addr & 0xFF); //get the rest of the data into that checksum + checksum_calc = ~checksum_calc + 1; //checksum is 2's complement + + //now read the checksum of the record + checksum_read = (asc2nibble(input[9 + (record->length<<1)]) << 4) + asc2nibble(input[10 + (record->length<<1)]); + if(checksum_calc != checksum_read) return -5; //compare 'em + + return 0; +} diff --git a/firmware/zpu/lib/ihex.h b/firmware/zpu/lib/ihex.h new file mode 100644 index 000000000..9f471fbe2 --- /dev/null +++ b/firmware/zpu/lib/ihex.h @@ -0,0 +1,18 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + */ + +#include <stdint.h> +#include <stddef.h> + +typedef struct { + uint8_t type; + size_t length; + uint32_t addr; + uint8_t *data; +} ihex_record_t; + + +int ihex_parse(char input[], ihex_record_t *record); diff --git a/firmware/zpu/lib/mdelay.c b/firmware/zpu/lib/mdelay.c new file mode 100644 index 000000000..8f9b14112 --- /dev/null +++ b/firmware/zpu/lib/mdelay.c @@ -0,0 +1,31 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "mdelay.h" +#include "memory_map.h" + +void mdelay(int ms){ + if (hwconfig_simulation_p()) return; + for(int i = 0; i < ms; i++){ + static const uint32_t num_ticks = MASTER_CLK_RATE/1000; + const uint32_t ticks_begin = router_status->time64_ticks_rb; + while((router_status->time64_ticks_rb - ticks_begin) < num_ticks){ + /*NOP*/ + } + } +} diff --git a/firmware/zpu/lib/mdelay.h b/firmware/zpu/lib/mdelay.h new file mode 100644 index 000000000..226bbb3f7 --- /dev/null +++ b/firmware/zpu/lib/mdelay.h @@ -0,0 +1,29 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_MDELAY_H +#define INCLUDED_MDELAY_H + +/*! + * \brief Delay about ms milliseconds + * + * If simulating, _very_ short delay + */ +void mdelay(int ms); + +#endif /* INCLUDED_MDELAY_H */ diff --git a/firmware/zpu/lib/memcpy_wa.c b/firmware/zpu/lib/memcpy_wa.c new file mode 100644 index 000000000..ef20efaa9 --- /dev/null +++ b/firmware/zpu/lib/memcpy_wa.c @@ -0,0 +1,42 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "memcpy_wa.h" +#include <stdint.h> +#include <stdlib.h> + +/* + * For copying to/from non-byte-adressable memory, such as + * the buffers. dst, src, and nbytes must all satisfy (x % 4 == 0) + */ +void +memcpy_wa(void *dst, const void *src, size_t nbytes) +{ + if (((intptr_t) dst & 0x3) + || ((intptr_t) src & 0x3) + || (nbytes & 0x3)) + exit(1); /* die! */ + + int *dp = (int *) dst; + int *sp = (int *) src; + unsigned nw = nbytes/4; + + unsigned i; + for (i = 0; i < nw; i++) + dp[i] = sp[i]; +} diff --git a/firmware/zpu/lib/memcpy_wa.h b/firmware/zpu/lib/memcpy_wa.h new file mode 100644 index 000000000..072fc148f --- /dev/null +++ b/firmware/zpu/lib/memcpy_wa.h @@ -0,0 +1,32 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_MEMCPY_WA_H +#define INCLUDED_MEMCPY_WA_H + +#include <stddef.h> + +/* + * For copying to/from non-byte-adressable memory, such as + * the buffers. dst, src, and nbytes must all satisfy (x % 4 == 0) + */ +void memcpy_wa(void *dst, const void *src, size_t nbytes); + +#endif /* INCLUDED_MEMCPY_WA_H */ + + diff --git a/firmware/zpu/lib/memory_map.h b/firmware/zpu/lib/memory_map.h new file mode 100644 index 000000000..4290ee20a --- /dev/null +++ b/firmware/zpu/lib/memory_map.h @@ -0,0 +1,458 @@ +// Copyright 2010-2012 Ettus Research LLC +/* + * Copyright 2007,2008,2009 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_MEMORY_MAP_H +#define INCLUDED_MEMORY_MAP_H + +#include <stdint.h> + +#define MASTER_CLK_RATE 100000000 // 100 MHz + +//////////////////////////////////////////////////////////////////////// +// Define slave bases +//////////////////////////////////////////////////////////////////////// +#define ROUTER_RAM_BASE 0x4000 +#define SPI_BASE 0x5000 +#define I2C_BASE 0x5400 +#define GPIO_BASE 0x5800 +#define READBACK_BASE 0x5C00 +#define ETH_BASE 0x6000 +#define SETTING_REGS_BASE 0x7000 +#define PIC_BASE 0x8000 +#define UART_BASE 0x8800 +#define ATR_BASE 0x8C00 +#ifdef USRP2 +#define SDSPI_BASE 0xB000 +#endif +#ifdef USRP2P +#define ICAP_BASE 0xA000 +#define SPIF_BASE 0xB000 +#define RAM_BASE 0xC000 +#endif + +///////////////////////////////////////////////////// +// SPI Core, Slave 2. See core docs for more info +///////////////////////////////////////////////////// + +// Masks for controlling different peripherals +#define SPI_SS_AD9510 1 +#define SPI_SS_AD9777 2 +#define SPI_SS_RX_DAC 4 +#define SPI_SS_RX_ADC 8 +#define SPI_SS_RX_DB 16 +#define SPI_SS_TX_DAC 32 +#define SPI_SS_TX_ADC 64 +#define SPI_SS_TX_DB 128 +#define SPI_SS_ADS62P44 256 + +// Masks for different parts of CTRL reg +#define SPI_CTRL_ASS (1<<13) +#define SPI_CTRL_IE (1<<12) +#define SPI_CTRL_LSB (1<<11) +#define SPI_CTRL_TXNEG (1<<10) +#define SPI_CTRL_RXNEG (1<< 9) +#define SPI_CTRL_GO_BSY (1<< 8) +#define SPI_CTRL_CHAR_LEN_MASK 0x7F + +//////////////////////////////////////////////// +// I2C, Slave 3 +//////////////////////////////////////////////// + +typedef struct { + volatile uint32_t prescaler_lo; // r/w + volatile uint32_t prescaler_hi; // r/w + volatile uint32_t ctrl; // r/w + volatile uint32_t data; // wr = transmit reg; rd = receive reg + volatile uint32_t cmd_status; // wr = command reg; rd = status reg +} i2c_regs_t; + +#define i2c_regs ((i2c_regs_t *) I2C_BASE) + +#define I2C_CTRL_EN (1 << 7) // core enable +#define I2C_CTRL_IE (1 << 6) // interrupt enable + +// +// STA, STO, RD, WR, and IACK bits are cleared automatically +// +#define I2C_CMD_START (1 << 7) // generate (repeated) start condition +#define I2C_CMD_STOP (1 << 6) // generate stop condition +#define I2C_CMD_RD (1 << 5) // read from slave +#define I2C_CMD_WR (1 << 4) // write to slave +#define I2C_CMD_NACK (1 << 3) // when a rcvr, send ACK (ACK=0) or NACK (ACK=1) +#define I2C_CMD_RSVD_2 (1 << 2) // reserved +#define I2C_CMD_RSVD_1 (1 << 1) // reserved +#define I2C_CMD_IACK (1 << 0) // set to clear pending interrupt + +#define I2C_ST_RXACK (1 << 7) // Received acknowledgement from slave (1 = NAK, 0 = ACK) +#define I2C_ST_BUSY (1 << 6) // 1 after START signal detected; 0 after STOP signal detected +#define I2C_ST_AL (1 << 5) // Arbitration lost. 1 when core lost arbitration +#define I2C_ST_RSVD_4 (1 << 4) // reserved +#define I2C_ST_RSVD_3 (1 << 3) // reserved +#define I2C_ST_RSVD_2 (1 << 2) // reserved +#define I2C_ST_TIP (1 << 1) // Transfer-in-progress +#define I2C_ST_IP (1 << 0) // Interrupt pending + +/////////////////////////////////////////////////// +// Packet Router Status, Slave 5 +/////////////////////////////////////////////////// + +typedef struct { + volatile uint32_t spi; + volatile uint32_t _padding[7]; + volatile uint32_t status; + volatile uint32_t _unused; + volatile uint32_t time64_secs_rb; + volatile uint32_t time64_ticks_rb; + volatile uint32_t compat_num; + volatile uint32_t irqs; +} router_status_t; + +#define SPI_READY_IRQ (1 << 12) + +#define router_status ((router_status_t *) READBACK_BASE) +#define readback_mux ((router_status_t *) READBACK_BASE) //alias with a better name + +/*! + * \brief return non-zero if we're running under the simulator + */ +inline static int +hwconfig_simulation_p(void) +{ + return 0; +} + +/*! + * \brief Return Wishbone Clock divisor. + * The processor runs at the Wishbone Clock rate which is MASTER_CLK_RATE / divisor. + */ +inline static int +hwconfig_wishbone_divisor(void) +{ + return 2; +} + +/////////////////////////////////////////////////// +// Ethernet Core, Slave 6 +/////////////////////////////////////////////////// + +typedef struct { + volatile int settings; + volatile int ucast_hi; + volatile int ucast_lo; + volatile int mcast_hi; + volatile int mcast_lo; + volatile int miimoder; + volatile int miiaddress; + volatile int miitx_data; + volatile int miicommand; + volatile int miistatus; + volatile int miirx_data; + volatile int pause_time; + volatile int pause_thresh; +} eth_mac_regs_t; + +// settings register +#define MAC_SET_PAUSE_EN (1 << 0) // Makes us respect received pause frames (normally on) +#define MAC_SET_PASS_ALL (1 << 1) // Enables promiscuous mode, currently broken +#define MAC_SET_PASS_PAUSE (1 << 2) // Sends pause frames through (normally off) +#define MAC_SET_PASS_BCAST (1 << 3) // Sends broadcast frames through (normally on) +#define MAC_SET_PASS_MCAST (1 << 4) // Sends multicast frames that match mcast addr (normally off) +#define MAC_SET_PASS_UCAST (1 << 5) // Sends unicast (normal) frames through if they hit in address filter (normally on) +#define MAC_SET_PAUSE_SEND_EN (1 << 6) // Enables sending pause frames + +// miicommand register +#define MIIC_SCANSSTAT (1 << 0) // Scan status +#define MIIC_RSTAT (1 << 1) // Read status +#define MIIC_WCTRLDATA (1 << 2) // Write control data + +// miistatus register +#define MIIS_LINKFAIL (1 << 0) // The link failed +#define MIIS_BUSY (1 << 1) // The MII is busy (operation in progress) +#define MIIS_NVALID (1 << 2) // The data in the status register is invalid + // This it is only valid when the scan status is active. + +#define eth_mac ((eth_mac_regs_t *) ETH_BASE) + +//////////////////////////////////////////////////// +// Settings Bus, Slave #7, Not Byte Addressable! +// +// Output-only from processor point-of-view. +// 1KB of address space (== 256 32-bit write-only regs) +//////////////////////////////////////////////////// + +#define SR_MISC 0 // 7 regs +#define SR_SIMTIMER 8 // 2 +#define SR_TIME64 10 // 6 +#define SR_BUF_POOL 16 // 4 +#define SR_SPI_CORE 20 // 3 +#define SR_RX_FRONT 24 // 5 +#define SR_RX_CTRL0 32 // 9 +#define SR_RX_DSP0 48 // 7 +#define SR_RX_CTRL1 80 // 9 +#define SR_RX_DSP1 96 // 7 + +#define SR_TX_FRONT 128 // ? +#define SR_TX_CTRL 144 // 6 +#define SR_TX_DSP 160 // 5 + +#define SR_UDP_SM 192 // 64 + +#define _SR_ADDR(sr) (SETTING_REGS_BASE + (sr) * sizeof(uint32_t)) + +#define SR_ADDR_BLDRDONE _SR_ADDR(5) + +// --- spi core control regs --- + +typedef struct { + volatile uint32_t divider; + volatile uint32_t control; + volatile uint32_t data; +} spi_core_t; + +#define SPI_CORE_SLAVE_SELECT_SHIFT 0 +#define SPI_CORE_NUM_BITS_SHIFT 24 +#define SPI_CORE_DATA_IN_EDGE_SHIFT 30 +#define SPI_CORE_DATA_OUT_EDGE_SHIFT 31 + +#define spi_core ((spi_core_t *) _SR_ADDR(SR_SPI_CORE)) + +// --- packet router control regs --- + +typedef struct { + volatile uint32_t mode_ctrl; + volatile uint32_t ip_addr; + volatile uint32_t data_ports; //dsp0 (low 16) dsp1 (high 16) + volatile uint32_t iface_ctrl; +} router_ctrl_t; + +#define router_ctrl ((router_ctrl_t *) _SR_ADDR(SR_BUF_POOL)) + +// --- misc outputs --- + +typedef struct { + volatile uint32_t clk_ctrl; + volatile uint32_t serdes_ctrl; + volatile uint32_t adc_ctrl; + volatile uint32_t leds; + volatile uint32_t phy_ctrl; // LSB is reset line to eth phy + volatile uint32_t debug_mux_ctrl; + volatile uint32_t led_src; // HW or SW control for LEDs + volatile uint32_t flush_icache; // Flush the icache +} output_regs_t; + +#define CLK_RESET (1<<4) +#define CLK_ENABLE (1<<3) | (1<<2) +#define CLK_SEL (1<<1) | (1<<0) + +#define SERDES_ENABLE 8 +#define SERDES_PRBSEN 4 +#define SERDES_LOOPEN 2 +#define SERDES_RXEN 1 + +#define ADC_CTRL_ON 0x0F +#define ADC_CTRL_OFF 0x00 + +// crazy order that matches the labels on the case + +#define LED_A (1 << 4) +#define LED_B (1 << 1) +#define LED_E (1 << 2) +#define LED_D (1 << 0) +#define LED_C (1 << 3) +// LED_F // controlled by CPLD +#define LED_RJ45 (1 << 5) + +#define output_regs ((output_regs_t *) SETTING_REGS_BASE) + +// --- protocol framer regs --- + +typedef struct{ + struct{ + volatile uint32_t entry[16]; + } table[4]; +} sr_proto_framer_t; + +#define sr_proto_framer_regs ((sr_proto_framer_t *) _SR_ADDR(SR_UDP_SM)) + +// --- VITA TX CTRL regs --- + +typedef struct { + volatile uint32_t _pad[4]; + volatile uint32_t cyc_per_up; +} sr_tx_ctrl_t; + +#define sr_tx_ctrl ((sr_tx_ctrl_t *) _SR_ADDR(SR_TX_CTRL)) + +// --- VITA RX CTRL regs --- +typedef struct { + volatile uint32_t _pad[3]; + volatile uint32_t clear; +} sr_rx_ctrl_t; + +#define sr_rx_ctrl0 ((sr_rx_ctrl_t *) _SR_ADDR(SR_RX_CTRL0)) +#define sr_rx_ctrl1 ((sr_rx_ctrl_t *) _SR_ADDR(SR_RX_CTRL1)) + +// ---------------------------------------------------------------- +// VITA49 64 bit time (write only) + /*! + * \brief Time 64 flags + * + * <pre> + * + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-----------------------------------------------------------+-+-+ + * | |S|P| + * +-----------------------------------------------------------+-+-+ + * + * P - PPS edge selection (0=negedge, 1=posedge, default=0) + * S - Source (0=sma, 1=mimo, 0=default) + * + * </pre> + */ +typedef struct { + volatile uint32_t secs; // value to set absolute secs to on next PPS + volatile uint32_t ticks; // value to set absolute ticks to on next PPS + volatile uint32_t flags; // flags - see chart above + volatile uint32_t imm; // set immediate (0=latch on next pps, 1=latch immediate, default=0) +} sr_time64_t; + +#define sr_time64 ((sr_time64_t *) _SR_ADDR(SR_TIME64)) + +/////////////////////////////////////////////////////// +// Simple Programmable Interrupt Controller, Slave 8 +/////////////////////////////////////////////////////// + +// Interrupt request lines +// Bit numbers (LSB == 0) that correpond to interrupts into PIC + +#define IRQ_BUFFER 0 // buffer manager +#define IRQ_ONETIME 1 +#define IRQ_SPI 2 +#define IRQ_I2C 3 +#define IRQ_PHY 4 // ethernet PHY +#define IRQ_UNDERRUN 5 +#define IRQ_OVERRUN 6 +#define IRQ_PPS 7 // pulse per second +#define IRQ_UART_RX 8 +#define IRQ_UART_TX 9 +#define IRQ_SERDES 10 +#define IRQ_CLKSTATUS 11 +#define IRQ_PERIODIC 12 +#define IRQ_BUTTON 13 + +#define IRQ_TO_MASK(x) (1 << (x)) + +#define PIC_BUFFER_INT IRQ_TO_MASK(IRQ_BUFFER) +#define PIC_ONETIME_INT IRQ_TO_MASK(IRQ_ONETIME) +#define PIC_SPI_INT IRQ_TO_MASK(IRQ_SPI) +#define PIC_I2C_INT IRQ_TO_MASK(IRQ_I2C) +#define PIC_PHY_INT IRQ_TO_MASK(IRQ_PHY) +#define PIC_UNDERRUN_INT IRQ_TO_MASK(IRQ_UNDERRUN) +#define PIC_OVERRUN_INT IRQ_TO_MASK(IRQ_OVERRUN) +#define PIC_PPS_INT IRQ_TO_MASK(IRQ_PPS) +#define PIC_UART_RX_INT IRQ_TO_MASK(IRQ_UART_RX) +#define PIC_UART_TX_INT IRQ_TO_MASK(IRQ_UART_TX) +#define PIC_SERDES IRQ_TO_MASK(IRQ_SERDES) +#define PIC_CLKSTATUS IRQ_TO_MASK(IRQ_CLKSTATUS) +#define PIC_BUTTON IRQ_TO_MASK(IRQ_BUTTON) + +typedef struct { + volatile uint32_t edge_enable; // mask: 1 -> edge triggered, 0 -> level + volatile uint32_t polarity; // mask: 1 -> rising edge + volatile uint32_t mask; // mask: 1 -> disabled + volatile uint32_t pending; // mask: 1 -> pending; write 1's to clear pending ints +} pic_regs_t; + +#define pic_regs ((pic_regs_t *) PIC_BASE) + +// ---------------------------------------------------------------- +// WB_CLK_RATE is the time base for this +typedef struct { + volatile uint32_t onetime; // Number of wb clk cycles till the onetime interrupt + volatile uint32_t periodic; // Repeat rate of periodic interrupt +} sr_simple_timer_t; + +#define sr_simple_timer ((sr_simple_timer_t *) _SR_ADDR(SR_SIMTIMER)) + +/////////////////////////////////////////////////// +// UART, Slave 10 +/////////////////////////////////////////////////// + +typedef struct { + // All elements are 8 bits except for clkdiv (16), but we use uint32 to make + // the hardware for decoding easier + volatile uint32_t clkdiv; // Set to 50e6 divided by baud rate (no x16 factor) + volatile uint32_t txlevel; // Number of spaces in the FIFO for writes + volatile uint32_t rxlevel; // Number of available elements in the FIFO for reads + volatile uint32_t txchar; // Write characters to be sent here + volatile uint32_t rxchar; // Read received characters here + volatile uint32_t padding[3]; //what is this i don't even +} uart_regs_t; + +#define uart_regs ((uart_regs_t *) UART_BASE) + +/////////////////////////////////////////////////// +// SD Card SPI interface, Slave 13 +// All regs are 8 bits wide, but are accessed as if they are 32 bits +/////////////////////////////////////////////////// +#ifdef USRP2 + +typedef struct { + volatile uint32_t status; // Write a 1 or 0 for controlling CS + volatile uint32_t clkdiv; + volatile uint32_t send_dat; + volatile uint32_t receive_dat; +} sdspi_regs_t; + +#define sdspi_regs ((sdspi_regs_t *) SDSPI_BASE) + +#endif //USRP2 + +/////////////////////////////////////////////////// +// ICAP, Slave 13 +/////////////////////////////////////////////////// +#ifdef USRP2P + +typedef struct { + uint32_t icap; //only the lower 8 bits matter +} icap_regs_t; + +#define icap_regs ((icap_regs_t *) ICAP_BASE) + +/////////////////////////////////////////////////// +// SPI Flash interface, Slave 14 +// Control register definitions are the same as SPI, so use SPI_CTRL_ASS, etc. +// Peripheral mask not needed since bus is dedicated (CE held low) +/////////////////////////////////////////////////// + +typedef struct { + volatile uint32_t txrx0; + volatile uint32_t txrx1; + volatile uint32_t txrx2; + volatile uint32_t txrx3; + volatile uint32_t ctrl; + volatile uint32_t div; + volatile uint32_t ss; +} spif_regs_t; + +#define spif_regs ((spif_regs_t *) SPIF_BASE) + +#endif //USRP2P + +#endif /* INCLUDED_MEMORY_MAP_H */ diff --git a/firmware/zpu/lib/memset_wa.c b/firmware/zpu/lib/memset_wa.c new file mode 100644 index 000000000..da5da21ab --- /dev/null +++ b/firmware/zpu/lib/memset_wa.c @@ -0,0 +1,45 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "memset_wa.h" +#include <stdint.h> +#include <stdlib.h> + +/* + * For setting non-byte-adressable memory, such as + * the buffers. dst and nbytes must all satisfy (x % 4 == 0) + */ +void * +memset_wa(void *dst, int c, size_t nbytes) +{ + if (((intptr_t) dst & 0x3) + || (nbytes & 0x3)) + exit(1); /* die! */ + + int *dp = (int *) dst; + + c &= 0xff; + int v = (c << 24) | (c << 16) | (c << 8) | c; + unsigned nw = nbytes/4; + + unsigned i; + for (i = 0; i < nw; i++) + dp[i] = v; + + return dst; +} diff --git a/firmware/zpu/lib/memset_wa.h b/firmware/zpu/lib/memset_wa.h new file mode 100644 index 000000000..46d903d53 --- /dev/null +++ b/firmware/zpu/lib/memset_wa.h @@ -0,0 +1,27 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_MEMSET_WA_H +#define INCLUDED_MEMSET_WA_H + +#include <stdlib.h> + +void *memset_wa(void *s, int c, size_t n); + + +#endif /* INCLUDED_MEMSET_WA_H */ diff --git a/firmware/zpu/lib/net/eth_mac_addr.h b/firmware/zpu/lib/net/eth_mac_addr.h new file mode 100644 index 000000000..01bf91988 --- /dev/null +++ b/firmware/zpu/lib/net/eth_mac_addr.h @@ -0,0 +1,29 @@ +/* + * Copyright 2009-2011 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_ETH_MAC_ADDR_H +#define INCLUDED_ETH_MAC_ADDR_H + +#include <stdint.h> + +// Ethernet MAC address + +typedef struct { + uint8_t addr[6]; +} eth_mac_addr_t; + +#endif /* INCLUDED_ETH_MAC_ADDR_H */ diff --git a/firmware/zpu/lib/net/padded_eth_hdr.h b/firmware/zpu/lib/net/padded_eth_hdr.h new file mode 100644 index 000000000..df816734f --- /dev/null +++ b/firmware/zpu/lib/net/padded_eth_hdr.h @@ -0,0 +1,37 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009,2010 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 <http://www.gnu.org/licenses/>. + */ +#ifndef INCLUDED_PADDED_ETH_HDR_H +#define INCLUDED_PADDED_ETH_HDR_H + +#include <compiler.h> +#include <net/eth_mac_addr.h> + +/*! + * \brief Standard 14-byte ethernet header plus two leading bytes of padding. + * + * This is what a buffer contains in line 1 when using the "slow mode" + */ +typedef struct { + uint16_t pad; + eth_mac_addr_t dst; + eth_mac_addr_t src; + uint16_t ethertype; +} _AL4 padded_eth_hdr_t; + + +#endif /* INCLUDED_PADDED_ETH_HDR_H */ diff --git a/firmware/zpu/lib/net/socket_address.h b/firmware/zpu/lib/net/socket_address.h new file mode 100644 index 000000000..336f30a0c --- /dev/null +++ b/firmware/zpu/lib/net/socket_address.h @@ -0,0 +1,41 @@ +/* -*- c -*- */ +/* + * Copyright 2010 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 <http://www.gnu.org/licenses/>. + */ +#ifndef INCLUDED_SOCKET_ADDRESS_H +#define INCLUDED_SOCKET_ADDRESS_H + +#include <lwip/ip_addr.h> + +// port and address are in network byte order + +typedef struct socket_address { + unsigned short port; + struct ip_addr addr; +} socket_address_t; + +static inline struct socket_address +make_socket_address(struct ip_addr addr, int port) +{ + struct socket_address r; + r.port = port; + r.addr = addr; + return r; +} + + + +#endif /* INCLUDED_SOCKET_ADDRESS_H */ diff --git a/firmware/zpu/lib/net_common.c b/firmware/zpu/lib/net_common.c new file mode 100644 index 000000000..9b75006d3 --- /dev/null +++ b/firmware/zpu/lib/net_common.c @@ -0,0 +1,503 @@ +/* + * Copyright 2009-2012 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 <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include "net_common.h" +#include "banal.h" +#include <hal_io.h> +#include <memory_map.h> +#include <memcpy_wa.h> +#include <ethernet.h> +#include <net/padded_eth_hdr.h> +#include <lwip/ip.h> +#include <lwip/udp.h> +#include <lwip/icmp.h> +#include <stdlib.h> +#include <nonstdio.h> +#include "arp_cache.h" +#include "if_arp.h" +#include <ethertype.h> +#include <string.h> +#include "pkt_ctrl.h" + +/*********************************************************************** + * Constants + Globals + **********************************************************************/ +static const bool debug = false; +static const size_t out_buff_size = 2048; +static const eth_mac_addr_t BCAST_MAC_ADDR = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; +#define MAX_UDP_LISTENERS 10 + +/*********************************************************************** + * 16-bit one's complement sum + **********************************************************************/ +static uint32_t chksum_buffer( + uint16_t *buf, size_t nshorts, + uint32_t initial_chksum +){ + uint32_t chksum = initial_chksum; + for (size_t i = 0; i < nshorts; i++) chksum += buf[i]; + + while (chksum >> 16) chksum = (chksum & 0xffff) + (chksum >> 16); + + return chksum; +} + +/*********************************************************************** + * Listener registry + **********************************************************************/ +static eth_mac_addr_t _local_mac_addr; +static struct ip_addr _local_ip_addr; +void register_addrs(const eth_mac_addr_t *mac_addr, const struct ip_addr *ip_addr){ + _local_mac_addr = *mac_addr; + _local_ip_addr = *ip_addr; +} + +struct listener_entry { + unsigned short port; + udp_receiver_t rcvr; +}; + +static struct listener_entry listeners[MAX_UDP_LISTENERS]; + +void init_udp_listeners(void){ + for (int i = 0; i < MAX_UDP_LISTENERS; i++){ + listeners[i].rcvr = NULL; + } +} + +static struct listener_entry * +find_listener_by_port(unsigned short port) +{ + for (int i = 0; i < MAX_UDP_LISTENERS; i++){ + if (port == listeners[i].port) + return &listeners[i]; + } + return 0; +} + +static struct listener_entry * +find_free_listener(void) +{ + for (int i = 0; i < MAX_UDP_LISTENERS; i++){ + if (listeners[i].rcvr == NULL) + return &listeners[i]; + } + abort(); +} + +void +register_udp_listener(int port, udp_receiver_t rcvr) +{ + struct listener_entry *lx = find_listener_by_port(port); + if (lx) + lx->rcvr = rcvr; + else { + lx = find_free_listener(); + lx->port = port; + lx->rcvr = rcvr; + } +} + +/*********************************************************************** + * Protocol framer + **********************************************************************/ +void setup_framer( + eth_mac_addr_t eth_dst, + eth_mac_addr_t eth_src, + struct socket_address sock_dst, + struct socket_address sock_src, + size_t which +){ + struct { + padded_eth_hdr_t eth; + struct ip_hdr ip; + struct udp_hdr udp; + } frame; + + //-- load Ethernet header --// + frame.eth.dst = eth_dst; + frame.eth.src = eth_src; + frame.eth.ethertype = ETHERTYPE_IPV4; + + //-- load IPv4 header --// + IPH_VHLTOS_SET(&frame.ip, 4, 5, 0); + IPH_LEN_SET(&frame.ip, 0); + IPH_ID_SET(&frame.ip, 0); + IPH_OFFSET_SET(&frame.ip, IP_DF); // don't fragment + IPH_TTL_SET(&frame.ip, 32); + IPH_PROTO_SET(&frame.ip, IP_PROTO_UDP); + IPH_CHKSUM_SET(&frame.ip, 0); + frame.ip.src = sock_src.addr; + frame.ip.dest = sock_dst.addr; + IPH_CHKSUM_SET(&frame.ip, chksum_buffer( + (unsigned short *) &frame.ip, + sizeof(frame.ip)/sizeof(short), 0 + )); + + //-- load UDP header --// + frame.udp.src = sock_src.port; + frame.udp.dest = sock_dst.port; + frame.udp.len = 0; + frame.udp.chksum = 0; + + //copy into the framer table registers + memcpy_wa((void *)(sr_proto_framer_regs->table[which].entry + 1), &frame, sizeof(frame)); +} + +/*********************************************************************** + * Slow-path packet framing and transmission + **********************************************************************/ +/*! + * low level routine to assembly an ethernet frame and send it. + * + * \param dst destination mac address + * \param ethertype ethertype field + * \param buf0 first part of data + * \param len0 length of first part of data + * \param buf1 second part of data + * \param len1 length of second part of data + * \param buf2 third part of data + * \param len2 length of third part of data + */ +static void +send_pkt( + eth_mac_addr_t dst, int ethertype, + const void *buf0, size_t len0, + const void *buf1, size_t len1, + const void *buf2, size_t len2 +){ + + //control word for framed data + uint32_t ctrl_word = 0x0; + + //assemble the ethernet header + padded_eth_hdr_t ehdr; + ehdr.pad = 0; + ehdr.dst = dst; + ehdr.src = _local_mac_addr; + ehdr.ethertype = ethertype; + + //grab an out buffer and pointer + uint8_t *buff = (uint8_t *)pkt_ctrl_claim_outgoing_buffer(); + uint8_t *p = buff; + size_t total_len = 0; + + //create a list of all buffers to copy + const void *buffs[] = {&ctrl_word, &ehdr, buf0, buf1, buf2}; + size_t lens[] = {sizeof(ctrl_word), sizeof(ehdr), len0, len1, (len2 + 3) & ~3}; + + //copy each buffer into the out buffer + for (size_t i = 0; i < sizeof(buffs)/sizeof(buffs[0]); i++){ + total_len += lens[i]; //use full length (not clipped) + size_t bytes_remaining = out_buff_size - (size_t)(p - buff); + if (lens[i] > bytes_remaining) lens[i] = bytes_remaining; + if (lens[i] && ((lens[i] & 0x3) || (intptr_t) buffs[i] & 0x3)) + printf("send_pkt: bad alignment of len and/or buf\n"); + memcpy_wa(p, buffs[i], lens[i]); + p += lens[i]; + } + + //ensure that minimum length requirements are met + if (total_len < 64) total_len = 64; //60 + ctrl word + + pkt_ctrl_commit_outgoing_buffer(total_len/sizeof(uint32_t)); + if (debug) printf("sent %d bytes\n", (int)total_len); +} + +void +send_ip_pkt(struct ip_addr dst, int protocol, + const void *buf0, size_t len0, + const void *buf1, size_t len1) +{ + struct ip_hdr ip; + IPH_VHLTOS_SET(&ip, 4, 5, 0); + IPH_LEN_SET(&ip, IP_HLEN + len0 + len1); + IPH_ID_SET(&ip, 0); + IPH_OFFSET_SET(&ip, IP_DF); /* don't fragment */ + IPH_TTL_SET(&ip, 32); + IPH_PROTO_SET(&ip, protocol); + IPH_CHKSUM_SET(&ip, 0); + ip.src = _local_ip_addr; + ip.dest = dst; + + IPH_CHKSUM_SET(&ip, ~chksum_buffer( + (unsigned short *) &ip, sizeof(ip)/sizeof(short), 0 + )); + + eth_mac_addr_t dst_mac; + bool found = arp_cache_lookup_mac(&ip.dest, &dst_mac); + if (!found){ + printf("net_common: failed to hit cache looking for "); + print_ip_addr(&ip.dest); + newline(); + return; + } + + send_pkt(dst_mac, ETHERTYPE_IPV4, + &ip, sizeof(ip), buf0, len0, buf1, len1); +} + +void +send_udp_pkt(int src_port, struct socket_address dst, + const void *buf, size_t len) +{ + struct udp_hdr udp _AL4; + udp.src = src_port; + udp.dest = dst.port; + udp.len = UDP_HLEN + len; + udp.chksum = 0; + + send_ip_pkt(dst.addr, IP_PROTO_UDP, + &udp, sizeof(udp), buf, len); +} + +static void +handle_udp_packet(struct ip_addr src_ip, struct ip_addr dst_ip, + struct udp_hdr *udp, size_t len) +{ + if (len != udp->len){ + printf("UDP inconsistent lengths: %d %d\n", (int)len, udp->len); + return; + } + + unsigned char *payload = ((unsigned char *) udp) + UDP_HLEN; + int payload_len = len - UDP_HLEN; + + if (0){ + printf("\nUDP: src = %d dst = %d len = %d\n", + udp->src, udp->dest, udp->len); + + //print_bytes(0, payload, payload_len); + } + + struct listener_entry *lx = find_listener_by_port(udp->dest); + if (lx){ + struct socket_address src = make_socket_address(src_ip, udp->src); + struct socket_address dst = make_socket_address(dst_ip, udp->dest); + lx->rcvr(src, dst, payload, payload_len); + } +} + +static void +handle_icmp_packet(struct ip_addr src, struct ip_addr dst, + struct icmp_echo_hdr *icmp, size_t len) +{ + switch (icmp->type){ + case ICMP_DUR: // Destinatino Unreachable + if (icmp->code == ICMP_DUR_PORT){ // port unreachable + //handle destination port unreachable (the host ctrl+c'd the app): + + //filter out non udp data response + struct ip_hdr *ip = (struct ip_hdr *)(((uint8_t*)icmp) + sizeof(struct icmp_echo_hdr)); + struct udp_hdr *udp = (struct udp_hdr *)(((char *)ip) + IP_HLEN); + if (IPH_PROTO(ip) != IP_PROTO_UDP) break; + + struct listener_entry *lx = find_listener_by_port(udp->src); + if (lx){ + struct socket_address src = make_socket_address(ip->src, udp->src); + struct socket_address dst = make_socket_address(ip->dest, udp->dest); + lx->rcvr(src, dst, NULL, 0); + } + + putchar('i'); + } + else { + //printf("icmp dst unr (code: %d)", icmp->code); + putchar('i'); + } + break; + + case ICMP_ECHO:{ + const void *icmp_data_buff = ((uint8_t*)icmp) + sizeof(struct icmp_echo_hdr); + size_t icmp_data_len = len - sizeof(struct icmp_echo_hdr); + + struct icmp_echo_hdr echo_reply; + echo_reply.type = 0; + echo_reply.code = 0; + echo_reply.chksum = 0; + echo_reply.id = icmp->id; + echo_reply.seqno = icmp->seqno; + echo_reply.chksum = ~chksum_buffer( //data checksum + (unsigned short *)icmp_data_buff, + icmp_data_len/sizeof(short), + chksum_buffer( //header checksum + (unsigned short *)&echo_reply, + sizeof(echo_reply)/sizeof(short), + 0) + ); + + send_ip_pkt( + src, IP_PROTO_ICMP, + &echo_reply, sizeof(echo_reply), + icmp_data_buff, icmp_data_len + ); + break; + } + default: + break; + } +} + +static void +send_arp_reply(struct arp_eth_ipv4 *req, eth_mac_addr_t our_mac) +{ + struct arp_eth_ipv4 reply _AL4; + reply.ar_hrd = req->ar_hrd; + reply.ar_pro = req->ar_pro; + reply.ar_hln = req->ar_hln; + reply.ar_pln = req->ar_pln; + reply.ar_op = ARPOP_REPLY; + memcpy(reply.ar_sha, &our_mac, 6); + memcpy(reply.ar_sip, req->ar_tip, 4); + memcpy(reply.ar_tha, req->ar_sha, 6); + memcpy(reply.ar_tip, req->ar_sip, 4); + + eth_mac_addr_t t; + memcpy(t.addr, reply.ar_tha, 6); + send_pkt(t, ETHERTYPE_ARP, &reply, sizeof(reply), 0, 0, 0, 0); +} + +void net_common_send_arp_request(const struct ip_addr *addr){ + struct arp_eth_ipv4 req _AL4; + req.ar_hrd = ARPHRD_ETHER; + req.ar_pro = ETHERTYPE_IPV4; + req.ar_hln = sizeof(eth_mac_addr_t); + req.ar_pln = sizeof(struct ip_addr); + req.ar_op = ARPOP_REQUEST; + memcpy(req.ar_sha, ethernet_mac_addr(), sizeof(eth_mac_addr_t)); + memcpy(req.ar_sip, get_ip_addr(), sizeof(struct ip_addr)); + memset(req.ar_tha, 0x00, sizeof(eth_mac_addr_t)); + memcpy(req.ar_tip, addr, sizeof(struct ip_addr)); + + //send the request with a broadcast ethernet mac address + send_pkt(BCAST_MAC_ADDR, ETHERTYPE_ARP, &req, sizeof(req), 0, 0, 0, 0); +} + +void send_gratuitous_arp(void){ + struct arp_eth_ipv4 req _AL4; + req.ar_hrd = ARPHRD_ETHER; + req.ar_pro = ETHERTYPE_IPV4; + req.ar_hln = sizeof(eth_mac_addr_t); + req.ar_pln = sizeof(struct ip_addr); + req.ar_op = ARPOP_REQUEST; + memcpy(req.ar_sha, ethernet_mac_addr(), sizeof(eth_mac_addr_t)); + memcpy(req.ar_sip, get_ip_addr(), sizeof(struct ip_addr)); + memset(req.ar_tha, 0x00, sizeof(eth_mac_addr_t)); + memcpy(req.ar_tip, get_ip_addr(), sizeof(struct ip_addr)); + + //send the request with a broadcast ethernet mac address + send_pkt(BCAST_MAC_ADDR, ETHERTYPE_ARP, &req, sizeof(req), 0, 0, 0, 0); +} + +static void +handle_arp_packet(struct arp_eth_ipv4 *p, size_t size) +{ + if (size < sizeof(struct arp_eth_ipv4)){ + printf("\nhandle_arp: weird size = %d\n", (int)size); + return; + } + + if (0){ + printf("ar_hrd = %d\n", p->ar_hrd); + printf("ar_pro = %d\n", p->ar_pro); + printf("ar_hln = %d\n", p->ar_hln); + printf("ar_pln = %d\n", p->ar_pln); + printf("ar_op = %d\n", p->ar_op); + printf("ar_sha = "); print_mac_addr(p->ar_sha); newline(); + printf("ar_sip = "); print_ip_addr (p->ar_sip); newline(); + printf("ar_tha = "); print_mac_addr(p->ar_tha); newline(); + printf("ar_tip = "); print_ip_addr (p->ar_tip); newline(); + } + + if (p->ar_hrd != ARPHRD_ETHER + || p->ar_pro != ETHERTYPE_IPV4 + || p->ar_hln != 6 + || p->ar_pln != 4) + return; + + if (p->ar_op == ARPOP_REPLY){ + struct ip_addr ip_addr; + memcpy(&ip_addr, p->ar_sip, sizeof(ip_addr)); + eth_mac_addr_t mac_addr; + memcpy(&mac_addr, p->ar_sha, sizeof(mac_addr)); + arp_cache_update(&ip_addr, &mac_addr); + } + + if (p->ar_op != ARPOP_REQUEST) + return; + + struct ip_addr sip; + struct ip_addr tip; + + sip.addr = get_int32(p->ar_sip); + tip.addr = get_int32(p->ar_tip); + + if (memcmp(&tip, &_local_ip_addr, sizeof(_local_ip_addr)) == 0){ // They're looking for us... + send_arp_reply(p, _local_mac_addr); + } +} + +void +handle_eth_packet(uint32_t *p, size_t nlines) +{ + static size_t bcount = 0; + if (debug) printf("===> %d\n", (int)bcount++); + if (debug) print_buffer(p, nlines); + + padded_eth_hdr_t *eth_hdr = (padded_eth_hdr_t *)p; + + if (eth_hdr->ethertype == ETHERTYPE_ARP){ + struct arp_eth_ipv4 *arp = (struct arp_eth_ipv4 *)(p + 4); + handle_arp_packet(arp, nlines*sizeof(uint32_t) - 14); + } + else if (eth_hdr->ethertype == ETHERTYPE_IPV4){ + struct ip_hdr *ip = (struct ip_hdr *)(p + 4); + if (IPH_V(ip) != 4 || IPH_HL(ip) != 5) // ignore pkts w/ bad version or options + return; + + if (IPH_OFFSET(ip) & (IP_MF | IP_OFFMASK)) // ignore fragmented packets + return; + + // filter on dest ip addr (should be broadcast or for us) + bool is_bcast = memcmp(ð_hdr->dst, &BCAST_MAC_ADDR, sizeof(BCAST_MAC_ADDR)) == 0; + bool is_my_ip = memcmp(&ip->dest, &_local_ip_addr, sizeof(_local_ip_addr)) == 0; + if (!is_bcast && !is_my_ip) return; + + arp_cache_update(&ip->src, (eth_mac_addr_t *)(((char *)p)+8)); + + int protocol = IPH_PROTO(ip); + int len = IPH_LEN(ip) - IP_HLEN; + + switch (protocol){ + case IP_PROTO_UDP: + handle_udp_packet(ip->src, ip->dest, (struct udp_hdr *)(((char *)ip) + IP_HLEN), len); + break; + + case IP_PROTO_ICMP: + handle_icmp_packet(ip->src, ip->dest, (struct icmp_echo_hdr *)(((char *)ip) + IP_HLEN), len); + break; + + default: // ignore + break; + } + } + else + return; // Not ARP or IPV4, ignore +} diff --git a/firmware/zpu/lib/net_common.h b/firmware/zpu/lib/net_common.h new file mode 100644 index 000000000..5e6daf689 --- /dev/null +++ b/firmware/zpu/lib/net_common.h @@ -0,0 +1,61 @@ +/* + * Copyright 2009-2012 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 <http://www.gnu.org/licenses/>. + */ +#ifndef INCLUDED_NET_COMMON_H +#define INCLUDED_NET_COMMON_H + +#include <stdint.h> +#include <stddef.h> +#include <net/socket_address.h> +#include <net/eth_mac_addr.h> + +/*! + * Setup an entry in the protocol framer for a UDP socket. + * + * \param eth_dst ethernet destination mac addr + * \param eth_src ethernet source mac addr + * \param sock_dst udp/ip socket destination + * \param sock_src udp/ip socket source + * \param which the index into the table + */ +void setup_framer( + eth_mac_addr_t eth_dst, + eth_mac_addr_t eth_src, + struct socket_address sock_dst, + struct socket_address sock_src, + size_t which +); + +typedef void (*udp_receiver_t)(struct socket_address src, struct socket_address dst, + unsigned char *payload, int payload_len); + +void init_udp_listeners(void); + +void register_addrs(const eth_mac_addr_t *mac_addr, const struct ip_addr *ip_addr); + +void register_udp_listener(int port, udp_receiver_t rcvr); + +void send_udp_pkt(int src_port, struct socket_address dst, + const void *buf, size_t len); + +void handle_eth_packet(uint32_t *p, size_t nlines); + +void send_gratuitous_arp(void); + +//! Send an ARP request for the given IP address +void net_common_send_arp_request(const struct ip_addr *addr); + +#endif /* INCLUDED_NET_COMMON_H */ diff --git a/firmware/zpu/lib/nonstdio.c b/firmware/zpu/lib/nonstdio.c new file mode 100644 index 000000000..4b5fa4123 --- /dev/null +++ b/firmware/zpu/lib/nonstdio.c @@ -0,0 +1,123 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <nonstdio.h> + +static const char hex[16] = "0123456789ABCDEF"; + +// %x +void +puthex4(unsigned long x) +{ + putchar(hex[x & 0xf]); +} + +// %02x +void +puthex8(unsigned long x) +{ + putchar(hex[(x >> 4) & 0xf]); + putchar(hex[x & 0xf]); +} + +// %04x +void +puthex16(unsigned long x) +{ + puthex8(x >> 8); + puthex8(x); +} + +// %08x +void +puthex32(unsigned long x) +{ + puthex16(x >> 16); + puthex16(x); +} + +void +puthex4_nl(unsigned long x) +{ + puthex4(x); + newline(); +} + +void +puthex8_nl(unsigned long x) +{ + puthex8(x); + newline(); +} + +void +puthex16_nl(unsigned long x) +{ + puthex16(x); + newline(); +} + +void +puthex32_nl(unsigned long x) +{ + puthex32(x); + newline(); +} +/* +void reverse(char s[]) +{ + int c, i, j; + + for (i = 0, j = strlen(s)-1; i<j; i++, j--) { + c = s[i]; + s[i] = s[j]; + s[j] = c; + } +} + +int abs(signed long value) { + return (value >= 0) ? value : 0-value; +} + +//we'll keep the puthex functions above because they're way more lightweight. but sometimes you just want to print in decimal, you know? +char *itoa(signed long value, char *result, int base) +{ + // check that the base if valid + if (base < 2 || base > 16) { *result = 0; return result; } + + char* out = result; + signed long quotient = value; + + do { + *out = hex[ abs(quotient % base) ]; + ++out; + quotient /= base; + } while ( quotient ); + + // Only apply negative sign for base 10 + if ( value < 0 && base == 10) *out++ = '-'; + + *out = 0; + reverse( result ); + + return result; + +} +*/ + + diff --git a/firmware/zpu/lib/nonstdio.h b/firmware/zpu/lib/nonstdio.h new file mode 100644 index 000000000..a47a6df6e --- /dev/null +++ b/firmware/zpu/lib/nonstdio.h @@ -0,0 +1,47 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_NONSTDIO_H +#define INCLUDED_NONSTDIO_H + +#include <stdio.h> +#include <stdint.h> +#include <stddef.h> + +void putstr(const char *s); // cf puts, no added newline +void puthex4(unsigned long x); // output 1 hex digit +void puthex8(unsigned long x); // output 2 hex digits +void puthex16(unsigned long x); // output 4 hex digits +void puthex32(unsigned long x); // output 8 hex digits +void puthex4_nl(unsigned long x); // ... followed by newline +void puthex8_nl(unsigned long x); +void puthex16_nl(unsigned long x); +void puthex32_nl(unsigned long x); +#define puthex puthex32 +#define puthex_nl puthex32_nl +void newline(); // putchar('\n') + +void print_mac_addr(const void *addr); + +void print_ip_addr(const void *addr); + +void print_buffer(uint32_t *buf, size_t n); + +#endif /* INCLUDED_NONSTDIO_H */ diff --git a/firmware/zpu/lib/pic.c b/firmware/zpu/lib/pic.c new file mode 100644 index 000000000..bd627ce6b --- /dev/null +++ b/firmware/zpu/lib/pic.c @@ -0,0 +1,89 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "pic.h" +#include "hal_io.h" +#include "memory_map.h" + + +#define NVECTORS 8 + +/* + * Our secondary interrupt vector. + */ +irq_handler_t pic_vector[NVECTORS]; + +void +pic_init(void) +{ + // uP is level triggered + + pic_regs->mask = ~0; // mask all interrupts + pic_regs->edge_enable = PIC_ONETIME_INT | PIC_UNDERRUN_INT | PIC_OVERRUN_INT | PIC_PPS_INT; + pic_regs->polarity = ~0 & ~PIC_PHY_INT; // rising edge + pic_regs->pending = ~0; // clear all pending ints + + for (int i = 0; i < NVECTORS; i++){ + pic_vector[i] = pic_nop_handler; + } +} + +/* + * This magic gets pic_interrupt_handler wired into the + * system interrupt handler with the appropriate prologue and + * epilogue. + */ +//FIXME zpu-gcc does not install interrupt_handler like this +//void pic_interrupt_handler() __attribute__ ((interrupt_handler)); + +void pic_interrupt_handler() +{ + // pending and not masked interrupts + int live = pic_regs->pending & ~pic_regs->mask; + + // FIXME loop while there are interrupts to service. + // That will reduce our overhead. + + // handle the first one set + int i; + int mask; + for (i=0, mask=1; i < NVECTORS; i++, mask <<= 1){ + if (mask & live){ // handle this one + // puthex_nl(i); + (*pic_vector[i])(i); + pic_regs->pending = mask; // clear pending interrupt + return; + } + } +} + +void +pic_register_handler(unsigned irq, irq_handler_t handler) +{ + if (irq >= NVECTORS) + return; + pic_vector[irq] = handler; + + pic_regs->mask &= ~IRQ_TO_MASK(irq); +} + +void +pic_nop_handler(unsigned irq) +{ + // nop +} diff --git a/firmware/zpu/lib/pic.h b/firmware/zpu/lib/pic.h new file mode 100644 index 000000000..cfdf721f4 --- /dev/null +++ b/firmware/zpu/lib/pic.h @@ -0,0 +1,36 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_PIC_H +#define INCLUDED_PIC_H + +typedef void (*irq_handler_t)(unsigned irq); + +void pic_init(void); +void pic_register_handler(unsigned irq, irq_handler_t handler); + +void pic_nop_handler(unsigned irq); // default handler does nothing + +// FIXME inline assembler +int pic_disable_interrupts(); +int pic_enable_interrupts(); +void pic_restore_interrupts(int prev_status); + +void pic_interrupt_handler(); + +#endif /* INCLUDED_PIC_H */ diff --git a/firmware/zpu/lib/pkt_ctrl.c b/firmware/zpu/lib/pkt_ctrl.c new file mode 100644 index 000000000..2bbe2f843 --- /dev/null +++ b/firmware/zpu/lib/pkt_ctrl.c @@ -0,0 +1,100 @@ +/* + * Copyright 2010-2011 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 <http://www.gnu.org/licenses/>. + */ + +#include "pkt_ctrl.h" +#include "memory_map.h" +#include <nonstdio.h> + +//status signals from WB into PR +#define CPU_STAT_RD_DONE (1 << 0) +#define CPU_STAT_RD_EROR (1 << 1) +#define CPU_STAT_RD_IDLE (1 << 2) + +//status signals from PR into WB +#define CPU_STAT_WR_DONE (1 << 4) +#define CPU_STAT_WR_EROR (1 << 5) +#define CPU_STAT_WR_IDLE (1 << 6) + +//control signals from WB into PR +#define CPU_CTRL_RD_CLEAR (1 << 0) +#define CPU_CTRL_RD_START (1 << 1) + +//control signals from PR into WB +#define CPU_CTRL_WR_CLEAR (1 << 2) +#define CPU_CTRL_WR_START (1 << 3) + +void pkt_ctrl_program_inspector( + const struct ip_addr *ip_addr, uint16_t data_port +){ + router_ctrl->ip_addr = ip_addr->addr; + router_ctrl->data_ports = data_port; +} + +void pkt_ctrl_set_routing_mode(pkt_ctrl_routing_mode_t mode){ + //About to change the mode; ensure that we are accepting packets. + //The plumbing will not switch if it cannot pass an end of packet. + pkt_ctrl_release_incoming_buffer(); + + //Change the mode; this switches the valves and crossbars. + router_ctrl->mode_ctrl = mode; +} + +static inline void cpu_stat_wait_for(int bm){ + while((router_status->status & bm) == 0){ + /* NOP */ + } +} + +void *pkt_ctrl_claim_incoming_buffer(size_t *num_lines){ + uint32_t status = router_status->status; + + //if done: clear the read and return the buffer + if (status & CPU_STAT_RD_DONE){ + *num_lines = (router_status->status >> 16) & 0xffff; + return ((uint32_t *) ROUTER_RAM_BASE); + } + + //if error: drop the packet and start a new read + if (status & CPU_STAT_RD_EROR){ + putstr("E"); + pkt_ctrl_release_incoming_buffer(); + } + + //otherwise null for nothing ready + return NULL; +} + +void pkt_ctrl_release_incoming_buffer(void){ + //clear, wait for idle, and start a new read + router_ctrl->iface_ctrl = CPU_CTRL_RD_CLEAR; + cpu_stat_wait_for(CPU_STAT_RD_IDLE); + router_ctrl->iface_ctrl = CPU_CTRL_RD_START; +} + +void *pkt_ctrl_claim_outgoing_buffer(void){ + //wait for idle and return the buffer + cpu_stat_wait_for(CPU_STAT_WR_IDLE); + return ((uint32_t *) ROUTER_RAM_BASE); +} + +void pkt_ctrl_commit_outgoing_buffer(size_t num_lines){ + //start a new write with the given length + router_ctrl->iface_ctrl = ((num_lines & 0xffff) << 16) | CPU_CTRL_WR_START; + //wait for the write to become done + cpu_stat_wait_for(CPU_STAT_WR_DONE); + router_ctrl->iface_ctrl = CPU_CTRL_WR_CLEAR; +} diff --git a/firmware/zpu/lib/pkt_ctrl.h b/firmware/zpu/lib/pkt_ctrl.h new file mode 100644 index 000000000..15e4b0c4d --- /dev/null +++ b/firmware/zpu/lib/pkt_ctrl.h @@ -0,0 +1,63 @@ +/* + * Copyright 2010-2011 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_PKT_CTRL_H +#define INCLUDED_PKT_CTRL_H + +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> +#include <lwip/ip_addr.h> + +typedef enum { + PKT_CTRL_ROUTING_MODE_SLAVE = 0, + PKT_CTRL_ROUTING_MODE_MASTER = 1 +} pkt_ctrl_routing_mode_t; + +//! Program the decision values into the packet inspector +void pkt_ctrl_program_inspector( + const struct ip_addr *ip_addr, uint16_t data_port +); + +//! Set the routing mode for this device +void pkt_ctrl_set_routing_mode(pkt_ctrl_routing_mode_t mode); + +/*! + * Try to claim an incomming buffer. + * \param num_lines filled with the buffer size + * \return a pointer to the buffer memory or NULL + */ +void *pkt_ctrl_claim_incoming_buffer(size_t *num_lines); + +/*! + * Release the incoming buffer. Call when done. + */ +void pkt_ctrl_release_incoming_buffer(void); + +/*! + * Claim an outgoing buffer. + * \return a pointer to the buffer + */ +void *pkt_ctrl_claim_outgoing_buffer(void); + +/*! + * Commit the outgoing buffer. + * \param num_lines how many lines written. + */ +void pkt_ctrl_commit_outgoing_buffer(size_t num_lines); + +#endif /* INCLUDED_PKT_CTRL_H */ diff --git a/firmware/zpu/lib/print_addrs.c b/firmware/zpu/lib/print_addrs.c new file mode 100644 index 000000000..fa2a49fc3 --- /dev/null +++ b/firmware/zpu/lib/print_addrs.c @@ -0,0 +1,33 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ +#include "nonstdio.h" + +void +print_mac_addr(const void *addr) +{ + uint8_t *p = (uint8_t *)addr; + for(size_t i = 0; i < 6; i++){ + if(i) putchar(':'); + puthex8(p[i]); + } +} + +void print_ip_addr(const void *addr){ + uint8_t *p = (uint8_t *)addr; + printf("%d.%d.%d.%d", p[0], p[1], p[2], p[3]); +} diff --git a/firmware/zpu/lib/print_buffer.c b/firmware/zpu/lib/print_buffer.c new file mode 100644 index 000000000..9f9104bb5 --- /dev/null +++ b/firmware/zpu/lib/print_buffer.c @@ -0,0 +1,36 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ +#include <nonstdio.h> + +void +print_buffer(uint32_t *buf, size_t n) +{ + size_t i; + for (i = 0; i < n; i++){ + if (i % 4 == 0) + puthex16(i * 4); + + putchar(' '); + puthex32(buf[i]); + if (i % 4 == 3) + newline(); + } + + newline(); +} + diff --git a/firmware/zpu/lib/print_rmon_regs.c b/firmware/zpu/lib/print_rmon_regs.c new file mode 100644 index 000000000..6d9986909 --- /dev/null +++ b/firmware/zpu/lib/print_rmon_regs.c @@ -0,0 +1,44 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "print_rmon_regs.h" +#include "eth_mac.h" +#include "nonstdio.h" + +void +print_rmon_regs(void) +{ + int i; + for (i=0; i <= 0x10; i++){ + putstr("RMON[0x"); + puthex8(i); + putstr("] = "); + printf("%d\n", eth_mac_read_rmon(i)); + } + + for (i=0x20; i <= 0x30; i++){ + putstr("RMON[0x"); + puthex8(i); + putstr("] = "); + printf("%d\n", eth_mac_read_rmon(i)); + } +} diff --git a/firmware/zpu/lib/print_rmon_regs.h b/firmware/zpu/lib/print_rmon_regs.h new file mode 100644 index 000000000..44e52da84 --- /dev/null +++ b/firmware/zpu/lib/print_rmon_regs.h @@ -0,0 +1,24 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_PRINT_RMON_REGS_H +#define INCLUDED_PRINT_RMON_REGS_H + +void print_rmon_regs(void); + +#endif /* INCLUDED_PRINT_RMON_REGS_H */ diff --git a/firmware/zpu/lib/printf.c b/firmware/zpu/lib/printf.c new file mode 100644 index 000000000..45bd57cb9 --- /dev/null +++ b/firmware/zpu/lib/printf.c @@ -0,0 +1,134 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +/* + * Based on code from the SDCC z80 library ;) + */ + +#include <stdarg.h> +#include <stdio.h> + +static void +_printn(unsigned u, unsigned base, char issigned, + void (*emitter)(char, void *), void *pData) +{ + const char *_hex = "0123456789ABCDEF"; + if (issigned && ((int)u < 0)) { + (*emitter)('-', pData); + u = (unsigned)-((int)u); + } + if (u >= base) + _printn(u/base, base, 0, emitter, pData); + (*emitter)(_hex[u%base], pData); +} + +static void +_printf(const char *format, void (*emitter)(char, void *), + void *pData, va_list va) +{ + while (*format) { + if (*format != '%') + (*emitter)(*format, pData); + else { + switch (*++format) { + case 0: /* hit end of format string */ + return; + case 'c': + { + char c = (char)va_arg(va, int); + (*emitter)(c, pData); + break; + } + case 'u': + { + unsigned u = va_arg(va, unsigned); + _printn(u, 10, 0, emitter, pData); + break; + } + case 'd': + { + unsigned u = va_arg(va, unsigned); + _printn(u, 10, 1, emitter, pData); + break; + } + case 'x': + case 'p': + { + unsigned u = va_arg(va, unsigned); + _printn(u, 16, 0, emitter, pData); + break; + } + case 's': + { + char *s = va_arg(va, char *); + while (*s) { + (*emitter)(*s, pData); + s++; + } + break; + } + } + } + format++; + } +} + +static void +_char_emitter(char c, void *pData __attribute__((unused))) +{ + putchar(c); +} + +int +printf(const char *format, ...) +{ + va_list va; + va_start(va, format); + + _printf(format, _char_emitter, NULL, va); + + va_end(va); + + // wrong return value... + return 0; +} + + +#if 0 + +// Totally dangerous. Don't use +static void +_buf_emitter(char c, void *pData) +{ + *((*((char **)pData)))++ = c; +} + +int sprintf(char *pInto, const char *format, ...) +{ + va_list va; + va_start(va, format); + + _printf(format, _buf_emitter, &pInto, va); + *pInto++ = '\0'; + + va_end(va); + + // FIXME wrong return value + return 0; +} +#endif diff --git a/firmware/zpu/lib/printf.c.smaller b/firmware/zpu/lib/printf.c.smaller new file mode 100644 index 000000000..4d858648d --- /dev/null +++ b/firmware/zpu/lib/printf.c.smaller @@ -0,0 +1,134 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +/* + * Based on code from the SDCC z80 library ;) + */ + +#include <stdarg.h> +#include <stdio.h> +#include <hal_io.h> /* FIXME refactor into stdio */ + +#define PUTCHAR(x) hal_putc(x) + + +static void +_printn(unsigned u, unsigned base, char issigned) +{ + const char *_hex = "0123456789ABCDEF"; + if (issigned && ((int)u < 0)) { + PUTCHAR('-'); + u = (unsigned)-((int)u); + } + if (u >= base) + _printn(u/base, base, 0); + PUTCHAR(_hex[u%base]); +} + +static void +_printf(const char *format, va_list va) +{ + while (*format) { + if (*format != '%') + PUTCHAR(*format); + else { + switch (*++format) { + case 0: /* hit end of format string */ + return; + case 'c': + { + char c = (char)va_arg(va, int); + PUTCHAR(c); + break; + } + case 'u': + { + unsigned u = va_arg(va, unsigned); + _printn(u, 10, 0); + break; + } + case 'd': + { + unsigned u = va_arg(va, unsigned); + _printn(u, 10, 1); + break; + } + case 'x': + case 'p': + { + unsigned u = va_arg(va, unsigned); + _printn(u, 16, 0); + break; + } + case 's': + { + char *s = va_arg(va, char *); + while (*s) { + PUTCHAR(*s); + s++; + } + break; + } + } + } + format++; + } +} + +#if 0 +static void +_char_emitter(char c, void *pData __attribute__((unused))) +{ + hal_putc(c); +} +#endif + +int +printf(const char *format, ...) +{ + va_list va; + va_start(va, format); + + _printf(format, va); + + // wrong return value... + return 0; +} + + +#if 0 + +// Totally dangerous. Don't use +static void +_buf_emitter(char c, void *pData) +{ + *((*((char **)pData)))++ = c; +} + +int sprintf(char *pInto, const char *format, ...) +{ + va_list va; + va_start(va, format); + + _printf(format, _buf_emitter, &pInto, va); + *pInto++ = '\0'; + + // FIXME wrong return value + return 0; +} +#endif diff --git a/firmware/zpu/lib/spi.c b/firmware/zpu/lib/spi.c new file mode 100644 index 000000000..6f2f74899 --- /dev/null +++ b/firmware/zpu/lib/spi.c @@ -0,0 +1,55 @@ +/* + * Copyright 2012 Ettus Research LLC + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "spi.h" +#include "memory_map.h" +#include "nonstdio.h" + +void spi_init(void) +{ + spi_core->divider = 10; +} + +void spi_wait(void) +{ + while ((readback_mux->irqs & SPI_READY_IRQ) == 0){ + //NOP + } +} + +uint32_t spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags) +{ + uint32_t control_word = 0; + control_word |= (slave << SPI_CORE_SLAVE_SELECT_SHIFT); + control_word |= (length << SPI_CORE_NUM_BITS_SHIFT); + if ((flags & SPI_PUSH_RISE) != 0) control_word |= (1 << SPI_CORE_DATA_OUT_EDGE_SHIFT); + if ((flags & SPI_PUSH_FALL) != 0) control_word |= (0 << SPI_CORE_DATA_OUT_EDGE_SHIFT); + if ((flags & SPI_LATCH_RISE) != 0) control_word |= (1 << SPI_CORE_DATA_IN_EDGE_SHIFT); + if ((flags & SPI_LATCH_FALL) != 0) control_word |= (0 << SPI_CORE_DATA_IN_EDGE_SHIFT); + + const uint32_t data_out = data << (32 - length); + + spi_wait(); + spi_core->control = control_word; + spi_core->data = data_out; + + if (!readback) return 0; + + spi_wait(); + return readback_mux->spi; +} diff --git a/firmware/zpu/lib/spi.h b/firmware/zpu/lib/spi.h new file mode 100644 index 000000000..125e1a502 --- /dev/null +++ b/firmware/zpu/lib/spi.h @@ -0,0 +1,49 @@ +/* + * Copyright 2012 Ettus Research LLC + * Copyright 2006,2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_SPI_H +#define INCLUDED_SPI_H + +#include <stdbool.h> +#include <stdint.h> + +/*! + * \brief One time call to initialize SPI + */ +void spi_init(void); + +/*! + * \brief Wait for last SPI transaction to complete. + * Unless you need to know it completed, it's not necessary to call this. + */ +void spi_wait(void); + +#define SPI_TXONLY false // readback: no +#define SPI_TXRX true // readback: yes + +/* + * Flags for spi_transact + */ +#define SPI_PUSH_RISE (1 << 0) // push tx data on rising edge of SCLK +#define SPI_PUSH_FALL (1 << 1) // push tx data on falling edge of SCLK +#define SPI_LATCH_RISE (1 << 2) // latch rx data on rising edge of SCLK +#define SPI_LATCH_FALL (1 << 3) // latch rx data on falling edge of SCLK + +uint32_t spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags); + +#endif /* INCLUDED_SPI_H */ diff --git a/firmware/zpu/lib/stdint.h b/firmware/zpu/lib/stdint.h new file mode 100644 index 000000000..b5a8611a9 --- /dev/null +++ b/firmware/zpu/lib/stdint.h @@ -0,0 +1,34 @@ +/* -*- c -*- */ +/* + * Copyright 2007,2009 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_STDINT_H +#define INCLUDED_STDINT_H + +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned int uint32_t; +typedef long long int int64_t; +typedef unsigned long long int uint64_t; + +typedef int intptr_t; +typedef unsigned int uintptr_t; + +#endif /* INCLUDED_STDINT_H */ diff --git a/firmware/zpu/lib/stdio.h b/firmware/zpu/lib/stdio.h new file mode 100644 index 000000000..12a7ed0bb --- /dev/null +++ b/firmware/zpu/lib/stdio.h @@ -0,0 +1,38 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_STDIO_H +#define INCLUDED_STDIO_H + +// very trimmed down stdio.h See also nonstdio.h + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef EOF +#define EOF (-1) +#endif + +int putchar(int c); +int puts(const char *s); +int printf(const char *format, ...); + +int getchar(void); + +#endif /* INCLUDED_STDIO_H */ diff --git a/firmware/zpu/lib/u2_init.c b/firmware/zpu/lib/u2_init.c new file mode 100644 index 000000000..77c8c0722 --- /dev/null +++ b/firmware/zpu/lib/u2_init.c @@ -0,0 +1,84 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "pic.h" +#include "hal_io.h" +#include "hal_uart.h" +#include "i2c.h" +#include "mdelay.h" +#include "clocks.h" +#include "usrp2/fw_common.h" +#include "nonstdio.h" + +/* + * We ought to arrange for this to be called before main, but for now, + * we require that the user's main call u2_init as the first thing... + */ +bool +u2_init(void) +{ + hal_disable_ints(); + hal_io_init(); + + // init spi, so that we can switch over to the high-speed clock + spi_init(); + + // set up the default clocks + clocks_init(); + + hal_uart_init(); + + // init i2c so we can read our rev + pic_init(); // progammable interrupt controller + i2c_init(); + hal_enable_ints(); + + // flash all leds to let us know board is alive +#ifndef BOOTLOADER + hal_set_led_src(0x0, 0x1f); /* software ctrl */ + hal_set_leds(0x0, 0x1f); mdelay(300); + hal_set_leds(LED_E, LED_E); mdelay(300); + hal_set_leds(LED_C, LED_C); mdelay(300); + hal_set_leds(LED_A, LED_A); mdelay(300); + for (int i = 0; i < 3; i++){ //blink all + static const int blinks = LED_E | LED_C | LED_A; + hal_set_leds(0x0, 0x1f); mdelay(100); + hal_set_leds(blinks, 0x1f); mdelay(100); + } +#endif + hal_set_led_src(0x1f & ~LED_D, 0x1f); /* hardware ctrl */ + hal_set_leds(LED_D, 0x1f); // Leave one on + +#if 0 + // test register readback + int rr, vv; + vv = ad9777_read_reg(0); + printf("ad9777 reg[0] = 0x%x\n", vv); + + for (rr = 0x04; rr <= 0x0d; rr++){ + vv = ad9510_read_reg(rr); + printf("ad9510 reg[0x%x] = 0x%x\n", rr, vv); + } +#endif + + output_regs->serdes_ctrl = (SERDES_ENABLE | SERDES_RXEN); + + return true; +} diff --git a/firmware/zpu/lib/u2_init.h b/firmware/zpu/lib/u2_init.h new file mode 100644 index 000000000..848bd88de --- /dev/null +++ b/firmware/zpu/lib/u2_init.h @@ -0,0 +1,28 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ +#ifndef INCLUDED_U2_INIT_H +#define INCLUDED_U2_INIT_H + +#include <stdbool.h> + +/*! + * one-time init + */ +bool u2_init(void); + +#endif /* INCLUDED_U2_INIT_H */ diff --git a/firmware/zpu/lib/udp_fw_update.h b/firmware/zpu/lib/udp_fw_update.h new file mode 100644 index 000000000..d98447aef --- /dev/null +++ b/firmware/zpu/lib/udp_fw_update.h @@ -0,0 +1,75 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 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 <http://www.gnu.org/licenses/>. + */ + +#include "net_common.h" + +#define USRP2_UDP_UPDATE_PORT 49154 + +typedef enum { + USRP2_FW_UPDATE_ID_WAT = ' ', + + USRP2_FW_UPDATE_ID_OHAI_LOL = 'a', + USRP2_FW_UPDATE_ID_OHAI_OMG = 'A', + + USRP2_FW_UPDATE_ID_WATS_TEH_FLASH_INFO_LOL = 'f', + USRP2_FW_UPDATE_ID_HERES_TEH_FLASH_INFO_OMG = 'F', + + USRP2_FW_UPDATE_ID_ERASE_TEH_FLASHES_LOL = 'e', + USRP2_FW_UPDATE_ID_ERASING_TEH_FLASHES_OMG = 'E', + + USRP2_FW_UPDATE_ID_R_U_DONE_ERASING_LOL = 'd', + USRP2_FW_UPDATE_ID_IM_DONE_ERASING_OMG = 'D', + USRP2_FW_UPDATE_ID_NOPE_NOT_DONE_ERASING_OMG = 'B', + + USRP2_FW_UPDATE_ID_WRITE_TEH_FLASHES_LOL = 'w', + USRP2_FW_UPDATE_ID_WROTE_TEH_FLASHES_OMG = 'W', + + USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL = 'r', + USRP2_FW_UPDATE_ID_KK_READ_TEH_FLASHES_OMG = 'R', + + USRP2_FW_UPDATE_ID_RESET_MAH_COMPUTORZ_LOL = 's', + USRP2_FW_UPDATE_ID_RESETTIN_TEH_COMPUTORZ_OMG = 'S', + + USRP2_FW_UPDATE_ID_I_CAN_HAS_HW_REV_LOL = 'v', + USRP2_FW_UPDATE_ID_HERES_TEH_HW_REV_OMG = 'V', + + USRP2_FW_UPDATE_ID_KTHXBAI = '~' + +} usrp2_fw_update_id_t; + +typedef struct { + uint32_t proto_ver; + uint32_t id; + uint32_t seq; + union { + uint32_t ip_addr; + uint32_t hw_rev; + struct { + uint32_t flash_addr; + uint32_t length; + uint8_t data[256]; + } flash_args; + struct { + uint32_t sector_size_bytes; + uint32_t memory_size_bytes; + } flash_info_args; + } data; +} usrp2_fw_update_data_t; + +void handle_udp_fw_update_packet(struct socket_address src, struct socket_address dst, + unsigned char *payload, int payload_len); diff --git a/firmware/zpu/lib/udp_uart.c b/firmware/zpu/lib/udp_uart.c new file mode 100644 index 000000000..a3940c05f --- /dev/null +++ b/firmware/zpu/lib/udp_uart.c @@ -0,0 +1,116 @@ +/* + * Copyright 2011 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 <http://www.gnu.org/licenses/>. + */ + +#include "udp_uart.h" +#include "hal_uart.h" +#include "net_common.h" +#include "compiler.h" +#include <stdbool.h> + +/*********************************************************************** + * Constants + **********************************************************************/ +#define MAX_NUM_UARTS 4 +#ifndef UDP_UART_MASK + #error missing definition for UDP_UART_MASK enable mask +#endif +static const size_t num_idle_cyc_b4_flush = 11; //small but lucky number + +/*********************************************************************** + * Globals + **********************************************************************/ +static uint16_t _base_port; + +typedef struct{ + struct socket_address dst; + _AL4 uint8_t buf[256]; + size_t len; //length of buffer + size_t cyc; //idle cycle count +} udp_uart_state_t; + +static udp_uart_state_t _states[MAX_NUM_UARTS]; + +/*********************************************************************** + * UDP handler for UARTs + **********************************************************************/ +static void handle_uart_data_packet( + struct socket_address src, struct socket_address dst, + unsigned char *payload, int payload_len +){ + //handle ICMP destination unreachable + if (payload == NULL){ + const size_t which = src.port-_base_port; + if (which >= MAX_NUM_UARTS) return; + _states[which].dst.port = 0; + } + + //handle a regular blocking UART write + else{ + const size_t which = dst.port-_base_port; + if (which >= MAX_NUM_UARTS) return; + _states[which].dst = src; + for (size_t i = 0; i < payload_len; i++){ + hal_uart_putc((hal_uart_name_t)which, (int)payload[i]); + } + } +} + +/*********************************************************************** + * Public init function + **********************************************************************/ +void udp_uart_init(const uint16_t base_port){ + _base_port = base_port; + for(size_t i = 0; i < MAX_NUM_UARTS; i++){ + _states[i].dst.port = 0; //reset to null port + _states[i].len = 0; + _states[i].cyc = 0; + register_udp_listener(_base_port+i, handle_uart_data_packet); + } +} + +/*********************************************************************** + * Public poll function + **********************************************************************/ +void udp_uart_poll(void){ + for (size_t i = 0; i < MAX_NUM_UARTS; i++){ + if (((UDP_UART_MASK) & (1 << i)) == 0) continue; + + bool newline = false; + udp_uart_state_t *state = &_states[i]; + + //read all characters we can without blocking + for (size_t j = state->len; j < sizeof(_states[0].buf); j++){ + int ret = hal_uart_getc_noblock((hal_uart_name_t)i); + if (ret == -1) break; + char ch = (char) ret; + if (ch == '\n' || ch == '\r') newline = true; + state->buf[j] = ch; + state->len++; + state->cyc = 0; //reset idle cycles + } + + //nothing in buffer, continue to next uart + if (state->len == 0) continue; + + //send out a message if newline or forced flush + if (newline || state->cyc++ > num_idle_cyc_b4_flush){ + if (state->dst.port != 0) send_udp_pkt(_base_port+i, state->dst, state->buf, state->len); + state->len = 0; + state->cyc = 0; + } + } +} diff --git a/firmware/zpu/lib/udp_uart.h b/firmware/zpu/lib/udp_uart.h new file mode 100644 index 000000000..d448e7611 --- /dev/null +++ b/firmware/zpu/lib/udp_uart.h @@ -0,0 +1,36 @@ +/* + * Copyright 2011 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_UDP_UART_H +#define INCLUDED_UDP_UART_H + +#include <stdint.h> + +/*! + * Initialize the UDP/UART module. + * Registers handler into the network. + * \param base_port the source port for UART0 + */ +void udp_uart_init(const uint16_t base_port); + +/*! + * Polls the UART state machine, + * and sends messages over UDP. + */ +void udp_uart_poll(void); + +#endif /* INCLUDED_UDP_UART_H */ |