diff options
Diffstat (limited to 'firmware/zpu/lib')
65 files changed, 5443 insertions, 0 deletions
| diff --git a/firmware/zpu/lib/CMakeLists.txt b/firmware/zpu/lib/CMakeLists.txt new file mode 100644 index 000000000..193d63cfa --- /dev/null +++ b/firmware/zpu/lib/CMakeLists.txt @@ -0,0 +1,47 @@ +# +# 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 +) 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..4d3acb65d --- /dev/null +++ b/firmware/zpu/lib/ad9510.c @@ -0,0 +1,42 @@ +/* -*- 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 "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, SPIF_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, +			    SPIF_PUSH_FALL | SPIF_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..9c586fa6b --- /dev/null +++ b/firmware/zpu/lib/arp_cache.c @@ -0,0 +1,90 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 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..8e84a1f94 --- /dev/null +++ b/firmware/zpu/lib/arp_cache.h @@ -0,0 +1,33 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 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..42937957f --- /dev/null +++ b/firmware/zpu/lib/banal.c @@ -0,0 +1,31 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 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..eb7ed509a --- /dev/null +++ b/firmware/zpu/lib/banal.h @@ -0,0 +1,71 @@ +/* -*- c -*- */ +/* + * Copyright 2009 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/bootconfig.c b/firmware/zpu/lib/bootconfig.c new file mode 100644 index 000000000..93adc05c2 --- /dev/null +++ b/firmware/zpu/lib/bootconfig.c @@ -0,0 +1,101 @@ +/* -*- c -*- */ +/* + * Copyright 2009 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 "bootconfig.h" +#include "bootconfig_private.h" +#include <stdint.h> +#include <stddef.h> +#include <i2c.h> +#include <quadradio/i2c_addr.h> +#include <mdelay.h> +#include <xilinx_v5_icap.h> +#include <nonstdio.h> + +eeprom_boot_info_t eeprom_shadow; + +static eeprom_boot_info_t eeprom_default = { +  .magic = EEPROM_BOOT_INFO_MAGIC, +  .nattempts = 1, +  .next_boot.fpga_image_number = 0, +  .next_boot.firmware_image_number = 0, +  .default_boot.fpga_image_number = 0, +  .default_boot.firmware_image_number = 0 +}; + +eeprom_boot_info_t * +_bc_get_eeprom_shadow(void) +{ +  return &eeprom_shadow; +} + + +bool +_bc_write_eeprom_shadow(void) +{ +  return eeprom_write(I2C_ADDR_MBOARD, BOOT_INFO_OFFSET, &eeprom_shadow, sizeof(eeprom_shadow)); +} + +void +bootconfig_init(void) +{ +  if (!eeprom_read(I2C_ADDR_MBOARD, BOOT_INFO_OFFSET, &eeprom_shadow, sizeof(eeprom_shadow)) +      || eeprom_shadow.magic != EEPROM_BOOT_INFO_MAGIC){ +    eeprom_shadow = eeprom_default; +    _bc_write_eeprom_shadow(); +  } +} + +bootconfig_t  +bootconfig_get_default(void) +{ +  return eeprom_shadow.default_boot; +} + +bool +bootconfig_set_default(bootconfig_t bc) +{ +  if (!validate_bootconfig(bc)) +    return false; + +  eeprom_shadow.default_boot  = bc; +  eeprom_shadow.next_boot  = bc; +  return _bc_write_eeprom_shadow(); +} + +void +bootconfig_boot(bootconfig_t bc) +{ +  if (!validate_bootconfig(bc)) +    return; + +  eeprom_shadow.next_boot = bc; +  eeprom_shadow.nattempts = 1; +  _bc_write_eeprom_shadow(); + +  if (1){ +    puts("\nbootconfig: chaining to FPGA slot 0 bootloader"); +    mdelay(100); +  } + +  while (1){ +    // Reload fpga with code from SPI flash address 0x0. +    icap_reload_fpga(0x00000000); +  } +}   diff --git a/firmware/zpu/lib/clock_bits.h b/firmware/zpu/lib/clock_bits.h new file mode 100644 index 000000000..d2052e941 --- /dev/null +++ b/firmware/zpu/lib/clock_bits.h @@ -0,0 +1,55 @@ +// +// Copyright 2010 Ettus Research LLC +// +/* + * 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. + */ +#ifndef INCLUDED_USRP2_CLOCK_BITS_H +#define INCLUDED_USRP2_CLOCK_BITS_H + +#define	_MC_WE_LOCK			0x0001 +#define	_MC_MIMO_CLK_INPUT		0x0002		// else SMA input + +/* + * Derived masks (use these): + * + * We get our input from 1 of three places: + *  Our free running oscilator, our SMA connector, or from the MIMO connector + */ +#define	MC_WE_DONT_LOCK			0x0000 +#define	MC_WE_LOCK_TO_SMA		(_MC_WE_LOCK | 0) +#define	MC_WE_LOCK_TO_MIMO		(_MC_WE_LOCK | _MC_MIMO_CLK_INPUT) + +/* + * Independent of the source of the clock, we may or may not drive our + * clock onto the mimo connector.  Note that there are dedicated clock + * signals in each direction, so disaster doesn't occurs if we're + * unnecessarily providing clock. + */ +#define	MC_PROVIDE_CLK_TO_MIMO		0x0004 + +#define MC_REF_CLK_MASK          0x0f + +#define MC_PPS_SOURCE_SMA        (0x00 << 4) +#define MC_PPS_SOURCE_MIMO       (0x01 << 4) + +#define MC_PPS_POLARITY_NEG      (0x00 << 5) +#define MC_PPS_POLARITY_POS      (0x01 << 5) + +#endif /* INCLUDED_USRP2_CLOCK_BITS_H */ diff --git a/firmware/zpu/lib/clocks.c b/firmware/zpu/lib/clocks.c new file mode 100644 index 000000000..2b352a385 --- /dev/null +++ b/firmware/zpu/lib/clocks.c @@ -0,0 +1,266 @@ +/* -*- 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 <clocks.h> + +#include "memory_map.h" +#include "ad9510.h" +#include "spi.h" +#include "u2_init.h" + +//USRP2PLUS clocks: +//Clock 0: testclk +//Clock 1: FPGA clk +//Clock 2: ADC clk +//Clock 3: DAC clk +//Clock 4: SER clk +//Clock 5: TX dboard clk +//Clock 6: EXP clk +//Clock 7: RX dboard clk + +//TODO: should have enough brains to init the FPGA clock for USRP2+. all others are suspect. +//note that without EEPROM support u2_hw_rev_major is going to be incorrect. + +void  +clocks_init(void) +{ +  // Set up basic clocking functions in AD9510 +  ad9510_write_reg(0x45, 0x01); // CLK2 drives distribution + +  //enable the 100MHz clock output to the FPGA for 50MHz CPU clock +  clocks_enable_fpga_clk(true, 1); + +  spi_wait(); + +  // Set up PLL for 10 MHz reference +  // Reg 4, A counter, Don't Care +//  ad9510_write_reg(0x05, 0x00);  // Reg 5, B counter MSBs, 0 +//  ad9510_write_reg(0x06, 0x05);  // Reg 6, B counter LSBs, 5 +  // Reg 7, Loss of reference detect, doesn't work yet, 0 +//  ad9510_write_reg(0x5A, 0x01); // Update Regs + +  // Primary clock configuration +//  clocks_mimo_config(MC_WE_DONT_LOCK); + + +  //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; + +  // Set up other clocks +  //clocks_enable_test_clk(false, 0); +  //clocks_enable_tx_dboard(false, 0); +  //clocks_enable_rx_dboard(false, 0); +//  clocks_enable_eth_phyclk(false, 0); //PHY clk is separate now (u2r4, u2p) + +  // Enable clock to ADCs and DACs +  //clocks_enable_dac_clk(true, 1); +  //clocks_enable_adc_clk(true, 1); +} + +/* +void +clocks_mimo_config(int flags) +{ +  if (flags & _MC_WE_LOCK){ +    // Reg 8, Charge pump on, dig lock det, positive PFD, 47 +    ad9510_write_reg(0x08, 0x47); +  } +  else { +    // Reg 8, Charge pump off, dig lock det, positive PFD +    ad9510_write_reg(0x08, 0x00); +  } +   +  // Reg 9, Charge pump current, 0x40=3mA, 0x00=650uA +  ad9510_write_reg(0x09, 0x00); +  // Reg A, Prescaler of 2, everything normal 04 +  ad9510_write_reg(0x0A, 0x04); +  // Reg B, R Div MSBs, 0 +  ad9510_write_reg(0x0B, 0x00); +  // Reg C, R Div LSBs, 1 +  ad9510_write_reg(0x0C, 0x01); +  // Reg D, Antibacklash, Digital lock det, 0 + +  ad9510_write_reg(0x5A, 0x01); // Update Regs + +  spi_wait(); +   +  // Allow for clock switchover +  // The below masks include 0x10, which issues a reset to the DCM.   +  if (flags & _MC_WE_LOCK){		// WE LOCK +    if (flags & _MC_MIMO_CLK_INPUT) { +      // Turn on ref output and choose the MIMO connector +      output_regs->clk_ctrl = 0x15;   +    } +    else { +      // turn on ref output and choose the SMA +      output_regs->clk_ctrl = 0x1C;  +    } +  } +  else {				// WE DONT LOCK +    // Disable both ext clk inputs +    output_regs->clk_ctrl = 0x10; +  } + +  // Do we drive a clock onto the MIMO connector? +//  if (flags & MC_PROVIDE_CLK_TO_MIMO) +//    clocks_enable_clkexp_out(true,10); +//  else +//    clocks_enable_clkexp_out(false,0);  +} +*/ + +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 0 +/*void +clocks_enable_test_clk(bool enable, int divisor) +{ +  clocks_enable_XXX_clk(enable,divisor,0x3C,0x48,CLOCK_MODE_PECL); +}*/ + +// Clock 1 +void +clocks_enable_fpga_clk(bool enable, int divisor) +{ +  clocks_enable_XXX_clk(enable,divisor,0x3D,0x4A,CLOCK_MODE_PECL); +} +/* +// Clock 2 on Rev 3, Clock 5 on Rev 4, Clock 6 on USRP2+ +void +clocks_enable_clkexp_out(bool enable, int divisor) +{ +  if(u2_hw_rev_major == 3) +    clocks_enable_XXX_clk(enable,divisor,0x3E,0x4C,CLOCK_MODE_PECL); +  else if(u2_hw_rev_major == 4) { +    ad9510_write_reg(0x34,0x00);  // Turn on fine delay +    ad9510_write_reg(0x35,0x00);  // Set Full Scale to nearly 10ns +    ad9510_write_reg(0x36,0x1c);  // Set fine delay.  0x20 is midscale +    clocks_enable_XXX_clk(enable,divisor,0x41,0x52,CLOCK_MODE_LVDS); +  } +	else if(u2_hw_rev_major == 10) { +		ad9510_write_reg(0x34, 0x00); +		ad9510_write_reg(0x35, 0x00); +		ad9510_write_reg(0x36, 0x1C); +		clocks_enable_XXX_clk(enable, divisor, 0x42, 0x52, CLOCK_MODE_LVDS); +	} +  else +    putstr("ERR (clocks_enable_clkexp_out): Invalid hw rev, don't know what to do!\n"); +} +*/ +/* +// Clock 5 on Rev 3, none (was 2) on Rev 4, none on USRP2+ +void +clocks_enable_eth_phyclk(bool enable, int divisor) +{ +  if(u2_hw_rev_major == 3) +    clocks_enable_XXX_clk(enable,divisor,0x41,0x52,CLOCK_MODE_LVDS); +  else if(u2_hw_rev_major == 4) +    clocks_enable_XXX_clk(enable,divisor,0x3E,0x4C,CLOCK_MODE_PECL); +  else +    putstr("(clocks_enable_eth_phyclk): no eth PHY clock or invalid hw rev\n"); //not really an error +} +*/ +// Clock 3 +/*void +clocks_enable_dac_clk(bool enable, int divisor) +{ +  clocks_enable_XXX_clk(enable,divisor,0x3F,0x4E,CLOCK_MODE_PECL); +}*/ + +// Clock 4 +/*void +clocks_enable_adc_clk(bool enable, int divisor) +{ +  clocks_enable_XXX_clk(enable,divisor,0x40,0x50,CLOCK_MODE_LVDS); +}*/ + +// Clock 6 +/*void +clocks_enable_tx_dboard(bool enable, int divisor) +{ +  clocks_enable_XXX_clk(enable,divisor,0x42,0x54,CLOCK_MODE_CMOS); +}*/ + +// Clock 7 +/*void +clocks_enable_rx_dboard(bool enable, int divisor) +{ +  clocks_enable_XXX_clk(enable,divisor,0x43,0x56,CLOCK_MODE_CMOS); +}*/ diff --git a/firmware/zpu/lib/clocks.h b/firmware/zpu/lib/clocks.h new file mode 100644 index 000000000..28d1d542f --- /dev/null +++ b/firmware/zpu/lib/clocks.h @@ -0,0 +1,95 @@ +// +// Copyright 2010 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 + +/* + * Routines to configure our multitude of clocks + */ + +#include <stdbool.h> +#include "clock_bits.h" + + +/*! + * One time call to initialize all clocks to a reasonable state.  We + * come out of here using our free running 100MHz oscilator and not + * providing a clock to the MIMO connector (CMC_WE_DONT_LOCK) + */ +void clocks_init(void); + + +/*! + * \brief MIMO clock configuration. + * + * Configure our master clock source, and whether or not we drive a + * clock onto the mimo connector.  See MC_flags in usrp2_mimo_config.h. + */ +//void clocks_mimo_config(int flags); + +/*! + * \brief Lock Detect -- Return True if our PLL is locked + */ +bool clocks_lock_detect(); + +/*! + * \brief Enable or disable test clock (extra clock signal) + */ +//void clocks_enable_test_clk(bool enable, int divisor); + +/*! + * \brief Enable or disable fpga clock.  Disabling would wedge and require a power cycle. + */ +void clocks_enable_fpga_clk(bool enable, int divisor); + +/*! + * \brief Enable or disable clock output sent to MIMO connector + */ +//void clocks_enable_clkexp_out(bool enable, int divisor); + +/*! + * \brief Enable or disable ethernet phyclk, should always be disabled + */ +//void clocks_enable_eth_phyclk(bool enable, int divisor); + +/*! + * \brief Enable or disable clock to DAC + */ +//void clocks_enable_dac_clk(bool enable, int divisor); + +/*! + * \brief Enable or disable clock to ADC + */ +//void clocks_enable_adc_clk(bool enable, int divisor); + +/*! + * \brief Enable or disable clock to Rx daughterboard + */ +//void clocks_enable_rx_dboard(bool enable, int divisor); + + +/*! + * \brief Enable or disable clock to Tx daughterboard + */ +//void clocks_enable_tx_dboard(bool enable, int divisor); + + +#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..ff5d04f4d --- /dev/null +++ b/firmware/zpu/lib/eth_addrs.c @@ -0,0 +1,146 @@ +/* + * Copyright 2010 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 "i2c.h" +#include "usrp2/fw_common.h" + +//////////////////////////////////////////////////////////////////////// +// EEPROM Layout +//////////////////////////////////////////////////////////////////////// +#define USRP2_EE_MBOARD_MAC_ADDR 0x02 //6 bytes +#define USRP2_EE_MBOARD_IP_ADDR  0x0C //uint32, big-endian + +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; +} + +//////////////////// MAC Addr Stuff /////////////////////// + +static int8_t src_mac_addr_initialized = false; + +static const eth_mac_addr_t default_mac_addr = {{ +    0x00, 0x50, 0xC2, 0x85, 0x3f, 0xff +  }}; + +static eth_mac_addr_t src_mac_addr = {{ +    0x00, 0x50, 0xC2, 0x85, 0x3f, 0xff +  }}; +   +void set_default_mac_addr(void) +{ +    src_mac_addr_initialized = true; +    src_mac_addr = default_mac_addr; +} + +const eth_mac_addr_t * +ethernet_mac_addr(void) +{ +  if (!src_mac_addr_initialized){    // fetch from eeprom +    src_mac_addr_initialized = true; + +    // if we're simulating, don't read the EEPROM model, it's REALLY slow +    if (hwconfig_simulation_p()) +      return &src_mac_addr; + +    eth_mac_addr_t tmp; +    bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, &tmp, sizeof(tmp)); +    if (!ok || unprogrammed(&tmp, sizeof(tmp))){ +      // use the default +    } +    else +      src_mac_addr = tmp; +  } + +  return &src_mac_addr; +} + +bool +ethernet_set_mac_addr(const eth_mac_addr_t *t) +{ +  bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, t, sizeof(eth_mac_addr_t)); +  if (ok){ +    src_mac_addr = *t; +    src_mac_addr_initialized = true; +    //eth_mac_set_addr(t); //this breaks the link +  } + +  return ok; +} + +//////////////////// IP Addr Stuff /////////////////////// + +static int8_t src_ip_addr_initialized = false; + +static const struct ip_addr default_ip_addr = { +    (192 << 24 | 168 << 16 | 10 << 8 | 2 << 0) +}; + +static struct ip_addr src_ip_addr = { +    (192 << 24 | 168 << 16 | 10 << 8 | 2 << 0) +}; + +void set_default_ip_addr(void) +{ +    src_ip_addr_initialized = true; +    src_ip_addr = default_ip_addr; +} + +const struct ip_addr *get_ip_addr(void) +{ +  if (!src_ip_addr_initialized){    // fetch from eeprom +    src_ip_addr_initialized = true; + +    // if we're simulating, don't read the EEPROM model, it's REALLY slow +    if (hwconfig_simulation_p()) +      return &src_ip_addr; + +    struct ip_addr tmp; +    bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, &tmp, sizeof(tmp)); +    if (!ok || unprogrammed(&tmp, sizeof(tmp))){ +      // use the default +    } +    else +      src_ip_addr = tmp; +  } + +  return &src_ip_addr; +} + +bool set_ip_addr(const struct ip_addr *t){ +  bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, t, sizeof(struct ip_addr)); +  if (ok){ +    src_ip_addr = *t; +    src_ip_addr_initialized = true; +  } + +  return ok; +} 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/eth_mac_regs.h b/firmware/zpu/lib/eth_mac_regs.h new file mode 100644 index 000000000..d680f8de0 --- /dev/null +++ b/firmware/zpu/lib/eth_mac_regs.h @@ -0,0 +1,62 @@ +/* -*- 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_REGS_H +#define INCLUDED_ETH_MAC_REGS_H + +/* + * Simple GEMAC + * + */ +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. + +#endif /* INCLUDED_ETH_MAC_REGS_H */ diff --git a/firmware/zpu/lib/ethernet.h b/firmware/zpu/lib/ethernet.h new file mode 100644 index 000000000..52b297349 --- /dev/null +++ b/firmware/zpu/lib/ethernet.h @@ -0,0 +1,99 @@ +/* -*- 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_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); + +/*!set mac addr to default*/ +void set_default_mac_addr(void); + +/*! + * \brief write mac address to eeprom and begin using it + */ +bool ethernet_set_mac_addr(const eth_mac_addr_t *t); + +/*! + * \returns IP address + */ +const struct ip_addr *get_ip_addr(void); + +/*!set ip addr to default*/ +void set_default_ip_addr(void); + +/*! + * \brief write ip address to eeprom and begin using it + */ +bool set_ip_addr(const struct ip_addr *t); + + +/* + * \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..11f4bafec --- /dev/null +++ b/firmware/zpu/lib/ethertype.h @@ -0,0 +1,27 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 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/gdbstub2.c b/firmware/zpu/lib/gdbstub2.c new file mode 100644 index 000000000..4c63dfce2 --- /dev/null +++ b/firmware/zpu/lib/gdbstub2.c @@ -0,0 +1,506 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 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/>. + */ + +/* + * Implement a eensy weensy part of the GDB Remote Serial Protocol + * + * See Appendix D of the GDB manual + * + *   m<addr>,<length> 		-- read <length> bytes of memory starting at <addr> + *     Reply: + *     XX...		XX... is memory contents in hex + *     ENN		ENN   NN is a hex error number + * + *   M<addr>,<length>:XX...     -- write memory, data in hex + *     Reply: + *     OK		for success + *     ENN		for an error.  NN is a hex error number + * + *   X<addr>,<length>:XX...     -- write memory, data in binary + *     Reply: + *     OK		for success + *     ENN		for an error.  NN is a hex error number + * + *   c<addr>			-- continue.  <addr> is the address to resume (goto). + *     Reply: <none> + * + *   \x80 New Format... + */ + +#include "gdbstub2.h" +#include "loader_parser.h" +#include "hal_uart.h" +#include <stdbool.h> +#include <stddef.h> + +#define MAX_PACKET	1024 + +/* + * Get raw character from serial port, no echo. + */ +static inline int  +gdb_getc(void) +{ +  return hal_uart_getc(); +} + +/* + * Put character to serial port.  Raw output. + */ +static inline void +gdb_putc(int ch) +{ +  hal_uart_putc(ch); +} + +// ------------------------------------------------------------------------ + +#define	GDB_ESCAPE 0x7d + +static unsigned char hex_table[16] = {  +  '0', '1', '2', '3', '4', '5', '6', '7', +  '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' +}; + +static int +put_hex8_checksum(int ch, int checksum) +{ +  unsigned char t = hex_table[(ch >> 4) & 0xf]; +  checksum += t; +  gdb_putc(t); + +  t = hex_table[ch & 0xf]; +  checksum += t; +  gdb_putc(t); +  return checksum; +} + +static void +put_hex8(int ch) +{ +  put_hex8_checksum(ch, 0); +} + +static bool +hex4_to_bin(int ch, int *value) +{ +  if ('0' <= ch && ch <= '9'){ +    *value = ch - '0'; +    return true; +  } +  if ('a' <= ch && ch <= 'f'){ +    *value = ch - 'a' + 10; +    return true; +  } +  if ('A' <= ch && ch <= 'F'){ +    *value = ch - 'A' + 10; +    return true; +  } +  *value = 0; +  return false; +} + +static bool +hex8_to_bin(const unsigned char *s, int *value) +{ +  int v0, v1; +  if (hex4_to_bin(s[0], &v0) && hex4_to_bin(s[1], &v1)){ +    *value = (v0 << 4) | v1; +    return true; +  } +  return false; +} + +static bool +hex_to_bin_array(unsigned char *binary_data, const unsigned char *hex_data, size_t nbytes) +{ +  for (size_t i = 0; i < nbytes; i++){ +    int t; +    if (!hex8_to_bin(&hex_data[2*i], &t)) +      return false; +    binary_data[i] = t; +  } +  return true; +} + +static bool +needs_escaping(int ch) +{ +  return ch == '$' || ch == '#' || ch == GDB_ESCAPE; +} + +/* + * \brief Wait for a packet.   + * \param[out] pkt_buf gets the received packet payload. + * \param[in]  max_size is the maximum number of bytes to write into \p pkt_buf. + * \param[out] actual_size is the number of bytes written to \p pkt_buf. + * + * \returns true iff the payload fits and the checksum is OK. + * + * Packets have this format: + * + *  $<packet-data>#<checksum> + * + * Where <packet-data> is anything and <checksum> is a two byte hex + * checksum.  In <packet-data> '$', '#' and 0x7d are escaped with 0x7d. + * The checksum is computed as the modulo 256 sum of all characters + * btween the leading '$' and the trailing '#' (an 8-bit unsigned + * checksum). + */ +static bool +get_packet(unsigned char *pkt_buf, size_t max_size, size_t *actual_size) +{ +  typedef enum states { +    LOOKING_FOR_DOLLAR, +    LOOKING_FOR_HASH, +    CSUM1, +    CSUM2, +  } state_t; + +  *actual_size = 0; +  unsigned char csum[2] = {0, 0}; +  state_t state = LOOKING_FOR_DOLLAR; +  size_t  pi = 0; + +  while (1){ +    int ch = gdb_getc(); + +    switch (state){ +    case LOOKING_FOR_DOLLAR: +      if (ch == '$'){ +	pi = 0; +	state = LOOKING_FOR_HASH; +      } +      else if (ch == '#'){	// most likely missed the $ +	return false; +      } +      break; +	 +    case LOOKING_FOR_HASH: +      if (ch == '$'){ +	return false; +      } +      else if (ch == '#'){ +	state = CSUM1; +      } +      else { +	if (pi >= max_size)	// payload too big +	  return false; + +	if (ch == GDB_ESCAPE) +	  ch = gdb_getc(); + +	pkt_buf[pi++] = ch; +      } +      break; +       +    case CSUM1: +      csum[0] = ch; +      state = CSUM2; +      break; + +    case CSUM2: +      csum[1] = ch; +      *actual_size = pi; + +      // accept .. as a correct checksum +      if (csum[0] == '.' && csum[1] == '.') +	return true; + +      int expected_checksum; +      if (!hex8_to_bin(csum, &expected_checksum)) +	return false; + +      int checksum = 0; +      for (size_t i = 0; i < pi; i++) +	checksum += pkt_buf[i]; + +      checksum &= 0xff; +      return checksum == expected_checksum; +    } +  } +} + +static void +put_packet_trailer(int checksum) +{ +  gdb_putc('#'); +  put_hex8(checksum & 0xff); +  gdb_putc('\r'); +  gdb_putc('\n'); +} + +static void +put_packet(const unsigned char *pkt_buf, size_t size) +{ +  gdb_putc('$'); + +  int checksum = 0; +  for (size_t i = 0; i < size; i++){ +    int ch = pkt_buf[i]; +    if (needs_escaping(ch)) +      gdb_putc(GDB_ESCAPE); +    gdb_putc(ch); +    checksum += ch; +  } +  put_packet_trailer(checksum); +} + +/*! + * Read a hex number + * + * \param[inout] bufptr - pointer to pointer to buffer (updated on return) + * \param[in] end - one past end of valid data in buf + * \param[out] value - the parsed value + * + * \returns true iff a valid hex number was read from bufptr + */ +static bool +parse_number(const unsigned char **bufptr, const unsigned char *end, unsigned int *value) +{ +  const unsigned char *buf = *bufptr; +  unsigned int v = 0; +  bool valid = false; +  int nibble; + +  while (buf < end && hex4_to_bin(*buf, &nibble)){ +    valid = true; +    v = (v << 4) | nibble; +    buf++; +  } +   +  *value = v; +  *bufptr = buf; +  return valid; +} + +static bool +parse_char(const unsigned char **bufptr, const unsigned char *end, unsigned char *ch) +{ +  const unsigned char *buf = *bufptr; +  if (buf < end){ +    *ch = *buf++; +    *bufptr = buf; +    return true; +  } +  return false; +} + +static bool +expect_char(const unsigned char **bufptr, const unsigned char *end, unsigned char expected) +{ +  unsigned char ch; +  return parse_char(bufptr, end, &ch) && ch == expected; +} + +static bool +expect_end(const unsigned char **bufptr, const unsigned char *end) +{ +  return *bufptr == end; +} + +static bool +parse_addr_length(const unsigned char **bufptr, const unsigned char *end, +		  unsigned int *addr, unsigned int *length) +{ +  return (parse_number(bufptr, end, addr) +	  && expect_char(bufptr, end, ',') +	  && parse_number(bufptr, end, length)); +} + +static void +put_error(int error) +{ +  unsigned char buf[3]; +  buf[0] = 'E'; +  buf[1] = hex_table[(error >> 4) & 0xf]; +  buf[2] = hex_table[error & 0xf]; +   +  put_packet(buf, sizeof(buf)); +} + +static void +put_ok(void) +{ +  const unsigned char buf[2] = "OK"; +  put_packet(buf, sizeof(buf)); +} + +/* + * Read memory and send the reply. + * We do it on the fly so that our packet size is effectively unlimited + */ +static void +read_memory(unsigned int addr, unsigned int nbytes) +{ +  int checksum = 0; +  gdb_putc('$'); + +  if ((addr & 0x3) == 0 && (nbytes & 0x3) == 0){	// word aligned +    union { +      unsigned int	i; +      unsigned char	c[4]; +    } u; + +    unsigned int *p = (unsigned int *) addr; +    unsigned int length = nbytes / 4; + +    for (unsigned int i = 0; i < length; i++){ +      u.i = p[i];	// do a word read +      checksum = put_hex8_checksum(u.c[0], checksum); +      checksum = put_hex8_checksum(u.c[1], checksum); +      checksum = put_hex8_checksum(u.c[2], checksum); +      checksum = put_hex8_checksum(u.c[3], checksum); +    } +  } +  else {						// byte aligned +    unsigned char *p = (unsigned char *) addr; +    for (unsigned int i = 0; i < nbytes; i++) +      checksum = put_hex8_checksum(p[i], checksum); +  } + +  put_packet_trailer(checksum); +} + +static unsigned int +get_unaligned_int(const unsigned char *p) +{ +  // we're bigendian +  return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]); +} + +static bool +write_memory(unsigned int addr, size_t nbytes, +	     const unsigned char *data) +{ +  if ((addr & 0x3) == 0 && (nbytes & 0x3) == 0){	// word-aligned dst +    unsigned int *dst = (unsigned int *) addr; +    size_t length = nbytes / 4; +    for (size_t i = 0; i < length; i++){ +      unsigned int t = get_unaligned_int(&data[4*i]); +      dst[i] = t;					// word writes +    } +  } +  else {						// non-word-aligned dst +    unsigned char *dst = (unsigned char *) addr; +    for (size_t i = 0; i < nbytes; i++){ +      dst[i] = data[i]; +    } +  } +  return true; +} + +void +gdbstub2_main_loop(void) +{ +  unsigned char inpkt[MAX_PACKET + 24]; +  unsigned char binary_data[MAX_PACKET/2] __attribute__((aligned (4))); + +  hal_uart_set_mode(UART_MODE_RAW); //tell UART HAL not to map \n to \r\n + +  while (1){ +    size_t	inpkt_len; +    bool ok = get_packet(inpkt, sizeof(inpkt), &inpkt_len); +    if (!ok){ +      gdb_putc('-'); +      continue; +    } +    gdb_putc('+'); + +    const unsigned char *buf = inpkt; +    const unsigned char *end = inpkt + inpkt_len; +    unsigned char ch; + +    if (!parse_char(&buf, end, &ch)){	// empty packet +      put_packet(0, 0); +      continue; +    } + +    unsigned int addr; +    unsigned int length; + +    switch(ch){ +    case 'm':		// m<addr>,<length>  -- read <length> bytes starting at <addr> +      if (!(parse_addr_length(&buf, end, &addr, &length) && expect_end(&buf, end))){ +	put_error(1); +      } +      else { +	read_memory(addr, length); +      } +      break; + +    case 'M':		// M<addr>,<length>:XX...  -- write <length> bytes starting at <addr> +			//   XX... is the data in hex +      if (!(parse_addr_length(&buf, end, &addr, &length) +	    && expect_char(&buf, end, ':') +	    && (end - buf) == 2 * length)){ +	put_error(1); +      } +      else { +	if (!hex_to_bin_array(binary_data, buf, length)) +	  put_error(2); +	else if (!write_memory(addr, length, binary_data)) +	  put_error(3); +	else +	  put_ok(); +      } +      break; + +    case 'X':		// X<addr>,<length>:XX...  -- write <length> bytes starting at <addr> +			//   XX... is the data in binary +      if (!(parse_addr_length(&buf, end, &addr, &length) +	    && expect_char(&buf, end, ':') +	    && (end - buf) == length)){ +	put_error(1); +      } +      else { +	if (!write_memory(addr, length, buf)) +	  put_error(3); +	else +	  put_ok(); +      } +      break; + +    case 'c':		// c<addr>	-- continue.  <addr> is the address to resume (goto). +      if (!(parse_number(&buf, end, &addr) +	    && expect_end(&buf, end))){ +	put_error(1); +      } +      else { +	typedef void (*fptr_t)(void); +	(*(fptr_t) addr)();	// most likely no return +      } +      break; +/* +    case 0x80: +      { +	unsigned char *output = binary_data;  // reuse +	size_t sizeof_output = sizeof(binary_data); +	size_t actual_olen; +	loader_parser(buf, end-buf, +		      output, sizeof_output, &actual_olen); +	put_packet(output, actual_olen); +      } +      break; +*/ +    default:		// unknown packet type +      put_packet(0, 0); +      break; +    } +  } +} diff --git a/firmware/zpu/lib/gdbstub2.h b/firmware/zpu/lib/gdbstub2.h new file mode 100644 index 000000000..15cdde939 --- /dev/null +++ b/firmware/zpu/lib/gdbstub2.h @@ -0,0 +1,25 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 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_GDBSTUB_H +#define INCLUDED_GDBSTUB_H + +void gdbstub2_main_loop(void); + +#endif /* INCLUDED_GDBSTUB_H */ + diff --git a/firmware/zpu/lib/hal_io.c b/firmware/zpu/lib/hal_io.c new file mode 100644 index 000000000..be4c570c7 --- /dev/null +++ b/firmware/zpu/lib/hal_io.c @@ -0,0 +1,271 @@ +/* -*- 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_timeout(hal_uart_name_t u, char * const s, int len) +{ +  char *x = s; + +  while(((*x=(char)hal_uart_getc_timeout(u)) != '\n') && (*x != -1) && ((x-s) < len)) x++; +  *x = 0; +  //printf("Returning from fngets() with string %d of length %d\n", s[0], x-s); +  return (x-s); +} + +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..574df7d3e --- /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_timeout(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..f0921f4f0 --- /dev/null +++ b/firmware/zpu/lib/hal_uart.c @@ -0,0 +1,120 @@ +/* -*- 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_timeout(hal_uart_name_t u) +{ +  int timeout = 0; +  while (((uart_regs[u].rxlevel) == 0) && (timeout++ < HAL_UART_TIMEOUT_MS)) +    mdelay(1); +  return (timeout >= HAL_UART_TIMEOUT_MS) ? -1 : uart_regs[u].rxchar; //return -1 if nothing there, cause fngets to quit +} + +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..758c8cb5e --- /dev/null +++ b/firmware/zpu/lib/hal_uart.h @@ -0,0 +1,94 @@ +/* -*- 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 + +#define HAL_UART_TIMEOUT_MS 300 + +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 Blocking read of next char from serial port with timeout + */ +int hal_uart_getc_timeout(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..958acf3f5 --- /dev/null +++ b/firmware/zpu/lib/mdelay.c @@ -0,0 +1,74 @@ +/* -*- 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" + +// Delay about one millisecond. +// +// Need 33,333 cycles at 33 MHz. +// Each time around the loop is 10 cycles +// + +#define LOOPCNT(wb_div) (MASTER_CLK_RATE/(wb_div) / 10000) + +inline static void +delay_1ms(int loop_count) +{ +/*  int	i; +  for (i = 0; i < loop_count; i++){ +    asm volatile ("or  r0, r0, r0\n\ +		   or  r0, r0, r0\n\ +		   or  r0, r0, r0\n\ +		   or  r0, r0, r0\n\ +		   or  r0, r0, r0\n\ +		   or  r0, r0, r0\n\ +		   or  r0, r0, r0\n"); +  } +*/ +} + +// delay about ms milliseconds +void +mdelay(int ms) +{ +  static int loop_count = -1; + +  if (hwconfig_simulation_p()) +    return; + +  if (loop_count < 0){ +    // set correct loop_count +    static unsigned short lc[8] = { +      0, +      LOOPCNT(1), +      LOOPCNT(2), +      LOOPCNT(3), +      LOOPCNT(4), +      LOOPCNT(5), +      LOOPCNT(6), +      LOOPCNT(7) +    }; + +    loop_count = lc[hwconfig_wishbone_divisor() & 0x7]; +  } + +  int i; +  for (i = 0; i < ms; i++) +    delay_1ms(loop_count); +} 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/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..b44fb68f7 --- /dev/null +++ b/firmware/zpu/lib/net/eth_mac_addr.h @@ -0,0 +1,29 @@ +/* + * Copyright 2009 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..c1ca280d9 --- /dev/null +++ b/firmware/zpu/lib/net_common.c @@ -0,0 +1,463 @@ +/* -*- 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/>. + */ + +#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" + +static const bool debug = false; + +static const eth_mac_addr_t BCAST_MAC_ADDR = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; + +//used in the top level application... +struct socket_address fp_socket_src, fp_socket_dst; + +// ------------------------------------------------------------------------ + +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; +} + +//------------------------------------------------------------------------- + +#define	MAX_UDP_LISTENERS	6 + +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; +  } +} + +// ------------------------------------------------------------------------ + + +/*! + * 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) +{ + +  // Assemble the header +  padded_eth_hdr_t	ehdr; +  ehdr.pad = 0; +  ehdr.dst = dst; +  ehdr.src = _local_mac_addr; +  ehdr.ethertype = ethertype; + +  uint32_t *buff = (uint32_t *)pkt_ctrl_claim_outgoing_buffer(); + +  // Copy the pieces into the buffer +  uint32_t *p = buff; +  *p++ = 0x0;  				  // slow path +  memcpy_wa(p, &ehdr, sizeof(ehdr));      // 4 lines +  p += sizeof(ehdr)/sizeof(uint32_t); + + +  // FIXME modify memcpy_wa to do read/modify/write if reqd + +  if (len0 && ((len0 & 0x3) || (intptr_t) buf0 & 0x3)) +    printf("send_pkt: bad alignment of len0 and/or buf0\n"); + +  if (len1 && ((len1 & 0x3) || (intptr_t) buf1 & 0x3)) +    printf("send_pkt: bad alignment of len1 and/or buf1\n"); + +  if (len2 && ((len2 & 0x3) || (intptr_t) buf2 & 0x3)) +    printf("send_pkt: bad alignment of len2 and/or buf2\n"); + +  if (len0){ +    memcpy_wa(p, buf0, len0); +    p += len0/sizeof(uint32_t); +  } +  if (len1){ +    memcpy_wa(p, buf1, len1); +    p += len1/sizeof(uint32_t); +  } +  if (len2){ +    memcpy_wa(p, buf2, len2); +    p += len2/sizeof(uint32_t); +  } + +  size_t total_len = (p - buff) * sizeof(uint32_t); +  if (total_len < 60)		// ensure that we don't try to send a short packet +    total_len = 60; + +  pkt_ctrl_commit_outgoing_buffer(total_len/4); +  if (debug) printf("sent %d bytes\n", (int)total_len); +} + +unsigned int CHKSUM(unsigned int x, unsigned int *chksum) +{ +  *chksum += x; +  *chksum = (*chksum & 0xffff) + (*chksum>>16); +  *chksum = (*chksum & 0xffff) + (*chksum>>16); +  return x; +} + +static unsigned int +chksum_buffer(unsigned short *buf, int nshorts, unsigned int initial_chksum) +{ +  unsigned int chksum = initial_chksum; +  for (int i = 0; i < nshorts; i++) +    CHKSUM(buf[i], &chksum); + +  return chksum; +} + +void +send_ip_pkt(struct ip_addr dst, int protocol, +	    const void *buf0, size_t len0, +	    const void *buf1, size_t len1) +{ +  int ttl = 32; + +  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 */ +  ip._ttl_proto = (ttl << 8) | (protocol & 0xff); +  ip._chksum = 0; +  ip.src = _local_ip_addr; +  ip.dest = dst; + +  ip._chksum = ~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 || udp->dest != fp_socket_dst.port) return; + +      //end async update packets per second +      sr_tx_ctrl->cyc_per_up = 0; + +      //the end continuous streaming command +      sr_rx_ctrl->cmd = 1 << 31; //no samples now +      sr_rx_ctrl->time_secs = 0; +      sr_rx_ctrl->time_ticks = 0; //latch the command + +      //struct udp_hdr *udp = (struct udp_hdr *)((char *)icmp + 28); +      //printf("icmp port unr %d\n", udp->dest); +      putchar('i'); +    } +    else { +      //printf("icmp dst unr (code: %d)", icmp->code); +      putchar('i'); +    } +    break; + +  case ICMP_ECHO:{ +    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( +        (unsigned short *)&echo_reply, +        sizeof(echo_reply)/sizeof(short), +    0); +    send_ip_pkt( +        src, IP_PROTO_ICMP, &echo_reply, sizeof(echo_reply), +        ((uint8_t*)icmp) + sizeof(struct icmp_echo_hdr), +        len - sizeof(struct icmp_echo_hdr) +    ); +    break; +  } +  default: +    break; +  } +} + +static void __attribute__((unused)) +print_arp_ip(const unsigned char ip[4]) +{ +  printf("%d.%d.%d.%d", ip[0], ip[1], ip[2],ip[3]); +} + +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 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_arp_ip(p->ar_sip);    newline(); +    printf("ar_tha = "); print_mac_addr(p->ar_tha); newline(); +    printf("ar_tip = "); print_arp_ip(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_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 +} + +// ------------------------------------------------------------------------ + +void +print_ip(struct ip_addr ip) +{ +  unsigned int t = ntohl(ip.addr); +  printf("%d.%d.%d.%d", +	 (t >> 24) & 0xff, +	 (t >> 16) & 0xff, +	 (t >>  8) & 0xff, +	 t & 0xff); +} diff --git a/firmware/zpu/lib/net_common.h b/firmware/zpu/lib/net_common.h new file mode 100644 index 000000000..409022352 --- /dev/null +++ b/firmware/zpu/lib/net_common.h @@ -0,0 +1,49 @@ +/* -*- 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_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> + +/* + * 1's complement sum for IP and UDP headers + * + * init chksum to zero to start. + */ +unsigned int CHKSUM(unsigned int x, unsigned int *chksum); + +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); + +#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..6aca7ed9a --- /dev/null +++ b/firmware/zpu/lib/nonstdio.h @@ -0,0 +1,50 @@ +// +// Copyright 2010 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 unsigned char addr[6]); +void print_uint64(uint64_t v); + +void print_buffer(uint32_t *buf, size_t n); +//char *itoa(signed long value, char *result, int base); +//void reverse(char s[]); + +void print_ip_addr(const void *t); + +#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..a5659eb33 --- /dev/null +++ b/firmware/zpu/lib/pkt_ctrl.c @@ -0,0 +1,71 @@ +/* + * 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 "pkt_ctrl.h" +#include "memory_map.h" +#include <nonstdio.h> + +void pkt_ctrl_program_inspector( +    const struct ip_addr *ip_addr, uint16_t ctrl_port, uint16_t data_port +){ +    buffer_pool_ctrl->ip_addr = ip_addr->addr; +    buffer_pool_ctrl->ctrl_ports = ctrl_port; +    buffer_pool_ctrl->data_ports = data_port; +} + +void pkt_ctrl_set_routing_mode(pkt_ctrl_routing_mode_t mode){ +    switch(mode){ +    case PKT_CTRL_ROUTING_MODE_SLAVE: +        buffer_pool_ctrl->misc_ctrl = 0; +        break; +    case PKT_CTRL_ROUTING_MODE_MASTER: +        buffer_pool_ctrl->misc_ctrl = 1; +        break; +    } +} + +static inline bool is_status_bit_set(int bit){ +    return buffer_pool_status->status & (1 << bit); +} + +#define CPU_OUT_HS_BIT 0 //from packet router to CPU +#define CPU_INP_HS_BIT 1 //from CPU to packet router + +void *pkt_ctrl_claim_incoming_buffer(size_t *num_lines){ +    buffer_pool_ctrl->cpu_out_ctrl = 0; +    if (!is_status_bit_set(CPU_OUT_HS_BIT)) return NULL; +    *num_lines = (buffer_pool_status->status >> 16) & 0xffff; +    return buffer_ram(0); +} + +void pkt_ctrl_release_incoming_buffer(void){ +    buffer_pool_ctrl->cpu_out_ctrl = 1; +    while (is_status_bit_set(CPU_OUT_HS_BIT)){} +    buffer_pool_ctrl->cpu_out_ctrl = 0; +} + +void *pkt_ctrl_claim_outgoing_buffer(void){ +    buffer_pool_ctrl->cpu_inp_ctrl = 0; +    while (!is_status_bit_set(CPU_INP_HS_BIT)){} +    return buffer_ram(1); +} + +void pkt_ctrl_commit_outgoing_buffer(size_t num_lines){ +    buffer_pool_ctrl->cpu_inp_ctrl = ((num_lines & 0xffff) << 16) | 1; +    while (is_status_bit_set(CPU_INP_HS_BIT)){} +    buffer_pool_ctrl->cpu_inp_ctrl = 0; +} diff --git a/firmware/zpu/lib/pkt_ctrl.h b/firmware/zpu/lib/pkt_ctrl.h new file mode 100644 index 000000000..346e22094 --- /dev/null +++ b/firmware/zpu/lib/pkt_ctrl.h @@ -0,0 +1,63 @@ +/* + * 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_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, +    PKT_CTRL_ROUTING_MODE_MASTER, +} 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 ctrl_port, 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..29601c47c --- /dev/null +++ b/firmware/zpu/lib/print_addrs.c @@ -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/>. + */ +#include "nonstdio.h" + +void +print_mac_addr(const unsigned char addr[6]) +{ +  for(size_t i = 0; i < 6; i++){ +    if(i) putchar(':'); +    puthex8(addr[i]); +  } +} + +void print_ip_addr(const void *t){ +    uint8_t *p = (uint8_t *)t; +    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..af0d8a68f --- /dev/null +++ b/firmware/zpu/lib/spi.c @@ -0,0 +1,110 @@ +/* + * 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 "pic.h" +#include "nonstdio.h" + +//void (*volatile spi_callback)(void); //SPI callback when xfer complete. + +//static void spi_irq_handler(unsigned irq); + +void +spi_init(void)  +{ +  /* +   * f_sclk = f_wb / ((div + 1) * 2) +   */ +  spi_regs->div = 1;  // 0 = Div by 2 (25 MHz); 1 = Div-by-4 (12.5 MHz) +} + +void +spi_wait(void)  +{ +  while (spi_regs->ctrl & SPI_CTRL_GO_BSY) +    ; +} + +uint32_t +spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags)  +{ +  flags &= (SPI_CTRL_TXNEG | SPI_CTRL_RXNEG); +  int ctrl = SPI_CTRL_ASS | (SPI_CTRL_CHAR_LEN_MASK & length) | flags; + +  spi_wait(); + +  // Tell it which SPI slave device to access +  spi_regs->ss = slave & 0xffff; + +  // Data we will send +  spi_regs->txrx0 = data; + +  // Run it -- write once and rewrite with GO set +  spi_regs->ctrl = ctrl; +  spi_regs->ctrl = ctrl | SPI_CTRL_GO_BSY; + +  if(readback) { +    spi_wait(); +    return spi_regs->txrx0; +  } +  else +    return 0; +} + +/* +void spi_register_callback(void (*volatile callback)(void)) { +  spi_callback = callback; +} + +static void spi_irq_handler(unsigned irq) { +//  printf("SPI IRQ handler\n"); +//  uint32_t wat = spi_regs->ctrl; //read a register just to clear the interrupt +  //spi_regs->ctrl &= ~SPI_CTRL_IE; +  if(spi_callback) spi_callback(); //we could just use the PIC to register the user's callback, but this provides the ability to do other things later +} + +uint32_t spi_get_data(void) { +  return spi_regs->txrx0; +} + +bool  +spi_async_transact(int slave, uint32_t data, int length, uint32_t flags, void (*volatile callback)(void)) { +  flags &= (SPI_CTRL_TXNEG | SPI_CTRL_RXNEG); +  int ctrl = SPI_CTRL_ASS | SPI_CTRL_IE | (SPI_CTRL_CHAR_LEN_MASK & length) | flags; + +  if(spi_regs->ctrl & SPI_CTRL_GO_BSY) { +    printf("Async SPI busy!\n"); +    return false; //we don't wait on busy, we just return failure. we count on the host to not set up another transaction before the last one finishes. +  } + +  // Tell it which SPI slave device to access +  spi_regs->ss = slave & 0xffff; + +  // Data we will send +  spi_regs->txrx0 = data; + +  spi_register_callback(callback); +  pic_register_handler(IRQ_SPI, spi_irq_handler); + +  // Run it -- write once and rewrite with GO set +  spi_regs->ctrl = ctrl; +  spi_regs->ctrl = ctrl | SPI_CTRL_GO_BSY; + +  return true; +} +*/ diff --git a/firmware/zpu/lib/spi.h b/firmware/zpu/lib/spi.h new file mode 100644 index 000000000..71245150a --- /dev/null +++ b/firmware/zpu/lib/spi.h @@ -0,0 +1,77 @@ +/* -*- c -*- */ +/* + * 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 <memory_map.h> +#include <stdbool.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 SPIF_PUSH_RISE   0		// push tx data on rising edge of SCLK +#define SPIF_PUSH_FALL   SPI_CTRL_TXNEG	// push tx data on falling edge of SCLK +#define SPIF_LATCH_RISE  0		// latch rx data on rising edge of SCLK +#define SPIF_LATCH_FALL  SPI_CTRL_RXNEG	// latch rx data on falling edge of SCLK + + +uint32_t +spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags); + +//uint32_t spi_get_data(void); +//static void spi_irq_handler(unsigned irq); +//void spi_register_callback(void (*volatile callback)(void)); + +//bool  +//spi_async_transact(int slave, uint32_t data, int length, uint32_t flags, void (*volatile callback)(void)); + +// ---------------------------------------------------------------- +// Routines that manipulate the FLASH SPI BUS +// ---------------------------------------------------------------- + +/*! + * \brief One time call to initialize SPI + */ +void spif_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 spif_wait(void); + +uint32_t +spif_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..191a0e816 --- /dev/null +++ b/firmware/zpu/lib/u2_init.c @@ -0,0 +1,75 @@ +/* + * 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 +  hal_set_leds(0x0, 0x1f); +  mdelay(100); +  hal_set_leds(0x1f, 0x1f); +  mdelay(100); +  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..d25525bd2 --- /dev/null +++ b/firmware/zpu/lib/udp_fw_update.h @@ -0,0 +1,71 @@ +/* -*- 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_KTHXBAI = '~' + +} usrp2_fw_update_id_t; + +typedef struct { +  uint32_t proto_ver; +  uint32_t id; +  uint32_t seq; +  union { +      uint32_t ip_addr; +    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); | 
