diff options
Diffstat (limited to 'firmware/microblaze/lib')
33 files changed, 1581 insertions, 1495 deletions
diff --git a/firmware/microblaze/lib/.gitignore b/firmware/microblaze/lib/.gitignore deleted file mode 100644 index 5d838bf6c..000000000 --- a/firmware/microblaze/lib/.gitignore +++ /dev/null @@ -1,40 +0,0 @@ -*~ -/*-stamp -/*.a -/*.bin -/*.dump -/*.log -/*.rom -/.deps -/Makefile -/Makefile.in -/aclocal.m4 -/autom4te.cache -/blink_leds -/blink_leds2 -/build -/compile -/config.h -/config.h.in -/config.log -/config.status -/configure -/depcomp -/eth_test -/gen_eth_packets -/ibs_rx_test -/ibs_tx_test -/install-sh -/libtool -/ltmain.sh -/missing -/py-compile -/rcv_eth_packets -/run_tests.sh -/stamp-h1 -/test1 -/test_phy_comm -/timer_test -/buf_ram_test -/buf_ram_zero -/hello diff --git a/firmware/microblaze/lib/Makefile.am b/firmware/microblaze/lib/Makefile.am deleted file mode 100644 index b51d74463..000000000 --- a/firmware/microblaze/lib/Makefile.am +++ /dev/null @@ -1,87 +0,0 @@ -# -# 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 $(top_srcdir)/Makefile.common - -noinst_LIBRARIES = \ - libu2fw.a - -libu2fw_a_SOURCES = \ - abort.c \ - ad9510.c \ - bsm12.c \ - buffer_pool.c \ - clocks.c \ - dbsm.c \ - eeprom.c \ - ethernet.c \ - eth_mac.c \ - _exit.c \ - exit.c \ - hal_io.c \ - hal_uart.c \ - i2c.c \ - mdelay.c \ - memcpy_wa.c \ - memset_wa.c \ - nonstdio.c \ - pic.c \ - print_mac_addr.c \ - print_rmon_regs.c \ - print_buffer.c \ - printf.c \ - sd.c \ - spi.c \ - u2_init.c \ - net_common.c \ - arp_cache.c \ - banal.c - -noinst_HEADERS = \ - ad9510.h \ - bsm12.h \ - buffer_pool.h \ - clocks.h \ - dbsm.h \ - eth_mac.h \ - eth_mac_regs.h \ - eth_phy.h \ - ethernet.h \ - hal_io.h \ - hal_uart.h \ - i2c.h \ - mdelay.h \ - memcpy_wa.h \ - memory_map.h \ - memset_wa.h \ - nonstdio.h \ - pic.h \ - print_rmon_regs.h \ - sd.h \ - spi.h \ - stdint.h \ - stdio.h \ - u2_init.h \ - usrp2_bytesex.h \ - wb16550.h \ - net_common.h \ - if_arp.h \ - arp_cache.h \ - banal.h \ - ethertype.h diff --git a/firmware/microblaze/lib/Makefile.inc b/firmware/microblaze/lib/Makefile.inc new file mode 100644 index 000000000..0e88298b8 --- /dev/null +++ b/firmware/microblaze/lib/Makefile.inc @@ -0,0 +1,48 @@ +# +# 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/>. +# + +COMMON_SRCS = \ + $(top_srcdir)/lib/u2_init.c \ + $(top_srcdir)/lib/abort.c \ + $(top_srcdir)/lib/ad9510.c \ + $(top_srcdir)/lib/bsm12.c \ + $(top_srcdir)/lib/buffer_pool.c \ + $(top_srcdir)/lib/dbsm.c \ + $(top_srcdir)/lib/eeprom.c \ + $(top_srcdir)/lib/ethernet.c \ + $(top_srcdir)/lib/eth_mac.c \ + $(top_srcdir)/lib/_exit.c \ + $(top_srcdir)/lib/exit.c \ + $(top_srcdir)/lib/hal_io.c \ + $(top_srcdir)/lib/hal_uart.c \ + $(top_srcdir)/lib/i2c.c \ + $(top_srcdir)/lib/mdelay.c \ + $(top_srcdir)/lib/memcpy_wa.c \ + $(top_srcdir)/lib/memset_wa.c \ + $(top_srcdir)/lib/nonstdio.c \ + $(top_srcdir)/lib/pic.c \ + $(top_srcdir)/lib/print_mac_addr.c \ + $(top_srcdir)/lib/print_rmon_regs.c \ + $(top_srcdir)/lib/print_buffer.c \ + $(top_srcdir)/lib/printf.c \ + $(top_srcdir)/lib/ihex.c \ + $(top_srcdir)/lib/spi.c \ + $(top_srcdir)/lib/net_common.c \ + $(top_srcdir)/lib/arp_cache.c \ + $(top_srcdir)/lib/banal.c diff --git a/firmware/microblaze/lib/bootconfig.c b/firmware/microblaze/lib/bootconfig.c new file mode 100644 index 000000000..93adc05c2 --- /dev/null +++ b/firmware/microblaze/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/microblaze/lib/clock_bits.h b/firmware/microblaze/lib/clock_bits.h new file mode 100644 index 000000000..d2052e941 --- /dev/null +++ b/firmware/microblaze/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/microblaze/lib/clocks.c b/firmware/microblaze/lib/clocks.c deleted file mode 100644 index ccc4a7cc7..000000000 --- a/firmware/microblaze/lib/clocks.c +++ /dev/null @@ -1,239 +0,0 @@ -/* -*- 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" -#include "nonstdio.h" - -void -clocks_init(void) -{ - // Set up basic clocking functions in AD9510 - ad9510_write_reg(0x45, 0x00); // CLK2 drives distribution - - 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); - - // 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); - - // 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 - - 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() -{ - if(pic_regs->pending & PIC_CLKSTATUS) - return true; - return false; -} - -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 - -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_PECL : - enable_word = enable ? 0x08 : 0x0A; - break; - case CLOCK_MODE_LVDS : - enable_word = enable ? 0x02 : 0x03; - break; - case CLOCK_MODE_CMOS : - enable_word = enable ? 0x08 : 0x09; - 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 -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 - putstr("ERR: Invalid Rev\n"); -} - -// Clock 5 on Rev 3, none (was 2) on Rev 4 -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("ERR: Invalid Rev\n"); -} - -// 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/microblaze/lib/clocks.h b/firmware/microblaze/lib/clocks.h index 43d5a05c2..a285e03dd 100644 --- a/firmware/microblaze/lib/clocks.h +++ b/firmware/microblaze/lib/clocks.h @@ -26,7 +26,7 @@ */ #include <stdbool.h> -#include <usrp2_clock_bits.h> +#include "clock_bits.h" /*! diff --git a/firmware/microblaze/lib/compiler.h b/firmware/microblaze/lib/compiler.h new file mode 100644 index 000000000..4fa9b49f8 --- /dev/null +++ b/firmware/microblaze/lib/compiler.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_COMPILER_H +#define INCLUDED_COMPILER_H + +// FIXME gcc specific. +#define _AL4 __attribute__((aligned (4))) + + +#endif /* INCLUDED_COMPILER_H */ diff --git a/firmware/microblaze/lib/ethernet.c b/firmware/microblaze/lib/ethernet.c index 34a3ad7c1..2d7c4d7bd 100644 --- a/firmware/microblaze/lib/ethernet.c +++ b/firmware/microblaze/lib/ethernet.c @@ -25,8 +25,7 @@ #include "nonstdio.h" #include <stdbool.h> #include "i2c.h" -#include "usrp2_i2c_addr.h" - +#include "usrp2/fw_common.h" #define VERBOSE 0 @@ -302,7 +301,7 @@ ethernet_mac_addr(void) return &src_mac_addr; eth_mac_addr_t tmp; - bool ok = eeprom_read(I2C_ADDR_MBOARD, MBOARD_MAC_ADDR, &tmp, sizeof(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 } @@ -316,7 +315,7 @@ ethernet_mac_addr(void) bool ethernet_set_mac_addr(const eth_mac_addr_t *t) { - bool ok = eeprom_write(I2C_ADDR_MBOARD, MBOARD_MAC_ADDR, t, sizeof(eth_mac_addr_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; @@ -344,7 +343,7 @@ const struct ip_addr *get_ip_addr(void) return &src_ip_addr; struct ip_addr tmp; - bool ok = eeprom_read(I2C_ADDR_MBOARD, MBOARD_IP_ADDR, &tmp, sizeof(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 } @@ -356,7 +355,7 @@ const struct ip_addr *get_ip_addr(void) } bool set_ip_addr(const struct ip_addr *t){ - bool ok = eeprom_write(I2C_ADDR_MBOARD, MBOARD_IP_ADDR, t, sizeof(struct ip_addr)); + 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; diff --git a/firmware/microblaze/lib/gdbstub2.c b/firmware/microblaze/lib/gdbstub2.c new file mode 100644 index 000000000..4c63dfce2 --- /dev/null +++ b/firmware/microblaze/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/microblaze/lib/gdbstub2.h b/firmware/microblaze/lib/gdbstub2.h new file mode 100644 index 000000000..15cdde939 --- /dev/null +++ b/firmware/microblaze/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/microblaze/lib/hal_io.c b/firmware/microblaze/lib/hal_io.c index 0afd6a2cc..58b1e681e 100644 --- a/firmware/microblaze/lib/hal_io.c +++ b/firmware/microblaze/lib/hal_io.c @@ -193,3 +193,13 @@ puts(const char *s) putchar('\n'); return 0; } + +char * +gets(char * const s) +{ + char *x = s; + while((*x=(char)hal_uart_getc()) != '\n') x++; + *x = 0; + return s; +} + diff --git a/firmware/microblaze/lib/hal_io.h b/firmware/microblaze/lib/hal_io.h index d8967f063..c67d96c62 100644 --- a/firmware/microblaze/lib/hal_io.h +++ b/firmware/microblaze/lib/hal_io.h @@ -23,6 +23,7 @@ void hal_io_init(void); void hal_finish(); +char *gets(char * const s); /* * ------------------------------------------------------------------------ diff --git a/firmware/microblaze/lib/hal_uart.c b/firmware/microblaze/lib/hal_uart.c index 75b12b432..fe3b7515a 100644 --- a/firmware/microblaze/lib/hal_uart.c +++ b/firmware/microblaze/lib/hal_uart.c @@ -39,16 +39,25 @@ divisor_table[MAX_WB_DIV+1][NSPEEDS] = { #define u uart_regs +static char uart_mode = UART_MODE_ONLCR; + +void +hal_uart_set_mode(int mode) +{ + uart_mode = mode; +} + void hal_uart_init(void) { + hal_uart_set_mode(UART_MODE_ONLCR); u->clkdiv = 217; // 230400 bps } void hal_uart_putc(int ch) { - if (ch == '\n') // FIXME for now map \n -> \r\n + if (ch == '\n')// && (uart_mode == UART_MODE_ONLCR)) //map \n->\r\n if necessary hal_uart_putc('\r'); while (u->txlevel == 0) // wait for fifo to have space @@ -60,7 +69,7 @@ hal_uart_putc(int ch) void hal_uart_putc_nowait(int ch) { - if (ch == '\n') // FIXME for now map \n -> \r\n + if (ch == '\n')// && (uart_mode == UART_MODE_ONLCR)) //map \n->\r\n if necessary hal_uart_putc('\r'); if(u->txlevel) // If fifo has space diff --git a/firmware/microblaze/lib/hal_uart.h b/firmware/microblaze/lib/hal_uart.h index 2ddfa6259..dfd73c323 100644 --- a/firmware/microblaze/lib/hal_uart.h +++ b/firmware/microblaze/lib/hal_uart.h @@ -19,6 +19,16 @@ #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) + +/* + * \brief Set uart mode + */ +void hal_uart_set_mode(int flags); /*! * \brief one-time call to init diff --git a/firmware/microblaze/lib/ihex.c b/firmware/microblaze/lib/ihex.c new file mode 100644 index 000000000..97ecf73b6 --- /dev/null +++ b/firmware/microblaze/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/microblaze/lib/ihex.h b/firmware/microblaze/lib/ihex.h new file mode 100644 index 000000000..9f471fbe2 --- /dev/null +++ b/firmware/microblaze/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/microblaze/lib/loader_parser.c b/firmware/microblaze/lib/loader_parser.c new file mode 100644 index 000000000..96457a164 --- /dev/null +++ b/firmware/microblaze/lib/loader_parser.c @@ -0,0 +1,324 @@ +/* -*- 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 "loader_parser.h" +#include <quadradio/loader_bits.h> +#include <quadradio/flashdir.h> +#include <quadradio/simple_binary_format.h> +#include <spi_flash.h> +#include <nonstdio.h> +//#include <assert.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include "ethernet.h" +#include "qr_settings.h" + +#define min(a,b) ((a) < (b) ? (a) : (b)) + +static spi_flash_async_state_t async_state; + + +static caldiv_eeprom_setter_t _caldiv_set_rev = NULL; +static caldiv_eeprom_setter_t _caldiv_set_ser = NULL; +static caldiv_eeprom_setter_t _caldiv_set_mod = NULL; + +void +register_caldiv_eeprom_setters(caldiv_eeprom_setter_t set_rev, + caldiv_eeprom_setter_t set_ser, + caldiv_eeprom_setter_t set_mod) +{ + _caldiv_set_rev = set_rev; + _caldiv_set_ser = set_ser; + _caldiv_set_mod = set_mod; +} + + +// big-endian +static uint32_t +get32(const unsigned char *s) +{ + return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]; +} + +// big-endian +static unsigned char * +put32(unsigned char *s, uint32_t v) +{ + s[0] = (v >> 24) & 0xff; + s[1] = (v >> 16) & 0xff; + s[2] = (v >> 8) & 0xff; + s[3] = v & 0xff; + return s + 4; +} + +static bool +erased_p(uint32_t flash_addr, size_t nbytes) +{ + unsigned char buf[64]; + + size_t n; + for (size_t i = 0; i < nbytes; i += n, flash_addr += n){ + n = min(nbytes - i, sizeof(buf)); + spi_flash_read(flash_addr, n, buf); + for (size_t j = 0; j < n; j++) + if (buf[j] != 0xff) + return false; + } + return true; +} + +static bool +erase_flash(uint32_t addr, uint32_t len) +{ + if (addr % spi_flash_sector_size() != 0) + return false; + + if (len % spi_flash_sector_size() != 0) + return false; + + spi_flash_async_erase_start(&async_state, addr, len); + // FIXME? check to see if erase was successful + return true; +} + +static bool +map_slot(uint32_t slot, uint32_t *slot_start, uint32_t *slot_len, uint32_t *status) +{ + // This case doesn't require a valid flashdir, and in fact can be used as + // part of writing the intial flashdir. + if (QLD_SLOT_DOM(slot) == QLD_DOM_UNMAPPED){ + int flash_size = get_flash_size(); + if (flash_size == 0){ + *status = QLDS_FAILED; // Can't find the flash. most likely a h/w problem. + return false; + } + *slot_start = 0; + *slot_len = flash_size; + return true; + } + + const struct flashdir *fd = get_flashdir(); + if (fd == 0) + return false; + + uint32_t slot_num = QLD_SLOT_NUM(slot); + + switch(QLD_SLOT_DOM(slot)){ + case QLD_DOM_FPGA: + if (slot_num >= fd->fpga_nslots){ + *status = QLDS_INVALID_ARG; + return false; + } + *slot_start = fd->slot[slot_num + fd->fpga_slot0].start << spi_flash_log2_sector_size(); + *slot_len = fd->slot[slot_num + fd->fpga_slot0].len << spi_flash_log2_sector_size(); + return true; + + case QLD_DOM_FW: + if (slot_num >= fd->fw_nslots){ + *status = QLDS_INVALID_ARG; + return false; + } + *slot_start = fd->slot[slot_num + fd->fw_slot0].start << spi_flash_log2_sector_size(); + *slot_len = fd->slot[slot_num + fd->fw_slot0].len << spi_flash_log2_sector_size(); + return true; + + default: + *status = QLDS_INVALID_ARG; + return false; + } +} + + +static bool +check_flashdir(void) +{ + return get_flashdir() != 0; +} + +void +loader_parser(const unsigned char *input, size_t ilen, + unsigned char *output, size_t max_olen, size_t *actual_olen) +{ + //assert (max_olen >= 8); + if (!(max_olen >= 8)) + abort(); + + *actual_olen = 0; + uint32_t status = QLDS_BAD_PKT; + + uint32_t cmd = get32(input); + uint32_t nonce = get32(input+4); + uint32_t slot = 0; + uint32_t addr = 0; + uint32_t len = 0; + + if (ilen < 8){ + nonce = -1; + goto done; + } + + uint32_t slot_start; // offset in flash + uint32_t slot_len; // length in bytes + + if (ilen >= 5 * sizeof(uint32_t)){ + slot = get32(input+8); + addr = get32(input+12); + len = get32(input+16); + } + + switch (cmd){ + case QLD_FLASH_ERASE_START: + // <QLD_FLASH_ERASE_START> <nonce> <slot> <addr> <len> + if (ilen != 5 * sizeof(uint32_t)) + goto done; + + if (!check_flashdir()){ + status = QLDS_BAD_FLASHDIR; + goto done; + } + if (!map_slot(slot, &slot_start, &slot_len, &status)) + goto done; + + if (QLD_SLOT_DOM(slot) != QLD_DOM_UNMAPPED){ + addr = slot_start; + len = slot_len; + } + //printf("flash_erase: addr = 0x%x, len=0x%x\n", addr, len); + + if (0 && erased_p(addr, len)){ // already erased? + async_state.first = async_state.last = async_state.current = 0; + goto ok; + } + + if (erase_flash(addr, len)) + goto ok; + + status = QLDS_FAILED; + goto done; + + + case QLD_FLASH_ERASE_POLL: + // <QLD_FLASH_ERASE_POLL> <nonce> + if (ilen != 2 * sizeof(uint32_t)) + goto done; + + if (spi_flash_async_erase_poll(&async_state)) + goto ok; + + status = QLDS_BUSY; + goto done; + + + case QLD_FLASH_WRITE: + // <QLD_FLASH_WRITE> <nonce> <slot> <addr> <len> <data ...> + if (ilen < 5 * sizeof(uint32_t)) + goto done; + + if (ilen != 5 * sizeof(uint32_t) + len) + goto done; + + if (!check_flashdir()){ + status = QLDS_BAD_FLASHDIR; + goto done; + } + if (!map_slot(slot, &slot_start, &slot_len, &status)) + goto done; + + addr += slot_start; + len = min(len, slot_len); + + if (spi_flash_program(addr, len, &input[5*sizeof(uint32_t)])) + goto ok; + + status = QLDS_FAILED; + goto done; + + + case QLD_FLASH_READ: + case QLD_MEM_READ: + case QLD_MEM_WRITE: + case QLD_GOTO: + status = QLDS_NOTIMPLEMENTED; + goto done; + + case QLD_PING: + // <QLD_PING> <nonce> + if (ilen != 2 * sizeof(uint32_t)) + goto done; + goto ok; + +#if 0 + case QLD_EEPROM_SET_XXX: + // <QLD_EEPROM_SET_XXX> <nonce> <arg> <idlen> <idstr> <data ...> + { + uint32_t arg = get32(input+2*sizeof(uint32_t)); + uint32_t idlen = get32(input+3*sizeof(uint32_t)); + uint8_t *idstr = (uint8_t*)input+4*sizeof(uint32_t); + uint8_t *data_p = idstr+idlen; + + //handle the ethernet cases + if (strncmp((char*)idstr, "ip", idlen) == 0){ + struct ip_addr addr = {get32(data_p)}; + ethernet_set_ip_addr(arg, addr); + } + else if (strncmp((char*)idstr, "mac", idlen) == 0){ + eth_mac_addr_t addr; + memcpy(&addr, data_p, sizeof(addr)); + ethernet_set_mac_addr(arg, &addr); + } + //handle the main board eeprom + else if (strncmp((char*)idstr, "qrrev", idlen) == 0){ + qr_set_revision(get32(data_p)); + } + else if (strncmp((char*)idstr, "qrser", idlen) == 0){ + qr_set_serial(get32(data_p)); + } + else if (strncmp((char*)idstr, "qrmod", idlen) == 0){ + qr_set_model(get32(data_p)); + } + //handle the caldiv eeprom + else if (strncmp((char*)idstr, "cdrev", idlen) == 0){ + if (_caldiv_set_rev) _caldiv_set_rev(get32(data_p)); + } + else if (strncmp((char*)idstr, "cdser", idlen) == 0){ + if (_caldiv_set_ser) _caldiv_set_ser(get32(data_p)); + } + else if (strncmp((char*)idstr, "cdmod", idlen) == 0){ + if (_caldiv_set_ser) _caldiv_set_mod(get32(data_p)); + } + else { + goto done; + } + } + goto ok; +#endif + + default: + status = QLDS_UNKNOWN_CMD; + goto done; + } + + ok: + status = QLDS_OK; + + done: + put32(output, nonce); + put32(output+4, status); + *actual_olen = 2*sizeof(uint32_t); +} diff --git a/firmware/microblaze/lib/loader_parser.h b/firmware/microblaze/lib/loader_parser.h new file mode 100644 index 000000000..365317bd7 --- /dev/null +++ b/firmware/microblaze/lib/loader_parser.h @@ -0,0 +1,38 @@ +/* -*- 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 <stddef.h> +#include <stdint.h> + +/* + * max_olen must be at least 8 bytes. 1KB is recommended. + */ +void +loader_parser(const unsigned char *input, size_t ilen, + unsigned char *output, size_t max_olen, size_t *actual_olen); + +/* + * Major kludge-master altert! + * This function registers functions for setting caldiv eeprom stuff. + * This way, the parser does not depend on the qpn apps at compile time. + */ +typedef void(*caldiv_eeprom_setter_t)(uint32_t); +void register_caldiv_eeprom_setters( + caldiv_eeprom_setter_t set_rev, + caldiv_eeprom_setter_t set_ser, + caldiv_eeprom_setter_t set_mod); diff --git a/firmware/microblaze/lib/memory_map.h b/firmware/microblaze/lib/memory_map.h deleted file mode 100644 index cdf3dd338..000000000 --- a/firmware/microblaze/lib/memory_map.h +++ /dev/null @@ -1,792 +0,0 @@ -/* -*- c -*- */ -/* - * Copyright 2007,2008,2009 Free Software Foundation, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -/* Overall Memory Map - * 0000-7FFF 32K RAM space (16K on 1500, 24K on 2000, 32K on DSP) - * 8000-BFFF 16K Buffer Pool - * C000-FFFF 16K Peripherals - */ - - -#ifndef INCLUDED_MEMORY_MAP_H -#define INCLUDED_MEMORY_MAP_H - -#include <stdint.h> - - -#define MASTER_CLK_RATE 100000000 // 100 MHz - - -//////////////////////////////////////////////////////////////// -// -// Memory map for embedded wishbone bus -// -//////////////////////////////////////////////////////////////// - - -//////////////////////////////////////////////////////////////// -// Main RAM, Slave 0 - -#define RAM_BASE 0x0000 - -//////////////////////////////////////////////////////////////// -// Buffer Pool RAM, Slave 1 -// -// The buffers themselves are located in Slave 1, Buffer Pool RAM. -// The status registers are in Slave 5, Buffer Pool Status. -// The control register is in Slave 7, Settings Bus. - -#define BUFFER_POOL_RAM_BASE 0x8000 - -#define NBUFFERS 8 -#define BP_NLINES 0x0200 // number of 32-bit lines in a buffer -#define BP_LAST_LINE (BP_NLINES - 1) // last line in a buffer - -#define buffer_pool_ram \ - ((uint32_t *) BUFFER_POOL_RAM_BASE) - -#define buffer_ram(n) (&buffer_pool_ram[(n) * BP_NLINES]) - - -///////////////////////////////////////////////////// -// SPI Core, Slave 2. See core docs for more info -#define SPI_BASE 0xC000 // Base address (16-bit) - -typedef struct { - volatile uint32_t txrx0; - volatile uint32_t txrx1; - volatile uint32_t txrx2; - volatile uint32_t txrx3; - volatile uint32_t ctrl; - volatile uint32_t div; - volatile uint32_t ss; -} spi_regs_t; - -#define spi_regs ((spi_regs_t *) SPI_BASE) - - -// Masks for controlling different peripherals -#define SPI_SS_AD9510 1 -#define SPI_SS_AD9777 2 -#define SPI_SS_RX_DAC 4 -#define SPI_SS_RX_ADC 8 -#define SPI_SS_RX_DB 16 -#define SPI_SS_TX_DAC 32 -#define SPI_SS_TX_ADC 64 -#define SPI_SS_TX_DB 128 - -// Masks for different parts of CTRL reg -#define SPI_CTRL_ASS (1<<13) -#define SPI_CTRL_IE (1<<12) -#define SPI_CTRL_LSB (1<<11) -#define SPI_CTRL_TXNEG (1<<10) -#define SPI_CTRL_RXNEG (1<< 9) -#define SPI_CTRL_GO_BSY (1<< 8) -#define SPI_CTRL_CHAR_LEN_MASK 0x7F - -//////////////////////////////////////////////// -// I2C, Slave 3 -// See Wishbone I2C-Master Core Specification. - -#define I2C_BASE 0xC400 - -typedef struct { - volatile uint32_t prescaler_lo; // r/w - volatile uint32_t prescaler_hi; // r/w - volatile uint32_t ctrl; // r/w - volatile uint32_t data; // wr = transmit reg; rd = receive reg - volatile uint32_t cmd_status; // wr = command reg; rd = status reg -} i2c_regs_t; - -#define i2c_regs ((i2c_regs_t *) I2C_BASE) - -#define I2C_CTRL_EN (1 << 7) // core enable -#define I2C_CTRL_IE (1 << 6) // interrupt enable - -// -// STA, STO, RD, WR, and IACK bits are cleared automatically -// -#define I2C_CMD_START (1 << 7) // generate (repeated) start condition -#define I2C_CMD_STOP (1 << 6) // generate stop condition -#define I2C_CMD_RD (1 << 5) // read from slave -#define I2C_CMD_WR (1 << 4) // write to slave -#define I2C_CMD_NACK (1 << 3) // when a rcvr, send ACK (ACK=0) or NACK (ACK=1) -#define I2C_CMD_RSVD_2 (1 << 2) // reserved -#define I2C_CMD_RSVD_1 (1 << 1) // reserved -#define I2C_CMD_IACK (1 << 0) // set to clear pending interrupt - -#define I2C_ST_RXACK (1 << 7) // Received acknowledgement from slave (1 = NAK, 0 = ACK) -#define I2C_ST_BUSY (1 << 6) // 1 after START signal detected; 0 after STOP signal detected -#define I2C_ST_AL (1 << 5) // Arbitration lost. 1 when core lost arbitration -#define I2C_ST_RSVD_4 (1 << 4) // reserved -#define I2C_ST_RSVD_3 (1 << 3) // reserved -#define I2C_ST_RSVD_2 (1 << 2) // reserved -#define I2C_ST_TIP (1 << 1) // Transfer-in-progress -#define I2C_ST_IP (1 << 0) // Interrupt pending - - -//////////////////////////////////////////////// -// GPIO, Slave 4 -// -// These go to the daughterboard i/o pins - -#define GPIO_BASE 0xC800 - -typedef struct { - volatile uint32_t io; // tx data in high 16, rx in low 16 - volatile uint32_t ddr; // 32 bits, 1 means output. tx in high 16, rx in low 16 - volatile uint32_t tx_sel; // 16 2-bit fields select which source goes to TX DB - volatile uint32_t rx_sel; // 16 2-bit fields select which source goes to RX DB -} gpio_regs_t; - -// each 2-bit sel field is layed out this way -#define GPIO_SEL_SW 0 // if pin is an output, set by software in the io reg -#define GPIO_SEL_ATR 1 // if pin is an output, set by ATR logic -#define GPIO_SEL_DEBUG_0 2 // if pin is an output, debug lines from FPGA fabric -#define GPIO_SEL_DEBUG_1 3 // if pin is an output, debug lines from FPGA fabric - -#define gpio_base ((gpio_regs_t *) GPIO_BASE) - -/////////////////////////////////////////////////// -// Buffer Pool Status, Slave 5 -// -// The buffers themselves are located in Slave 1, Buffer Pool RAM. -// The status registers are in Slave 5, Buffer Pool Status. -// The control register is in Slave 7, Settings Bus. - -#define BUFFER_POOL_STATUS_BASE 0xCC00 - -typedef struct { - volatile uint32_t last_line[NBUFFERS]; // last line xfer'd in buffer - volatile uint32_t status; // error and done flags - volatile uint32_t hw_config; // see below - volatile uint32_t dummy[3]; - volatile uint32_t irqs; - volatile uint32_t pri_enc_bp_status; - volatile uint32_t cycle_count; -} buffer_pool_status_t; - -#define buffer_pool_status ((buffer_pool_status_t *) BUFFER_POOL_STATUS_BASE) - -/* - * Buffer n's xfer is done. - * Clear this bit by issuing bp_clear_buf(n) - */ -#define BPS_DONE(n) (0x00000001 << (n)) -#define BPS_DONE_0 BPS_DONE(0) -#define BPS_DONE_1 BPS_DONE(1) -#define BPS_DONE_2 BPS_DONE(2) -#define BPS_DONE_3 BPS_DONE(3) -#define BPS_DONE_4 BPS_DONE(4) -#define BPS_DONE_5 BPS_DONE(5) -#define BPS_DONE_6 BPS_DONE(6) -#define BPS_DONE_7 BPS_DONE(7) - -/* - * Buffer n's xfer had an error. - * Clear this bit by issuing bp_clear_buf(n) - */ -#define BPS_ERROR(n) (0x00000100 << (n)) -#define BPS_ERROR_0 BPS_ERROR(0) -#define BPS_ERROR_1 BPS_ERROR(1) -#define BPS_ERROR_2 BPS_ERROR(2) -#define BPS_ERROR_3 BPS_ERROR(3) -#define BPS_ERROR_4 BPS_ERROR(4) -#define BPS_ERROR_5 BPS_ERROR(5) -#define BPS_ERROR_6 BPS_ERROR(6) -#define BPS_ERROR_7 BPS_ERROR(7) - -/* - * Buffer n is idle. A buffer is idle if it's not - * DONE, ERROR, or processing a transaction. If it's - * IDLE, it's safe to start a new transaction. - * - * Clear this bit by starting a xfer with - * bp_send_from_buf or bp_receive_to_buf. - */ -#define BPS_IDLE(n) (0x00010000 << (n)) -#define BPS_IDLE_0 BPS_IDLE(0) -#define BPS_IDLE_1 BPS_IDLE(1) -#define BPS_IDLE_2 BPS_IDLE(2) -#define BPS_IDLE_3 BPS_IDLE(3) -#define BPS_IDLE_4 BPS_IDLE(4) -#define BPS_IDLE_5 BPS_IDLE(5) -#define BPS_IDLE_6 BPS_IDLE(6) -#define BPS_IDLE_7 BPS_IDLE(7) - -/* - * Buffer n has a "slow path" packet in it. - * This bit is orthogonal to the bits above and indicates that - * the FPGA ethernet rx protocol engine has identified this packet - * as one requiring firmware intervention. - */ -#define BPS_SLOWPATH(n) (0x01000000 << (n)) -#define BPS_SLOWPATH_0 BPS_SLOWPATH(0) -#define BPS_SLOWPATH_1 BPS_SLOWPATH(1) -#define BPS_SLOWPATH_2 BPS_SLOWPATH(2) -#define BPS_SLOWPATH_3 BPS_SLOWPATH(3) -#define BPS_SLOWPATH_4 BPS_SLOWPATH(4) -#define BPS_SLOWPATH_5 BPS_SLOWPATH(5) -#define BPS_SLOWPATH_6 BPS_SLOWPATH(6) -#define BPS_SLOWPATH_7 BPS_SLOWPATH(7) - - -#define BPS_DONE_ALL 0x000000ff // mask of all dones -#define BPS_ERROR_ALL 0x0000ff00 // mask of all errors -#define BPS_IDLE_ALL 0x00ff0000 // mask of all idles -#define BPS_SLOWPATH_ALL 0xff000000 // mask of all slowpaths - -// The hw_config register - -#define HWC_SIMULATION 0x80000000 -#define HWC_WB_CLK_DIV_MASK 0x0000000f - -/*! - * \brief return non-zero if we're running under the simulator - */ -inline static int -hwconfig_simulation_p(void) -{ - return buffer_pool_status->hw_config & HWC_SIMULATION; -} - -/*! - * \brief Return Wishbone Clock divisor. - * The processor runs at the Wishbone Clock rate which is MASTER_CLK_RATE / divisor. - */ -inline static int -hwconfig_wishbone_divisor(void) -{ - return buffer_pool_status->hw_config & HWC_WB_CLK_DIV_MASK; -} - -/////////////////////////////////////////////////// -// Ethernet Core, Slave 6 - -#define ETH_BASE 0xD000 - -#include "eth_mac_regs.h" - -#define eth_mac ((eth_mac_regs_t *) ETH_BASE) - -//////////////////////////////////////////////////// -// Settings Bus, Slave #7, Not Byte Addressable! -// -// Output-only from processor point-of-view. -// 1KB of address space (== 256 32-bit write-only regs) - - -#define MISC_OUTPUT_BASE 0xD400 -#define TX_PROTOCOL_ENGINE_BASE 0xD480 -#define RX_PROTOCOL_ENGINE_BASE 0xD4C0 -#define BUFFER_POOL_CTRL_BASE 0xD500 -#define LAST_SETTING_REG 0xD7FC // last valid setting register - -#define SR_MISC 0 -#define SR_TX_PROT_ENG 32 -#define SR_RX_PROT_ENG 48 -#define SR_BUFFER_POOL_CTRL 64 -#define SR_UDP_SM 96 -#define SR_TX_DSP 208 -#define SR_TX_CTRL 224 -#define SR_RX_DSP 160 -#define SR_RX_CTRL 176 -#define SR_TIME64 192 -#define SR_SIMTIMER 198 -#define SR_LAST 255 - -#define _SR_ADDR(sr) (MISC_OUTPUT_BASE + (sr) * sizeof(uint32_t)) - -// --- buffer pool control regs --- - -typedef struct { - volatile uint32_t ctrl; -} buffer_pool_ctrl_t; - -// buffer pool ports - -#define PORT_SERDES 0 // serial/deserializer -#define PORT_DSP 1 // DSP tx or rx pipeline -#define PORT_ETH 2 // ethernet tx or rx -#define PORT_RAM 3 // RAM tx or rx - -// the buffer pool ctrl register fields - -#define BPC_BUFFER(n) (((n) & 0xf) << 28) -#define BPC_BUFFER_MASK BPC_BUFFER(~0) -#define BPC_BUFFER_0 BPC_BUFFER(0) -#define BPC_BUFFER_1 BPC_BUFFER(1) -#define BPC_BUFFER_2 BPC_BUFFER(2) -#define BPC_BUFFER_3 BPC_BUFFER(3) -#define BPC_BUFFER_4 BPC_BUFFER(4) -#define BPC_BUFFER_5 BPC_BUFFER(5) -#define BPC_BUFFER_6 BPC_BUFFER(6) -#define BPC_BUFFER_7 BPC_BUFFER(7) -#define BPC_BUFFER_NIL BPC_BUFFER(0x8) // disable - -#define BPC_PORT(n) (((n) & 0x7) << 25) -#define BPC_PORT_MASK BPC_PORT(~0) -#define BPC_PORT_SERDES BPC_PORT(PORT_SERDES) -#define BPC_PORT_DSP BPC_PORT(PORT_DSP) -#define BPC_PORT_ETH BPC_PORT(PORT_ETH) -#define BPC_PORT_RAM BPC_PORT(PORT_RAM) -#define BPC_PORT_NIL BPC_PORT(0x4) // disable - -#define BPC_CLR (1 << 24) // mutually excl commands -#define BPC_READ (1 << 23) -#define BPC_WRITE (1 << 22) - -#define BPC_STEP(step) (((step) & 0xf) << 18) -#define BPC_STEP_MASK BPC_STEP(~0) -#define BPC_LAST_LINE(line) (((line) & 0x1ff) << 9) -#define BPC_LAST_LINE_MASK BPC_LAST_LINE(~0) -#define BPC_FIRST_LINE(line) (((line) & 0x1ff) << 0) -#define BPC_FIRST_LINE_MASK BPC_FIRST_LINE(~0) - -#define buffer_pool_ctrl ((buffer_pool_ctrl_t *) BUFFER_POOL_CTRL_BASE) - -// --- misc outputs --- - -typedef struct { - volatile uint32_t clk_ctrl; - volatile uint32_t serdes_ctrl; - volatile uint32_t adc_ctrl; - volatile uint32_t leds; - volatile uint32_t phy_ctrl; // LSB is reset line to eth phy - volatile uint32_t debug_mux_ctrl; - volatile uint32_t ram_page; // FIXME should go somewhere else... - volatile uint32_t flush_icache; // Flush the icache - volatile uint32_t led_src; // HW or SW control for LEDs -} output_regs_t; - -#define SERDES_ENABLE 8 -#define SERDES_PRBSEN 4 -#define SERDES_LOOPEN 2 -#define SERDES_RXEN 1 - -#define ADC_CTRL_ON 0x0F -#define ADC_CTRL_OFF 0x00 - -// crazy order that matches the labels on the case - -#define LED_A (1 << 4) -#define LED_B (1 << 1) -#define LED_C (1 << 3) -#define LED_D (1 << 0) -#define LED_E (1 << 2) -// LED_F // controlled by CPLD -#define LED_RJ45 (1 << 5) - -#define output_regs ((output_regs_t *) MISC_OUTPUT_BASE) - -// --- udp tx regs --- - -typedef struct { - // Bits 19:16 are control info; bits 15:0 are data (see below) - // First two words are unused. - volatile uint32_t _nope[2]; - //--- ethernet header - 14 bytes--- - volatile struct{ - uint32_t mac_dst_0_1; //word 2 - uint32_t mac_dst_2_3; - uint32_t mac_dst_4_5; - uint32_t mac_src_0_1; - uint32_t mac_src_2_3; - uint32_t mac_src_4_5; - uint32_t ether_type; //word 8 - } eth_hdr; - //--- ip header - 20 bytes --- - volatile struct{ - uint32_t ver_ihl_tos; //word 9 - uint32_t total_length; - uint32_t identification; - uint32_t flags_frag_off; - uint32_t ttl_proto; - uint32_t checksum; - uint32_t src_addr_high; - uint32_t src_addr_low; - uint32_t dst_addr_high; - uint32_t dst_addr_low; //word 18 - } ip_hdr; - //--- udp header - 8 bytes --- - volatile struct{ - uint32_t src_port; //word 19 - uint32_t dst_port; - uint32_t length; - uint32_t checksum; //word 22 - } udp_hdr; - volatile uint32_t _pad[32-23]; -} sr_udp_sm_t; - -// control bits (all expect UDP_SM_LAST_WORD are mutually exclusive) - -// This is the last word of the header -#define UDP_SM_LAST_WORD (1 << 19) - -// Insert IP header checksum here. Data is the xor of 16'hFFFF and -// the values written into regs 9-13 and 15-18. -#define UDP_SM_INS_IP_HDR_CHKSUM (1 << 18) - -// Insert IP Length here (data ignored) -#define UDP_SM_INS_IP_LEN (1 << 17) - -// Insert UDP Length here (data ignore) -#define UDP_SM_INS_UDP_LEN (1 << 16) - -#define sr_udp_sm ((sr_udp_sm_t *) _SR_ADDR(SR_UDP_SM)) - -// --- dsp tx regs --- - -#define MIN_CIC_INTERP 1 -#define MAX_CIC_INTERP 128 - -typedef struct { - volatile uint32_t num_chan; - volatile uint32_t clear_state; // clears out state machine, fifos, -} sr_tx_ctrl_t; - -#define sr_tx_ctrl ((sr_tx_ctrl_t *) _SR_ADDR(SR_TX_CTRL)) - -typedef struct { - volatile int32_t freq; - volatile uint32_t scale_iq; // {scale_i,scale_q} - volatile uint32_t interp_rate; - volatile uint32_t _padding0; // padding for the tx_mux - // NOT freq, scale, interp - /*! - * \brief output mux configuration. - * - * <pre> - * 3 2 1 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-------------------------------+-------+-------+-------+-------+ - * | | DAC1 | DAC0 | - * +-------------------------------+-------+-------+-------+-------+ - * - * There are N DUCs (1 now) with complex inputs and outputs. - * There are two DACs. - * - * Each 4-bit DACx field specifies the source for the DAC - * Each subfield is coded like this: - * - * 3 2 1 0 - * +-------+ - * | N | - * +-------+ - * - * N specifies which DUC output is connected to this DAC. - * - * N which interp output - * --- ------------------- - * 0 DUC 0 I - * 1 DUC 0 Q - * 2 DUC 1 I - * 3 DUC 1 Q - * F All Zeros - * - * The default value is 0x10 - * </pre> - */ - volatile uint32_t tx_mux; - -} dsp_tx_regs_t; - -#define dsp_tx_regs ((dsp_tx_regs_t *) _SR_ADDR(SR_TX_DSP)) - -// --- VITA RX CTRL regs --- -typedef struct { - // The following 3 are logically a single command register. - // They are clocked into the underlying fifo when time_ticks is written. - volatile uint32_t cmd; // {now, chain, num_samples(30) - volatile uint32_t time_secs; - volatile uint32_t time_ticks; - - volatile uint32_t clear_overrun; // write anything to clear overrun - volatile uint32_t vrt_header; // word 0 of packet. FPGA fills in packet counter - volatile uint32_t vrt_stream_id; // word 1 of packet. - volatile uint32_t vrt_trailer; - volatile uint32_t nsamples_per_pkt; - volatile uint32_t nchannels; // 1 in basic case, up to 4 for vector sources - volatile uint32_t pad[7]; // Make each structure 16 elements long -} sr_rx_ctrl_t; - -#define sr_rx_ctrl ((sr_rx_ctrl_t *) _SR_ADDR(SR_RX_CTRL)) - -// --- dsp rx regs --- -#define MIN_CIC_DECIM 1 -#define MAX_CIC_DECIM 128 - -typedef struct { - volatile int32_t freq; - volatile uint32_t scale_iq; // {scale_i,scale_q} - volatile uint32_t decim_rate; - volatile uint32_t dcoffset_i; // Bit 31 high sets fixed offset mode, using lower 14 bits, - // otherwise it is automatic - volatile uint32_t dcoffset_q; // Bit 31 high sets fixed offset mode, using lower 14 bits - - /*! - * \brief input mux configuration. - * - * This determines which ADC (or constant zero) is connected to - * each DDC input. There are N DDCs (1 now). Each has two inputs. - * - * <pre> - * Mux value: - * - * 3 2 1 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | |Q0 |I0 | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * - * Each 2-bit I field is either 00 (A/D A), 01 (A/D B) or 1X (const zero) - * Each 2-bit Q field is either 00 (A/D A), 01 (A/D B) or 1X (const zero) - * - * The default value is 0x4 - * </pre> - */ - volatile uint32_t rx_mux; // called adc_mux in dsp_core_rx.v - - /*! - * \brief Streaming GPIO configuration - * - * This determines whether the LSBs of I and Q samples come from the DSP - * pipeline or from the io_rx GPIO pins. To stream GPIO, one must first - * set the GPIO data direction register to have io_rx[15] and/or io_rx[14] - * configured as inputs. The GPIO pins will be sampled at the time the - * remainder of the DSP sample is strobed into the RX sample FIFO. There - * will be a decimation-dependent fixed time offset between the GPIO - * sample stream and the associated RF samples. - * - * 3 2 1 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | MBZ |Q|I| - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * - * I 0=LSB comes from DSP pipeline (default) - * 1=LSB comes from io_rx[15] - * - * Q 0=LSB comes from DSP pipeline (default) - * 1=LSB comes from io_rx[14] - */ - volatile uint32_t gpio_stream_enable; - -} dsp_rx_regs_t; - -#define dsp_rx_regs ((dsp_rx_regs_t *) _SR_ADDR(SR_RX_DSP)) - -// ---------------------------------------------------------------- -// VITA49 64 bit time (write only) - /*! - * \brief Time 64 flags - * - * <pre> - * - * 3 2 1 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-----------------------------------------------------------+-+-+ - * | |S|P| - * +-----------------------------------------------------------+-+-+ - * - * P - PPS edge selection (0=negedge, 1=posedge, default=0) - * S - Source (0=sma, 1=mimo, 0=default) - * - * </pre> - */ -typedef struct { - volatile uint32_t secs; // value to set absolute secs to on next PPS - volatile uint32_t ticks; // value to set absolute ticks to on next PPS - volatile uint32_t flags; // flags - see chart above - volatile uint32_t imm; // set immediate (0=latch on next pps, 1=latch immediate, default=0) -} sr_time64_t; - -#define sr_time64 ((sr_time64_t *) _SR_ADDR(SR_TIME64)) - - -/* - * --- ethernet tx protocol engine regs (write only) --- - * - * These registers control the transmit portion of the ethernet - * protocol engine (out of USRP2). The protocol engine handles fifo - * status and sequence number insertion in outgoing packets, and - * automagically generates status packets when required to inform the - * host of changes in fifo availability. - * - * All outgoing packets have their fifo_status field set to the number - * of 32-bit lines of fifo available in the ethernet Rx fifo (see - * usrp2_eth_packet.h). Seqno's are set if FIXME, else 0. - * - * FIXME clean this up once we know how it's supposed to behave. - */ - -typedef struct { - volatile uint32_t flags; // not yet fully defined (channel?) - volatile uint32_t mac_dst0123; // 4 bytes of destination mac addr - volatile uint32_t mac_dst45src01; // 2 bytes of dest mac addr; 2 bytes of src mac addr - volatile uint32_t mac_src2345; // 4 bytes of destination mac addr - volatile uint32_t seqno; // Write to init seqno. It autoincs on match -} tx_proto_engine_regs_t; - -#define tx_proto_engine ((tx_proto_engine_regs_t *) TX_PROTOCOL_ENGINE_BASE) - -/* - * --- ethernet rx protocol engine regs (write only) --- - * - * These registers control the receive portion of the ethernet - * protocol engine (into USRP2). The protocol engine offloads common - * packet inspection operations so that firmware has less to do on - * "fast path" packets. - * - * The registers define conditions which must be matched for a packet - * to be considered a "fast path" packet. If a received packet - * matches the src and dst mac address, ethertype, flags field, and - * expected seqno number it is considered a "fast path" packet, and - * the expected seqno is updated. If the packet fails to satisfy any - * of the above conditions it's a "slow path" packet, and the - * corresponding SLOWPATH flag will be set buffer_status register. - */ - -typedef struct { - volatile uint32_t flags; // not yet fully defined (channel?) - volatile uint32_t mac_dst0123; // 4 bytes of destination mac addr - volatile uint32_t mac_dst45src01; // 2 bytes of dest mac addr; 2 bytes of src mac addr - volatile uint32_t mac_src2345; // 4 bytes of destination mac addr - volatile uint32_t ethertype_pad; // ethertype in high 16-bits -} rx_proto_engine_regs_t; - -#define rx_proto_engine ((rx_proto_engine_regs_t *) RX_PROTOCOL_ENGINE_BASE) - - - -/////////////////////////////////////////////////// -// Simple Programmable Interrupt Controller, Slave 8 - -#define PIC_BASE 0xD800 - -// Interrupt request lines -// Bit numbers (LSB == 0) that correpond to interrupts into PIC - -#define IRQ_BUFFER 0 // buffer manager -#define IRQ_ONETIME 1 -#define IRQ_SPI 2 -#define IRQ_I2C 3 -#define IRQ_PHY 4 // ethernet PHY -#define IRQ_UNDERRUN 5 -#define IRQ_OVERRUN 6 -#define IRQ_PPS 7 // pulse per second -#define IRQ_UART_RX 8 -#define IRQ_UART_TX 9 -#define IRQ_SERDES 10 -#define IRQ_CLKSTATUS 11 -#define IRQ_PERIODIC 12 - -#define IRQ_TO_MASK(x) (1 << (x)) - -#define PIC_BUFFER_INT IRQ_TO_MASK(IRQ_BUFFER) -#define PIC_ONETIME_INT IRQ_TO_MASK(IRQ_ONETIME) -#define PIC_SPI_INT IRQ_TO_MASK(IRQ_SPI) -#define PIC_I2C_INT IRQ_TO_MASK(IRQ_I2C) -#define PIC_PHY_INT IRQ_TO_MASK(IRQ_PHY) -#define PIC_UNDERRUN_INT IRQ_TO_MASK(IRQ_UNDERRUN) -#define PIC_OVERRUN_INT IRQ_TO_MASK(IRQ_OVERRUN) -#define PIC_PPS_INT IRQ_TO_MASK(IRQ_PPS) -#define PIC_UART_RX_INT IRQ_TO_MASK(IRQ_UART_RX) -#define PIC_UART_TX_INT IRQ_TO_MASK(IRQ_UART_TX) -#define PIC_SERDES IRQ_TO_MASK(IRQ_SERDES) -#define PIC_CLKSTATUS IRQ_TO_MASK(IRQ_CLKSTATUS) - -typedef struct { - volatile uint32_t edge_enable; // mask: 1 -> edge triggered, 0 -> level - volatile uint32_t polarity; // mask: 1 -> rising edge - volatile uint32_t mask; // mask: 1 -> disabled - volatile uint32_t pending; // mask: 1 -> pending; write 1's to clear pending ints -} pic_regs_t; - -#define pic_regs ((pic_regs_t *) PIC_BASE) - -// ---------------------------------------------------------------- -// WB_CLK_RATE is the time base for this -typedef struct { - volatile uint32_t onetime; // Number of wb clk cycles till the onetime interrupt - volatile uint32_t periodic; // Repeat rate of periodic interrupt -} sr_simple_timer_t; - -#define sr_simple_timer ((sr_simple_timer_t *) _SR_ADDR(SR_SIMTIMER)) - -/////////////////////////////////////////////////// -// UART, Slave 10 - -#define UART_BASE 0xE000 - -typedef struct { - // All elements are 8 bits except for clkdiv (16), but we use uint32 to make - // the hardware for decoding easier - volatile uint32_t clkdiv; // Set to 50e6 divided by baud rate (no x16 factor) - volatile uint32_t txlevel; // Number of spaces in the FIFO for writes - volatile uint32_t rxlevel; // Number of available elements in the FIFO for reads - volatile uint32_t txchar; // Write characters to be sent here - volatile uint32_t rxchar; // Read received characters here -} uart_regs_t; - -#define uart_regs ((uart_regs_t *) UART_BASE) - -/////////////////////////////////////////////////// -// ATR Controller, Slave 11 - -#define ATR_BASE 0xE400 - -typedef struct { - volatile uint32_t v[16]; -} atr_regs_t; - -#define ATR_IDLE 0x0 // indicies into v -#define ATR_TX 0x1 -#define ATR_RX 0x2 -#define ATR_FULL 0x3 - -#define atr_regs ((atr_regs_t *) ATR_BASE) - -/////////////////////////////////////////////////// -// SD Card SPI interface, Slave 13 -// All regs are 8 bits wide, but are accessed as if they are 32 bits - -#define SDSPI_BASE 0xEC00 - -typedef struct { - volatile uint32_t status; // Write a 1 or 0 for controlling CS - volatile uint32_t clkdiv; - volatile uint32_t send_dat; - volatile uint32_t receive_dat; -} sdspi_regs_t; - -#define sdspi_regs ((sdspi_regs_t *) SDSPI_BASE) - -/////////////////////////////////////////////////// -// External RAM interface, Slave 14 -// Pages are 1K. Page is 10 bits, set by a control register -// output_regs->ram_page - -#define EXTRAM_BASE 0xF000 -#define extram ((volatile uint32_t *) EXTRAM_BASE) - - -/////////////////////////////////////////////////// - -#endif - diff --git a/firmware/microblaze/lib/net/.gitignore b/firmware/microblaze/lib/net/.gitignore new file mode 100644 index 000000000..282522db0 --- /dev/null +++ b/firmware/microblaze/lib/net/.gitignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/firmware/microblaze/lib/net/eth_mac_addr.h b/firmware/microblaze/lib/net/eth_mac_addr.h new file mode 100644 index 000000000..b44fb68f7 --- /dev/null +++ b/firmware/microblaze/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/microblaze/lib/net/padded_eth_hdr.h b/firmware/microblaze/lib/net/padded_eth_hdr.h new file mode 100644 index 000000000..df816734f --- /dev/null +++ b/firmware/microblaze/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/microblaze/lib/net/socket_address.h b/firmware/microblaze/lib/net/socket_address.h new file mode 100644 index 000000000..336f30a0c --- /dev/null +++ b/firmware/microblaze/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/microblaze/lib/nonstdio.c b/firmware/microblaze/lib/nonstdio.c index 1c991afee..4b5fa4123 100644 --- a/firmware/microblaze/lib/nonstdio.c +++ b/firmware/microblaze/lib/nonstdio.c @@ -78,3 +78,46 @@ 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/microblaze/lib/nonstdio.h b/firmware/microblaze/lib/nonstdio.h index 3fd9e39bb..62ebfa46d 100644 --- a/firmware/microblaze/lib/nonstdio.h +++ b/firmware/microblaze/lib/nonstdio.h @@ -1,4 +1,6 @@ -/* -*- c -*- */ +// +// Copyright 2010 Ettus Research LLC +// /* * Copyright 2007 Free Software Foundation, Inc. * @@ -20,7 +22,7 @@ #define INCLUDED_NONSTDIO_H #include <stdio.h> -#include <usrp2_types.h> +#include <stdint.h> #include <stddef.h> void putstr(const char *s); // cf puts, no added newline @@ -37,10 +39,10 @@ void puthex32_nl(unsigned long x); void newline(); // putchar('\n') void print_mac_addr(const unsigned char addr[6]); -void print_fxpt_freq(u2_fxpt_freq_t v); -void print_fxpt_gain(u2_fxpt_gain_t v); 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[]); #endif /* INCLUDED_NONSTDIO_H */ diff --git a/firmware/microblaze/lib/sd.c b/firmware/microblaze/lib/sd.c deleted file mode 100644 index d000b28ae..000000000 --- a/firmware/microblaze/lib/sd.c +++ /dev/null @@ -1,197 +0,0 @@ -/* -*- c -*- */ -/* - * Copyright 2008 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 "sd.h" -#include "memory_map.h" -#include "stdint.h" -#include "stdio.h" - -static inline void -sd_packarg(unsigned char *argument,unsigned int value) -{ - argument[3] = (unsigned char)(value >> 24); - argument[2] = (unsigned char)(value >> 16); - argument[1] = (unsigned char)(value >> 8); - argument[0] = (unsigned char)(value); -} - -int -sd_init(void) -{ - unsigned char response[5]; - unsigned char argument[4]; - int i,j; - - for(i=0;i<4;i++) - argument[i] = 0; - - // Set clock to less than 400 kHz to start out - sdspi_regs->clkdiv = 128; - - // Delay at least 74 cycles - sd_assert_cs(); - for(i = 0; i < 100; i++) - sd_send_byte(SD_IDLE); - sd_deassert_cs(); - - // Initialization Sequence -- CMD0 CMD55 ACMD41 CMD58 - // Put card in idle state - if(sd_send_command(SD_CMD0,SD_CMD0_R,response,argument)==0) - return 0; // Something went wrong in command - - j = 0; - do { - j++; - if(sd_send_command(SD_CMD55,SD_CMD55_R,response,argument)==1) - sd_send_command(SD_ACMD41,SD_ACMD41_R,response,argument); - else - j = SD_IDLE_WAIT_MAX; - } - while(((response[0] & SD_MSK_IDLE) == SD_MSK_IDLE) && (j < SD_IDLE_WAIT_MAX)); - - if(j>= SD_IDLE_WAIT_MAX) // IDLE timeout exceeded, card asleep - return 0; - - // CMD58 reads the SD card capabilities - if(sd_send_command(SD_CMD58,SD_CMD58_R,response,argument)==0) - return 0; // CMD58 FAIL - - if((response[2] & SD_MSK_OCR_33) != SD_MSK_OCR_33) - return 0; // Card doesn't do 3.3V - - //printf("OCR = %x %x %x %x\n",response[0],response[1],response[2],response[3]); - - // Set blocklen here - sd_packarg(argument,SD_BLOCKLEN); - if(sd_send_command(SD_CMD16,SD_CMD16_R,response,argument)==0) - return 0; // Set Blocklen failed - - // Reset back to high speed - sdspi_regs->clkdiv = 4; - //puts("finished init\n"); - return 1; -} - -int sd_send_command(unsigned char cmd,unsigned char response_type, - unsigned char *response,unsigned char *argument) -{ - int i; - char response_length; - unsigned char tmp; - - sd_assert_cs(); - sd_send_byte((cmd & 0x3F) | 0x40); - for(i=3;i>=0;i--) - sd_send_byte(argument[i]); - sd_send_byte(SD_CRC); // Always the same - - response_length = 0; - switch(response_type) - { - case SD_R1: - case SD_R1B: - response_length = 1; - break; - case SD_R2: - response_length = 2; - break; - case SD_R3: - response_length = 5; - break; - default: - break; - } - - // Wait for a response, which will have a 0 start bit - i = 0; - do - { - tmp = sd_rcv_byte(); - i++; - } - while(((tmp & 0x80) != 0) && i < SD_CMD_TIMEOUT); - - if(i>= SD_CMD_TIMEOUT) - { - sd_deassert_cs(); - //puts("cmd send timeout\n"); - return 0; - } - - for(i=response_length-1; i>=0; i--) - { - response[i] = tmp; - tmp = sd_rcv_byte(); - } - i = 0; - if(response_type == SD_R1B) - { - do - { - i++; - tmp = sd_rcv_byte(); - } - while(tmp != SD_IDLE); - sd_send_byte(SD_IDLE); - } - - //puts("send cmd success\n"); - sd_deassert_cs(); - return 1; -} - -int -sd_read_block (unsigned int blockaddr, unsigned char *buf) -{ - unsigned char response[5]; - unsigned char argument[4]; - unsigned int i = 0; - unsigned char tmp; - - blockaddr <<= SD_BLOCKLEN_NBITS; - sd_packarg(argument,blockaddr); - if(sd_send_command(SD_CMD17,SD_CMD17_R,response,argument)==0) - return 0; //Failed READ; - if(response[0] != 0) - return 0; //Misaligned READ - - sd_assert_cs(); - i = 0; - do - { - tmp = sd_rcv_byte(); - i++; - } - while((tmp == 0xFF) && (i < SD_RD_TIMEOUT)); - if((i>= SD_RD_TIMEOUT) ||((tmp & SD_MSK_TOK_DATAERROR) == 0)) - { - sd_send_byte(SD_IDLE); // Send a dummy before quitting - return 0; // Data ERROR - } - for(i=0;i<SD_BLOCKLEN;i++) - buf[i] = sd_rcv_byte(); - return 1; - -} - -int -sd_write_block(unsigned int blockaddr, const unsigned char *buf) -{ - // FIXME not implemented yet - return 0; -} diff --git a/firmware/microblaze/lib/sd.h b/firmware/microblaze/lib/sd.h deleted file mode 100644 index e2d0ae38e..000000000 --- a/firmware/microblaze/lib/sd.h +++ /dev/null @@ -1,122 +0,0 @@ -/* -*- c -*- */ -/* - * Copyright 2008 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_SD_H -#define INCLUDED_SD_H - -#include "memory_map.h" - -#define SD_READY 1 -#define SD_IDLE_WAIT_MAX 100 -#define SD_CMD_TIMEOUT 100 -#define SD_RD_TIMEOUT 1000 - -#define SD_CMD0 0 -#define SD_CMD1 1 -#define SD_CMD9 9 -#define SD_CMD10 10 -#define SD_CMD12 12 -#define SD_CMD13 13 -#define SD_CMD16 16 -#define SD_CMD17 17 -#define SD_CMD18 18 -#define SD_CMD24 24 -#define SD_CMD25 25 -#define SD_CMD27 27 -#define SD_CMD28 28 -#define SD_CMD29 29 -#define SD_CMD30 30 -#define SD_CMD32 32 -#define SD_CMD33 33 -#define SD_CMD38 38 -#define SD_CMD55 55 -#define SD_CMD58 58 -#define SD_CMD59 59 -#define SD_ACMD41 41 -#define SD_IDLE 0xFF -#define SD_CRC 0x95 - -#define SD_R1 1 -#define SD_R1B 2 -#define SD_R2 3 -#define SD_R3 4 - -#define SD_CMD0_R SD_R1 -#define SD_CMD16_R SD_R1 -#define SD_CMD17_R SD_R1 -#define SD_CMD55_R SD_R1 -#define SD_ACMD41_R SD_R1 -#define SD_CMD58_R SD_R3 - -#define SD_BLOCKLEN 512 -#define SD_BLOCKLEN_NBITS 9 - -#define SD_MSK_IDLE 0x01 -#define SD_MSK_OCR_33 0xC0 -#define SD_MSK_TOK_DATAERROR 0xE0 - - -int sd_init(void); - -static inline void -sd_assert_cs(void) -{ - // Wait for idle before doing anything - while(sdspi_regs->status != SD_READY) - ; - sdspi_regs->status = 1; -} - -static inline void -sd_deassert_cs(void) -{ - // Wait for idle before doing anything - while(sdspi_regs->status != SD_READY) - ; - sdspi_regs->status = 0; -} - -static inline char -sd_rcv_byte(void) -{ - // Wait for idle before doing anything - while(sdspi_regs->status != SD_READY) - ; - sdspi_regs->send_dat = SD_IDLE; - while(sdspi_regs->status != SD_READY) - ; - return sdspi_regs-> receive_dat; -} - -static inline void -sd_send_byte(char dat) -{ - // Wait for idle before doing anything - while(sdspi_regs->status != SD_READY) - ; // Wait for status = 1 (ready) - sdspi_regs->send_dat = dat; -} - - -int sd_send_command(unsigned char cmd,unsigned char response_type, - unsigned char *response,unsigned char *argument); - -int sd_read_block (unsigned int blockaddr, unsigned char *buf); -int sd_write_block(unsigned int blockaddr, const unsigned char *buf); - -#endif /* INCLUDED_SD_H */ diff --git a/firmware/microblaze/lib/spi.h b/firmware/microblaze/lib/spi.h index f5b69b270..01e4d26fd 100644 --- a/firmware/microblaze/lib/spi.h +++ b/firmware/microblaze/lib/spi.h @@ -48,5 +48,23 @@ void spi_wait(void); uint32_t spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags); +// ---------------------------------------------------------------- +// 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/microblaze/lib/u2_init.c b/firmware/microblaze/lib/u2_init.c index 6809101c0..ff558d673 100644 --- a/firmware/microblaze/lib/u2_init.c +++ b/firmware/microblaze/lib/u2_init.c @@ -25,9 +25,7 @@ #include "i2c.h" #include "mdelay.h" #include "clocks.h" -#include "usrp2_i2c_addr.h" - -//#include "nonstdio.h" +#include "usrp2/fw_common.h" unsigned char u2_hw_rev_major; unsigned char u2_hw_rev_minor; @@ -35,8 +33,8 @@ unsigned char u2_hw_rev_minor; static inline void get_hw_rev(void) { - bool ok = eeprom_read(I2C_ADDR_MBOARD, MBOARD_REV_LSB, &u2_hw_rev_minor, 1); - ok &= eeprom_read(I2C_ADDR_MBOARD, MBOARD_REV_MSB, &u2_hw_rev_major, 1); + bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_REV_LSB, &u2_hw_rev_minor, 1); + ok &= eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_REV_MSB, &u2_hw_rev_major, 1); } /* diff --git a/firmware/microblaze/lib/udp_burner_packet.c b/firmware/microblaze/lib/udp_burner_packet.c new file mode 100644 index 000000000..d86a4cf4a --- /dev/null +++ b/firmware/microblaze/lib/udp_burner_packet.c @@ -0,0 +1,38 @@ +/* -*- 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 "udp_burner_packet.h" +#include "net_common.h" +#include "loader_parser.h" +#include <stdint.h> +#include <compiler.h> +#include <nonstdio.h> + + +void +handle_udp_burner_packet(struct socket_address src, struct socket_address dst, + unsigned char *payload, int payload_len) +{ + unsigned char reply[128] _AL4; + size_t actual_reply_len; + loader_parser(payload, payload_len, reply, sizeof(reply), &actual_reply_len); + send_udp_pkt(dst.port, src, reply, actual_reply_len); +} diff --git a/firmware/microblaze/lib/udp_burner_packet.h b/firmware/microblaze/lib/udp_burner_packet.h new file mode 100644 index 000000000..0f4025712 --- /dev/null +++ b/firmware/microblaze/lib/udp_burner_packet.h @@ -0,0 +1,28 @@ +/* -*- 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_UDP_BURNER_PACKET_H +#define INCLUDED_UDP_BURNER_PACKET_H + +#include <net/socket_address.h> + +void +handle_udp_burner_packet(struct socket_address src, struct socket_address dst, + unsigned char *payload, int payload_len); + + +#endif /* INCLUDED_UDP_BURNER_PACKET_H */ diff --git a/firmware/microblaze/lib/xilinx_s3_icap.c b/firmware/microblaze/lib/xilinx_s3_icap.c new file mode 100644 index 000000000..8aa7fd297 --- /dev/null +++ b/firmware/microblaze/lib/xilinx_s3_icap.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/>. + */ + + +/* Changes required to work for the Spartan-3A series: + * The ICAP interface on the 3A is 8 bits wide, instead of 32. + * Everything is Xilinx standard LSB-first. + * The operations are all different. + * Commands are 16 bits long, presented to the ICAP interface 8 bits at a time. +*/ + +#include <xilinx_s3_icap.h> +#include <memory_map.h> +#include <spi_flash_private.h> //for READ_CMD + + +/* bit swap end-for-end */ +static unsigned char +swap8(unsigned char x) +{ + unsigned char r = 0; + r |= (x >> 7) & 0x01; + r |= (x >> 5) & 0x02; + r |= (x >> 3) & 0x04; + r |= (x >> 1) & 0x08; + + r |= (x << 1) & 0x10; + r |= (x << 3) & 0x20; + r |= (x << 5) & 0x40; + r |= (x << 7) & 0x80; + + return r; +} + +void +wr_icap(uint8_t x) +{ + uint8_t t = swap8(x); + + icap_regs->icap = t; //DEBUG: does not swap bits +} + +uint8_t +rd_icap(void) +{ + return swap8(icap_regs->icap); +} + + +void +icap_reload_fpga(uint32_t flash_address) +//this DOES NOT WORK right now. reboot is not getting executed correctly. +{ + union { + uint32_t i; + uint8_t c[4]; + } t; + t.i = flash_address; + + //note! t.c[0] MUST contain the byte-wide read command for the flash device used. + //for the 25P64, and most other flash devices, this is 0x03. + t.c[0] = READ_CMD; //legacy command, use FAST_READ_CMD 0x0B after testing + + //TODO: look up the watchdog timer, ensure it won't fire too soon + + //UG332 p279 +// wr_icap(0xff); +// wr_icap(0xff); //dummy word, probably unnecessary + wr_icap(0xAA); + wr_icap(0x99); //sync word + wr_icap(0x32); + wr_icap(0x61); //Type 1 write General 1 (1 word) + wr_icap(t.c[2]); //bits 15-8 + wr_icap(t.c[3]); //bits 7-0 + wr_icap(0x32); + wr_icap(0x81); //Type 1 write General 2 (1 word) + wr_icap(t.c[0]); //C0-C8, the byte-wide read command + wr_icap(t.c[1]); //Upper 8 bits of 24-bit address + wr_icap(0x30); + wr_icap(0xA1); //Type 1 write CMD (1 word) + wr_icap(0x00); + wr_icap(0x0E); //REBOOT command + wr_icap(0x20); + wr_icap(0x00); //Type 1 NOP + +} |