#include "appl_version.h"
#include "appl_fpga.h"
-volatile uint16_t *fpga_configure_line = 0x8003FFFC;
+#define SWAB32(x) ((x >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | (x << 24))
+
+/* Registers in FPGA */
+volatile uint32_t *tumbl_control = (volatile uint32_t *)FPGA_TUMBL_CONTROL_REG;
+volatile uint32_t *tumbl_trace_kick = (volatile uint32_t *)FPGA_TUMBL_TRACE_KICK_REG;
+volatile uint32_t *tumbl_pc = (volatile uint32_t *)FPGA_TUMBL_PC;
+volatile uint32_t *tumbl_base = (volatile uint32_t *)FPGA_TUMBL_IMEM_BASE;
+volatile uint32_t *tumbl_imem = (volatile uint32_t *)FPGA_TUMBL_IMEM_BASE;
+volatile uint32_t *tumbl_dmem = (volatile uint32_t *)FPGA_TUMBL_DMEM_BASE;
+
+volatile struct irc_register *irc1 = (volatile struct irc_register *)FPGA_IRC1_BASE;
+volatile struct irc_register *irc2 = (volatile struct irc_register *)FPGA_IRC2_BASE;
+volatile struct irc_register *irc3 = (volatile struct irc_register *)FPGA_IRC3_BASE;
+volatile struct irc_register *irc4 = (volatile struct irc_register *)FPGA_IRC4_BASE;
+
+/* Variables for configuration */
+volatile uint16_t *fpga_configure_line = (volatile uint16_t *)0x8003FFFC;
int fpga_configured = 0;
int fpga_reconfiguration_locked = 1;
+/* BUS calibration - registers to measure the delay necessary for reading and writing */
+volatile uint32_t *fpga_bus_calib_read1 = (volatile uint32_t *)0x8003FFF0;
+volatile uint32_t *fpga_bus_calib_read2 = (volatile uint32_t *)0x8003FFF4;
+
+volatile uint32_t *fpga_bus_calib_write1 = (volatile uint32_t *)0x8003FFF8;
+volatile uint32_t *fpga_bus_calib_write2 = (volatile uint32_t *)0x8003FFFC;
+
+/* BUS calibration - values (shifting all bits) */
+#define CALIB_VAL1 0xAAAAAAAA
+#define CALIB_VAL2 0x55555555
+
void appl_fpga_init()
{
/* Initialze EMC for FPGA */
LPC_EMC->StaticConfig0 = 0x00000002;
/* Delays - not calibrated at this point
- * Read: use default: 32 cycles
- * Write: use default: 33 cycles
- * Turnaround: use default: 16 cycles
+ * We're running on 72 MHz, FPGA bus is running on 100 MHz async.
+ * Read: 32 cycles
+ * Write: 33 cycles
+ * Turnaround: 2 cycles (cca. 28 ns)
*/
+ LPC_EMC->StaticWaitRd0 = 0x1F;
+ LPC_EMC->StaticWaitWr0 = 0x1F;
+ LPC_EMC->StaticWaitTurn0 = 0x01;
/* Shift addresses by 2 (32-bit bus) */
LPC_SC->SCS &= 0xFFFFFFFE;
- printf("EMC for FPGA configured!\n");
+ printf("EMC for FPGA initialized!\n");
+}
+
+int appl_fpga_tumbl_set_reset(int reset)
+{
+ int i;
+
+ if (reset)
+ *tumbl_control |= FPGA_TUMBL_CONTROL_REG_RESET_BIT;
+ else
+ *tumbl_control &= ~FPGA_TUMBL_CONTROL_REG_RESET_BIT;
+ return 0;
+}
+
+int appl_fpga_tumbl_set_halt(int halt)
+{
+ if (halt)
+ *tumbl_control |= FPGA_TUMBL_CONTROL_REG_HALT_BIT;
+ else
+ *tumbl_control &= ~FPGA_TUMBL_CONTROL_REG_HALT_BIT;
+
+ return 0;
+}
+
+int appl_fpga_tumbl_set_trace(int trace)
+{
+ if (trace)
+ *tumbl_control |= FPGA_TUMBL_CONTROL_REG_TRACE_BIT;
+ else
+ *tumbl_control &= ~FPGA_TUMBL_CONTROL_REG_TRACE_BIT;
+
+ return 0;
+}
+
+int appl_fpga_tumbl_kick_trace()
+{
+ int i;
+
+ *tumbl_trace_kick = 1;
+ __memory_barrier();
+
+ /* Make sure it's processed */
+ for (i = 0; i < 32; i++)
+ {}
+
+ __memory_barrier();
+ printf("Tumbl PC: 0x%08X\n", (unsigned int) *tumbl_pc);
+ return 0;
+}
+
+void appl_fpga_tumbl_write(unsigned int offset, unsigned char *ptr, int len)
+{
+ int i;
+ unsigned int *iptr = (unsigned int *)ptr;
+
+ for (i = 0; i < len / 4; i++)
+ tumbl_base[(offset / 4) + i] = SWAB32(iptr[i]);
+}
+
+/*
+ * Bus calibration - functions can be called via USB interface
+ * Proper usage:
+ * 1) Calibrate read
+ * 2) Calibrate write
+ * 3) Set turnaround
+ * bus is not pipelined, therefore
+ * just necessary delay for I/O to enter
+ * high impedance state (synchronous clocking => only 1 cycle necessary)
+ */
+
+/* Cannot be on stack due to memory barrier for gcc */
+static uint32_t a, b;
+
+int appl_fpga_calibrate_bus_read()
+{
+ int i;
+
+ /* Set the delays are set to highest (default) value */
+ LPC_EMC->StaticWaitRd0 = 0x1F;
+
+ while (LPC_EMC->StaticWaitRd0 >= 0)
+ {
+ for (i = 0; i < 1024; i++)
+ {
+ /* Reset the values */
+ __memory_barrier();
+ a = 0xFFFFFFFF;
+ b = 0xFFFFFFFF;
+ __memory_barrier();
+ /* Read the values several times - so there are two flips at least
+ * NOTE: SDRAM reads / writes may occur in between!
+ */
+ a = *fpga_bus_calib_read1;
+ b = *fpga_bus_calib_read2;
+ a = *fpga_bus_calib_read1;
+ b = *fpga_bus_calib_read2;
+ a = *fpga_bus_calib_read1;
+ b = *fpga_bus_calib_read2;
+ a = *fpga_bus_calib_read1;
+ b = *fpga_bus_calib_read2;
+ __memory_barrier();
+
+ /* Verify */
+ if (a != CALIB_VAL1 || b != CALIB_VAL2)
+ {
+ if (LPC_EMC->StaticWaitRd0 == 0x1F)
+ {
+ printf("ERROR: FPGA bus is not working properly!\n");
+ return 1;
+ }
+ else
+ {
+ LPC_EMC->StaticWaitRd0++;
+ printf("FPGA bus: StaticWaitRd0 set to 0x%02X\n", (unsigned int) LPC_EMC->StaticWaitRd0);
+ return 0;
+ }
+ }
+ }
+
+ /* We're good, lower it */
+ if (LPC_EMC->StaticWaitRd0 == 0)
+ {
+ printf("FPGA bus: StaticWaitRd0 set to 0x%02X\n", (unsigned int) LPC_EMC->StaticWaitRd0);
+ break;
+ }
+ else
+ LPC_EMC->StaticWaitRd0--;
+ }
+
+ return 0;
}
-void appl_fpga_set_reconfiguartion_lock(int lock)
+int appl_fpga_calibrate_bus_write()
+{
+ int i;
+
+ /* Set the delays are set to highest (default) value */
+ LPC_EMC->StaticWaitWr0 = 0x1F;
+
+ while (LPC_EMC->StaticWaitWr0 >= 0)
+ {
+ for (i = 0; i < 1024; i++)
+ {
+ /* Make sure there is nothing other going on */
+ __memory_barrier();
+ *fpga_bus_calib_write1 = 0x00000000;
+ *fpga_bus_calib_write2 = 0x00000000;
+ __memory_barrier();
+ a = 0xFFFFFFFF;
+ b = 0xFFFFFFFF;
+ __memory_barrier();
+ /* Write the values several times - so there are two flips at least
+ * NOTE: SDRAM reads / writes may occur in between!
+ */
+ *fpga_bus_calib_write1 = CALIB_VAL1;
+ *fpga_bus_calib_write2 = CALIB_VAL2;
+ *fpga_bus_calib_write1 = CALIB_VAL1;
+ *fpga_bus_calib_write2 = CALIB_VAL2;
+ *fpga_bus_calib_write1 = CALIB_VAL1;
+ *fpga_bus_calib_write2 = CALIB_VAL2;
+ *fpga_bus_calib_write1 = CALIB_VAL1;
+ *fpga_bus_calib_write2 = CALIB_VAL2;
+ /*
+ * Strongly ordered memory
+ * GCC is blocked by volatilness
+ */
+ __memory_barrier();
+ a = *fpga_bus_calib_write1;
+ b = *fpga_bus_calib_write2;
+ __memory_barrier();
+
+ /* Verify */
+ if (a != CALIB_VAL1 || b != CALIB_VAL2)
+ {
+ if (LPC_EMC->StaticWaitWr0 == 0x1F)
+ {
+ printf("ERROR: FPGA bus is not working properly!\n");
+ printf("a = 0x%08X, b = 0x%08X\n", (unsigned int) a, (unsigned int) b);
+ return 1;
+ }
+ else
+ {
+ LPC_EMC->StaticWaitWr0++;
+ printf("FPGA bus: StaticWaitWr0 set to 0x%02X\n", (unsigned int) LPC_EMC->StaticWaitWr0);
+ return 0;
+ }
+ }
+ }
+
+ /* We're good, lower it */
+ if (LPC_EMC->StaticWaitWr0 == 0)
+ {
+ printf("FPGA bus: StaticWaitWr0 set to 0x%02X\n", (unsigned int) LPC_EMC->StaticWaitWr0);
+ break;
+ }
+ else
+ LPC_EMC->StaticWaitWr0--;
+ }
+
+ return 0;
+}
+
+void appl_fpga_set_reconfiguration_lock(int lock)
{
fpga_reconfiguration_locked = lock;
}
-int appl_fpga_get_reconfiguartion_lock()
+int appl_fpga_get_reconfiguration_lock()
{
return fpga_reconfiguration_locked;
}
j++;
}
+
+ /* Use highest EMC delays */
+ LPC_EMC->StaticWaitRd0 = 0x1F;
+ LPC_EMC->StaticWaitWr0 = 0x1F;
/* Assert RWDR to WRITE */
hal_gpio_set_value(XC_RDWR_PIN, 0);
}
}
- /* Issue startup clocks with data in all 1 (at least 8 recommended) */
+ /* Issue startup clocks with data all 1s (at least 8 recommended) */
for (i = 0; i < 16; i++)
*fpga_configure_line = 0xFFFF;
/* Hold it for some time */
for (i = 0; i < 128; i++)
{}
+
+ /* Use EMC delays obtained through calibration */
+ LPC_EMC->StaticWaitRd0 = 0x04;
+ LPC_EMC->StaticWaitWr0 = 0x01;
/* Lift the reset */
hal_gpio_direction_output(XC_INIT_PIN, 1);
+
+ /* Give it some time */
+ for (i = 0; i < 1024; i++)
+ {}
+
fpga_configured = 1;
printf("FPGA configured!\n");
return FPGA_CONF_SUCESS;
#include "appl_defs.h"
+/* Register defines */
+
+/* Tumbl */
+
+#define FPGA_TUMBL_IMEM_BASE 0x80000000
+#define FPGA_TUMBL_DMEM_BASE 0x80001000
+#define FPGA_TUMBL_CONTROL_REG 0x80003000
+#define FPGA_TUMBL_TRACE_KICK_REG 0x80003004
+#define FPGA_TUMBL_PC 0x80003008
+
+#define FPGA_TUMBL_CONTROL_REG_RESET_BIT 0x01
+#define FPGA_TUMBL_CONTROL_REG_INT_BIT 0x02
+#define FPGA_TUMBL_CONTROL_REG_HALT_BIT 0x04
+#define FPGA_TUMBL_CONTROL_REG_TRACE_BIT 0x08
+
+extern volatile uint32_t *tumbl_control;
+extern volatile uint32_t *tumbl_trace_kick;
+extern volatile uint32_t *tumbl_imem;
+extern volatile uint32_t *tumbl_dmem;
+
+/* IRC */
+
+#define FPGA_IRC1_BASE 0x80020000
+#define FPGA_IRC2_BASE 0x80020010
+#define FPGA_IRC3_BASE 0x80020020
+#define FPGA_IRC4_BASE 0x80020030
+
+struct irc_register
+{
+ uint32_t count;
+ uint32_t count_index;
+ uint32_t state;
+};
+
+extern volatile struct irc_register *irc1;
+extern volatile struct irc_register *irc2;
+extern volatile struct irc_register *irc3;
+extern volatile struct irc_register *irc4;
+
+extern volatile uint32_t *fpga_bcd;
+
+/* Configuration defines */
+
#define FPGA_CONFIGURATION_FILE_ADDRESS 0xA1C00000
#define FPGA_CONF_SUCESS 0
#define FPGA_CONF_ERR_WRITE_ERR 3
#define FPGA_CONF_ERR_CRC_ERR 4
+int appl_fpga_tumbl_set_reset(int reset);
+int appl_fpga_tumbl_set_halt(int halt);
+int appl_fpga_tumbl_set_trace(int trace);
+int appl_fpga_tumbl_kick_trace();
+
+void appl_fpga_tumbl_write(unsigned int offset, unsigned char *ptr, int len);
+
void appl_fpga_init();
int appl_fpga_configure();
-void appl_fpga_set_reconfiguartion_lock(int lock);
-int appl_fpga_get_reconfiguartion_lock();
+int appl_fpga_calibrate_bus_read();
+int appl_fpga_calibrate_bus_write();
+void appl_fpga_set_reconfiguration_lock(int lock);
+int appl_fpga_get_reconfiguration_lock();
#endif /*_APPL_FPGA_H*/
#define SWAP(x) (x)
#endif
-#define USB_CMD_FPGA_CONFIGURE 0xF000
+#define USB_VENDOR_TARGET_TUMBL 0x03
+
+#define USB_CMD_FPGA_CONFIGURE 0xF000
+#define USB_CMD_FPGA_CALIBRATE_READ 0xF001
+#define USB_CMD_FPGA_CALIBRATE_WRITE 0xF002
+#define USB_CMD_FPGA_TEST_IRC 0xF004
+#define USB_CMD_FPGA_TEST_BCD 0xF005
+
+#define USB_CMD_FPGA_TUMBL_SET_RESET 0xF100
+#define USB_CMD_FPGA_TUMBL_SET_HALT 0xF101
+#define USB_CMD_FPGA_TUMBL_SET_TRACE 0xF102
+#define USB_CMD_FPGA_TUMBL_KICK_TRACE 0xF103
+
+#define USB_CMD_FPGA_TUMBL_DUMP_IMEM 0xF200
+#define USB_CMD_FPGA_TUMBL_DUMP_DMEM 0xF201
+
+#define USB_CMD_FPGA_RESET 0xFFFF
usb_device_t usb_device;
usb_ep_t eps[NUM_ENDPOINTS];
return USB_COMPLETE_OK;
}
+static int usb_tumbl_pkt_wr(struct usb_ep_t *ep, int len, int code)
+{
+ unsigned char *ptr = ep->ptr - len;
+
+ appl_fpga_tumbl_write(ep->user_data, ptr, len);
+
+ ep->user_data += len;
+ ep->ptr = ep0_buffer;
+ return USB_COMPLETE_OK;
+}
+
static int usb_flash_erase(unsigned addr, unsigned len)
{
#ifdef CONFIG_KEYVAL
uint16_t appl_usb_vendor_call(uint16_t command, uint16_t argument)
{
- if (command == USB_CMD_FPGA_CONFIGURE)
- return appl_fpga_configure();
+ int i, j;
+
+ switch (command)
+ {
+ case USB_CMD_FPGA_CONFIGURE:
+ return appl_fpga_configure();
+
+ case USB_CMD_FPGA_CALIBRATE_READ:
+ return appl_fpga_calibrate_bus_read();
+
+ case USB_CMD_FPGA_CALIBRATE_WRITE:
+ return appl_fpga_calibrate_bus_write();
+
+ case USB_CMD_FPGA_TEST_IRC:
+ printf("IRC1: count = %d, count index = %d\n", (unsigned int) irc1->count, (unsigned int) irc1->count_index);
+ printf("IRC2: count = %d, count index = %d\n", (unsigned int) irc2->count, (unsigned int) irc2->count_index);
+ printf("IRC3: count = %d, count index = %d\n", (unsigned int) irc3->count, (unsigned int) irc3->count_index);
+ printf("IRC4: count = %d, count index = %d\n", (unsigned int) irc4->count, (unsigned int) irc4->count_index);
+ return 0;
+
+ case USB_CMD_FPGA_TUMBL_SET_RESET:
+ return appl_fpga_tumbl_set_reset(argument);
+
+ case USB_CMD_FPGA_TUMBL_SET_HALT:
+ return appl_fpga_tumbl_set_halt(argument);
+
+ case USB_CMD_FPGA_TUMBL_SET_TRACE:
+ return appl_fpga_tumbl_set_trace(argument);
+
+ case USB_CMD_FPGA_TUMBL_KICK_TRACE:
+ return appl_fpga_tumbl_kick_trace();
+
+ case USB_CMD_FPGA_TUMBL_DUMP_IMEM:
+ printf("TUMBL IMEM:\n");
+ for (i = 0; i < 64; i++)
+ {
+ for (j = 0; j < 8; j++)
+ printf("%08X ", (unsigned int) tumbl_imem[i*8 + j]);
+
+ printf("\n");
+ }
+ return 0;
+
+ case USB_CMD_FPGA_TUMBL_DUMP_DMEM:
+ printf("TUMBL DMEM:\n");
+ for (i = 0; i < 128; i++)
+ {
+ for (j = 0; j < 8; j++)
+ printf("%08X ", (unsigned int) tumbl_dmem[i*8 + j]);
+
+ printf("\n");
+ }
+ return 0;
+
+ case USB_CMD_FPGA_RESET:
+ hal_gpio_direction_output(XC_INIT_PIN, 0);
+
+ for (i = 0; i < 128; i++)
+ {}
+
+ hal_gpio_direction_output(XC_INIT_PIN, 1);
+ return 0;
+ }
return 0xFFFF;
}
udev->ep0.user_data = addr;
udev->ep0.ptr = ep0_buffer;
break;
+
+ case USB_VENDOR_TARGET_TUMBL:
+ udev->ep0.next_pkt_fnc = usb_tumbl_pkt_wr;
+ udev->ep0.user_data = addr;
+ udev->ep0.ptr = ep0_buffer;
+ break;
default:
return -1;