From 4f57ecab13e37f132c99ec797d412def3f1e2a66 Mon Sep 17 00:00:00 2001 From: Mark Meserve Date: Thu, 11 Apr 2019 15:14:37 -0500 Subject: b200: add custom bootloader - Adds custom bootloader code - Refactor common functions in firmware and bootloader --- firmware/fx3/.gitignore | 2 + firmware/fx3/README.md | 33 +- firmware/fx3/b200/.gitignore | 3 + firmware/fx3/b200/b200_gpifconfig.h | 176 -- firmware/fx3/b200/b200_i2c.c | 82 - firmware/fx3/b200/b200_i2c.h | 40 - firmware/fx3/b200/b200_main.c | 3161 --------------------- firmware/fx3/b200/b200_main.h | 140 - firmware/fx3/b200/b200_usb_descriptors.c | 690 ----- firmware/fx3/b200/bootloader/.gitignore | 5 + firmware/fx3/b200/bootloader/main.c | 55 + firmware/fx3/b200/bootloader/makefile | 92 + firmware/fx3/b200/bootloader/usb_boot.c | 807 ++++++ firmware/fx3/b200/bootloader/usb_descriptors.c | 187 ++ firmware/fx3/b200/bootloader/usb_descriptors.h | 26 + firmware/fx3/b200/common/common_const.h | 51 + firmware/fx3/b200/common/common_descriptors.c | 237 ++ firmware/fx3/b200/common/common_descriptors.h | 50 + firmware/fx3/b200/common/common_helpers.c | 199 ++ firmware/fx3/b200/common/common_helpers.h | 34 + firmware/fx3/b200/firmware/b200_const.h | 124 + firmware/fx3/b200/firmware/b200_gpifconfig.h | 176 ++ firmware/fx3/b200/firmware/b200_i2c.c | 82 + firmware/fx3/b200/firmware/b200_i2c.h | 40 + firmware/fx3/b200/firmware/b200_main.c | 3125 ++++++++++++++++++++ firmware/fx3/b200/firmware/b200_usb_descriptors.c | 359 +++ firmware/fx3/b200/firmware/b200_usb_descriptors.h | 21 + firmware/fx3/b200/firmware/makefile | 53 + firmware/fx3/b200/fx3_mem_map.patch | 23 + firmware/fx3/b200/makefile | 51 - 30 files changed, 5775 insertions(+), 4349 deletions(-) delete mode 100755 firmware/fx3/b200/b200_gpifconfig.h delete mode 100644 firmware/fx3/b200/b200_i2c.c delete mode 100644 firmware/fx3/b200/b200_i2c.h delete mode 100644 firmware/fx3/b200/b200_main.c delete mode 100644 firmware/fx3/b200/b200_main.h delete mode 100644 firmware/fx3/b200/b200_usb_descriptors.c create mode 100644 firmware/fx3/b200/bootloader/.gitignore create mode 100644 firmware/fx3/b200/bootloader/main.c create mode 100644 firmware/fx3/b200/bootloader/makefile create mode 100644 firmware/fx3/b200/bootloader/usb_boot.c create mode 100644 firmware/fx3/b200/bootloader/usb_descriptors.c create mode 100644 firmware/fx3/b200/bootloader/usb_descriptors.h create mode 100644 firmware/fx3/b200/common/common_const.h create mode 100644 firmware/fx3/b200/common/common_descriptors.c create mode 100644 firmware/fx3/b200/common/common_descriptors.h create mode 100644 firmware/fx3/b200/common/common_helpers.c create mode 100644 firmware/fx3/b200/common/common_helpers.h create mode 100644 firmware/fx3/b200/firmware/b200_const.h create mode 100644 firmware/fx3/b200/firmware/b200_gpifconfig.h create mode 100644 firmware/fx3/b200/firmware/b200_i2c.c create mode 100644 firmware/fx3/b200/firmware/b200_i2c.h create mode 100644 firmware/fx3/b200/firmware/b200_main.c create mode 100644 firmware/fx3/b200/firmware/b200_usb_descriptors.c create mode 100644 firmware/fx3/b200/firmware/b200_usb_descriptors.h create mode 100644 firmware/fx3/b200/firmware/makefile delete mode 100644 firmware/fx3/b200/makefile diff --git a/firmware/fx3/.gitignore b/firmware/fx3/.gitignore index f2c372d44..81a6777c4 100644 --- a/firmware/fx3/.gitignore +++ b/firmware/fx3/.gitignore @@ -1,3 +1,5 @@ +boot_fw common +elf2img lpp_source u3p_firmware diff --git a/firmware/fx3/README.md b/firmware/fx3/README.md index 9b3d65489..00f38185f 100644 --- a/firmware/fx3/README.md +++ b/firmware/fx3/README.md @@ -5,7 +5,7 @@ INSTRUCTIONS The USRP B200 and B210 each use the Cypress FX3 USB3 PHY for USB3 connectivity. This device has an ARM core on it, which is programmed in C. This README will -show you how to build our firmware source +show you how to build our firmware and bootloader source. **A brief "Theory of Operations":** The host sends commands to the FX3, our USB3 PHY, which has an on-board ARM @@ -32,9 +32,11 @@ tools. These variables are: $ export ARMGCC_VERSION=4.5.2 ``` -Now, you'll need to set-up the Cypress SDK, as well. In the SDK, navigate to -the `firmware` directory, and copy the following sub-directories into -`uhd.git/firmware/fx3`: `common/`, `lpp_source/`, `u3p_firmware/`. +Now, you'll need to set-up the Cypress SDK, as well. In the SDK, copy the +following sub-directories from the `firmware` directory to +`uhd.git/firmware/fx3`: `common/`, `lpp_source/`, `u3p_firmware/`, `boot_fw/`. +In addition, copy the `elf2img` sub-directory from the `util` directory to +`uhd.git/firmware/fx3`. Your directory structure should now look like: @@ -46,7 +48,9 @@ uhd.git/ --fx3/ | --b200/ # From UHD + --boot_fw/ # From Cypress SDK --common/ # From Cypress SDK + --elf2img/ # From Cypress SDK --gpif2_designer/ # From UHD --lpp_source/ # From Cypress SDK --u3p_firmware/ # From Cypress SDK @@ -61,22 +65,33 @@ into the `common/` directory you just copied from the Cypress SDK, and apply the patch `b200/fx3_mem_map.patch`. ``` - # cd uhd.git/firmware/fx3/common/ - $ patch -p2 < ../b200/fx3_mem_map.patch + # cd uhd.git/firmware/fx3 + $ patch -p1 < ../b200/fx3_mem_map.patch ``` If you don't see any errors print on the screen, then the patch was successful. ## Building the Firmware -Now, you should be able to head into the `b200/` directory and simply build the -firmware: +Now, you should be able to head into the `b200/firmware` directory and simply +build the firmware: ``` - $ cd uhd.git/firmware/fx3/b200 + $ cd uhd.git/firmware/fx3/b200/firmware $ make ``` It will generate a `usrp_b200_fw.hex` file, which you can then give to UHD to program your USRP B200 or USRP B210. +## Building the Bootloader + +The bootloader is built in the `b200/bootloader` directory: + +``` + $ cd uhd.git/firmware/fx3/b200/bootloader + $ make +``` + +It will generate a `usrp_b200_bl.img` file, which you can supply as an argument +to b2xx_fx3_utils to load it onto the device. diff --git a/firmware/fx3/b200/.gitignore b/firmware/fx3/b200/.gitignore index 13c187886..2c36b03cd 100644 --- a/firmware/fx3/b200/.gitignore +++ b/firmware/fx3/b200/.gitignore @@ -1,4 +1,7 @@ +lib +!common *.o *.elf *.hex *.map +*.img diff --git a/firmware/fx3/b200/b200_gpifconfig.h b/firmware/fx3/b200/b200_gpifconfig.h deleted file mode 100755 index a6a24e0c5..000000000 --- a/firmware/fx3/b200/b200_gpifconfig.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Project Name: ssf2-edit.cyfx - * Time : 11/17/2014 13:01:01 - * Device Type: FX3 - * Project Type: GPIF2 - * - * - * - * - * This is a generated file and should not be modified - * This file need to be included only once in the firmware - * This file is generated by Gpif2 designer tool version - 1.0.837.1 - * - */ - -#ifndef _INCLUDED_CYFXGPIF2CONFIG_ -#define _INCLUDED_CYFXGPIF2CONFIG_ -#include "cyu3types.h" -#include "cyu3gpif.h" - -/* Summary - Number of states in the state machine - */ -#define CY_NUMBER_OF_STATES 7 - -/* Summary - Mapping of user defined state names to state indices - */ -#define RESET 0 -#define IDLE 1 -#define READ 2 -#define WRITE 3 -#define SHORT_PKT 4 -#define ZLP 5 -#define DSS_STATE 6 - - -/* Summary - Initial value of early outputs from the state machine. - */ -#define ALPHA_RESET 0xC - - -/* Summary - Transition function values used in the state machine. - */ -uint16_t CyFxGpifTransition[] = { - 0x0000, 0x8080, 0x2222, 0x5555, 0x7F7F, 0x1F1F, 0x8888 -}; - -/* Summary - Table containing the transition information for various states. - This table has to be stored in the WAVEFORM Registers. - This array consists of non-replicated waveform descriptors and acts as a - waveform table. - */ -CyU3PGpifWaveData CyFxGpifWavedata[] = { - {{0x1E086001,0x000302C4,0x80000000},{0x00000000,0x00000000,0x00000000}}, - {{0x4E080302,0x00000300,0x80000000},{0x1E086006,0x000302C4,0x80000000}}, - {{0x1E086001,0x000302C4,0x80000000},{0x4E040704,0x20000300,0xC0100000}}, - {{0x4E080302,0x00000300,0x80000000},{0x1E086001,0x000302C4,0x80000000}}, - {{0x00000000,0x00000000,0x00000000},{0x00000000,0x00000000,0x00000000}}, - {{0x00000000,0x00000000,0x00000000},{0x3E738705,0x00000300,0xC0100000}}, - {{0x00000000,0x00000000,0x00000000},{0x5E002703,0x2003030C,0x80000000}}, - {{0x00000000,0x00000000,0x00000000},{0x4E040704,0x20000300,0xC0100000}} -}; - -/* Summary - Table that maps state indices to the descriptor table indices. - */ -uint8_t CyFxGpifWavedataPosition[] = { - 0,1,0,2,0,0,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 0,5,0,2,0,0,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 0,6,0,2,0,0,6,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 0,7,0,2,0,0,7 -}; - -/* Summary - GPIF II configuration register values. - */ -uint32_t CyFxGpifRegValue[] = { - 0x80000380, /* CY_U3P_PIB_GPIF_CONFIG */ - 0x000010AC, /* CY_U3P_PIB_GPIF_BUS_CONFIG */ - 0x01070002, /* CY_U3P_PIB_GPIF_BUS_CONFIG2 */ - 0x00000044, /* CY_U3P_PIB_GPIF_AD_CONFIG */ - 0x00000000, /* CY_U3P_PIB_GPIF_STATUS */ - 0x00000000, /* CY_U3P_PIB_GPIF_INTR */ - 0x00000000, /* CY_U3P_PIB_GPIF_INTR_MASK */ - 0x00000082, /* CY_U3P_PIB_GPIF_SERIAL_IN_CONFIG */ - 0x00000782, /* CY_U3P_PIB_GPIF_SERIAL_OUT_CONFIG */ - 0x00000500, /* CY_U3P_PIB_GPIF_CTRL_BUS_DIRECTION */ - 0x0000FFCF, /* CY_U3P_PIB_GPIF_CTRL_BUS_DEFAULT */ - 0x000000BF, /* CY_U3P_PIB_GPIF_CTRL_BUS_POLARITY */ - 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_TOGGLE */ - 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ - 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ - 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ - 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ - 0x00000018, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ - 0x00000019, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ - 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ - 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ - 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ - 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ - 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ - 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ - 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ - 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ - 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ - 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ - 0x00000006, /* CY_U3P_PIB_GPIF_CTRL_COUNT_CONFIG */ - 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_COUNT_RESET */ - 0x0000FFFF, /* CY_U3P_PIB_GPIF_CTRL_COUNT_LIMIT */ - 0x0000010A, /* CY_U3P_PIB_GPIF_ADDR_COUNT_CONFIG */ - 0x00000000, /* CY_U3P_PIB_GPIF_ADDR_COUNT_RESET */ - 0x0000FFFF, /* CY_U3P_PIB_GPIF_ADDR_COUNT_LIMIT */ - 0x00000000, /* CY_U3P_PIB_GPIF_STATE_COUNT_CONFIG */ - 0x0000FFFF, /* CY_U3P_PIB_GPIF_STATE_COUNT_LIMIT */ - 0x0000010A, /* CY_U3P_PIB_GPIF_DATA_COUNT_CONFIG */ - 0x00000000, /* CY_U3P_PIB_GPIF_DATA_COUNT_RESET */ - 0x0000FFFF, /* CY_U3P_PIB_GPIF_DATA_COUNT_LIMIT */ - 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_COMP_VALUE */ - 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_COMP_MASK */ - 0x00000000, /* CY_U3P_PIB_GPIF_DATA_COMP_VALUE */ - 0x00000000, /* CY_U3P_PIB_GPIF_DATA_COMP_MASK */ - 0x00000000, /* CY_U3P_PIB_GPIF_ADDR_COMP_VALUE */ - 0x00000000, /* CY_U3P_PIB_GPIF_ADDR_COMP_MASK */ - 0x00000000, /* CY_U3P_PIB_GPIF_DATA_CTRL */ - 0x00000000, /* CY_U3P_PIB_GPIF_INGRESS_DATA */ - 0x00000000, /* CY_U3P_PIB_GPIF_INGRESS_DATA */ - 0x00000000, /* CY_U3P_PIB_GPIF_INGRESS_DATA */ - 0x00000000, /* CY_U3P_PIB_GPIF_INGRESS_DATA */ - 0x00000000, /* CY_U3P_PIB_GPIF_EGRESS_DATA */ - 0x00000000, /* CY_U3P_PIB_GPIF_EGRESS_DATA */ - 0x00000000, /* CY_U3P_PIB_GPIF_EGRESS_DATA */ - 0x00000000, /* CY_U3P_PIB_GPIF_EGRESS_DATA */ - 0x00000000, /* CY_U3P_PIB_GPIF_INGRESS_ADDRESS */ - 0x00000000, /* CY_U3P_PIB_GPIF_INGRESS_ADDRESS */ - 0x00000000, /* CY_U3P_PIB_GPIF_INGRESS_ADDRESS */ - 0x00000000, /* CY_U3P_PIB_GPIF_INGRESS_ADDRESS */ - 0x00000000, /* CY_U3P_PIB_GPIF_EGRESS_ADDRESS */ - 0x00000000, /* CY_U3P_PIB_GPIF_EGRESS_ADDRESS */ - 0x00000000, /* CY_U3P_PIB_GPIF_EGRESS_ADDRESS */ - 0x00000000, /* CY_U3P_PIB_GPIF_EGRESS_ADDRESS */ - 0x80010400, /* CY_U3P_PIB_GPIF_THREAD_CONFIG */ - 0x80010401, /* CY_U3P_PIB_GPIF_THREAD_CONFIG */ - 0x80010402, /* CY_U3P_PIB_GPIF_THREAD_CONFIG */ - 0x80010403, /* CY_U3P_PIB_GPIF_THREAD_CONFIG */ - 0x00000000, /* CY_U3P_PIB_GPIF_LAMBDA_STAT */ - 0x00000000, /* CY_U3P_PIB_GPIF_ALPHA_STAT */ - 0x00000000, /* CY_U3P_PIB_GPIF_BETA_STAT */ - 0x000C0000, /* CY_U3P_PIB_GPIF_WAVEFORM_CTRL_STAT */ - 0x00000000, /* CY_U3P_PIB_GPIF_WAVEFORM_SWITCH */ - 0x00000000, /* CY_U3P_PIB_GPIF_WAVEFORM_SWITCH_TIMEOUT */ - 0x00000000, /* CY_U3P_PIB_GPIF_CRC_CONFIG */ - 0x00000000, /* CY_U3P_PIB_GPIF_CRC_DATA */ - 0xFFFFFFC1 /* CY_U3P_PIB_GPIF_BETA_DEASSERT */ -}; - -/* Summary - This structure holds all the configuration inputs for the GPIF II. - */ -const CyU3PGpifConfig_t CyFxGpifConfig = { - (uint16_t)(sizeof(CyFxGpifWavedataPosition)/sizeof(uint8_t)), - CyFxGpifWavedata, - CyFxGpifWavedataPosition, - (uint16_t)(sizeof(CyFxGpifTransition)/sizeof(uint16_t)), - CyFxGpifTransition, - (uint16_t)(sizeof(CyFxGpifRegValue)/sizeof(uint32_t)), - CyFxGpifRegValue -}; - -#endif /* _INCLUDED_CYFXGPIF2CONFIG_ */ diff --git a/firmware/fx3/b200/b200_i2c.c b/firmware/fx3/b200/b200_i2c.c deleted file mode 100644 index c6fa67c77..000000000 --- a/firmware/fx3/b200/b200_i2c.c +++ /dev/null @@ -1,82 +0,0 @@ -// -// Copyright 2013-2014 Ettus Research LLC -// - -#include "b200_i2c.h" - -#include "cyu3i2c.h" - -/* I2c initialization for EEPROM programming. */ -void CyFxI2cInit (uint16_t pageLen) { - CyU3PI2cConfig_t i2cConfig; - - /* Initialize and configure the I2C master module. */ - CyU3PI2cInit (); - - /* Start the I2C master block. The bit rate is set at 100KHz. - * The data transfer is done via DMA. */ - CyU3PMemSet ((uint8_t *)&i2cConfig, 0, sizeof(i2cConfig)); - i2cConfig.bitRate = CY_FX_USBI2C_I2C_BITRATE; - i2cConfig.busTimeout = 0xFFFFFFFF; - i2cConfig.dmaTimeout = 0xFFFF; - i2cConfig.isDma = CyFalse; - - CyU3PI2cSetConfig (&i2cConfig, NULL); - glI2cPageSize = pageLen; -} - -/* I2C read / write for programmer application. */ -void CyFxUsbI2cTransfer ( - uint16_t byteAddress, - uint8_t devAddr, - uint16_t byteCount, - uint8_t *buffer, - CyBool_t isRead) -{ - CyU3PI2cPreamble_t preamble; - uint16_t pageCount = (byteCount / glI2cPageSize); - uint16_t resCount = glI2cPageSize; - - if (byteCount == 0) { - return; - } - - if ((byteCount % glI2cPageSize) != 0) { - pageCount ++; - resCount = byteCount % glI2cPageSize; - } - - while (pageCount != 0) { - if (isRead) { - /* Update the preamble information. */ - preamble.length = 4; - preamble.buffer[0] = devAddr; - preamble.buffer[1] = (uint8_t)(byteAddress >> 8); - preamble.buffer[2] = (uint8_t)(byteAddress & 0xFF); - preamble.buffer[3] = (devAddr | 0x01); - preamble.ctrlMask = 0x0004; - - CyU3PI2cReceiveBytes (&preamble, buffer, (pageCount == 1) ? resCount : glI2cPageSize, 0); - } else { - /* Write. Update the preamble information. */ - preamble.length = 3; - preamble.buffer[0] = devAddr; - preamble.buffer[1] = (uint8_t)(byteAddress >> 8); - preamble.buffer[2] = (uint8_t)(byteAddress & 0xFF); - preamble.ctrlMask = 0x0000; - - CyU3PI2cTransmitBytes (&preamble, buffer, (pageCount == 1) ? resCount : glI2cPageSize, 0); - /* Wait for the write to complete. */ - preamble.length = 1; - CyU3PI2cWaitForAck(&preamble, 200); - } - - /* An additional delay seems to be required after receiving an ACK. */ - CyU3PThreadSleep (1); - - /* Update the parameters */ - byteAddress += glI2cPageSize; - buffer += glI2cPageSize; - pageCount --; - } -} diff --git a/firmware/fx3/b200/b200_i2c.h b/firmware/fx3/b200/b200_i2c.h deleted file mode 100644 index c5c781946..000000000 --- a/firmware/fx3/b200/b200_i2c.h +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright 2013-2014 Ettus Research LLC -// - -#ifndef _B200_I2C_H -#define _B200_I2C_H - -#include "cyu3externcstart.h" - -#include "cyu3usbconst.h" -#include "cyu3types.h" - -/* Following two definitions made in b200_main.h for consistency. */ -/* define B200_VREQ_EEPROM_WRITE (uint8_t)(0xBA) */ -/* define B200_VREQ_EEPROM_READ (uint8_t)(0xBB) */ - -static uint16_t glI2cPageSize = 0x40; /* I2C Page size to be used for transfers. */ - -/* This application uses EEPROM as the slave I2C device. The I2C EEPROM - * part number used is 24LC256. The capacity of the EEPROM is 256K bits */ -#define CY_FX_USBI2C_I2C_MAX_CAPACITY (32 * 1024) /* Capacity in bytes */ - -/* The following constant is defined based on the page size that the I2C - * device support. 24LC256 support 64 byte page write access. */ -#define CY_FX_USBI2C_I2C_PAGE_SIZE (64) - -/* I2C Data rate */ -#define CY_FX_USBI2C_I2C_BITRATE (100000) - -/* Give a timeout value of 5s for any programming. */ -#define CY_FX_USB_I2C_TIMEOUT (5000) - -/* Function forward-declerations. */ -void CyFxI2cInit (uint16_t pageLen); -void CyFxUsbI2cTransfer (uint16_t byteAddress, uint8_t devAddr, - uint16_t byteCount, uint8_t *buffer, CyBool_t isRead); - -#include "cyu3externcend.h" - -#endif /* _B200_I2C_H */ diff --git a/firmware/fx3/b200/b200_main.c b/firmware/fx3/b200/b200_main.c deleted file mode 100644 index ac4988ae0..000000000 --- a/firmware/fx3/b200/b200_main.c +++ /dev/null @@ -1,3161 +0,0 @@ -// -// Copyright 2013-2015 Ettus Research LLC -// - -/* This file defines the application that runs on the Cypress FX3 device, and - * enables the user to program the FPGA with an FPGA image. Since the FPGA - * doesn't yet have a clock, the image must be bit-banged into the FPGA. - */ - -#include -#include - -#include "b200_main.h" -#include "b200_gpifconfig.h" -#include "b200_i2c.h" - -#include "cyu3dma.h" -#include "cyu3error.h" -#include "cyu3gpif.h" -#include "cyu3gpio.h" -#include "cyu3spi.h" -#include "cyu3os.h" -#include "cyu3pib.h" -#include "cyu3system.h" -#include "cyu3usb.h" -#include "cyu3utils.h" -#include "cyfxversion.h" -#include "pib_regs.h" - -#define STATIC_SAVER static // Save stack space for variables in a non-re-entrant function (e.g. USB setup callback) - -/* - * WARNING: Before you enable any of the features below, please read the comments on the same line for that feature! - * Indented features must have the parent feature enabled as well. - */ - -#define HAS_HEAP // This requires memory to be set aside for the heap (e.g. required for printing floating-point numbers). You can apply the accompanying patch ('fx3_mem_map.patch') to fx3.ld & cyfxtx.c to create one. -#define ENABLE_MSG // This will cause the compiled code to exceed the default text memory area (SYS_MEM). You can apply the accompanying patch ('fx3_mem_map.patch') to fx3.ld & cyfxtx.c to resize the memory map so it will fit. -#define ENABLE_MANUAL_DMA_XFER // Allows us to set it from the host (using the side channel util), doesn't auto-enable it -//#define ENABLE_P2U_SUSP_EOP -#define ENABLE_MANUAL_DMA_XFER_FROM_HOST -#define ENABLE_MANUAL_DMA_XFER_TO_HOST -//#define ENABLE_DMA_BUFFER_PACKET_DEBUG -#define ENABLE_FPGA_SB // Be careful: this will add an ever-so-slight delay to some operations (e.g. AD3961 tune) -#define ENABLE_RE_ENUM_THREAD -#define ENABLE_USB_EVENT_LOGGING -//#define PREVENT_LOW_POWER_MODE -/*#define ENABLE_INIT_B_WORKAROUND // This should only be enabled if you have a board where the FPGA INIT_B line is broken, but the FPGA is known to work*/ -/*#define ENABLE_DONE_WORKAROUND // This should only be enabled if you have a board where the FPGA DONE line is broken, but the FPGA is known to work*/ - -#define WATCHDOG_TIMEOUT 1500 -#define CHECK_POWER_STATE_SLEEP_TIME 500 // Should be less than WATCHDOG_TIMEOUT - -#define FPGA_PROGRAMMING_POLL_SLEEP 10 // ticks -#define FPGA_PROGRAMMING_BITSTREAM_START_POLL_COUNT 250 // ~2.5 secs -#define FPGA_PROGRAMMING_INITB_POLL_COUNT 100 // ~1 sec -#define FPGA_PROGRAMMING_DONE_POLL_COUNT 250 // ~2.5 secs // This is the interval *after* no FPGA programming activity has been detected - -#define FPGA_RESET_SETTLING_TIME (1*10) // ~10ms (for SB to initialise) - -#define RE_ENUM_THREAD_SLEEP_TIME 100 -#define KEEP_ALIVE_LOOP_COUNT 200 - -#pragma message "----------------------" - -#ifdef ENABLE_MSG -#pragma message "msg enabled" -#else -#pragma message "msg disabled" -#endif // ENABLE_MSG - -#ifdef ENABLE_MANUAL_DMA_XFER -#pragma message "Manual DMA transfers" - -#ifdef ENABLE_MANUAL_DMA_XFER_FROM_HOST -#pragma message " -> From host" -#endif // ENABLE_MANUAL_DMA_XFER_FROM_HOST - -#ifdef ENABLE_MANUAL_DMA_XFER_TO_HOST -#pragma message " <- To host" -#endif // ENABLE_MANUAL_DMA_XFER_TO_HOST - -#ifdef ENABLE_DMA_BUFFER_PACKET_DEBUG -#pragma message " Packet debugging enabled" -#endif // ENABLE_DMA_BUFFER_PACKET_DEBUG - -#else -#pragma message "Auto DMA transfers" -#endif // ENABLE_MANUAL_DMA_XFER - -#ifdef ENABLE_FPGA_SB -#pragma message "FPGA Settings Bus enabled" -#else -#pragma message "FPGA Settings Bus disabled" -#endif // ENABLE_FPGA_SB - -#ifdef ENABLE_RE_ENUM_THREAD -#pragma message "Re-enumeration & statistics thread enabled" -#else -#pragma message "Re-enumeration & statistics thread disabled" -#endif // ENABLE_RE_ENUM_THREAD - -#ifdef ENABLE_USB_EVENT_LOGGING -#pragma message "USB event logging enabled" -#else -#pragma message "USB event logging disabled" -#endif // ENABLE_USB_EVENT_LOGGING - -#ifdef PREVENT_LOW_POWER_MODE -#pragma message "Preventing Low Power Mode" -#else -#pragma message "Allowing Low Power Mode" -#endif // PREVENT_LOW_POWER_MODE - -#ifdef HAS_HEAP -#pragma message "Heap enabled" -#else -#pragma message "Heap disabled" -#endif // HAS_HEAP - -#ifdef ENABLE_INIT_B_WORKAROUND -#pragma message "INIT_B workaround enabled" -#else -#pragma message "INIT_B workaround disabled" -#endif // ENABLE_INIT_B_WORKAROUND - -#ifdef ENABLE_DONE_WORKAROUND -#pragma message "DONE workaround enabled" -#else -#pragma message "DONE workaround disabled" -#endif // ENABLE_DONE_WORKAROUND - -#pragma message "----------------------" - -/* Declare global & static fields for our bit-bang application. */ -static CyU3PDmaChannel data_cons_to_prod_chan_handle; -static CyU3PDmaChannel data_prod_to_cons_chan_handle; - -static CyU3PDmaChannel ctrl_cons_to_prod_chan_handle; -static CyU3PDmaChannel ctrl_prod_to_cons_chan_handle; - -static CyU3PEvent g_event_usb_config; -static CyU3PThread thread_main_app; -static CyU3PThread thread_fpga_config; -#ifdef ENABLE_RE_ENUM_THREAD -static CyU3PThread thread_re_enum; -#endif // ENABLE_RE_ENUM_THREAD - -static CyBool_t g_app_running = CyFalse; -static uint8_t g_fx3_state = STATE_UNDEFINED; - -#define USB2_VREQ_BUF_SIZE 64 -#define USB3_VREQ_BUF_SIZE 512 -#define MIN_VREQ_BUF_SIZE USB2_VREQ_BUF_SIZE -#define MAX_VREQ_BUF_SIZE USB3_VREQ_BUF_SIZE - -static uint16_t g_vendor_req_buff_size = MIN_VREQ_BUF_SIZE; -static uint8_t g_vendor_req_buffer[MAX_VREQ_BUF_SIZE] __attribute__ ((aligned (32))); -static uint16_t g_vendor_req_read_count = 0; - -static uint8_t fpga_hash[4] __attribute__ ((aligned (32))); -static uint8_t fw_hash[4] __attribute__ ((aligned (32))); -static uint8_t compat_num[2]; -static uint32_t g_fpga_programming_write_count = 0; - -#define COUNTER_MAGIC 0x10024001 -#define LOG_BUFFER_SIZE /*MAX_VREQ_BUF_SIZE*/1024 // [Max vreq @ USB3 (64 @ USB2)] Can be larger -static char log_buffer[LOG_BUFFER_SIZE]; -static char log_contiguous_buffer[LOG_BUFFER_SIZE]; -static int log_buffer_idx = 0, log_buffer_len = 0; -#ifdef ENABLE_MSG -static int log_count = 0; -#endif // ENABLE_MSG - -#define USB_EVENT_LOG_SIZE 64 -static uint8_t g_usb_event_log[USB_EVENT_LOG_SIZE]; -static uint16_t g_last_usb_event_log_index = 0; -static uint8_t g_usb_event_log_contiguous_buf[USB_EVENT_LOG_SIZE]; - -#ifdef ENABLE_FPGA_SB -static CyBool_t g_fpga_sb_enabled = CyFalse; -//static uint16_t g_fpga_sb_uart_div = 434*2; -static uint16_t g_fpga_sb_last_usb_event_log_index = 0; -static CyU3PThread thread_fpga_sb_poll; -static CyU3PMutex g_suart_lock; -#endif // ENABLE_FPGA_SB - -static CyU3PMutex g_log_lock, g_counters_lock, g_counters_dma_from_host_lock, g_counters_dma_to_host_lock; - -#define FPGA_SB_UART_ADDR_BASE 0x00 - -enum UARTRegs -{ - SUART_CLKDIV, - SUART_TXLEVEL, - SUART_RXLEVEL, - SUART_TXCHAR, - SUART_RXCHAR -}; - -enum UARTPacketType -{ - UPT_NONE = '\0', - UPT_MSG = ' ', - UPT_COUNTERS = 'C', - UPT_USB_EVENTS = 'U', -}; - -enum ConfigFlags { - CF_NONE = 0, - CF_TX_SWING = 1 << 0, - CF_TX_DEEMPHASIS = 1 << 1, - CF_DISABLE_USB2 = 1 << 2, - CF_ENABLE_AS_SUPERSPEED = 1 << 3, - CF_PPORT_DRIVE_STRENGTH = 1 << 4, - CF_DMA_BUFFER_SIZE = 1 << 5, - CF_DMA_BUFFER_COUNT = 1 << 6, - CF_MANUAL_DMA = 1 << 7, - CF_SB_BAUD_DIV = 1 << 8, - - CF_RE_ENUM = 1 << 31 -}; - -typedef struct Config { - int tx_swing; // [90] [65] 45 - int tx_deemphasis; // 0x11 - int disable_usb2; // 0 - int enable_as_superspeed; // 1 - int pport_drive_strength; // CY_U3P_DS_THREE_QUARTER_STRENGTH - int dma_buffer_size; // [USB3] (max) - int dma_buffer_count; // [USB3] 2 - int manual_dma; // 0 - int sb_baud_div; // 434*2 -} CONFIG, *PCONFIG; - -typedef struct ConfigMod { - int flags; - CONFIG config; -} CONFIG_MOD, *PCONFIG_MOD; - -static CONFIG g_config = { - 65, // tx_swing - 0x11, // tx_deemphasis - 0, // disable_usb2 - 1, // enable_as_superspeed - CY_U3P_DS_THREE_QUARTER_STRENGTH, // pport_drive_strength - 16*1024, // dma_buffer_size - optimized value from Cypress AN86947 - 2, // dma_buffer_count - optimized value from Cypress AN86947 - 0, // manual_dma - 434*2 // sb_baud_div -}; -static CONFIG_MOD g_config_mod; - -#define REG_LNK_PHY_ERROR_STATUS 0xE0033044 - -enum PhyErrors { - PHYERR_PHY_LOCK_EV = 1 << 8, - PHYERR_TRAINING_ERROR_EV = 1 << 7, - PHYERR_RX_ERROR_CRC32_EV = 1 << 6, - PHYERR_RX_ERROR_CRC16_EV = 1 << 5, - PHYERR_RX_ERROR_CRC5_EV = 1 << 4, - PHYERR_PHY_ERROR_DISPARITY_EV = 1 << 3, - PHYERR_PHY_ERROR_EB_UND_EV = 1 << 2, - PHYERR_PHY_ERROR_EB_OVR_EV = 1 << 1, - PHYERR_PHY_ERROR_DECODE_EV = 1 << 0, - - PHYERR_MAX = PHYERR_PHY_LOCK_EV, - PHYERR_MASK = (PHYERR_MAX << 1) - 1 -}; - -typedef struct USBErrorCounters { - int phy_error_count; - int link_error_count; - - int PHY_LOCK_EV; - int TRAINING_ERROR_EV; - int RX_ERROR_CRC32_EV; - int RX_ERROR_CRC16_EV; - int RX_ERROR_CRC5_EV; - int PHY_ERROR_DISPARITY_EV; - int PHY_ERROR_EB_UND_EV; - int PHY_ERROR_EB_OVR_EV; - int PHY_ERROR_DECODE_EV; -} USB_ERROR_COUNTERS, *PUSB_ERROR_COUNTERS; - -typedef struct DMACounters { - int XFER_CPLT; - int SEND_CPLT; - int RECV_CPLT; - int PROD_EVENT; - int CONS_EVENT; - int ABORTED; - int ERROR; - int PROD_SUSP; - int CONS_SUSP; - - int BUFFER_MARKER; - int BUFFER_EOP; - int BUFFER_ERROR; - int BUFFER_OCCUPIED; - - int last_count; - int last_size; - - int last_sid; - int bad_sid_count; -} DMA_COUNTERS, *PDMA_COUNTERS; - -typedef struct PIBCounters -{ - int socket_inactive; // CYU3P_PIB_ERR_THR1_SCK_INACTIVE -} PIB_COUNTERS, *PPIB_COUNTERS; - -typedef struct Counters { - int magic; - - DMA_COUNTERS dma_to_host; - DMA_COUNTERS dma_from_host; - - int log_overrun_count; - - int usb_error_update_count; - USB_ERROR_COUNTERS usb_error_counters; - - int usb_ep_underrun_count; - - int heap_size; - - int resume_count; - - int state_transition_count; - int invalid_gpif_state; - - PIB_COUNTERS pib_counters[4]; -} COUNTERS, *PCOUNTERS; - -volatile static COUNTERS g_counters; - -#ifndef min -#define min(a,b) ((a)<(b)?(a):(b)) -#endif // min - -#define LOCKP(p) CyU3PMutexGet(p, CYU3P_WAIT_FOREVER) -#define UNLOCKP(p) CyU3PMutexPut(p) -#define LOCK(p) LOCKP(&p) -#define UNLOCK(p) UNLOCKP(&p) - -//////////////////////////////////////////////////////////////////////////////// - -char *heap_end = 0; -caddr_t _sbrk(int incr) -{ -#ifdef HAS_HEAP - extern char __heap_start; - extern char __heap_end; - char *prev_heap_end; - - if (heap_end == 0) - { - heap_end = (char *)&__heap_start; - } - prev_heap_end = heap_end; - - if (heap_end + incr > &__heap_end) - { - return (caddr_t) 0; - } - heap_end += incr; - g_counters.heap_size += incr; // Not sync'd - - return (caddr_t) prev_heap_end; -#else - return (caddr_t) -1; -#endif // HAS_HEAP -} - -//////////////////////////////////////////////////////////////////////////////// - -void b200_start_fpga_sb_gpio(void); -void sb_write(uint8_t reg, uint32_t val); -void _sb_write_string(const char* msg); - -void msg(const char* str, ...) { -#define msg_CHECK_USE_LOCK -//void _msgv(int use_lock, const char* str, va_list args) { -//#define msg_CHECK_USE_LOCK if (use_lock) -#ifdef ENABLE_MSG - va_list args; - static char buf[LOG_BUFFER_SIZE]; - int idx = 0; - - msg_CHECK_USE_LOCK - LOCK(g_log_lock); - - ++log_count; - log_count %= 10000; - - va_start(args, str); - - if (1) { // FIXME: Optional - uint32_t time_now = CyU3PGetTime(); - idx += sprintf(buf, "%08X %04i ", (uint)time_now, log_count); - } - else - idx += sprintf(buf, "%04i ", log_count); - idx += vsnprintf(buf + idx, LOG_BUFFER_SIZE - idx, str, args); - - va_end(args); - - if ((LOG_BUFFER_SIZE - log_buffer_len) < (idx + 1 + 1)) { - msg_CHECK_USE_LOCK - LOCK(g_counters_lock); - ++g_counters.log_overrun_count; - msg_CHECK_USE_LOCK - UNLOCK(g_counters_lock); - - goto msg_exit; - } - - // Circular buffer if we need it later, but currently won't wrap due to above condition - memcpy(log_buffer + log_buffer_len, buf, min(idx + 1, LOG_BUFFER_SIZE - log_buffer_len)); - if ((idx + 1) > (LOG_BUFFER_SIZE - log_buffer_len)) - { - memcpy(log_buffer, buf + (LOG_BUFFER_SIZE - log_buffer_len), (idx + 1) - (LOG_BUFFER_SIZE - log_buffer_len)); - log_buffer[(idx + 1) - (LOG_BUFFER_SIZE - log_buffer_len)] = '\0'; - } - else - log_buffer[log_buffer_len + idx + 1] = '\0'; - - log_buffer_len += (idx + 1); -msg_exit: - msg_CHECK_USE_LOCK - UNLOCK(g_log_lock); -#ifdef ENABLE_FPGA_SB - LOCK(g_suart_lock); - sb_write(SUART_TXCHAR, UPT_MSG); - _sb_write_string(buf); - _sb_write_string("\r\n"); - UNLOCK(g_suart_lock); -#endif // ENABLE_FPGA_SB -#endif // ENABLE_MSG -} -/* -void msg(const char* str, ...) -{ - va_list args; - va_start(args, str); - _msgv(1, str, args); - va_end(args); -} - -void msg_nl(const char* str, ...) -{ - va_list args; - va_start(args, str); - _msgv(0, str, args); - va_end(args); -} -*/ -void log_reset(void) { - //LOCK(g_log_lock); - - log_buffer_idx = 0; - log_buffer_len = 0; - log_buffer[0] = '\0'; - - //UNLOCK(g_log_lock); -} - -void counters_auto_reset(void) { - //LOCK(g_counters_lock); - - g_counters.log_overrun_count = 0; - - //UNLOCK(g_counters_lock); -} - -void counters_dma_reset(void) { - LOCK(g_counters_lock); - - LOCK(g_counters_dma_to_host_lock); - memset((void*)&g_counters.dma_to_host, 0x00, sizeof(DMA_COUNTERS)); - UNLOCK(g_counters_dma_to_host_lock); - - LOCK(g_counters_dma_from_host_lock); - memset((void*)&g_counters.dma_from_host, 0x00, sizeof(DMA_COUNTERS)); - UNLOCK(g_counters_dma_from_host_lock); - - UNLOCK(g_counters_lock); -} - -void counters_reset_usb_errors(void) { - LOCK(g_counters_lock); - - g_counters.usb_error_update_count = 0; - memset((void*)&g_counters.usb_error_counters, 0x00, sizeof(g_counters.usb_error_counters)); - - UNLOCK(g_counters_lock); -} - -#ifdef ENABLE_MANUAL_DMA_XFER -/* Callback funtion for the DMA event notification. */ -void dma_callback ( - CyU3PDmaChannel *chHandle, /* Handle to the DMA channel. */ - CyU3PDmaCbType_t type, /* Callback type. */ - CyU3PDmaCBInput_t *input, /* Callback status. */ - int from_host) -{ - CyU3PReturnStatus_t status = CY_U3P_SUCCESS; - - PDMA_COUNTERS cnt = (PDMA_COUNTERS)(from_host ? &g_counters.dma_from_host : &g_counters.dma_to_host); - CyU3PMutex* lock = (from_host ? &g_counters_dma_from_host_lock : &g_counters_dma_to_host_lock); - - uint16_t buffer_status = (input->buffer_p.status & CY_U3P_DMA_BUFFER_STATUS_MASK); - if (buffer_status & CY_U3P_DMA_BUFFER_MARKER) - { - cnt->BUFFER_MARKER++; - } - if (buffer_status & CY_U3P_DMA_BUFFER_EOP) - { - cnt->BUFFER_EOP++; - } - if (buffer_status & CY_U3P_DMA_BUFFER_ERROR) - { - cnt->BUFFER_ERROR++; - } - if (buffer_status & CY_U3P_DMA_BUFFER_OCCUPIED) - { - cnt->BUFFER_OCCUPIED++; - } - - if (type == CY_U3P_DMA_CB_PROD_EVENT) - { -#ifdef ENABLE_DMA_BUFFER_PACKET_DEBUG - LOCKP(lock); - int prod_cnt = cnt->PROD_EVENT++; - UNLOCKP(lock); - - //if (cnt->last_count != input->buffer_p.count) - // msg("[DMA%d %05d] buffer.count (%05d) != last_count (%05d)", from_host, prod_cnt, input->buffer_p.count, cnt->last_count); - cnt->last_count = input->buffer_p.count; - - if (cnt->last_size != input->buffer_p.size) - msg("[DMA%d %05d] buffer.size (%05d) != last_size (%05d)", from_host, prod_cnt, input->buffer_p.size, cnt->last_size); - cnt->last_size = input->buffer_p.size; - - uint32_t* p32 = input->buffer_p.buffer; - uint32_t sid = p32[1]; - cnt->last_sid = (int)sid; - if (((from_host == 0) && ((sid != 0xa0) && (sid != 0xb0))) || - ((from_host == 1) && ((sid != 0x50) && (sid != 0x60)))) - { - cnt->bad_sid_count++; - msg("[DMA%d %05d] Bad SID: 0x%08x", from_host, prod_cnt, sid); - } - - uint16_t* p16 = input->buffer_p.buffer; - - if (p32[0] & (((uint32_t)1) << 31)) - { - msg("[DMA%d %05d] Error code: 0x%x (packet len: %05d, buffer count: %05d, seq: %04d)", from_host, prod_cnt, p32[4], p16[0], input->buffer_p.count, (p16[1] & 0x0fff)); // Status - - //msg("[DMA%d] 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x", from_host, p32[0], p32[1], p32[2], p32[3], p32[4], p32[5]); - } - else - { - if (p16[1] & (((uint16_t)1) << 12)) - { - msg("[DMA%d %05d] EOB (packet len: %05d, buffer count: %05d)", from_host, prod_cnt, p16[0], input->buffer_p.count); // Comes with one sample - } - - if ((p16[0] != input->buffer_p.count) && - ((p16[0] + 4) != input->buffer_p.count)) // Case of overrun packet length being padded (being rounded up) - { - if (from_host == 0) - msg("[DMA%d %05d] Packet len (%05d) != buffer count (%05d), seq: %04d [0x%04x 0x%04x]", from_host, prod_cnt, p16[0], input->buffer_p.count, (p16[1] & 0x0fff), p16[0], p16[1]); - } - - //msg("[DMA%d] 0x%04x 0x%04x 0x%04x 0x%04x", from_host, p16[0], p16[1], p16[2], p16[3]); - - if (p16[1] & (((uint16_t)1) << 12)) - msg("[DMA%d %05d] 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x", from_host, prod_cnt, p32[0], p32[1], p32[2], p32[3], p32[4], p32[5]); - } -#endif // ENABLE_DMA_BUFFER_PACKET_DEBUG - status = CyU3PDmaChannelCommitBuffer (chHandle, input->buffer_p.count, 0); -#ifndef ENABLE_DMA_BUFFER_PACKET_DEBUG - LOCKP(lock); - cnt->PROD_EVENT++; - UNLOCKP(lock); -#endif // !ENABLE_DMA_BUFFER_PACKET_DEBUG - } - else if (type == CY_U3P_DMA_CB_CONS_EVENT) - { - LOCKP(lock); - cnt->CONS_EVENT++; - UNLOCKP(lock); - } - else if (type == CY_U3P_DMA_CB_XFER_CPLT) - { - LOCKP(lock); - cnt->XFER_CPLT++; - UNLOCKP(lock); - } - else if (type == CY_U3P_DMA_CB_SEND_CPLT) - { - LOCKP(lock); - cnt->SEND_CPLT++; - UNLOCKP(lock); - } - else if (type == CY_U3P_DMA_CB_RECV_CPLT) - { - LOCKP(lock); - cnt->RECV_CPLT++; - UNLOCKP(lock); - } - else if (type == CY_U3P_DMA_CB_ABORTED) - { - LOCKP(lock); - cnt->ABORTED++; - UNLOCKP(lock); - - msg("! Aborted %i", from_host); - } - else if (type == CY_U3P_DMA_CB_ERROR) - { - LOCKP(lock); - cnt->ERROR++; - UNLOCKP(lock); - - msg("! Error %i", from_host); - } - else if (type == CY_U3P_DMA_CB_PROD_SUSP) - { - LOCKP(lock); - cnt->PROD_SUSP++; - UNLOCKP(lock); - - msg("! Prod suspend %i", from_host); - } - else if (type == CY_U3P_DMA_CB_CONS_SUSP) - { - LOCKP(lock); - cnt->CONS_SUSP++; - UNLOCKP(lock); - - //msg("! Cons suspend %i", from_host); - - CyU3PDmaChannelResume (chHandle, CyFalse, CyTrue); - } -} - -void from_host_dma_callback ( - CyU3PDmaChannel *chHandle, /* Handle to the DMA channel. */ - CyU3PDmaCbType_t type, /* Callback type. */ - CyU3PDmaCBInput_t *input) /* Callback status. */ -{ - return dma_callback(chHandle, type, input, 1); -} - -void to_host_dma_callback ( - CyU3PDmaChannel *chHandle, /* Handle to the DMA channel. */ - CyU3PDmaCbType_t type, /* Callback type. */ - CyU3PDmaCBInput_t *input) /* Callback status. */ -{ - return dma_callback(chHandle, type, input, 0); -} -#endif // ENABLE_MANUAL_DMA_XFER - -/*! Interrupt callback for GPIOs. - * - * This function is invoked by the GPIO interrupt handler when pins configured - * as inputs with interrupts are triggered. */ -void gpio_interrupt_callback(uint8_t gpio_id) { - CyBool_t gpio_value; - - if ((gpio_id == GPIO_DONE) && (g_fx3_state == STATE_CONFIGURING_FPGA)) { // Only proceed if in the correct FX3 state - CyU3PGpioGetValue(gpio_id, &gpio_value); - - if(gpio_value == CyTrue) { - //msg("DONE HIGH"); - CyU3PEventSet(&g_event_usb_config, EVENT_GPIO_DONE_HIGH, CYU3P_EVENT_OR); - } - } else if ((gpio_id == GPIO_INIT_B) && (g_fx3_state == STATE_FPGA_READY)) { // Only proceed if in the correct FX3 state - CyU3PGpioGetValue(gpio_id, &gpio_value); - - if(gpio_value == CyTrue) { - //msg("INITB_RISE"); - CyU3PEventSet(&g_event_usb_config, EVENT_GPIO_INITB_RISE, CYU3P_EVENT_OR); - } - } -} - - -/*! Stops the application, and destroys transport data structures. - * - * This function is essentially a destructor for all transport configurations. - * It ensures that if the USB configuration is reset without a power reboot, - * everything will come back up properly. */ -void b200_fw_stop(void) { - msg("b200_fw_stop"); - - CyU3PEpConfig_t usb_endpoint_config; - - /* Update the flag. */ - g_app_running = CyFalse; - - /* Flush the endpoint memory */ - CyU3PUsbFlushEp(DATA_ENDPOINT_PRODUCER); - CyU3PUsbFlushEp(DATA_ENDPOINT_CONSUMER); - CyU3PUsbFlushEp(CTRL_ENDPOINT_PRODUCER); - CyU3PUsbFlushEp(CTRL_ENDPOINT_CONSUMER); - - /* Reset the DMA channels */ - // SDK 1.3 known issue #1 - probably not necessary since Destroy is next, but just in case - CyU3PDmaChannelReset(&data_cons_to_prod_chan_handle); - CyU3PDmaChannelReset(&data_prod_to_cons_chan_handle); - CyU3PDmaChannelReset(&ctrl_cons_to_prod_chan_handle); - CyU3PDmaChannelReset(&ctrl_prod_to_cons_chan_handle); - - /* Destroy the DMA channels */ - CyU3PDmaChannelDestroy(&data_cons_to_prod_chan_handle); - CyU3PDmaChannelDestroy(&data_prod_to_cons_chan_handle); - CyU3PDmaChannelDestroy(&ctrl_cons_to_prod_chan_handle); - CyU3PDmaChannelDestroy(&ctrl_prod_to_cons_chan_handle); - - /* Disable endpoints. */ - CyU3PMemSet((uint8_t *) &usb_endpoint_config, 0, \ - sizeof(usb_endpoint_config)); - usb_endpoint_config.enable = CyFalse; - - CyU3PSetEpConfig(DATA_ENDPOINT_PRODUCER, &usb_endpoint_config); - CyU3PSetEpConfig(DATA_ENDPOINT_CONSUMER, &usb_endpoint_config); - CyU3PSetEpConfig(CTRL_ENDPOINT_PRODUCER, &usb_endpoint_config); - CyU3PSetEpConfig(CTRL_ENDPOINT_CONSUMER, &usb_endpoint_config); -} - - -void reset_gpif(void) { - g_fx3_state = STATE_BUSY; - - // Put the FPGA into RESET - CyU3PGpioSetValue(GPIO_FPGA_RESET, CyTrue); - - // Bring down GPIF - CyU3PGpifDisable(/*CyTrue*/CyFalse); - - /* Reset the DMA channels */ - CyU3PDmaChannelReset(&data_cons_to_prod_chan_handle); - CyU3PDmaChannelReset(&data_prod_to_cons_chan_handle); - CyU3PDmaChannelReset(&ctrl_cons_to_prod_chan_handle); - CyU3PDmaChannelReset(&ctrl_prod_to_cons_chan_handle); - - /* Reset the DMA transfers */ - CyU3PDmaChannelSetXfer(&data_cons_to_prod_chan_handle, DMA_SIZE_INFINITE); - CyU3PDmaChannelSetXfer(&data_prod_to_cons_chan_handle, DMA_SIZE_INFINITE); - CyU3PDmaChannelSetXfer(&ctrl_cons_to_prod_chan_handle, DMA_SIZE_INFINITE); - CyU3PDmaChannelSetXfer(&ctrl_prod_to_cons_chan_handle, DMA_SIZE_INFINITE); - - /* Flush the USB endpoints */ - CyU3PUsbFlushEp(DATA_ENDPOINT_PRODUCER); - CyU3PUsbFlushEp(DATA_ENDPOINT_CONSUMER); - CyU3PUsbFlushEp(CTRL_ENDPOINT_PRODUCER); - CyU3PUsbFlushEp(CTRL_ENDPOINT_CONSUMER); - - /* Load the GPIF configuration for Slave FIFO sync mode. */ - //CyU3PGpifLoad(&CyFxGpifConfig); - - /* Start the state machine. */ - //if (CyU3PGpifSMStart(RESET, ALPHA_RESET) != CY_U3P_SUCCESS) - // msg("! CyU3PGpifSMStart"); - - /* Configure the watermarks for the slfifo-write buffers. */ - //CyU3PGpifSocketConfigure(0, DATA_TX_PPORT_SOCKET, 5, CyFalse, 1); - //CyU3PGpifSocketConfigure(1, DATA_RX_PPORT_SOCKET, 6, CyFalse, 1); - //CyU3PGpifSocketConfigure(2, CTRL_COMM_PPORT_SOCKET, 5, CyFalse, 1); - //CyU3PGpifSocketConfigure(3, CTRL_RESP_PPORT_SOCKET, 6, CyFalse, 1); - - CyU3PGpioSetValue(GPIO_FPGA_RESET, CyFalse); - - CyU3PThreadSleep(FPGA_RESET_SETTLING_TIME); - - if (CyU3PGpifSMStart(RESET, ALPHA_RESET) != CY_U3P_SUCCESS) - msg("! CyU3PGpifSMStart"); - - msg("GPIF reset"); - - b200_start_fpga_sb_gpio(); - - g_fx3_state = STATE_RUNNING; -} - - -CyU3PReturnStatus_t b200_set_io_matrix(CyBool_t fpga_config_mode) { - CyU3PIoMatrixConfig_t io_config_matrix; - CyU3PReturnStatus_t res; - - /* Configure the IO peripherals on the FX3. The gpioSimpleEn arrays are - * bitmaps, where each bit represents the GPIO of the matching index - the - * second array is index + 32. */ - CyU3PMemSet((uint8_t *) &io_config_matrix, 0, sizeof(io_config_matrix)); - io_config_matrix.isDQ32Bit = (fpga_config_mode == CyFalse); - io_config_matrix.lppMode = CY_U3P_IO_MATRIX_LPP_DEFAULT; - io_config_matrix.gpioSimpleEn[0] = 0 | MASK_GPIO_FPGA_SB_SCL | MASK_GPIO_FPGA_SB_SDA; - io_config_matrix.gpioSimpleEn[1] = MASK_GPIO_PROGRAM_B \ - | MASK_GPIO_INIT_B \ - | (fpga_config_mode ? 0 : \ - // Used once FPGA config is done to bit-bang SPI, etc. - MASK_GPIO_SHDN_SW \ - | MASK_GPIO_AUX_PWR_ON \ - | MASK_GPIO_FX3_SCLK \ - | MASK_GPIO_FX3_CE \ - | MASK_GPIO_FX3_MISO \ - | MASK_GPIO_FX3_MOSI); - io_config_matrix.gpioComplexEn[0] = 0; - io_config_matrix.gpioComplexEn[1] = 0; - io_config_matrix.useUart = CyFalse; - io_config_matrix.useI2C = CyTrue; - io_config_matrix.useI2S = CyFalse; - io_config_matrix.useSpi = fpga_config_mode; - - res = CyU3PDeviceConfigureIOMatrix(&io_config_matrix); - if (res != CY_U3P_SUCCESS) - msg("! ConfigureIOMatrix"); - - return res; -} - - -CyU3PReturnStatus_t b200_gpio_init(CyBool_t set_callback) { - CyU3PGpioClock_t gpio_clock_config; - CyU3PReturnStatus_t res; - - /* Since we are only using FX3's 'simple GPIO' functionality, these values - * must *NOT* change. Cypress says changing them will break stuff. */ - CyU3PMemSet((uint8_t *) &gpio_clock_config, 0, \ - sizeof(gpio_clock_config)); - gpio_clock_config.fastClkDiv = 2; - gpio_clock_config.slowClkDiv = 0; - gpio_clock_config.simpleDiv = CY_U3P_GPIO_SIMPLE_DIV_BY_2; - gpio_clock_config.clkSrc = CY_U3P_SYS_CLK; - gpio_clock_config.halfDiv = 0; - - res = CyU3PGpioInit(&gpio_clock_config, (set_callback ? gpio_interrupt_callback : NULL)); - if (res != CY_U3P_SUCCESS) - msg("! CyU3PGpioInit"); - - return res; -} - - -void sb_write(uint8_t reg, uint32_t val) { -#ifdef ENABLE_FPGA_SB - const int len = 32; - int i; - - if (g_fpga_sb_enabled == CyFalse) - return; - - reg += FPGA_SB_UART_ADDR_BASE; - - //CyU3PBusyWait(1); // Can be used after each SetValue to slow down bit changes - - // START - CyU3PGpioSetValue(GPIO_FPGA_SB_SCL, 1); // Should already be 1 - CyU3PGpioSetValue(GPIO_FPGA_SB_SDA, 0); - - // ADDR[8] - for (i = 7; i >= 0; i--) { - uint8_t bit = ((reg & (0x1 << i)) ? 0x01 : 0x00); - CyU3PGpioSetValue(GPIO_FPGA_SB_SCL, 0); - CyU3PGpioSetValue(GPIO_FPGA_SB_SDA, bit); - - CyU3PGpioSetValue(GPIO_FPGA_SB_SCL, 1); // FPGA reads bit - } - - // DATA[32] - for (i = (len-1); i >= 0; i--) { - uint8_t bit = ((val & (0x1 << i)) ? 0x01 : 0x00); - CyU3PGpioSetValue(GPIO_FPGA_SB_SCL, 0); - CyU3PGpioSetValue(GPIO_FPGA_SB_SDA, bit); - - CyU3PGpioSetValue(GPIO_FPGA_SB_SCL, 1); // FPGA reads bit - } - - // STOP - CyU3PGpioSetValue(GPIO_FPGA_SB_SDA, 0); - CyU3PGpioSetValue(GPIO_FPGA_SB_SCL, 0); - CyU3PGpioSetValue(GPIO_FPGA_SB_SCL, 1); // Actual stop - CyU3PGpioSetValue(GPIO_FPGA_SB_SDA, 1); // Xact occurs -#endif // ENABLE_FPGA_SB -} - - -void _sb_write_string(const char* msg) { -#ifdef ENABLE_FPGA_SB - while (*msg) { - sb_write(SUART_TXCHAR, (uint8_t)(*(msg++))); - } -#endif // ENABLE_FPGA_SB -} - - -void sb_write_string(const char* msg) { -#ifdef ENABLE_FPGA_SB - LOCK(g_suart_lock); - _sb_write_string(msg); - UNLOCK(g_suart_lock); -#endif // ENABLE_FPGA_SB -} - - -void b200_enable_fpga_sb_gpio(CyBool_t enable) { -#ifdef ENABLE_FPGA_SB - CyU3PGpioSimpleConfig_t gpio_config; - CyU3PReturnStatus_t res; - - if (enable == CyFalse) { - g_fpga_sb_enabled = CyFalse; - - return; - } - - gpio_config.outValue = CyFalse; - gpio_config.driveLowEn = CyTrue; - gpio_config.driveHighEn = CyTrue; - gpio_config.inputEn = CyFalse; - gpio_config.intrMode = CY_U3P_GPIO_NO_INTR; - - res = CyU3PGpioSetSimpleConfig(GPIO_FPGA_SB_SCL, &gpio_config); - if (res != CY_U3P_SUCCESS) { - msg("! GpioSetSimpleConfig GPIO_FPGA_SB_SCL"); - } - res = CyU3PGpioSetSimpleConfig(GPIO_FPGA_SB_SDA, &gpio_config); - if (res != CY_U3P_SUCCESS) { - msg("! GpioSetSimpleConfig GPIO_FPGA_SB_SDA"); - } - - CyU3PGpioSetValue(GPIO_FPGA_SB_SCL, 1); - CyU3PGpioSetValue(GPIO_FPGA_SB_SDA, 1); - - g_fpga_sb_enabled = CyTrue; - - msg("Debug SB OK"); -#endif // ENABLE_FPGA_SB -} - - -void b200_start_fpga_sb_gpio(void) { -#ifdef ENABLE_FPGA_SB - LOCK(g_suart_lock); - sb_write(SUART_CLKDIV, /*g_fpga_sb_uart_div*/g_config.sb_baud_div); // 16-bit reg, master clock = 100 MHz (434*2x = 230400/2) - _sb_write_string("\r\n B2x0 FPGA reset\r\n"); - UNLOCK(g_suart_lock); - - msg("Compat: %d.%d", FX3_COMPAT_MAJOR, FX3_COMPAT_MINOR); - msg("FX3 SDK: %d.%d.%d (build %d)", CYFX_VERSION_MAJOR, CYFX_VERSION_MINOR, CYFX_VERSION_PATCH, CYFX_VERSION_BUILD); -#endif // ENABLE_FPGA_SB -} - - -/*! Initialize and configure the GPIO module for FPGA programming. - * - * This function initializes the FX3 GPIO module, creating a configuration that - * allows us to program the FPGA. After the FPGA has been programmed, the - * application thread will re-configure some of the pins. */ -void b200_gpios_pre_fpga_config(void) { - CyU3PGpioSimpleConfig_t gpio_config; - - //b200_enable_fpga_sb_gpio(CyFalse); - - //CyU3PGpioDeInit(); - - b200_set_io_matrix(CyTrue); - - //b200_gpio_init(CyTrue); // This now done once during startup - - //////////////////////////////////// - - /* GPIO[0:32] must be set with the DeviceOverride function, instead of the - * SimpleEn array configuration. */ - CyU3PDeviceGpioOverride(GPIO_FPGA_RESET, CyTrue); - CyU3PDeviceGpioOverride(GPIO_DONE, CyTrue); - - /* Configure GPIOs: - * Outputs: - * driveLowEn = True - * driveHighEn = True - * inputEn = False - * Inputs: - * driveLowEn = False - * driveHighEn = False - * outValue = Ignored - */ - gpio_config.outValue = CyFalse; - gpio_config.driveLowEn = CyTrue; - gpio_config.driveHighEn = CyTrue; - gpio_config.inputEn = CyFalse; - gpio_config.intrMode = CY_U3P_GPIO_NO_INTR; - - CyU3PGpioSetSimpleConfig(GPIO_FPGA_RESET, &gpio_config); - CyU3PGpioSetSimpleConfig(GPIO_PROGRAM_B, &gpio_config); - - /* Reconfigure the GPIO configure struct for inputs that DO require - * interrupts attached to them. */ - gpio_config.outValue = CyTrue; - gpio_config.inputEn = CyTrue; - gpio_config.driveLowEn = CyFalse; - gpio_config.driveHighEn = CyFalse; - gpio_config.intrMode = CY_U3P_GPIO_INTR_POS_EDGE; - - CyU3PGpioSetSimpleConfig(GPIO_DONE, &gpio_config); - CyU3PGpioSetSimpleConfig(GPIO_INIT_B, &gpio_config); - - /* Initialize GPIO output values. */ - CyU3PGpioSetValue(GPIO_FPGA_RESET, 0); - CyU3PGpioSetValue(GPIO_PROGRAM_B, 1); - - b200_enable_fpga_sb_gpio(CyTrue); // So SCL/SDA are already high when SB state machine activates -} - - -void b200_slfifo_mode_gpio_config(void) { - CyU3PGpioSimpleConfig_t gpio_config; - - //b200_enable_fpga_sb_gpio(CyFalse); - - //CyU3PGpioDeInit(); - - b200_set_io_matrix(CyFalse); - - //b200_gpio_init(CyFalse); // This now done once during startup - - //////////////////////////////////// - - /* GPIO[0:32] must be set with the DeviceOverride function, instead of the - * SimpleEn array configuration. */ - CyU3PDeviceGpioOverride(GPIO_FPGA_RESET, CyTrue); - CyU3PDeviceGpioOverride(GPIO_DONE, CyTrue); - CyU3PDeviceGpioOverride(GPIO_FX3_SCLK, CyTrue); - CyU3PDeviceGpioOverride(GPIO_FX3_CE, CyTrue); - CyU3PDeviceGpioOverride(GPIO_FX3_MISO, CyTrue); - CyU3PDeviceGpioOverride(GPIO_FX3_MOSI, CyTrue); - - /* Configure GPIOs: - * Outputs: - * driveLowEn = True - * driveHighEn = True - * inputEn = False - * Inputs: - * driveLowEn = False - * driveHighEn = False - * outValue = Ignored - */ - gpio_config.outValue = CyFalse; - gpio_config.driveLowEn = CyTrue; - gpio_config.driveHighEn = CyTrue; - gpio_config.inputEn = CyFalse; - gpio_config.intrMode = CY_U3P_GPIO_NO_INTR; - - CyU3PGpioSetSimpleConfig(GPIO_FPGA_RESET, &gpio_config); - CyU3PGpioSetSimpleConfig(GPIO_SHDN_SW, &gpio_config); - CyU3PGpioSetSimpleConfig(GPIO_FX3_SCLK, &gpio_config); - CyU3PGpioSetSimpleConfig(GPIO_FX3_CE, &gpio_config); - CyU3PGpioSetSimpleConfig(GPIO_FX3_MOSI, &gpio_config); - - /* Reconfigure the GPIO configure struct for inputs that do NOT require - * interrupts attached to them. */ - gpio_config.outValue = CyFalse; - gpio_config.inputEn = CyTrue; - gpio_config.driveLowEn = CyFalse; - gpio_config.driveHighEn = CyFalse; - gpio_config.intrMode = CY_U3P_GPIO_NO_INTR; - - CyU3PGpioSetSimpleConfig(GPIO_FX3_MISO, &gpio_config); - CyU3PGpioSetSimpleConfig(GPIO_AUX_PWR_ON, &gpio_config); - CyU3PGpioSetSimpleConfig(GPIO_PROGRAM_B, &gpio_config); - CyU3PGpioSetSimpleConfig(GPIO_INIT_B, &gpio_config); - CyU3PGpioSetSimpleConfig(GPIO_DONE, &gpio_config); - - /* Initialize GPIO output values. */ - CyU3PGpioSetValue(GPIO_FPGA_RESET, 0); - CyU3PGpioSetValue(GPIO_SHDN_SW, 1); - CyU3PGpioSetValue(GPIO_FX3_SCLK, 0); - CyU3PGpioSetValue(GPIO_FX3_CE, 1); - CyU3PGpioSetValue(GPIO_FX3_MOSI, 0); - - // Disabled here as only useful once FPGA has been programmed - //b200_enable_fpga_sb_gpio(CyTrue); - //b200_start_fpga_sb_gpio(); // Set up SB USART -} - - -/*! Initializes and configures USB, and DMA. - * - * This function creates and connects the USB endpoints, and sets up the DMA - * channels. After this is done, everything is 'running' on the FX3 chip, and - * ready to receive data from the host. */ -void b200_fw_start(void) { - msg("b200_fw_start"); - - CyU3PDmaChannelConfig_t dma_channel_config; - CyU3PEpConfig_t usb_endpoint_config; - CyU3PUSBSpeed_t usb_speed; - uint16_t max_packet_size = 0; - uint16_t data_buffer_count = 0; - uint16_t data_buffer_size = 0; - uint16_t data_buffer_size_to_host = 0; - uint16_t data_buffer_size_from_host = 0; - uint8_t num_packets_per_burst = 0; - CyU3PReturnStatus_t apiRetStatus = CY_U3P_SUCCESS; - - /* Based on the USB bus speed, configure the endpoint packet size - * and the DMA buffer size */ - usb_speed = CyU3PUsbGetSpeed(); - switch(usb_speed) { - case CY_U3P_FULL_SPEED: - case CY_U3P_HIGH_SPEED: - max_packet_size = 512; - data_buffer_count = g_config.dma_buffer_count; - data_buffer_size = g_config.dma_buffer_size; - g_vendor_req_buff_size = USB2_VREQ_BUF_SIZE; // Max 64 - num_packets_per_burst = USB2_PACKETS_PER_BURST; // 1 - - data_buffer_size_to_host = data_buffer_size_from_host = data_buffer_size; - - break; - - case CY_U3P_SUPER_SPEED: -//#ifdef PREVENT_LOW_POWER_MODE - apiRetStatus = CyU3PUsbLPMDisable(); // This still allows my laptop to sleep - - if (apiRetStatus != CY_U3P_SUCCESS) - msg("! LPMDisable failed (%d)", apiRetStatus); - else - msg("LPMDisable OK"); -//#endif // PREVENT_LOW_POWER_MODE - max_packet_size = 1024; // Per USB3 spec - - // SDK ver: total available buffer memory - // 1.2.3: 204KB - // 1.3.1: 188KB - - // These options should be ignored - data_buffer_count *MUST* be 1 - // They follow is kept for future testing - - // 1K - //data_buffer_count = 64; - //data_buffer_size = 1024; - - // 4K - //data_buffer_count = 8; - //data_buffer_size = 4096; - - // 8K - //data_buffer_count = 4; - //data_buffer_size = 4096*2; - - // 16K - //data_buffer_count = 2*2; - //data_buffer_size = 16384; // Default 16K - - // 32K - //data_buffer_count = 2; - //data_buffer_size = 16384*2; - - //data_buffer_count = 1; - //data_buffer_size = ((1 << 16) - 1); - //data_buffer_size = 16384; - //data_buffer_size -= (data_buffer_size % 1024); // Align to 1K boundary - - data_buffer_count = g_config.dma_buffer_count; - data_buffer_size = g_config.dma_buffer_size; - - data_buffer_size_to_host = data_buffer_size; - data_buffer_size_from_host = data_buffer_size; - - g_vendor_req_buff_size = USB3_VREQ_BUF_SIZE; // Max 512 - num_packets_per_burst = USB3_PACKETS_PER_BURST; // 8 - break; - - case CY_U3P_NOT_CONNECTED: - msg("! CY_U3P_NOT_CONNECTED"); - return; - - default: - return; - } - - msg("[DMA] to host: %d, from host: %d, depth: %d, burst size: %d", data_buffer_size_to_host, data_buffer_size_from_host, data_buffer_count, num_packets_per_burst); - -#ifdef ENABLE_MANUAL_DMA_XFER - msg("[DMA] Callback enabled"); - -#ifdef ENABLE_P2U_SUSP_EOP - msg("[DMA] P2U_SUSP_EOP enabled"); -#endif // ENABLE_P2U_SUSP_EOP -#ifdef ENABLE_MANUAL_DMA_XFER_FROM_HOST - msg("[DMA] Manual transfers from host"); -#endif // ENABLE_MANUAL_DMA_XFER_FROM_HOST -#ifdef ENABLE_MANUAL_DMA_XFER_TO_HOST - msg("[DMA] Manual transfers to host"); -#endif // ENABLE_MANUAL_DMA_XFER_TO_HOST -#ifdef ENABLE_DMA_BUFFER_PACKET_DEBUG - msg("[DMA] Packet debugging enabled"); -#endif // ENABLE_DMA_BUFFER_PACKET_DEBUG - -#else - msg("[DMA] AUTO transfer mode"); -#endif // ENABLE_MANUAL_DMA_XFER - - msg("[DMA] Transfer override: %s", (g_config.manual_dma ? "manual" : "auto")); - - /************************************************************************* - * Slave FIFO Data DMA Channel Configuration - *************************************************************************/ - - /* Wipe out any old config. */ - CyU3PMemSet((uint8_t *) &usb_endpoint_config, 0, \ - sizeof(usb_endpoint_config)); - - /* This is the configuration for the USB Producer and Consumer endpoints. - * - * The Producer endpoint is actually the endpoint on the FX3 that is - * sending data BACK to the host. This endpoint enumerates as the - * 'BULK IN' endpoint. - - * The Consumer endpoint is the endpoint on the FX3 that is - * receiving data from the host. This endpoint enumerates as the - * 'BULK OUT' endpoint. - * - * Note that this is opposite of what you might expect!. */ - usb_endpoint_config.enable = CyTrue; - usb_endpoint_config.epType = CY_U3P_USB_EP_BULK; - usb_endpoint_config.burstLen = num_packets_per_burst; - usb_endpoint_config.streams = 0; - usb_endpoint_config.pcktSize = max_packet_size; - - /* Configure the endpoints that we are using for slave FIFO transfers. */ - CyU3PSetEpConfig(DATA_ENDPOINT_PRODUCER, &usb_endpoint_config); - CyU3PSetEpConfig(DATA_ENDPOINT_CONSUMER, &usb_endpoint_config); - - /* Create a DMA AUTO channel for U2P transfer. - * DMA size is set based on the USB speed. */ - //dma_channel_config.size = data_buffer_size; - dma_channel_config.size = data_buffer_size_from_host; - dma_channel_config.count = data_buffer_count; - dma_channel_config.prodSckId = PRODUCER_DATA_SOCKET; - dma_channel_config.consSckId = DATA_TX_PPORT_SOCKET; - dma_channel_config.dmaMode = CY_U3P_DMA_MODE_BYTE; - dma_channel_config.notification = 0 | -#if defined(ENABLE_MANUAL_DMA_XFER) && defined(ENABLE_MANUAL_DMA_XFER_FROM_HOST) -CY_U3P_DMA_CB_XFER_CPLT | -CY_U3P_DMA_CB_SEND_CPLT | -CY_U3P_DMA_CB_RECV_CPLT | -CY_U3P_DMA_CB_PROD_EVENT | -CY_U3P_DMA_CB_CONS_EVENT | -CY_U3P_DMA_CB_ABORTED | -CY_U3P_DMA_CB_ERROR | -CY_U3P_DMA_CB_PROD_SUSP | -CY_U3P_DMA_CB_CONS_SUSP | -#endif // ENABLE_MANUAL_DMA_XFER - 0; - //if (g_config.manual_dma == 0) - // dma_channel_config.notification = 0; // Force all off is manual is disabled - dma_channel_config.cb = -#if defined(ENABLE_MANUAL_DMA_XFER) && defined(ENABLE_MANUAL_DMA_XFER_FROM_HOST) - from_host_dma_callback; -#else - NULL; -#endif // ENABLE_MANUAL_DMA_XFER - dma_channel_config.prodHeader = 0; - dma_channel_config.prodFooter = 0; - dma_channel_config.consHeader = 0; - dma_channel_config.prodAvailCount = 0; - - CyU3PDmaChannelCreate (&data_cons_to_prod_chan_handle, -#if defined(ENABLE_MANUAL_DMA_XFER) && defined(ENABLE_MANUAL_DMA_XFER_FROM_HOST) - (g_config.manual_dma ? /*CY_U3P_DMA_TYPE_AUTO_SIGNAL*/CY_U3P_DMA_TYPE_MANUAL : CY_U3P_DMA_TYPE_AUTO), -#else - CY_U3P_DMA_TYPE_AUTO, -#endif // ENABLE_MANUAL_DMA_XFER - &dma_channel_config); - - // By default these will adopt 'usb_endpoint_config.pcktSize' - //CyU3PSetEpPacketSize(DATA_ENDPOINT_PRODUCER, 16384); - //CyU3PSetEpPacketSize(DATA_ENDPOINT_CONSUMER, 16384); - - /* Create a DMA AUTO channel for P2U transfer. */ - dma_channel_config.size = data_buffer_size_to_host; - dma_channel_config.prodSckId = DATA_RX_PPORT_SOCKET; - dma_channel_config.consSckId = CONSUMER_DATA_SOCKET; - dma_channel_config.notification = 0 | -#if defined(ENABLE_MANUAL_DMA_XFER) && defined(ENABLE_MANUAL_DMA_XFER_TO_HOST) -CY_U3P_DMA_CB_XFER_CPLT | -CY_U3P_DMA_CB_SEND_CPLT | -CY_U3P_DMA_CB_RECV_CPLT | -CY_U3P_DMA_CB_PROD_EVENT | -CY_U3P_DMA_CB_CONS_EVENT | -CY_U3P_DMA_CB_ABORTED | -CY_U3P_DMA_CB_ERROR | -CY_U3P_DMA_CB_PROD_SUSP | -CY_U3P_DMA_CB_CONS_SUSP | -#endif // ENABLE_MANUAL_DMA_XFER -#if defined(ENABLE_MANUAL_DMA_XFER) && defined(ENABLE_P2U_SUSP_EOP) -CY_U3P_DMA_CB_CONS_SUSP | // For 'CyU3PDmaChannelSetSuspend' below -#endif // ENABLE_P2U_SUSP_EOP - 0; - //if (g_config.manual_dma == 0) - // dma_channel_config.notification = 0; // Force all off is manual is disabled - dma_channel_config.cb = -#if defined(ENABLE_MANUAL_DMA_XFER) && (defined(ENABLE_MANUAL_DMA_XFER_TO_HOST) || defined(ENABLE_P2U_SUSP_EOP)) - to_host_dma_callback; -#else - NULL; -#endif // ENABLE_MANUAL_DMA_XFER - CyU3PDmaChannelCreate (&data_prod_to_cons_chan_handle, -#if defined(ENABLE_MANUAL_DMA_XFER) && defined(ENABLE_MANUAL_DMA_XFER_TO_HOST) - (g_config.manual_dma ? /*CY_U3P_DMA_TYPE_AUTO_SIGNAL*/CY_U3P_DMA_TYPE_MANUAL : CY_U3P_DMA_TYPE_AUTO), -#else - CY_U3P_DMA_TYPE_AUTO, -#endif // ENABLE_MANUAL_DMA_XFER - &dma_channel_config); -#ifdef ENABLE_P2U_SUSP_EOP - CyU3PDmaChannelSetSuspend(&data_prod_to_cons_chan_handle, CY_U3P_DMA_SCK_SUSP_NONE, CY_U3P_DMA_SCK_SUSP_EOP); -#endif // ENABLE_P2U_SUSP_EOP - /* Flush the Endpoint memory */ - CyU3PUsbFlushEp(DATA_ENDPOINT_PRODUCER); - CyU3PUsbFlushEp(DATA_ENDPOINT_CONSUMER); - - /* Set DMA channel transfer size. */ - CyU3PDmaChannelSetXfer(&data_cons_to_prod_chan_handle, DMA_SIZE_INFINITE); - CyU3PDmaChannelSetXfer(&data_prod_to_cons_chan_handle, DMA_SIZE_INFINITE); - - - /************************************************************************* - * Slave FIFO Control DMA Channel Configuration - *************************************************************************/ - - /* Wipe out any old config. */ - CyU3PMemSet((uint8_t *) &usb_endpoint_config, 0, \ - sizeof(usb_endpoint_config)); - - /* This is the configuration for the USB Producer and Consumer endpoints. - * - * The Producer endpoint is actually the endpoint on the FX3 that is - * sending data BACK to the host. This endpoint enumerates as the - * 'BULK IN' endpoint. - - * The Consumer endpoint is the endpoint on the FX3 that is - * receiving data from the host. This endpoint enumerates as the - * 'BULK OUT' endpoint. - * - * Note that this is opposite of what you might expect!. */ - usb_endpoint_config.enable = CyTrue; - usb_endpoint_config.epType = CY_U3P_USB_EP_BULK; - usb_endpoint_config.burstLen = num_packets_per_burst; - usb_endpoint_config.streams = 0; - usb_endpoint_config.pcktSize = max_packet_size; - - /* Configure the endpoints that we are using for slave FIFO transfers. */ - CyU3PSetEpConfig(CTRL_ENDPOINT_PRODUCER, &usb_endpoint_config); - CyU3PSetEpConfig(CTRL_ENDPOINT_CONSUMER, &usb_endpoint_config); - - /* Create a DMA AUTO channel for U2P transfer. - * DMA size is set based on the USB speed. */ - dma_channel_config.size = max_packet_size; - dma_channel_config.count = 2; - dma_channel_config.prodSckId = PRODUCER_CTRL_SOCKET; - dma_channel_config.consSckId = CTRL_COMM_PPORT_SOCKET; - dma_channel_config.dmaMode = CY_U3P_DMA_MODE_BYTE; - dma_channel_config.notification = 0; - dma_channel_config.cb = NULL; - dma_channel_config.prodHeader = 0; - dma_channel_config.prodFooter = 0; - dma_channel_config.consHeader = 0; - dma_channel_config.prodAvailCount = 0; - - CyU3PDmaChannelCreate (&ctrl_cons_to_prod_chan_handle, - CY_U3P_DMA_TYPE_AUTO, &dma_channel_config); - - /* Create a DMA AUTO channel for P2U transfer. */ - dma_channel_config.prodSckId = CTRL_RESP_PPORT_SOCKET; - dma_channel_config.consSckId = CONSUMER_CTRL_SOCKET; - dma_channel_config.cb = NULL; - CyU3PDmaChannelCreate (&ctrl_prod_to_cons_chan_handle, - CY_U3P_DMA_TYPE_AUTO, &dma_channel_config); - - /* Flush the Endpoint memory */ - CyU3PUsbFlushEp(CTRL_ENDPOINT_PRODUCER); - CyU3PUsbFlushEp(CTRL_ENDPOINT_CONSUMER); - - /* Set DMA channel transfer size. */ - CyU3PDmaChannelSetXfer(&ctrl_cons_to_prod_chan_handle, DMA_SIZE_INFINITE); - CyU3PDmaChannelSetXfer(&ctrl_prod_to_cons_chan_handle, DMA_SIZE_INFINITE); - - //CyU3PUsbEnableEPPrefetch(); // To address USB_EVENT_EP_UNDERRUN on EP 0x86 (didn't fix it though) - - /* Update the application status flag. */ - g_app_running = CyTrue; -} - - -/*! This callback is invoked when the FX3 detects a USB event. - * - * We currently handle SETCONF, RESET, and DISCONNECT. - * - * We are _not_ handling SUSPEND or CONNECT. - */ -void event_usb_callback (CyU3PUsbEventType_t event_type, uint16_t event_data) { - - switch(event_type) { - case CY_U3P_USB_EVENT_SETCONF: - msg("USB_EVENT_SETCONF (#%d)", event_data); //evData provides the configuration number that is selected by the host. - if(g_app_running) { - b200_fw_stop(); - } - - b200_fw_start(); - break; - - case CY_U3P_USB_EVENT_RESET: - case CY_U3P_USB_EVENT_DISCONNECT: - if (event_type == CY_U3P_USB_EVENT_RESET) - msg("USB_EVENT_RESET"); - else - msg("USB_EVENT_DISCONNECT"); - if(g_app_running) { - b200_fw_stop(); - } - break; - - case CY_U3P_USB_EVENT_CONNECT: - msg("USB_EVENT_CONNECT"); - break; - - case CY_U3P_USB_EVENT_SUSPEND: - msg("USB_EVENT_SUSPEND"); - break; - - case CY_U3P_USB_EVENT_RESUME: // Known issue: this is called repeatedly after a resume - //msg("USB_EVENT_RESUME"); - g_counters.resume_count++; // Not locked - break; - - case CY_U3P_USB_EVENT_SPEED: - msg("USB_EVENT_SPEED"); - break; - - case CY_U3P_USB_EVENT_SETINTF: - msg("USB_EVENT_SETINTF"); - break; - - case CY_U3P_USB_EVENT_SET_SEL: - msg("USB_EVENT_SET_SEL"); - break; - - case CY_U3P_USB_EVENT_SOF_ITP: // CyU3PUsbEnableITPEvent - //msg("USB_EVENT_SOF_ITP"); - break; - - case CY_U3P_USB_EVENT_EP0_STAT_CPLT: - //msg("USB_EVENT_EP0_STAT_CPLT"); // Occurs each time there's a control transfer - break; - - case CY_U3P_USB_EVENT_VBUS_VALID: - msg("USB_EVENT_VBUS_VALID"); - break; - - case CY_U3P_USB_EVENT_VBUS_REMOVED: - msg("USB_EVENT_VBUS_REMOVED"); - break; - - case CY_U3P_USB_EVENT_HOST_CONNECT: - msg("USB_EVENT_HOST_CONNECT"); - break; - - case CY_U3P_USB_EVENT_HOST_DISCONNECT: - msg("USB_EVENT_HOST_DISCONNECT"); - break; - - case CY_U3P_USB_EVENT_OTG_CHANGE: - msg("USB_EVENT_OTG_CHANGE"); - break; - - case CY_U3P_USB_EVENT_OTG_VBUS_CHG: - msg("USB_EVENT_OTG_VBUS_CHG"); - break; - - case CY_U3P_USB_EVENT_OTG_SRP: - msg("USB_EVENT_OTG_SRP"); - break; - - case CY_U3P_USB_EVENT_EP_UNDERRUN: // See SDK 1.3 known issues 17 if this happens (can probably ignore first logged occurence) - LOCK(g_counters_lock); - ++g_counters.usb_ep_underrun_count; - UNLOCK(g_counters_lock); - - msg("! USB_EVENT_EP_UNDERRUN on EP 0x%02x", event_data); - break; - - case CY_U3P_USB_EVENT_LNK_RECOVERY: - msg("USB_EVENT_LNK_RECOVERY"); - break; -#if (CYFX_VERSION_MAJOR >= 1) && (CYFX_VERSION_MINOR >= 3) - case CY_U3P_USB_EVENT_USB3_LNKFAIL: - msg("USB_EVENT_USB3_LNKFAIL"); - break; - - case CY_U3P_USB_EVENT_SS_COMP_ENTRY: - msg("USB_EVENT_SS_COMP_ENTRY"); - break; - - case CY_U3P_USB_EVENT_SS_COMP_EXIT: - msg("USB_EVENT_SS_COMP_EXIT"); - break; -#endif // (CYFX_VERSION_MAJOR >= 1) && (CYFX_VERSION_MINOR >= 3) - - default: - msg("! Unhandled USB event"); - break; - } -} - - -/*! Callback function that is invoked when a USB setup event occurs. - * - * We aren't actually handling the USB setup ourselves, but rather letting the - * USB driver take care of it since the default options work fine. The purpose - * of this function is to register that the event happened at all, so that the - * application thread knows it can proceed. - * - * This function is also responsible for receiving vendor requests, and triggering - * the appropriate RTOS event to wake up the vendor request handler thread. - */ -CyBool_t usb_setup_callback(uint32_t data0, uint32_t data1) { - STATIC_SAVER uint8_t bRequestType, bRequest, bType, bTarget, i2cAddr; - STATIC_SAVER uint16_t wValue, wIndex, wLength; - - CyBool_t handled = CyFalse; - - /* Decode the fields from the setup request. */ - bRequestType = (uint8_t)(data0 & CY_U3P_USB_REQUEST_TYPE_MASK); - bType = (uint8_t)(bRequestType & CY_U3P_USB_TYPE_MASK); - bTarget = (uint8_t)(bRequestType & CY_U3P_USB_TARGET_MASK); - bRequest = (uint8_t)((data0 & CY_U3P_USB_REQUEST_MASK) >> CY_U3P_USB_REQUEST_POS); - wValue = (uint16_t)((data0 & CY_U3P_USB_VALUE_MASK) >> CY_U3P_USB_VALUE_POS); - wIndex = (uint16_t)((data1 & CY_U3P_USB_INDEX_MASK) >> CY_U3P_USB_INDEX_POS); - wLength = (uint16_t)((data1 & CY_U3P_USB_LENGTH_MASK) >> CY_U3P_USB_LENGTH_POS); - - if(bType == CY_U3P_USB_STANDARD_RQT) { - /* Handle SET_FEATURE(FUNCTION_SUSPEND) and CLEAR_FEATURE(FUNCTION_SUSPEND) - * requests here. It should be allowed to pass if the device is in configured - * state and failed otherwise. */ - if((bTarget == CY_U3P_USB_TARGET_INTF) \ - && ((bRequest == CY_U3P_USB_SC_SET_FEATURE) \ - || (bRequest == CY_U3P_USB_SC_CLEAR_FEATURE)) && (wValue == 0)) { - - if(g_app_running) { - CyU3PUsbAckSetup(); - msg("ACK set/clear"); - } else { - CyU3PUsbStall(0, CyTrue, CyFalse); - msg("! STALL set/clear"); - } - - handled = CyTrue; - } - - /* Handle Microsoft OS String Descriptor request. */ - if((bTarget == CY_U3P_USB_TARGET_DEVICE) \ - && (bRequest == CY_U3P_USB_SC_GET_DESCRIPTOR) \ - && (wValue == ((CY_U3P_USB_STRING_DESCR << 8) | 0xEE))) { - /* Make sure we do not send more data than requested. */ - if(wLength > b200_usb_product_desc[0]) { - wLength = b200_usb_product_desc[0]; - } - - //msg("MS string desc"); - - CyU3PUsbSendEP0Data(wLength, ((uint8_t *) b200_usb_product_desc)); - handled = CyTrue; - } - - /* CLEAR_FEATURE request for endpoint is always passed to the setup callback - * regardless of the enumeration model used. When a clear feature is received, - * the previous transfer has to be flushed and cleaned up. This is done at the - * protocol level. Since this is just a loopback operation, there is no higher - * level protocol. So flush the EP memory and reset the DMA channel associated - * with it. If there are more than one EP associated with the channel reset both - * the EPs. The endpoint stall and toggle / sequence number is also expected to be - * reset. Return CyFalse to make the library clear the stall and reset the endpoint - * toggle. Or invoke the CyU3PUsbStall (ep, CyFalse, CyTrue) and return CyTrue. - * Here we are clearing the stall. */ - if((bTarget == CY_U3P_USB_TARGET_ENDPT) \ - && (bRequest == CY_U3P_USB_SC_CLEAR_FEATURE) - && (wValue == CY_U3P_USBX_FS_EP_HALT)) { - if(g_app_running) { - if(wIndex == DATA_ENDPOINT_PRODUCER) { - CyU3PDmaChannelReset(&data_cons_to_prod_chan_handle); - CyU3PUsbFlushEp(DATA_ENDPOINT_PRODUCER); - CyU3PUsbResetEp(DATA_ENDPOINT_PRODUCER); - CyU3PDmaChannelSetXfer(&data_cons_to_prod_chan_handle, \ - DMA_SIZE_INFINITE); - CyU3PUsbStall(wIndex, CyFalse, CyTrue); - handled = CyTrue; - CyU3PUsbAckSetup(); - - msg("Clear DATA_ENDPOINT_PRODUCER"); - } - - if(wIndex == DATA_ENDPOINT_CONSUMER) { - CyU3PDmaChannelReset(&data_prod_to_cons_chan_handle); - CyU3PUsbFlushEp(DATA_ENDPOINT_CONSUMER); - CyU3PUsbResetEp(DATA_ENDPOINT_CONSUMER); - CyU3PDmaChannelSetXfer(&data_prod_to_cons_chan_handle, \ - DMA_SIZE_INFINITE); - CyU3PUsbStall(wIndex, CyFalse, CyTrue); - handled = CyTrue; - CyU3PUsbAckSetup(); - - msg("Clear DATA_ENDPOINT_CONSUMER"); - } - - if(wIndex == CTRL_ENDPOINT_PRODUCER) { - CyU3PDmaChannelReset(&ctrl_cons_to_prod_chan_handle); - CyU3PUsbFlushEp(CTRL_ENDPOINT_PRODUCER); - CyU3PUsbResetEp(CTRL_ENDPOINT_PRODUCER); - CyU3PDmaChannelSetXfer(&ctrl_cons_to_prod_chan_handle, \ - DMA_SIZE_INFINITE); - CyU3PUsbStall(wIndex, CyFalse, CyTrue); - handled = CyTrue; - CyU3PUsbAckSetup(); - - msg("Clear CTRL_ENDPOINT_PRODUCER"); - } - - if(wIndex == CTRL_ENDPOINT_CONSUMER) { - CyU3PDmaChannelReset(&ctrl_prod_to_cons_chan_handle); - CyU3PUsbFlushEp(CTRL_ENDPOINT_CONSUMER); - CyU3PUsbResetEp(CTRL_ENDPOINT_CONSUMER); - CyU3PDmaChannelSetXfer(&ctrl_prod_to_cons_chan_handle, \ - DMA_SIZE_INFINITE); - CyU3PUsbStall(wIndex, CyFalse, CyTrue); - handled = CyTrue; - CyU3PUsbAckSetup(); - - msg("Clear CTRL_ENDPOINT_CONSUMER"); - } - } - } - } - /* This must be & and not == so that we catch VREQs that are both 'IN' and - * 'OUT' in direction. */ - else if(bRequestType & CY_U3P_USB_VENDOR_RQT) { - - handled = CyTrue; - uint16_t read_count = 0; - - switch(bRequest) { - case B200_VREQ_BITSTREAM_START: { - CyU3PUsbGetEP0Data(1, g_vendor_req_buffer, &read_count); - - g_fpga_programming_write_count = 0; - - CyU3PEventSet(&g_event_usb_config, EVENT_BITSTREAM_START, \ - CYU3P_EVENT_OR); - break; - } - - case B200_VREQ_BITSTREAM_DATA: { - CyU3PUsbGetEP0Data(g_vendor_req_buff_size, g_vendor_req_buffer, \ - &read_count); - - if (g_fx3_state == STATE_CONFIGURING_FPGA) { - ++g_fpga_programming_write_count; - CyU3PSpiTransmitWords(g_vendor_req_buffer, read_count); - CyU3PThreadSleep(1); // Newer controllers don't have an issue when this short sleep here - } - break; - } - - case B200_VREQ_BITSTREAM_DATA_FILL: { - CyU3PUsbGetEP0Data(g_vendor_req_buff_size, g_vendor_req_buffer, &g_vendor_req_read_count); - break; - } - - case B200_VREQ_BITSTREAM_DATA_COMMIT: { - /*CyU3PReturnStatus_t*/int spi_result = -1; - if (g_fx3_state == STATE_CONFIGURING_FPGA) { - ++g_fpga_programming_write_count; - spi_result = CyU3PSpiTransmitWords(g_vendor_req_buffer, g_vendor_req_read_count); - CyU3PThreadSleep(1); // 20 MHz, 512 bytes - } - CyU3PUsbSendEP0Data(sizeof(spi_result), (uint8_t*)&spi_result); - break; - } - - case B200_VREQ_FPGA_CONFIG: { - CyU3PUsbGetEP0Data(1, g_vendor_req_buffer, &read_count); - - CyU3PEventSet(&g_event_usb_config, EVENT_FPGA_CONFIG, CYU3P_EVENT_OR); - break; - } - - case B200_VREQ_GET_COMPAT: { - CyU3PUsbSendEP0Data(/*2*/sizeof(compat_num), compat_num); - break; - } - - case B200_VREQ_SET_FPGA_HASH: { - CyU3PUsbGetEP0Data(4, fpga_hash, &read_count); - break; - } - - case B200_VREQ_GET_FPGA_HASH: { - CyU3PUsbSendEP0Data(/*4*/sizeof(fpga_hash), fpga_hash); - break; - } - - case B200_VREQ_SET_FW_HASH: { - CyU3PUsbGetEP0Data(4, fw_hash, &read_count); - break; - } - - case B200_VREQ_GET_FW_HASH: { - CyU3PUsbSendEP0Data(/*4*/sizeof(fw_hash), fw_hash); - break; - } - - case B200_VREQ_LOOP_CODE: { - CyU3PUsbSendEP0Data(g_vendor_req_buff_size, g_vendor_req_buffer); - break; - } - - case B200_VREQ_GET_LOG: { - LOCK(g_log_lock); - - if (log_buffer_len == 0) { - log_buffer[0] = '\0'; - CyU3PUsbSendEP0Data(1, (uint8_t*)log_buffer); - //CyU3PUsbSendEP0Data(0, NULL); - //CyU3PUsbAckSetup(); - } - else if (log_buffer_idx == 0) - CyU3PUsbSendEP0Data(log_buffer_len, (uint8_t*)log_buffer); - else { - int len1 = min(LOG_BUFFER_SIZE - log_buffer_idx, log_buffer_len); - memcpy(log_contiguous_buffer, log_buffer + log_buffer_idx, len1); - //if ((log_buffer_idx + log_buffer_len) > LOG_BUFFER_SIZE) - if (len1 < log_buffer_len) - memcpy(log_contiguous_buffer + len1, log_buffer, log_buffer_len - len1); - CyU3PUsbSendEP0Data(log_buffer_len, (uint8_t*)log_contiguous_buffer); - } - - // FIXME: Necessary? Not used in the other ones - //CyU3PUsbSendEP0Data(0, NULL); // Send ZLP since previous send has resulted in an integral # of packets - - log_reset(); - - UNLOCK(g_log_lock); - - //log_reset(); - - break; - } - - case B200_VREQ_GET_COUNTERS: { - LOCK(g_counters_lock); - - CyU3PUsbSendEP0Data(sizeof(COUNTERS), (uint8_t*)&g_counters); - - counters_auto_reset(); - - UNLOCK(g_counters_lock); - - //counters_auto_reset(); - - break; - } - - case B200_VREQ_CLEAR_COUNTERS: { - CyU3PUsbAckSetup(); - //CyU3PUsbGetEP0Data(g_vendor_req_buff_size, g_vendor_req_buffer, &read_count); // Dummy - - counters_dma_reset(); - - break; - } - - case B200_VREQ_GET_USB_EVENT_LOG: { - uint16_t idx = CyU3PUsbGetEventLogIndex(); // Current *write* pointer - if (idx > (USB_EVENT_LOG_SIZE-1)) { - msg("! USB event log idx = %i", (int)idx); - break; - } - // Assuming logging won't wrap around between get calls (i.e. buffer should be long enough) - uint16_t len = 0; - if (idx < g_last_usb_event_log_index) { - uint16_t len1 = (USB_EVENT_LOG_SIZE - g_last_usb_event_log_index); - if (len1 > (USB_EVENT_LOG_SIZE-1)) { - msg("! USB event log len 2.1 = %i", (int)len1); - break; - } - len = len1 + idx; - if (len > (USB_EVENT_LOG_SIZE-1)) { - msg("! USB event log len 2.2 = %i", (int)len); - break; - } - memcpy(g_usb_event_log_contiguous_buf, g_usb_event_log + g_last_usb_event_log_index, len1); - memcpy(g_usb_event_log_contiguous_buf + len1, g_usb_event_log, idx); - //msg("USB event log [2] %i %i", (int)len1, (int)len); - } else { - len = idx - g_last_usb_event_log_index; - if (len > (USB_EVENT_LOG_SIZE-1)) { - msg("! USB event log len 1 = %i", (int)len); - break; - } - if (len > 0) { // ZLP should be OK - memcpy(g_usb_event_log_contiguous_buf, g_usb_event_log + g_last_usb_event_log_index, len); - //msg("USB event log [1] %i", (int)len); - } - } - - //if (len > 0) // Send a ZLP, otherwise it'll timeout - CyU3PUsbSendEP0Data(len, g_usb_event_log_contiguous_buf); - - g_last_usb_event_log_index = idx; - break; - } - - case B200_VREQ_SET_CONFIG: { - CyU3PUsbGetEP0Data(sizeof(CONFIG_MOD), (uint8_t*)g_vendor_req_buffer, &read_count); - if (read_count == sizeof(CONFIG_MOD)) { - memcpy(&g_config_mod, g_vendor_req_buffer, sizeof(CONFIG_MOD)); - CyU3PEventSet(&g_event_usb_config, EVENT_RE_ENUM, CYU3P_EVENT_OR); - } - break; - } - - case B200_VREQ_GET_CONFIG: { - CyU3PUsbSendEP0Data(sizeof(g_config), (uint8_t*)&g_config); - break; - } - - case B200_VREQ_WRITE_SB: { - CyU3PUsbGetEP0Data(g_vendor_req_buff_size, (uint8_t*)g_vendor_req_buffer, &read_count); -#ifdef ENABLE_FPGA_SB - uint16_t i; - LOCK(g_suart_lock); - for (i = 0; i < read_count; ++i) - sb_write(SUART_TXCHAR, g_vendor_req_buffer[i]); - UNLOCK(g_suart_lock); - - msg("Wrote %d SB chars", read_count); -#else - msg("SB is disabled"); -#endif // ENABLE_FPGA_SB - break; - } - - case B200_VREQ_SET_SB_BAUD_DIV: { - uint16_t div; - CyU3PUsbGetEP0Data(sizeof(div), (uint8_t*)&div, &read_count); - - if (read_count == sizeof(div)) { -#ifdef ENABLE_FPGA_SB - LOCK(g_suart_lock); - sb_write(SUART_CLKDIV, div); - UNLOCK(g_suart_lock); - msg("SUART_CLKDIV = %d", div); - /*g_fpga_sb_uart_div*/g_config.sb_baud_div = div; // Store for GPIF (FPGA) reset -#else - msg("SB is disabled"); -#endif // ENABLE_FPGA_SB - } - else - msg("! SUART_CLKDIV received %d bytes", read_count); - - break; - } - - case B200_VREQ_FLUSH_DATA_EPS: { - //msg("Flushing data EPs..."); - - //CyU3PUsbAckSetup(); - - //CyU3PUsbResetEndpointMemories(); - - // From host - //CyU3PDmaChannelReset(&data_cons_to_prod_chan_handle); - //CyU3PUsbFlushEp(DATA_ENDPOINT_PRODUCER); - //CyU3PUsbResetEp(DATA_ENDPOINT_PRODUCER); - //CyU3PDmaChannelSetXfer(&data_cons_to_prod_chan_handle, DMA_SIZE_INFINITE); - - //CyU3PDmaSocketDisable(DATA_RX_PPORT_SOCKET); - - //CyU3PDmaChannelReset(&data_cons_to_prod_chan_handle); - if (CyU3PDmaChannelReset(&data_prod_to_cons_chan_handle) != CY_U3P_SUCCESS) - { - msg("! CyU3PDmaChannelReset"); - } - //CyU3PUsbFlushEp(DATA_ENDPOINT_PRODUCER); - CyU3PUsbFlushEp(DATA_ENDPOINT_CONSUMER); - //CyU3PUsbResetEp(DATA_ENDPOINT_PRODUCER); -// CyU3PUsbResetEp(DATA_ENDPOINT_CONSUMER); - //CyU3PUsbStall(DATA_ENDPOINT_CONSUMER, CyFalse, CyTrue); - //CyU3PDmaChannelSetXfer(&data_cons_to_prod_chan_handle, DMA_SIZE_INFINITE); - //CyU3PDmaSocketEnable(DATA_RX_PPORT_SOCKET); - CyU3PDmaChannelSetXfer(&data_prod_to_cons_chan_handle, DMA_SIZE_INFINITE); - - //CyU3PUsbResetEndpointMemories(); - - // To host - //CyU3PDmaChannelReset(&data_prod_to_cons_chan_handle); - //CyU3PUsbFlushEp(DATA_ENDPOINT_CONSUMER); - //CyU3PUsbResetEp(DATA_ENDPOINT_CONSUMER); - //CyU3PDmaChannelSetXfer(&data_prod_to_cons_chan_handle, DMA_SIZE_INFINITE); - - CyU3PUsbAckSetup(); - - break; - } - - case B200_VREQ_EEPROM_WRITE: { - i2cAddr = 0xA0 | ((wValue & 0x0007) << 1); - CyU3PUsbGetEP0Data(((wLength + 15) & 0xFFF0), g_vendor_req_buffer, NULL); - - CyFxUsbI2cTransfer (wIndex, i2cAddr, wLength, - g_vendor_req_buffer, CyFalse); - break; - } - - case B200_VREQ_EEPROM_READ: { - i2cAddr = 0xA0 | ((wValue & 0x0007) << 1); - CyU3PMemSet (g_vendor_req_buffer, 0, sizeof (g_vendor_req_buffer)); - CyFxUsbI2cTransfer (wIndex, i2cAddr, wLength, - g_vendor_req_buffer, CyTrue); - - CyU3PUsbSendEP0Data(wLength, g_vendor_req_buffer); - break; - } - - case B200_VREQ_TOGGLE_FPGA_RESET: { - CyU3PUsbGetEP0Data(g_vendor_req_buff_size, g_vendor_req_buffer, \ - &read_count); - - /* CyBool_t value = (g_vendor_req_buffer[0] & 0x01) ? CyTrue : CyFalse; - CyU3PGpioSetValue(GPIO_FPGA_RESET, value); */ - break; - } - - case B200_VREQ_TOGGLE_GPIF_RESET: { - CyU3PUsbGetEP0Data(g_vendor_req_buff_size, g_vendor_req_buffer, \ - &read_count); - - reset_gpif(); - break; - } - - case B200_VREQ_RESET_DEVICE: { - CyU3PUsbGetEP0Data(4, g_vendor_req_buffer, &read_count); - - CyU3PDeviceReset(CyFalse); // FIXME: If CyTrue, this will *not* call static initialisers for global variables - must do this manually - break; - } - - case B200_VREQ_GET_USB_SPEED: { - CyU3PUSBSpeed_t usb_speed = CyU3PUsbGetSpeed(); - switch(usb_speed) { - case CY_U3P_SUPER_SPEED: - g_vendor_req_buffer[0] = 3; - break; - - case CY_U3P_FULL_SPEED: - case CY_U3P_HIGH_SPEED: - g_vendor_req_buffer[0] = 2; - break; - - default: - g_vendor_req_buffer[0] = 1; - break; - } - - CyU3PUsbSendEP0Data(1, g_vendor_req_buffer); - break; - } - - case B200_VREQ_GET_STATUS: { - g_vendor_req_buffer[0] = g_fx3_state; - CyU3PUsbSendEP0Data(1, g_vendor_req_buffer); - break; - } - - default: - msg("! Unknown VREQ %02X", (uint32_t)bRequest); - handled = CyFalse; - } - - /* After processing the vendor request, flush the endpoints. */ - CyU3PUsbFlushEp(VREQ_ENDPOINT_PRODUCER); - CyU3PUsbFlushEp(VREQ_ENDPOINT_CONSUMER); - } - - return handled; -} - - -/* Callback function to handle LPM requests from the USB 3.0 host. This function - * is invoked by the API whenever a state change from U0 -> U1 or U0 -> U2 - * happens. - * - * If we return CyTrue from this function, the FX3 device is retained - * in the low power state. If we return CyFalse, the FX3 device immediately - * tries to trigger an exit back to U0. - */ -CyBool_t lpm_request_callback(CyU3PUsbLinkPowerMode link_mode) { - msg("! lpm_request_callback = %i", link_mode); - return -//#ifdef PREVENT_LOW_POWER_MODE - CyFalse; // This still allows my laptop to sleep -//#else -// CyTrue; -//#endif // PREVENT_LOW_POWER_MODE -} - - -/* Callback function to check for PIB ERROR*/ -void gpif_error_cb(CyU3PPibIntrType cbType, uint16_t cbArg) -{ - if (cbType==CYU3P_PIB_INTR_ERROR) - { - switch (CYU3P_GET_PIB_ERROR_TYPE(cbArg)) - { - case CYU3P_PIB_ERR_NONE: - break; - case CYU3P_PIB_ERR_THR0_WR_OVERRUN: - msg("CYU3P_PIB_ERR_THR0_WR_OVERRUN"); - break; - case CYU3P_PIB_ERR_THR1_WR_OVERRUN: - msg("CYU3P_PIB_ERR_THR1_WR_OVERRUN"); - break; - case CYU3P_PIB_ERR_THR2_WR_OVERRUN: - msg("CYU3P_PIB_ERR_THR2_WR_OVERRUN"); - break; - case CYU3P_PIB_ERR_THR3_WR_OVERRUN: - msg("CYU3P_PIB_ERR_THR3_WR_OVERRUN"); - break; - case CYU3P_PIB_ERR_THR0_RD_UNDERRUN: - msg("CYU3P_PIB_ERR_THR0_RD_UNDERRUN"); - break; - case CYU3P_PIB_ERR_THR1_RD_UNDERRUN: - msg("CYU3P_PIB_ERR_THR1_RD_UNDERRUN"); - break; - case CYU3P_PIB_ERR_THR2_RD_UNDERRUN: - msg("CYU3P_PIB_ERR_THR2_RD_UNDERRUN"); - break; - case CYU3P_PIB_ERR_THR3_RD_UNDERRUN: - msg("CYU3P_PIB_ERR_THR3_RD_UNDERRUN"); - break; - case CYU3P_PIB_ERR_THR0_ADAP_UNDERRUN: - msg("CYU3P_PIB_ERR_THR0_ADAP_UNDERRUN"); - break; - case CYU3P_PIB_ERR_THR1_ADAP_OVERRUN: - msg("CYU3P_PIB_ERR_THR1_ADAP_OVERRUN"); - break; - // FIXME: Other threads - case CYU3P_PIB_ERR_THR1_SCK_INACTIVE: - //msg("CYU3P_PIB_ERR_THR1_SCK_INACTIVE"); - ++g_counters.pib_counters[1].socket_inactive; // UNSYNC'd - break; - default: - msg("Unknown CYU3P_PIB_ERR %i", CYU3P_GET_PIB_ERROR_TYPE(cbArg)); - break; - } - - switch (CYU3P_GET_GPIF_ERROR_TYPE(cbArg)) - { - case CYU3P_GPIF_ERR_NONE: /**< No GPIF state machine errors. */ - //msg("CYU3P_GPIF_ERR_NONE"); - break; - case CYU3P_GPIF_ERR_INADDR_OVERWRITE: /**< Content of INGRESS_ADDR register is overwritten before read. */ - msg("CYU3P_GPIF_ERR_INADDR_OVERWRITE"); - break; - case CYU3P_GPIF_ERR_EGADDR_INVALID: /**< Attempt to read EGRESS_ADDR register before it is written to. */ - msg("CYU3P_GPIF_ERR_EGADDR_INVALID"); - break; - case CYU3P_GPIF_ERR_DATA_READ_ERR: /**< Read from DMA data thread which is not ready. */ - msg("CYU3P_GPIF_ERR_DATA_READ_ERR"); - break; - case CYU3P_GPIF_ERR_DATA_WRITE_ERR: /**< Write to DMA data thread which is not ready. */ - msg("CYU3P_GPIF_ERR_DATA_WRITE_ERR"); - break; - case CYU3P_GPIF_ERR_ADDR_READ_ERR: /**< Read from DMA address thread which is not ready. */ - msg("CYU3P_GPIF_ERR_ADDR_READ_ERR"); - break; - case CYU3P_GPIF_ERR_ADDR_WRITE_ERR: /**< Write to DMA address thread which is not ready. */ - msg("CYU3P_GPIF_ERR_ADDR_WRITE_ERR"); - break; - case CYU3P_GPIF_ERR_INVALID_STATE: /**< GPIF state machine has reached an invalid state. */ - //msg("CYU3P_GPIF_ERR_INVALID_STATE"); - ++g_counters.invalid_gpif_state; // UNSYNC'd - break; - default: - msg("Unknown CYU3P_GPIF_ERR %i", CYU3P_GET_GPIF_ERROR_TYPE(cbArg)); - break; - } - } -} - - -void GpifStateChangeCb(uint8_t stateId) -{ - //msg("%d", stateId); - ++g_counters.state_transition_count; -} - - -/*! Initialize and start the GPIF state machine. - * - * This function starts the GPIF Slave FIFO state machine on the FX3. Because on - * of the GPIF pins is used for FPGA configuration, this cannot be done until - * after FPGA configuration is complete. */ -void b200_gpif_init(void) { - msg("b200_gpif_init"); - - CyU3PPibClock_t pib_clock_config; - - /* Initialize the p-port block; disable DLL for sync GPIF. */ - pib_clock_config.clkDiv = 2; - pib_clock_config.clkSrc = CY_U3P_SYS_CLK; - pib_clock_config.isHalfDiv = CyFalse; - pib_clock_config.isDllEnable = CyFalse; - if (CyU3PPibInit(CyTrue, &pib_clock_config) != CY_U3P_SUCCESS) - msg("! CyU3PPibInit"); - - /* Load the GPIF configuration for Slave FIFO sync mode. */ - if (CyU3PGpifLoad(&CyFxGpifConfig) != CY_U3P_SUCCESS) - msg("! CyU3PGpifLoad"); - - msg("GPIF loaded"); - - //CyU3PGpifRegisterSMIntrCallback(GpifStateChangeCb); - - /* Start the state machine. */ - //CyU3PGpifSMStart(RESET, ALPHA_RESET); - - /* Configure the watermarks for the slfifo-write buffers. */ - if (CyU3PGpifSocketConfigure(0, DATA_TX_PPORT_SOCKET, 5, CyFalse, 1) != CY_U3P_SUCCESS) - msg("! CyU3PGpifSocketConfigure 0"); - if (CyU3PGpifSocketConfigure(1, DATA_RX_PPORT_SOCKET, 6, CyFalse, 1) != CY_U3P_SUCCESS) - msg("! CyU3PGpifSocketConfigure 1"); - if (CyU3PGpifSocketConfigure(2, CTRL_COMM_PPORT_SOCKET, 5, CyFalse, 1) != CY_U3P_SUCCESS) - msg("! CyU3PGpifSocketConfigure 2"); - if (CyU3PGpifSocketConfigure(3, CTRL_RESP_PPORT_SOCKET, 6, CyFalse, 1) != CY_U3P_SUCCESS) - msg("! CyU3PGpifSocketConfigure 3"); - - //CyU3PGpifSMStart(RESET, ALPHA_RESET); - - /* Register a callback for notification of PIB interrupts*/ - CyU3PPibRegisterCallback(gpif_error_cb, CYU3P_PIB_INTR_ERROR); -} - - -/*! Start and configure the FX3's SPI module. - * - * This module is used for programming the FPGA. After the FPGA is configured, - * the SPI module is disabled, as it cannot be used while we are using GPIF - * 32-bit mode. */ -CyU3PReturnStatus_t b200_spi_init(void) { - msg("b200_spi_init"); - - CyU3PSpiConfig_t spiConfig; - - /* Start the SPI module and configure the master. */ - CyU3PSpiInit(); - - /* Start the SPI master block. Run the SPI clock at 8MHz - * and configure the word length to 8 bits. Also configure - * the slave select using FW. */ - CyU3PMemSet ((uint8_t *)&spiConfig, 0, sizeof(spiConfig)); - spiConfig.isLsbFirst = CyFalse; - spiConfig.cpol = CyFalse; - spiConfig.cpha = CyFalse; - spiConfig.ssnPol = CyTrue; - spiConfig.leadTime = CY_U3P_SPI_SSN_LAG_LEAD_HALF_CLK; - spiConfig.lagTime = CY_U3P_SPI_SSN_LAG_LEAD_HALF_CLK; - spiConfig.ssnCtrl = CY_U3P_SPI_SSN_CTRL_FW; - spiConfig.clock = 20000000; - spiConfig.wordLen = 8; - - CyU3PReturnStatus_t res = CyU3PSpiSetConfig(&spiConfig, NULL); - - if (res != CY_U3P_SUCCESS) - msg("! CyU3PSpiSetConfig"); - - return res; -} - - -/*! Initialize the USB module of the FX3 chip. - * - * This function handles USB initialization, re-enumeration (and thus coming up - * as a USRP B200 device), configures USB endpoints and the DMA module. - */ -void b200_usb_init(void) { - //msg("b200_usb_init"); - - /* Initialize the I2C interface for the EEPROM of page size 64 bytes. */ - CyFxI2cInit(CY_FX_USBI2C_I2C_PAGE_SIZE); - - /* Start the USB system! */ - CyU3PUsbStart(); - - /* Register our USB Setup callback. The boolean parameter indicates whether - * or not we are using FX3's 'Fast Enumeration' mode, which relies on the - * USB driver auto-detecting the connection speed and setting the correct - * descriptors. */ - CyU3PUsbRegisterSetupCallback(usb_setup_callback, CyTrue); - - CyU3PUsbRegisterEventCallback(event_usb_callback); - - CyU3PUsbRegisterLPMRequestCallback(lpm_request_callback); - - /* Check to see if a VID/PID is in the EEPROM that we should use. */ - uint8_t valid[4]; - uint8_t vidpid[4]; - CyU3PMemSet(valid, 0, 4); - CyFxUsbI2cTransfer(0x0, 0xA0, 4, valid, CyTrue); - if(*((uint32_t *) &(valid[0])) == 0xB2145943) { - - /* Pull the programmed device serial out of the i2c EEPROM, and copy the - * characters into the device serial string, which is then advertised as - * part of the USB descriptors. */ - CyU3PMemSet(vidpid, 0, 4); - CyFxUsbI2cTransfer(0x4, 0xA0, 4, vidpid, CyTrue); - b200_usb2_dev_desc[8] = vidpid[2]; - b200_usb2_dev_desc[9] = vidpid[3]; - b200_usb2_dev_desc[10] = vidpid[0]; - b200_usb2_dev_desc[11] = vidpid[1]; - - b200_usb3_dev_desc[8] = vidpid[2]; - b200_usb3_dev_desc[9] = vidpid[3]; - b200_usb3_dev_desc[10] = vidpid[0]; - b200_usb3_dev_desc[11] = vidpid[1]; - } - - /* We support two VIDs: - * Ettus Research: 0x2500 - * National Instruments: 0x3923 - * - * We support three PIDs: - * Ettus B200/B210: 0x0020 - * NI USRP-2900: 0x7813 - * NI USRP-2901: 0x7814 - */ - uint8_t *mfr_string = NULL; - uint8_t *product_string = NULL; - if((vidpid[3] == 0x25) && (vidpid[2] == 0x00)) { - mfr_string = b200_usb_manufacture_desc; - product_string = b200_usb_product_desc; - } else if((vidpid[3] == 0x39) && (vidpid[2] == 0x23)) { - mfr_string = niusrp_usb_manufacture_desc; - - if((vidpid[1] == 0x78) && (vidpid[0] == 0x13)) { - product_string = niusrp_2900_usb_product_desc; - } else if((vidpid[1] == 0x78) && (vidpid[0] == 0x14)) { - product_string = niusrp_2901_usb_product_desc; - } else { - product_string = unknown_desc; - } - } else { - mfr_string = unknown_desc; - product_string = unknown_desc; - } - - uint8_t ascii_serial[9]; - CyU3PMemSet(ascii_serial, 0, 9); - CyFxUsbI2cTransfer(0x4f7, 0xA0, 9, ascii_serial, CyTrue); - uint8_t count; - dev_serial[0] = 2; - for(count = 0; count < 9; count++) { - uint8_t byte = ascii_serial[count]; - if (byte < 32 || byte > 127) break; - dev_serial[2 + (count * 2)] = byte; - // FIXME: Set count*2 + 1 = 0x00 ? - dev_serial[0] += 2; - } - - /* Set our USB enumeration descriptors! Note that there are different - * function calls for each USB speed: FS, HS, SS. */ - - /* Device descriptors */ - CyU3PUsbSetDesc(CY_U3P_USB_SET_HS_DEVICE_DESCR, 0, - (uint8_t *) b200_usb2_dev_desc); - - CyU3PUsbSetDesc(CY_U3P_USB_SET_SS_DEVICE_DESCR, 0, - (uint8_t *) b200_usb3_dev_desc); - - /* Device qualifier descriptors */ - CyU3PUsbSetDesc(CY_U3P_USB_SET_DEVQUAL_DESCR, 0, - (uint8_t *) b200_dev_qual_desc); - - /* Configuration descriptors */ - CyU3PUsbSetDesc(CY_U3P_USB_SET_HS_CONFIG_DESCR, 0, - (uint8_t *) b200_usb_hs_config_desc); - - CyU3PUsbSetDesc(CY_U3P_USB_SET_FS_CONFIG_DESCR, 0, - (uint8_t *) b200_usb_fs_config_desc); - - CyU3PUsbSetDesc(CY_U3P_USB_SET_SS_CONFIG_DESCR, 0, - (uint8_t *) b200_usb_ss_config_desc); - - /* BOS Descriptor */ - CyU3PUsbSetDesc(CY_U3P_USB_SET_SS_BOS_DESCR, 0, - (uint8_t *) b200_usb_bos_desc); - - /* String descriptors */ - CyU3PUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 0, - (uint8_t *) b200_string_lang_id_desc); - - CyU3PUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 1, - (uint8_t *) mfr_string); - - CyU3PUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 2, - (uint8_t *) product_string); - - CyU3PUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 3, - (uint8_t *) dev_serial); - - //////////////////////////////////////////////////////// - - // FIXME: CyU3PUsbSetTxDeemphasis(0x11); <0x1F // Shouldn't need to change this - - const uint32_t tx_swing = g_config.tx_swing/*65*//*45*/; // 65 & 45 are OK, 120 causes much link recovery. <128. 1.2V is USB3 limit. - if (CyU3PUsbSetTxSwing(tx_swing) == CY_U3P_SUCCESS) - msg("CyU3PUsbSetTxSwing: %d", tx_swing); - else - msg("! CyU3PUsbSetTxSwing: %d", tx_swing); - - //////////////////////////////////////////////////////// - - /* Connect the USB pins, and enable SuperSpeed (USB 3.0). */ - if (CyU3PConnectState(CyTrue, (g_config.enable_as_superspeed != 0 ? CyTrue : CyFalse)) == CY_U3P_SUCCESS) { // connect, ssEnable - CyU3PUSBSpeed_t usb_speed = CyU3PUsbGetSpeed(); - msg("Link up (speed: USB %d)", (int)usb_speed); // MAGIC: Values happen to map - } - else - msg("! Failed to establish link"); -} - - -void b200_restore_gpio_for_fpga_config(void) { - CyU3PDeviceGpioRestore(GPIO_FPGA_RESET); - CyU3PDeviceGpioRestore(GPIO_DONE); - - CyU3PDeviceGpioRestore(GPIO_FX3_SCLK); - CyU3PDeviceGpioRestore(GPIO_FX3_CE); - CyU3PDeviceGpioRestore(GPIO_FX3_MISO); - CyU3PDeviceGpioRestore(GPIO_FX3_MOSI); - - //CyU3PGpioDeInit(); // Moved to just before init -} - -void thread_fpga_config_entry(uint32_t input) { - uint32_t event_flag; - - //msg("thread_fpga_config_entry"); - - for(;;) { - - // Event is set through VREQ - if(CyU3PEventGet(&g_event_usb_config, \ - (EVENT_FPGA_CONFIG), CYU3P_EVENT_AND_CLEAR, \ - &event_flag, CYU3P_WAIT_FOREVER) == CY_U3P_SUCCESS) { - - //uint8_t old_state = g_fx3_state; - uint32_t old_fpga_programming_write_count = 0; - - if(g_fx3_state == STATE_ERROR) { - CyU3PThreadRelinquish(); - continue; - } - - if(g_fx3_state == STATE_RUNNING) { - /* The FX3 is currently configured for SLFIFO mode. We need to tear down - * this configuration and re-configure to program the FPGA. */ - b200_restore_gpio_for_fpga_config(); - CyU3PGpifDisable(CyTrue); - } - - CyU3PSysWatchDogClear(); - - g_fx3_state = STATE_BUSY; - - /* Configure the device GPIOs for FPGA programming. */ - b200_gpios_pre_fpga_config(); - - CyU3PSysWatchDogClear(); - - /* Initialize the SPI module that will be used for FPGA programming. */ - b200_spi_init(); // This must be done *after* 'b200_gpios_pre_fpga_config' - - CyU3PSysWatchDogClear(); - - /* Wait for the signal from the host that the bitstream is starting. */ - uint32_t wait_count = 0; - - /* We can now begin configuring the FPGA. */ - g_fx3_state = STATE_FPGA_READY; - - msg("Begin FPGA"); - - // Event is set through VREQ - while(CyU3PEventGet(&g_event_usb_config, \ - (EVENT_BITSTREAM_START), CYU3P_EVENT_AND_CLEAR, \ - &event_flag, CYU3P_NO_WAIT) != CY_U3P_SUCCESS) { - - if(wait_count >= FPGA_PROGRAMMING_BITSTREAM_START_POLL_COUNT) { - msg("! Bitstream didn't start"); - g_fx3_state = STATE_UNCONFIGURED; // Since IO configuration has changed, leave it in the unconfigured state (rather than the previous one, which might have been running) - CyU3PThreadRelinquish(); - break; - } - - wait_count++; - CyU3PThreadSleep(FPGA_PROGRAMMING_POLL_SLEEP); - CyU3PSysWatchDogClear(); - } - - if (wait_count >= FPGA_PROGRAMMING_BITSTREAM_START_POLL_COUNT) - continue; - - /* Pull PROGRAM_B low and then release it. */ - CyU3PGpioSetValue(GPIO_PROGRAM_B, 0); - CyU3PThreadSleep(20); - CyU3PGpioSetValue(GPIO_PROGRAM_B, 1); - - /* Wait for INIT_B to fall and rise. */ - wait_count = 0; - - msg("Wait FPGA"); - - while(CyU3PEventGet(&g_event_usb_config, \ - (EVENT_GPIO_INITB_RISE), CYU3P_EVENT_AND_CLEAR, \ - &event_flag, CYU3P_NO_WAIT) != CY_U3P_SUCCESS) { - - if(wait_count >= FPGA_PROGRAMMING_INITB_POLL_COUNT) { - msg("! INITB didn't rise"); - g_fx3_state = STATE_UNCONFIGURED; // Safer to call it unconfigured than the previous state - CyU3PThreadRelinquish(); - break; - } - - wait_count++; - CyU3PThreadSleep(FPGA_PROGRAMMING_POLL_SLEEP); - CyU3PSysWatchDogClear(); - } -#ifdef ENABLE_INIT_B_WORKAROUND - if (wait_count >= FPGA_PROGRAMMING_INITB_POLL_COUNT) - { - CyBool_t gpio_init_b; - CyU3PGpioGetValue(GPIO_INIT_B, &gpio_init_b); - if (gpio_init_b == CyTrue) - { - wait_count = 0; - } - else - { - msg("! INIT_B still not high"); - } - } -#endif // ENABLE_INIT_B_WORKAROUND - if (wait_count >= FPGA_PROGRAMMING_INITB_POLL_COUNT) - continue; - - /* We are ready to accept the FPGA bitstream! */ - wait_count = 0; - g_fx3_state = STATE_CONFIGURING_FPGA; - - msg("Configuring FPGA"); - - // g_fpga_programming_write_count is zero'd by VREQ triggering EVENT_BITSTREAM_START - - while(CyU3PEventGet(&g_event_usb_config, \ - (EVENT_GPIO_DONE_HIGH), CYU3P_EVENT_AND_CLEAR, \ - &event_flag, CYU3P_NO_WAIT) != CY_U3P_SUCCESS) { - - /* Wait for the configuration to complete, which will be indicated - * by the DONE pin going high and triggering the associated - * interrupt. */ - - if(wait_count >= FPGA_PROGRAMMING_DONE_POLL_COUNT) { - msg("! DONE didn't go high"); - g_fx3_state = STATE_UNCONFIGURED; - CyU3PThreadRelinquish(); - break; - } - - if (old_fpga_programming_write_count == g_fpga_programming_write_count) // Only increment wait count if we haven't written anything - wait_count++; - else { - wait_count = 0; - old_fpga_programming_write_count = g_fpga_programming_write_count; - } - - CyU3PThreadSleep(FPGA_PROGRAMMING_POLL_SLEEP); - CyU3PSysWatchDogClear(); - } -#ifdef ENABLE_DONE_WORKAROUND - if (wait_count >= FPGA_PROGRAMMING_DONE_POLL_COUNT) - { - CyBool_t gpio_done; - CyU3PGpioGetValue(GPIO_DONE, &gpio_done); - if (gpio_done == CyTrue) - { - wait_count = 0; - } - else - { - msg("! DONE still not high"); - } - } -#endif // ENABLE_DONE_WORKAROUND - if (wait_count >= FPGA_PROGRAMMING_DONE_POLL_COUNT) - continue; - - msg("FPGA done"); - - /* Tell the host that we are ignoring it for a while. */ - g_fx3_state = STATE_BUSY; - - CyU3PSysWatchDogClear(); - - /* Now that the FPGA is configured, we need to tear down the current SPI and - * GPIO configs, and re-config for GPIF & bit-banged SPI operation. */ - CyU3PSpiDeInit(); - b200_restore_gpio_for_fpga_config(); - - CyU3PSysWatchDogClear(); - - /* Load the GPIO configuration for normal SLFIFO use. */ - b200_slfifo_mode_gpio_config(); - - /* Tone down the drive strength on the P-port. */ - //CyU3PSetPportDriveStrength(CY_U3P_DS_HALF_STRENGTH); - - CyU3PSysWatchDogClear(); - - /* FPGA configuration is complete! Time to get the GPIF state machine - * running for Slave FIFO. */ - b200_gpif_init(); - - CyU3PThreadSleep(1); - b200_start_fpga_sb_gpio(); // Moved here to give SB time to init - - /* RUN, BABY, RUN! */ - g_fx3_state = STATE_RUNNING; - - msg("Running"); - } - - CyU3PThreadRelinquish(); - } -} - - -/*! The primary program thread. - * - * This is the primary application thread running on the FX3 device. It is - * responsible for initializing much of the chip, and then bit-banging the FPGA - * image, as it is sent from the host, into the FPGA. It then re-configures the - * FX3 for slave-fifo, and enters an infinite loop where it simply updates the - * watchdog timer and does some minor power management state checking. - */ -void thread_main_app_entry(uint32_t input) { - //msg("thread_main_app_entry"); - - /* In your spectrum, stealing your Hz. */ - for(;;) { - CyU3PSysWatchDogClear(); - CyU3PThreadSleep(CHECK_POWER_STATE_SLEEP_TIME); -#ifdef PREVENT_LOW_POWER_MODE - /* Once data transfer has started, we keep trying to get the USB - * link to stay in U0. If this is done - * before data transfers have started, there is a likelihood of - * failing the TD 9.24 U1/U2 test. */ - { - CyU3PUsbLinkPowerMode current_state; - - if((CyU3PUsbGetSpeed () == CY_U3P_SUPER_SPEED)) { - - /* If the link is in U1/U2 states, try to get back to U0. */ - CyU3PUsbGetLinkPowerState(¤t_state); - - if (current_state > CyU3PUsbLPM_U3) - msg("Power state %i", current_state); - - while((current_state >= CyU3PUsbLPM_U1) \ - && (current_state <= CyU3PUsbLPM_U3)) { - - msg("! LPS = %i", current_state); - - CyU3PUsbSetLinkPowerState(CyU3PUsbLPM_U0); // This will wake up the host if it's trying to sleep - CyU3PThreadSleep(1); - - if (CyU3PUsbGetSpeed () != CY_U3P_SUPER_SPEED) - break; - - CyU3PUsbGetLinkPowerState (¤t_state); - } - } - } -#endif // PREVENT_LOW_POWER_MODE - } -} - -static uint16_t g_poll_last_phy_error_count = 0, g_poll_last_link_error_count = 0; -static uint32_t g_poll_last_phy_error_status = 0; - -void update_error_counters(void) { - if (CyU3PUsbGetSpeed () != CY_U3P_SUPER_SPEED) - return; - - uvint32_t reg = REG_LNK_PHY_ERROR_STATUS; - uint32_t val = 0; - if (CyU3PReadDeviceRegisters((uvint32_t*)reg, 1, &val) == CY_U3P_SUCCESS) { - g_poll_last_phy_error_status |= (val & PHYERR_MASK); - - // Reset after read - uint32_t zero = PHYERR_MASK; - if (CyU3PWriteDeviceRegisters((uvint32_t*)reg, 1, &zero) != CY_U3P_SUCCESS) - msg("! CyU3PWriteDeviceRegisters"); - } - else { - // FIXME: Log once - msg("! Reg read fail"); - } - - // Equivalent code: - //uint32_t* p = (uint32_t*)REG_LNK_PHY_ERROR_STATUS; - //val = (*p); - //(*p) = PHYERR_MASK; - - uint16_t phy_error_count = 0, link_error_count = 0; - if (CyU3PUsbGetErrorCounts(&phy_error_count, &link_error_count) == CY_U3P_SUCCESS) { // Resets internal counters after call - g_poll_last_phy_error_count += phy_error_count; - g_poll_last_link_error_count += link_error_count; - } - else { - // FIXME: Log once - msg("! CyU3PUsbGetErrorCounts"); - } - - LOCK(g_counters_lock); - g_counters.usb_error_update_count++; - g_counters.usb_error_counters.phy_error_count += phy_error_count; - g_counters.usb_error_counters.link_error_count += link_error_count; - if (val & PHYERR_MASK) { - if (val & PHYERR_PHY_LOCK_EV) g_counters.usb_error_counters.PHY_LOCK_EV++; - if (val & PHYERR_TRAINING_ERROR_EV) g_counters.usb_error_counters.TRAINING_ERROR_EV++; - if (val & PHYERR_RX_ERROR_CRC32_EV) g_counters.usb_error_counters.RX_ERROR_CRC32_EV++; - if (val & PHYERR_RX_ERROR_CRC16_EV) g_counters.usb_error_counters.RX_ERROR_CRC16_EV++; - if (val & PHYERR_RX_ERROR_CRC5_EV) g_counters.usb_error_counters.RX_ERROR_CRC5_EV++; - if (val & PHYERR_PHY_ERROR_DISPARITY_EV)g_counters.usb_error_counters.PHY_ERROR_DISPARITY_EV++; - if (val & PHYERR_PHY_ERROR_EB_UND_EV) g_counters.usb_error_counters.PHY_ERROR_EB_UND_EV++; - if (val & PHYERR_PHY_ERROR_EB_OVR_EV) g_counters.usb_error_counters.PHY_ERROR_EB_OVR_EV++; - if (val & PHYERR_PHY_ERROR_DECODE_EV) g_counters.usb_error_counters.PHY_ERROR_DECODE_EV++; - } - UNLOCK(g_counters_lock); // FIXME: Read/write regs -} - - -void thread_re_enum_entry(uint32_t input) { - uint32_t event_flag; - - //msg("thread_re_enum_entry"); - - int keep_alive = 0; - - while (1) { - if (CyU3PEventGet(&g_event_usb_config, \ - (EVENT_RE_ENUM), CYU3P_EVENT_AND_CLEAR, \ - &event_flag, RE_ENUM_THREAD_SLEEP_TIME) == CY_U3P_SUCCESS) { - msg("Re-config"); - - // FIXME: This section is not finished - - // Not locking this since we only expect one write in VREQ and read afterward here - - int re_enum = g_config_mod.flags & (CF_RE_ENUM | CF_TX_SWING | CF_TX_DEEMPHASIS | CF_DISABLE_USB2 | CF_ENABLE_AS_SUPERSPEED); - - CyU3PThreadSleep(100); // Wait for EP0 xaction to complete - - //b200_fw_stop(); - -/* - int tx_swing; // [90] [65] 45 - int tx_deemphasis; // 0x11 - int disable_usb2; // 0 - int enable_as_superspeed; // 1 - int pport_drive_strength; // CY_U3P_DS_THREE_QUARTER_STRENGTH - int dma_buffer_size; // [USB3] (max) - int dma_buffer_count; // [USB3] 1 - int manual_dma; // 0 - int sb_baud_div; // 434*2 -*/ - - if (re_enum) { - if (CyU3PConnectState(CyFalse, (g_config.enable_as_superspeed != 0 ? CyTrue : CyFalse)) == CY_U3P_SUCCESS) - msg("Link down"); - else - msg("! Failed to bring link down"); - } - - if (g_config_mod.flags & CF_TX_DEEMPHASIS) { -#if (CYFX_VERSION_MAJOR >= 1) && (CYFX_VERSION_MINOR >= 3) - if ((g_config_mod.config.tx_deemphasis < 0x1F) && (CyU3PUsbSetTxDeemphasis(g_config_mod.config.tx_deemphasis) == CY_U3P_SUCCESS)) { - msg("TX deemphasis now: %d (was: %d)", g_config_mod.config.tx_deemphasis, g_config.tx_deemphasis); - g_config.tx_deemphasis = g_config_mod.config.tx_deemphasis; - } - else -#endif // #if (CYFX_VERSION_MAJOR >= 1) && (CYFX_VERSION_MINOR >= 3) - msg("! Failed to set TX deemphasis: %d (still: %d)", g_config_mod.config.tx_deemphasis, g_config.tx_deemphasis); - } - - if (g_config_mod.flags & CF_TX_SWING) { - if ((g_config_mod.config.tx_swing < 128) && (CyU3PUsbSetTxSwing(g_config_mod.config.tx_swing) == CY_U3P_SUCCESS)) { - msg("TX swing now: %d (was: %d)", g_config_mod.config.tx_swing, g_config.tx_swing); - g_config.tx_swing = g_config_mod.config.tx_swing; - } - else - msg("! Failed to set TX swing: %d (still: %d)", g_config_mod.config.tx_swing, g_config.tx_swing); - } - - if (g_config_mod.flags & CF_DISABLE_USB2) { - if (CyU3PUsbControlUsb2Support((g_config_mod.config.disable_usb2 != 0 ? CyTrue : CyFalse)) == CY_U3P_SUCCESS) { - msg("USB 2 support now: %s (was: %d)", (g_config_mod.config.disable_usb2 ? "disabled" : "enabled"), (g_config.disable_usb2 ? "disabled" : "enabled")); - g_config.disable_usb2 = g_config_mod.config.disable_usb2; - } - else - msg("! Failed to change USB 2 support to: %s (still: %s)", (g_config_mod.config.disable_usb2 ? "enabled" : "disabled"), (g_config.disable_usb2 ? "enabled" : "disabled")); - } - - if (g_config_mod.flags & CF_PPORT_DRIVE_STRENGTH) { - // CY_U3P_DS_QUARTER_STRENGTH,CY_U3P_DS_HALF_STRENGTH,CY_U3P_DS_THREE_QUARTER_STRENGTH,CY_U3P_DS_FULL_STRENGTH - if ((g_config_mod.config.pport_drive_strength >= CY_U3P_DS_QUARTER_STRENGTH) && - (g_config_mod.config.pport_drive_strength <= CY_U3P_DS_FULL_STRENGTH) && - (CyU3PSetPportDriveStrength(g_config_mod.config.pport_drive_strength) == CY_U3P_SUCCESS)) { - msg("PPort drive strength now: %d (was: %d)", g_config_mod.config.pport_drive_strength, g_config.pport_drive_strength); - g_config.pport_drive_strength = g_config_mod.config.pport_drive_strength; - } - else - msg("! Failed to set PPort drive strength: %d (still: %d)", g_config_mod.config.pport_drive_strength, g_config.pport_drive_strength); - } - - int reinit_dma = g_config_mod.flags & (CF_MANUAL_DMA | CF_DMA_BUFFER_COUNT | CF_DMA_BUFFER_SIZE); - if (re_enum) - reinit_dma = 0; // Don't need to if re-enumerating - - if (g_config_mod.flags & CF_MANUAL_DMA) { -#ifdef ENABLE_MANUAL_DMA_XFER - msg("DMA transfers will be: %s (was: %s)", (g_config_mod.config.manual_dma ? "manual" : "auto"), (g_config.manual_dma ? "manual" : "auto")); - g_config.manual_dma = g_config_mod.config.manual_dma; -#else - msg("! Manual DMA transfers not compiled into FW"); -#endif // ENABLE_MANUAL_DMA_XFER - } - - if (g_config_mod.flags & CF_DMA_BUFFER_COUNT) { - msg("DMA buffer count will be: %d (was: %d)", g_config_mod.config.dma_buffer_count, g_config.dma_buffer_count); - g_config.dma_buffer_count = g_config_mod.config.dma_buffer_count; - } - - if (g_config_mod.flags & CF_DMA_BUFFER_SIZE) { - msg("DMA buffer size will be: %d (was: %d)", g_config_mod.config.dma_buffer_size, g_config.dma_buffer_size); - g_config.dma_buffer_size = g_config_mod.config.dma_buffer_size; - } - - if (g_config_mod.flags & CF_SB_BAUD_DIV) { -#ifdef ENABLE_FPGA_SB - LOCK(g_suart_lock); - sb_write(SUART_CLKDIV, g_config_mod.config.sb_baud_div); - UNLOCK(g_suart_lock); - msg("SUART_CLKDIV now: %d (was: %d)", g_config_mod.config.sb_baud_div, g_config.sb_baud_div); - g_config.sb_baud_div = g_config_mod.config.sb_baud_div; -#else - msg("! Failed to set SUART_CLKDIV: SB is disabled (still: %d)", g_config.sb_baud_div); -#endif // ENABLE_FPGA_SB - } - - //b200_fw_start() - - if (g_config_mod.flags & CF_ENABLE_AS_SUPERSPEED) { - msg("Enable SuperSpeed: %s (was: %s)", (g_config_mod.config.enable_as_superspeed ? "yes" : "no"), (g_config.enable_as_superspeed ? "yes" : "no")); - g_config.enable_as_superspeed = g_config_mod.config.enable_as_superspeed; - } - - if (reinit_dma) { - if (g_app_running) { - msg("Stopping FW..."); - - b200_fw_stop(); - } - - msg("Starting FW..."); - - b200_fw_start(); - } - else // Shouldn't be re-init'ing AND re-enum'ing - /* Connect the USB pins, and enable SuperSpeed (USB 3.0). */ - if (re_enum) { - msg("Connecting... (as SuperSpeed: %d)", g_config.enable_as_superspeed); - - if (CyU3PConnectState(CyTrue, (g_config.enable_as_superspeed != 0 ? CyTrue : CyFalse)) == CY_U3P_SUCCESS) { // CHECK: Assuming all other important state will persist - CyU3PUSBSpeed_t usb_speed = CyU3PUsbGetSpeed(); - msg("Link up (speed: USB %d)", (int)usb_speed); // MAGIC: Values happen to map - } - else - msg("! Failed to bring link up"); - } - - counters_reset_usb_errors(); - } - else { - if (++keep_alive == KEEP_ALIVE_LOOP_COUNT) { - msg("Keep-alive"); - keep_alive = 0; - } -#ifndef ENABLE_FPGA_SB - update_error_counters(); -#endif // !ENABLE_FPGA_SB - } - - CyU3PThreadRelinquish(); - } -} - - -void base16_encode(uint8_t v, char out[2], char first) { - out[0] = first + (v >> 4); - out[1] = first + (v & 0x0F); -} - - -#ifdef ENABLE_FPGA_SB -void thread_fpga_sb_poll_entry(uint32_t input) { - //msg("thread_fpga_sb_poll_entry"); - - while (1) { - uint16_t i; - uint8_t has_change = 0; - - update_error_counters(); - - /*if (g_poll_last_phy_error_count > 0) - has_change = 1; - if (g_poll_last_link_error_count > 0) - has_change = 1;*/ - if (g_poll_last_phy_error_status != 0) - has_change = 1; - - uint16_t idx = CyU3PUsbGetEventLogIndex(); // Current *write* pointer - if (idx > (USB_EVENT_LOG_SIZE-1)) { - msg("! USB event log idx = %i", (int)idx); - break; - } - - uint8_t has_usb_events = 0; - // Assuming logging won't wrap around between get calls (i.e. buffer should be long enough) - if (g_fpga_sb_last_usb_event_log_index != idx) { - if (idx < g_fpga_sb_last_usb_event_log_index) { - for (i = g_fpga_sb_last_usb_event_log_index; i < USB_EVENT_LOG_SIZE; i++) { - if (g_usb_event_log[i] != 0x14 && g_usb_event_log[i] != 0x15 && g_usb_event_log[i] != 0x16) { // CTRL, STATUS, ACKSETUP - has_usb_events = 1; - break; - } - } - - if (has_usb_events == 0) { - for (i = 0; i < idx; i++) { - if (g_usb_event_log[i] != 0x14 && g_usb_event_log[i] != 0x15 && g_usb_event_log[i] != 0x16) { // CTRL, STATUS, ACKSETUP - has_usb_events = 1; - break; - } - } - } - } - else { - for (i = g_fpga_sb_last_usb_event_log_index; i < idx; i++) { - if (g_usb_event_log[i] != 0x14 && g_usb_event_log[i] != 0x15 && g_usb_event_log[i] != 0x16) { // CTRL, STATUS, ACKSETUP - has_usb_events = 1; - break; - } - } - } - } - - if (has_change || has_usb_events) { - LOCK(g_suart_lock); - - sb_write(SUART_TXCHAR, UPT_USB_EVENTS); - - char out[3]; - out[2] = '\0'; - - if (has_usb_events) { - if (idx < g_fpga_sb_last_usb_event_log_index) { - for (i = g_fpga_sb_last_usb_event_log_index; i < USB_EVENT_LOG_SIZE; i++) { - if (g_usb_event_log[i] == 0x14 || g_usb_event_log[i] == 0x15 || g_usb_event_log[i] == 0x16) // CTRL, STATUS, ACKSETUP - continue; - base16_encode(g_usb_event_log[i], out, 'A'); - _sb_write_string(out); - } - - for (i = 0; i < idx; i++) { - if (g_usb_event_log[i] == 0x14 || g_usb_event_log[i] == 0x15 || g_usb_event_log[i] == 0x16) // CTRL, STATUS, ACKSETUP - continue; - base16_encode(g_usb_event_log[i], out, 'A'); - _sb_write_string(out); - } - } - else { - for (i = g_fpga_sb_last_usb_event_log_index; i < idx; i++) { - if (g_usb_event_log[i] == 0x14 || g_usb_event_log[i] == 0x15 || g_usb_event_log[i] == 0x16) // CTRL, STATUS, ACKSETUP - continue; - base16_encode(g_usb_event_log[i], out, 'A'); - _sb_write_string(out); - } - } - } - - // USB events: A-P,A-P - // PHY error status: a,a-i - - if (g_poll_last_phy_error_status != 0) { - uint32_t mask; - size_t offset; - for (mask = PHYERR_MAX, offset = 0; mask != 0; mask >>= 1, ++offset) { - if ((g_poll_last_phy_error_status & mask) != 0) { - sb_write(SUART_TXCHAR, 'a'); - sb_write(SUART_TXCHAR, 'a' + offset); - } - } - } - - /*char buf[6]; - - if (g_poll_last_phy_error_count > 0) { - sb_write(SUART_TXCHAR, 'b'); - snprintf(buf, sizeof(buf)-1, "%d", g_poll_last_phy_error_count); - _sb_write_string(buf); - } - - if (g_poll_last_link_error_count > 0) { - sb_write(SUART_TXCHAR, 'c'); - snprintf(buf, sizeof(buf)-1, "%d", g_poll_last_link_error_count); - _sb_write_string(buf); - }*/ - - _sb_write_string("\r\n"); - - UNLOCK(g_suart_lock); - } - - g_poll_last_phy_error_count = 0; - g_poll_last_link_error_count = 0; - g_poll_last_phy_error_status = 0; - - g_fpga_sb_last_usb_event_log_index = idx; - - CyU3PThreadRelinquish(); - } -} -#endif // ENABLE_FPGA_SB - -/*! Application define function which creates the threads. - * - * The name of this application cannot be changed, as it is called from the - * tx_application _define function, referenced in the rest of the FX3 build - * system. - * - * If thread creation fails, lock the system and force a power reset. - */ -void CyFxApplicationDefine(void) { - void *app_thread_ptr, *fpga_thread_ptr; -#ifdef ENABLE_RE_ENUM_THREAD - void *re_enum_thread_ptr; -#endif // ENABLE_RE_ENUM_THREAD -#ifdef ENABLE_FPGA_SB - void *fpga_sb_poll_thread_ptr; -#endif // ENABLE_FPGA_SB - - g_counters.magic = COUNTER_MAGIC; - //memset(&g_config, 0xFF, sizeof(g_config)); // Initialise to -1 - - CyU3PMutexCreate(&g_log_lock, CYU3P_NO_INHERIT); - CyU3PMutexCreate(&g_counters_lock, CYU3P_NO_INHERIT); - CyU3PMutexCreate(&g_counters_dma_from_host_lock, CYU3P_NO_INHERIT); - CyU3PMutexCreate(&g_counters_dma_to_host_lock, CYU3P_NO_INHERIT); -#ifdef ENABLE_FPGA_SB - CyU3PMutexCreate(&g_suart_lock, CYU3P_NO_INHERIT); -#endif // ENABLE_FPGA_SB -#ifdef ENABLE_USB_EVENT_LOGGING - CyU3PUsbInitEventLog(g_usb_event_log, USB_EVENT_LOG_SIZE); -#endif // ENABLE_USB_EVENT_LOGGING - - //////////////////////////////////////////////////////// - - /* Tell the host that we are ignoring it for a while. */ - g_fx3_state = STATE_BUSY; - - /* Set the FX3 compatibility number. */ - compat_num[0] = FX3_COMPAT_MAJOR; - compat_num[1] = FX3_COMPAT_MINOR; - - /* Initialize the USB system. */ - b200_usb_init(); - - /* Turn on the Watchdog Timer. */ - CyU3PSysWatchDogConfigure(CyTrue, WATCHDOG_TIMEOUT); - - /* Go do something. Probably not useful, because you aren't configured. */ - g_fx3_state = STATE_UNCONFIGURED; - - //////////////////////////////////////////////////////// - - b200_gpio_init(CyTrue); - - b200_enable_fpga_sb_gpio(CyTrue); - - msg("Compat: %d.%d", FX3_COMPAT_MAJOR, FX3_COMPAT_MINOR); - msg("FX3 SDK: %d.%d.%d (build %d)", CYFX_VERSION_MAJOR, CYFX_VERSION_MINOR, CYFX_VERSION_PATCH, CYFX_VERSION_BUILD); - msg("FW built: %s %s", __TIME__, __DATE__); - - //////////////////////////////////////////////////////// - - /* Create the USB event group that we will use to track USB events from the - * application thread. */ - CyU3PEventCreate(&g_event_usb_config); - - /* Allocate memory for the application thread. */ - app_thread_ptr = CyU3PMemAlloc(APP_THREAD_STACK_SIZE); - - /* Allocate memory for the FPGA configuration thread. */ - fpga_thread_ptr = CyU3PMemAlloc(APP_THREAD_STACK_SIZE); -#ifdef ENABLE_RE_ENUM_THREAD - re_enum_thread_ptr = CyU3PMemAlloc(APP_THREAD_STACK_SIZE); -#endif // ENABLE_RE_ENUM_THREAD -#ifdef ENABLE_FPGA_SB - fpga_sb_poll_thread_ptr = CyU3PMemAlloc(APP_THREAD_STACK_SIZE); -#endif // ENABLE_FPGA_SB - //////////////////////////////////////////////////////// - - /* Create the thread for the application */ - if (app_thread_ptr != NULL) - CyU3PThreadCreate(&thread_main_app, - "200:B200 Main", - thread_main_app_entry, - 0, - app_thread_ptr, - APP_THREAD_STACK_SIZE, - THREAD_PRIORITY, - THREAD_PRIORITY, - CYU3P_NO_TIME_SLICE, - CYU3P_AUTO_START); - - /* Create the thread for FPGA configuration. */ - if (fpga_thread_ptr != NULL) - CyU3PThreadCreate(&thread_fpga_config, - "300:B200 FPGA", - thread_fpga_config_entry, - 0, - fpga_thread_ptr, - APP_THREAD_STACK_SIZE, - THREAD_PRIORITY, - THREAD_PRIORITY, - CYU3P_NO_TIME_SLICE, - CYU3P_AUTO_START); -#ifdef ENABLE_RE_ENUM_THREAD - /* Create the thread for stats collection and re-enumeration/configuration */ - if (re_enum_thread_ptr != NULL) - CyU3PThreadCreate(&thread_re_enum, - "400:B200 Re-enum", - thread_re_enum_entry, - 0, - re_enum_thread_ptr, - APP_THREAD_STACK_SIZE, - THREAD_PRIORITY, - THREAD_PRIORITY, - CYU3P_NO_TIME_SLICE, - CYU3P_AUTO_START); -#endif // ENABLE_RE_ENUM_THREAD -#ifdef ENABLE_FPGA_SB - /* Create thread to handling Settings Bus logging/transactions */ - if (fpga_sb_poll_thread_ptr != NULL) - CyU3PThreadCreate(&thread_fpga_sb_poll, - "600:B200 FPGA SB poll", - thread_fpga_sb_poll_entry, - 0, - fpga_sb_poll_thread_ptr, - APP_THREAD_STACK_SIZE, - THREAD_PRIORITY, - THREAD_PRIORITY, - CYU3P_NO_TIME_SLICE, - CYU3P_AUTO_START); -#endif // ENABLE_FPGA_SB -} - - -int main(void) { - CyU3PReturnStatus_t status = CY_U3P_SUCCESS; - CyU3PSysClockConfig_t clock_config; - - /* Configure the FX3 Clocking scheme: - * CPU Divider: 2 (~200 MHz) - * DMA Divider: 2 (~100 MHz) - * MMIO Divider: 2 (~100 MHz) - * 32 kHz Standby Clock: Disabled - * System Clock Divider: 1 */ - clock_config.cpuClkDiv = 2; - clock_config.dmaClkDiv = 2; - clock_config.mmioClkDiv = 2; - clock_config.useStandbyClk = CyFalse; - clock_config.clkSrc = CY_U3P_SYS_CLK; - clock_config.setSysClk400 = CyTrue; - - status = CyU3PDeviceInit(&clock_config); - if(status != CY_U3P_SUCCESS) - goto handle_fatal_error; - - /* Initialize the caches. Enable instruction cache and keep data cache disabled. - * The data cache is useful only when there is a large amount of CPU based memory - * accesses. When used in simple cases, it can decrease performance due to large - * number of cache flushes and cleans and also it adds to the complexity of the - * code. */ - status = CyU3PDeviceCacheControl(CyTrue, CyFalse, CyFalse); // Icache, Dcache, DMAcache - if (status != CY_U3P_SUCCESS) - goto handle_fatal_error; - - /* Configure the IO peripherals on the FX3. The gpioSimpleEn arrays are - * bitmaps, where each bit represents the GPIO of the matching index - the - * second array is index + 32. */ - status = b200_set_io_matrix(CyTrue); - if(status != CY_U3P_SUCCESS) - goto handle_fatal_error; - - /* This function calls starts the RTOS kernel. - * - * ABANDON ALL HOPE, YE WHO ENTER HERE */ - CyU3PKernelEntry(); - - /* Although we will never make it here, this has to be here to make the - * compiler happy. */ - return 0; - - /* If an error occurs before the launch of the kernel, it is unrecoverable. - * Once you go down this hole, you aren't coming back out without a power - * reset. */ - handle_fatal_error: - while(1); -} diff --git a/firmware/fx3/b200/b200_main.h b/firmware/fx3/b200/b200_main.h deleted file mode 100644 index ddcc504b5..000000000 --- a/firmware/fx3/b200/b200_main.h +++ /dev/null @@ -1,140 +0,0 @@ -// -// Copyright 2013-2014 Ettus Research LLC -// - -#ifndef _B200_MAIN_H -#define _B200_MAIN_H - -#include "cyu3externcstart.h" - -#include "cyu3types.h" -#include "cyu3usbconst.h" - -#define FX3_COMPAT_MAJOR (uint8_t)(8) -#define FX3_COMPAT_MINOR (uint8_t)(0) - -/* GPIO Pins */ -#define GPIO_FPGA_RESET (uint32_t)(26) // CTL[9] -#define GPIO_DONE (uint32_t)(27) -#define GPIO_PROGRAM_B (uint32_t)(45) -#define GPIO_INIT_B (uint32_t)(50) -#define GPIO_AUX_PWR_ON (uint32_t)(51) -#define GPIO_SHDN_SW (uint32_t)(52) -#define GPIO_FX3_SCLK (uint32_t)(53) -#define GPIO_FX3_CE (uint32_t)(54) -#define GPIO_FX3_MISO (uint32_t)(55) -#define GPIO_FX3_MOSI (uint32_t)(56) -#define GPIO_FPGA_SB_SCL (uint32_t)(25) // CTL[8] -#define GPIO_FPGA_SB_SDA (uint32_t)(23) // CTL[6] - -/* Create the bit-shifts that define the above GPIOs for bitmaps. The bitshifts - * are relative to 32-bit masks, so shifts > 32 are adjusted accordingly. Note - * that GPIOs < 32 are configured without the use of masks. */ -#define MASK_GPIO_PROGRAM_B (uint32_t)(1 << (GPIO_PROGRAM_B - 32)) -#define MASK_GPIO_INIT_B (uint32_t)(1 << (GPIO_INIT_B - 32)) -#define MASK_GPIO_AUX_PWR_ON (uint32_t)(1 << (GPIO_AUX_PWR_ON - 32)) -#define MASK_GPIO_SHDN_SW (uint32_t)(1 << (GPIO_SHDN_SW - 32)) -#define MASK_GPIO_FX3_SCLK (uint32_t)(1 << (GPIO_FX3_SCLK - 32)) -#define MASK_GPIO_FX3_CE (uint32_t)(1 << (GPIO_FX3_CE - 32)) -#define MASK_GPIO_FX3_MISO (uint32_t)(1 << (GPIO_FX3_MISO - 32)) -#define MASK_GPIO_FX3_MOSI (uint32_t)(1 << (GPIO_FX3_MOSI - 32)) -#define MASK_GPIO_FPGA_SB_SCL (uint32_t)(1 << (GPIO_FPGA_SB_SCL - 0)) -#define MASK_GPIO_FPGA_SB_SDA (uint32_t)(1 << (GPIO_FPGA_SB_SDA - 0)) - -#define USB3_PACKETS_PER_BURST (8) // Optimized value from Cypress AN86947 -#define USB2_PACKETS_PER_BURST (1) -#define DMA_SIZE_INFINITE (0) - -#define APP_THREAD_STACK_SIZE (0x0800) -#define THREAD_PRIORITY (8) - -#define B200_VREQ_BITSTREAM_START (uint8_t)(0x02) -#define B200_VREQ_BITSTREAM_DATA (uint8_t)(0x12) -#define B200_VREQ_BITSTREAM_DATA_FILL (uint8_t)(0x13) -#define B200_VREQ_BITSTREAM_DATA_COMMIT (uint8_t)(0x14) -#define B200_VREQ_GET_COMPAT (uint8_t)(0x15) -#define B200_VREQ_SET_FPGA_HASH (uint8_t)(0x1C) -#define B200_VREQ_GET_FPGA_HASH (uint8_t)(0x1D) -#define B200_VREQ_SET_FW_HASH (uint8_t)(0x1E) -#define B200_VREQ_GET_FW_HASH (uint8_t)(0x1F) -#define B200_VREQ_LOOP_CODE (uint8_t)(0x22) -#define B200_VREQ_GET_LOG (uint8_t)(0x23) -#define B200_VREQ_GET_COUNTERS (uint8_t)(0x24) -#define B200_VREQ_CLEAR_COUNTERS (uint8_t)(0x25) -#define B200_VREQ_GET_USB_EVENT_LOG (uint8_t)(0x26) -#define B200_VREQ_SET_CONFIG (uint8_t)(0x27) -#define B200_VREQ_GET_CONFIG (uint8_t)(0x28) -#define B200_VREQ_WRITE_SB (uint8_t)(0x29) -#define B200_VREQ_SET_SB_BAUD_DIV (uint8_t)(0x30) -#define B200_VREQ_FLUSH_DATA_EPS (uint8_t)(0x31) -#define B200_VREQ_FPGA_CONFIG (uint8_t)(0x55) -#define B200_VREQ_TOGGLE_FPGA_RESET (uint8_t)(0x62) -#define B200_VREQ_TOGGLE_GPIF_RESET (uint8_t)(0x72) -#define B200_VREQ_GET_USB_SPEED (uint8_t)(0x80) -#define B200_VREQ_GET_STATUS (uint8_t)(0x83) -#define B200_VREQ_RESET_DEVICE (uint8_t)(0x99) -#define B200_VREQ_EEPROM_WRITE (uint8_t)(0xBA) -#define B200_VREQ_EEPROM_READ (uint8_t)(0xBB) - -#define EVENT_BITSTREAM_START (1 << 1) -#define EVENT_GPIO_DONE_HIGH (1 << 2) -#define EVENT_GPIO_INITB_RISE (1 << 3) -#define EVENT_FPGA_CONFIG (1 << 4) -#define EVENT_RE_ENUM (1 << 5) - - -/* FX3 States */ -#define STATE_UNDEFINED (0) -#define STATE_FPGA_READY (1) -#define STATE_CONFIGURING_FPGA (2) -#define STATE_BUSY (3) -#define STATE_RUNNING (4) -#define STATE_UNCONFIGURED (5) -#define STATE_ERROR (6) - - -/* Define the USB endpoints, sockets, and directions. The LSB is the socket - * number, and the MSB is the direction. For USB 2.0, sockets are mapped - * one-to-one since they must be uni-directional. */ -#define VREQ_ENDPOINT_PRODUCER 0x00 // OUT (host -> FX3) -#define VREQ_ENDPOINT_CONSUMER 0x80 // IN (FX3 -> host) - -#define DATA_ENDPOINT_PRODUCER 0x02 // OUT (host -> FX3), produces for FPGA -#define DATA_ENDPOINT_CONSUMER 0x86 // IN (FX3 -> host), consumes from FPGA - -#define CTRL_ENDPOINT_PRODUCER 0x04 // OUT (host -> FX3), produces for FPGA -#define CTRL_ENDPOINT_CONSUMER 0x88 // IN (FX3 -> host), consumes from FPGA - -#define PRODUCER_DATA_SOCKET CY_U3P_UIB_SOCKET_PROD_2 -#define CONSUMER_DATA_SOCKET CY_U3P_UIB_SOCKET_CONS_6 - -#define PRODUCER_CTRL_SOCKET CY_U3P_UIB_SOCKET_PROD_4 -#define CONSUMER_CTRL_SOCKET CY_U3P_UIB_SOCKET_CONS_8 - -#define DATA_TX_PPORT_SOCKET CY_U3P_PIB_SOCKET_0 -#define DATA_RX_PPORT_SOCKET CY_U3P_PIB_SOCKET_1 -#define CTRL_COMM_PPORT_SOCKET CY_U3P_PIB_SOCKET_2 -#define CTRL_RESP_PPORT_SOCKET CY_U3P_PIB_SOCKET_3 - - -/* Descriptor definitions for USB enumerations. */ -extern uint8_t b200_usb2_dev_desc[]; -extern uint8_t b200_usb3_dev_desc[]; -extern const uint8_t b200_dev_qual_desc[]; -extern const uint8_t b200_usb_fs_config_desc[]; -extern const uint8_t b200_usb_hs_config_desc[]; -extern const uint8_t b200_usb_bos_desc[]; -extern const uint8_t b200_usb_ss_config_desc[]; -extern const uint8_t b200_string_lang_id_desc[]; -extern const uint8_t b200_usb_manufacture_desc[]; -extern const uint8_t b200_usb_product_desc[]; -extern const uint8_t niusrp_usb_manufacture_desc[]; -extern const uint8_t niusrp_2900_usb_product_desc[]; -extern const uint8_t niusrp_2901_usb_product_desc[]; -extern const uint8_t unknown_desc[]; -extern uint8_t dev_serial[]; - - -#include "cyu3externcend.h" - -#endif /* _B200_MAIN_H */ diff --git a/firmware/fx3/b200/b200_usb_descriptors.c b/firmware/fx3/b200/b200_usb_descriptors.c deleted file mode 100644 index 53979219b..000000000 --- a/firmware/fx3/b200/b200_usb_descriptors.c +++ /dev/null @@ -1,690 +0,0 @@ -// -// Copyright 2013-2015 Ettus Research LLC -// - -/* Define the USB 2.0 and USB 3.0 enumeration descriptions for the USRP B200 - * device. */ - - -#include "b200_main.h" - - -/* Standard Device Descriptor for USB 2.0 */ -uint8_t b200_usb2_dev_desc[] __attribute__ ((aligned (32))) = -{ - 0x12, /* Descriptor size */ - CY_U3P_USB_DEVICE_DESCR, /* Device descriptor type */ - 0x10,0x02, /* USB 2.10 */ - 0xFF, /* Device class */ - 0x00, /* Device sub-class */ - 0x00, /* Device protocol */ - 0x40, /* Maxpacket size for EP0 : 64 bytes */ - 0xB4,0x04, /* Vendor ID */ - 0xF0,0x00, /* Product ID */ - 0x00,0x00, /* Device release number */ - 0x01, /* Manufacture string index */ - 0x02, /* Product string index */ - 0x03, /* Serial number string index */ - 0x01 /* Number of configurations */ -}; - - -/* Standard Device Descriptor for USB 3.0 */ -uint8_t b200_usb3_dev_desc[] __attribute__ ((aligned (32))) = -{ - 0x12, /* Descriptor size */ - CY_U3P_USB_DEVICE_DESCR, /* Device descriptor type */ - 0x00,0x03, /* USB 3.0 */ - 0xFF, /* Device class */ - 0x00, /* Device sub-class */ - 0x00, /* Device protocol */ - 0x09, /* Maxpacket size for EP0 : 2^9 */ - 0xB4,0x04, /* Vendor ID */ - 0xF0,0x00, /* Product ID */ - 0x00,0x00, /* Device release number */ - 0x01, /* Manufacture string index */ - 0x02, /* Product string index */ - 0x03, /* Serial number string index */ - 0x01 /* Number of configurations */ -}; - - -/* Binary Device Object Store Descriptor */ -const uint8_t b200_usb_bos_desc[] __attribute__ ((aligned (32))) = -{ - 0x05, /* Descriptor size */ - CY_U3P_BOS_DESCR, /* Device descriptor type */ - 0x16,0x00, /* Length of this descriptor and all sub descriptors */ - 0x02, /* Number of device capability descriptors */ - - /* USB 2.0 extension */ - 0x07, /* Descriptor size */ - CY_U3P_DEVICE_CAPB_DESCR, /* Device capability type descriptor */ - CY_U3P_USB2_EXTN_CAPB_TYPE, /* USB 2.0 extension capability type */ - 0x02,0x00,0x00,0x00, /* Supported device level features: LPM support */ - - /* SuperSpeed device capability */ - 0x0A, /* Descriptor size */ - CY_U3P_DEVICE_CAPB_DESCR, /* Device capability type descriptor */ - CY_U3P_SS_USB_CAPB_TYPE, /* SuperSpeed device capability type */ - 0x00, /* Supported device level features */ - 0x0E,0x00, /* Speeds supported by the device : SS, HS and FS */ - 0x03, /* Functionality support */ - 0x00, /* U1 Device Exit latency */ - 0x00,0x00 /* U2 Device Exit latency */ -}; - - -/* Standard Device Qualifier Descriptor */ -const uint8_t b200_dev_qual_desc[] __attribute__ ((aligned (32))) = -{ - 0x0A, /* Descriptor size */ - CY_U3P_USB_DEVQUAL_DESCR, /* Device qualifier descriptor type */ - 0x00,0x02, /* USB 2.0 */ - 0xFF, /* Device class */ - 0x00, /* Device sub-class */ - 0x00, /* Device protocol */ - 0x40, /* Maxpacket size for EP0 : 64 bytes */ - 0x01, /* Number of configurations */ - 0x00 /* Reserved */ -}; - - -/* Standard Full Speed Configuration Descriptor */ -const uint8_t b200_usb_fs_config_desc[] __attribute__ ((aligned (32))) = -{ - /* Configuration descriptor */ - 0x09, /* Descriptor size */ - CY_U3P_USB_CONFIG_DESCR, /* Configuration descriptor type */ - 0x52,0x00, /* Length of this descriptor and all sub descriptors */ - 0x05, /* Number of interfaces */ - 0x01, /* Configuration number */ - 0x00, /* Configuration string index */ - 0x80, /* Config characteristics - bus powered */ - 0x01, /* Lie about the max power consumption (in 2mA unit) : 2mA */ - - /* Interface descriptor */ - 0x09, /* Descriptor size */ - CY_U3P_USB_INTRFC_DESCR, /* Interface descriptor type */ - 0x00, /* Interface number */ - 0x00, /* Alternate setting number */ - 0x00, /* Number of endpoints */ - 0xFF, /* Interface class */ - 0x00, /* Interface sub class */ - 0x00, /* Interface protocol code */ - 0x02, /* Interface descriptor string index */ - - /* Interface descriptor */ - 0x09, /* Descriptor size */ - CY_U3P_USB_INTRFC_DESCR, /* Interface descriptor type */ - 0x01, /* Interface number */ - 0x00, /* Alternate setting number */ - 0x01, /* Number of endpoints */ - 0xFF, /* Interface class */ - 0x00, /* Interface sub class */ - 0x00, /* Interface protocol code */ - 0x02, /* Interface descriptor string index */ - - /* Endpoint descriptor for producer EP */ - 0x07, /* Descriptor size */ - CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ - DATA_ENDPOINT_PRODUCER, /* Endpoint address and description */ - CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ - 0x40,0x00, /* Max packet size = 64 bytes */ - 0x00, /* Servicing interval for data transfers : 0 for bulk */ - - /* Interface descriptor */ - 0x09, /* Descriptor size */ - CY_U3P_USB_INTRFC_DESCR, /* Interface descriptor type */ - 0x02, /* Interface number */ - 0x00, /* Alternate setting number */ - 0x01, /* Number of endpoints */ - 0xFF, /* Interface class */ - 0x00, /* Interface sub class */ - 0x00, /* Interface protocol code */ - 0x02, /* Interface descriptor string index */ - - /* Endpoint descriptor for consumer EP */ - 0x07, /* Descriptor size */ - CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ - DATA_ENDPOINT_CONSUMER, /* Endpoint address and description */ - CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ - 0x40,0x00, /* Max packet size = 64 bytes */ - 0x00, /* Servicing interval for data transfers : 0 for bulk */ - - /* Interface descriptor */ - 0x09, /* Descriptor size */ - CY_U3P_USB_INTRFC_DESCR, /* Interface descriptor type */ - 0x03, /* Interface number */ - 0x00, /* Alternate setting number */ - 0x01, /* Number of endpoints */ - 0xFF, /* Interface class */ - 0x00, /* Interface sub class */ - 0x00, /* Interface protocol code */ - 0x02, /* Interface descriptor string index */ - - /* Endpoint descriptor for producer EP */ - 0x07, /* Descriptor size */ - CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ - CTRL_ENDPOINT_PRODUCER, /* Endpoint address and description */ - CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ - 0x40,0x00, /* Max packet size = 64 bytes */ - 0x00, /* Servicing interval for data transfers : 0 for bulk */ - - /* Interface descriptor */ - 0x09, /* Descriptor size */ - CY_U3P_USB_INTRFC_DESCR, /* Interface descriptor type */ - 0x04, /* Interface number */ - 0x00, /* Alternate setting number */ - 0x01, /* Number of endpoints */ - 0xFF, /* Interface class */ - 0x00, /* Interface sub class */ - 0x00, /* Interface protocol code */ - 0x02, /* Interface descriptor string index */ - - /* Endpoint descriptor for consumer EP */ - 0x07, /* Descriptor size */ - CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ - CTRL_ENDPOINT_CONSUMER, /* Endpoint address and description */ - CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ - 0x40,0x00, /* Max packet size = 64 bytes */ - 0x00 /* Servicing interval for data transfers : 0 for bulk */ -}; - - -/* Standard High Speed Configuration Descriptor */ -const uint8_t b200_usb_hs_config_desc[] __attribute__ ((aligned (32))) = -{ - /* Configuration descriptor */ - 0x09, /* Descriptor size */ - CY_U3P_USB_CONFIG_DESCR, /* Configuration descriptor type */ - 0x52,0x00, /* Length of this descriptor and all sub descriptors */ - 0x05, /* Number of interfaces */ - 0x01, /* Configuration number */ - 0x00, /* COnfiguration string index */ - 0x80, /* Config characteristics - bus powered */ - 0x01, /* Lie about the max power consumption (in 2mA unit) : 2mA */ - - /* Interface descriptor */ - 0x09, /* Descriptor size */ - CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ - 0x00, /* Interface number */ - 0x00, /* Alternate setting number */ - 0x00, /* Number of endpoints */ - 0xFF, /* Interface class */ - 0x00, /* Interface sub class */ - 0x00, /* Interface protocol code */ - 0x02, /* Interface descriptor string index */ - - /* Interface descriptor */ - 0x09, /* Descriptor size */ - CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ - 0x01, /* Interface number */ - 0x00, /* Alternate setting number */ - 0x01, /* Number of endpoints */ - 0xFF, /* Interface class */ - 0x00, /* Interface sub class */ - 0x00, /* Interface protocol code */ - 0x02, /* Interface descriptor string index */ - - /* Endpoint descriptor for producer EP */ - 0x07, /* Descriptor size */ - CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ - DATA_ENDPOINT_PRODUCER, /* Endpoint address and description */ - CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ - 0x00,0x02, /* Max packet size = 512 bytes */ - 0x00, /* Servicing interval for data transfers : 0 for bulk */ - - /* Interface descriptor */ - 0x09, /* Descriptor size */ - CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ - 0x02, /* Interface number */ - 0x00, /* Alternate setting number */ - 0x01, /* Number of endpoints */ - 0xFF, /* Interface class */ - 0x00, /* Interface sub class */ - 0x00, /* Interface protocol code */ - 0x02, /* Interface descriptor string index */ - - /* Endpoint descriptor for consumer EP */ - 0x07, /* Descriptor size */ - CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ - DATA_ENDPOINT_CONSUMER, /* Endpoint address and description */ - CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ - 0x00,0x02, /* Max packet size = 512 bytes */ - 0x00, /* Servicing interval for data transfers : 0 for bulk */ - - /* Interface descriptor */ - 0x09, /* Descriptor size */ - CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ - 0x03, /* Interface number */ - 0x00, /* Alternate setting number */ - 0x01, /* Number of endpoints */ - 0xFF, /* Interface class */ - 0x00, /* Interface sub class */ - 0x00, /* Interface protocol code */ - 0x02, /* Interface descriptor string index */ - - /* Endpoint descriptor for producer EP */ - 0x07, /* Descriptor size */ - CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ - CTRL_ENDPOINT_PRODUCER, /* Endpoint address and description */ - CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ - 0x00,0x02, /* Max packet size = 512 bytes */ - 0x00, /* Servicing interval for data transfers : 0 for bulk */ - - /* Interface descriptor */ - 0x09, /* Descriptor size */ - CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ - 0x04, /* Interface number */ - 0x00, /* Alternate setting number */ - 0x01, /* Number of endpoints */ - 0xFF, /* Interface class */ - 0x00, /* Interface sub class */ - 0x00, /* Interface protocol code */ - 0x02, /* Interface descriptor string index */ - - /* Endpoint descriptor for consumer EP */ - 0x07, /* Descriptor size */ - CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ - CTRL_ENDPOINT_CONSUMER, /* Endpoint address and description */ - CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ - 0x00,0x02, /* Max packet size = 512 bytes */ - 0x00 /* Servicing interval for data transfers : 0 for bulk */ -}; - - -/* Standard Super Speed Configuration Descriptor */ -const uint8_t b200_usb_ss_config_desc[] __attribute__ ((aligned (32))) = -{ - /* Configuration descriptor */ - 0x09, /* Descriptor size */ - CY_U3P_USB_CONFIG_DESCR, /* Configuration descriptor type */ - 0x6A,0x00, /* Length of this descriptor and all sub descriptors */ - 0x05, /* Number of interfaces */ - 0x01, /* Configuration number */ - 0x00, /* Configuration string index */ - 0x80, /* Config characteristics - D6: Self power; D5: Remote wakeup */ - 0x01, /* Lie about the max power consumption (in 8mA unit) : 8mA */ - - /* Interface descriptor */ - 0x09, /* Descriptor size */ - CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ - 0x00, /* Interface number */ - 0x00, /* Alternate setting number */ - 0x00, /* Number of end points */ - 0xFF, /* Interface class */ - 0x00, /* Interface sub class */ - 0x00, /* Interface protocol code */ - 0x02, /* Interface descriptor string index */ - - /* Interface descriptor */ - 0x09, /* Descriptor size */ - CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ - 0x01, /* Interface number */ - 0x00, /* Alternate setting number */ - 0x01, /* Number of end points */ - 0xFF, /* Interface class */ - 0x00, /* Interface sub class */ - 0x00, /* Interface protocol code */ - 0x02, /* Interface descriptor string index */ - - /* Endpoint descriptor for producer EP */ - 0x07, /* Descriptor size */ - CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ - DATA_ENDPOINT_PRODUCER, /* Endpoint address and description */ - CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ - 0x00,0x04, /* Max packet size = 1024 bytes */ - 0x00, /* Servicing interval for data transfers : 0 for bulk */ - - /* Super speed endpoint companion descriptor for producer EP */ - 0x06, /* Descriptor size */ - CY_U3P_SS_EP_COMPN_DESCR, /* SS endpoint companion descriptor type */ - (USB3_PACKETS_PER_BURST - 1), /* Max no. of packets in a burst : 0: burst 1 packet at a time */ - 0x00, /* Max streams for bulk EP = 0 (No streams) */ - 0x00,0x00, /* Service interval for the EP : 0 for bulk */ - - /* Interface descriptor */ - 0x09, /* Descriptor size */ - CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ - 0x02, /* Interface number */ - 0x00, /* Alternate setting number */ - 0x01, /* Number of end points */ - 0xFF, /* Interface class */ - 0x00, /* Interface sub class */ - 0x00, /* Interface protocol code */ - 0x02, /* Interface descriptor string index */ - - /* Endpoint descriptor for consumer EP */ - 0x07, /* Descriptor size */ - CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ - DATA_ENDPOINT_CONSUMER, /* Endpoint address and description */ - CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ - 0x00,0x04, /* Max packet size = 1024 bytes */ - 0x00, /* Servicing interval for data transfers : 0 for Bulk */ - - /* Super speed endpoint companion descriptor for consumer EP */ - 0x06, /* Descriptor size */ - CY_U3P_SS_EP_COMPN_DESCR, /* SS endpoint companion descriptor type */ - (USB3_PACKETS_PER_BURST - 1), /* Max no. of packets in a burst : 0: burst 1 packet at a time */ - 0x00, /* Max streams for bulk EP = 0 (No streams) */ - 0x00,0x00, /* Service interval for the EP : 0 for bulk */ - - /* Interface descriptor */ - 0x09, /* Descriptor size */ - CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ - 0x03, /* Interface number */ - 0x00, /* Alternate setting number */ - 0x01, /* Number of end points */ - 0xFF, /* Interface class */ - 0x00, /* Interface sub class */ - 0x00, /* Interface protocol code */ - 0x02, /* Interface descriptor string index */ - - /* Endpoint descriptor for producer EP */ - 0x07, /* Descriptor size */ - CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ - CTRL_ENDPOINT_PRODUCER, /* Endpoint address and description */ - CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ - 0x00,0x04, /* Max packet size = 1024 bytes */ - 0x00, /* Servicing interval for data transfers : 0 for bulk */ - - /* Super speed endpoint companion descriptor for producer EP */ - 0x06, /* Descriptor size */ - CY_U3P_SS_EP_COMPN_DESCR, /* SS endpoint companion descriptor type */ - (USB3_PACKETS_PER_BURST - 1), /* Max no. of packets in a burst : 0: burst 1 packet at a time */ - 0x00, /* Max streams for bulk EP = 0 (No streams) */ - 0x00,0x00, /* Service interval for the EP : 0 for bulk */ - - /* Interface descriptor */ - 0x09, /* Descriptor size */ - CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ - 0x04, /* Interface number */ - 0x00, /* Alternate setting number */ - 0x01, /* Number of end points */ - 0xFF, /* Interface class */ - 0x00, /* Interface sub class */ - 0x00, /* Interface protocol code */ - 0x02, /* Interface descriptor string index */ - - /* Endpoint descriptor for consumer EP */ - 0x07, /* Descriptor size */ - CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ - CTRL_ENDPOINT_CONSUMER, /* Endpoint address and description */ - CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ - 0x00,0x04, /* Max packet size = 1024 bytes */ - 0x00, /* Servicing interval for data transfers : 0 for Bulk */ - - /* Super speed endpoint companion descriptor for consumer EP */ - 0x06, /* Descriptor size */ - CY_U3P_SS_EP_COMPN_DESCR, /* SS endpoint companion descriptor type */ - (USB3_PACKETS_PER_BURST - 1), /* Max no. of packets in a burst : 0: burst 1 packet at a time */ - 0x00, /* Max streams for bulk EP = 0 (No streams) */ - 0x00,0x00 /* Service interval for the EP : 0 for bulk */ -}; - - -const uint8_t b200_usb_ss_config_desc_new[] __attribute__ ((aligned (32))) = -{ - /* Configuration descriptor */ - 0x09, /* Descriptor size */ - CY_U3P_USB_CONFIG_DESCR, /* Configuration descriptor type */ - 0x4F,0x00, /* Length of this descriptor and all sub descriptors */ - 0x02, /* Number of interfaces */ - 0x01, /* Configuration number */ - 0x00, /* COnfiguration string index */ - 0x80, /* Config characteristics - D6: Self power; D5: Remote wakeup */ - 0x01, /* Lie about the max power consumption (in 8mA unit) : 8mA */ - - /* Interface descriptor */ - 0x09, /* Descriptor size */ - CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ - 0x00, /* Interface number */ - 0x00, /* Alternate setting number */ - 0x00, /* Number of end points */ - 0xFF, /* Interface class */ - 0x00, /* Interface sub class */ - 0x00, /* Interface protocol code */ - 0x02, /* Interface descriptor string index */ - - /* Interface descriptor */ - 0x09, /* Descriptor size */ - CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ - 0x01, /* Interface number */ - 0x00, /* Alternate setting number */ - 0x04, /* Number of end points */ - 0xFF, /* Interface class */ - 0x00, /* Interface sub class */ - 0x00, /* Interface protocol code */ - 0x02, /* Interface descriptor string index */ - - /* Endpoint descriptor for producer EP */ - 0x07, /* Descriptor size */ - CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ - DATA_ENDPOINT_PRODUCER, /* Endpoint address and description */ - CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ - 0x00,0x04, /* Max packet size = 1024 bytes */ - 0x00, /* Servicing interval for data transfers : 0 for bulk */ - - /* Super speed endpoint companion descriptor for producer EP */ - 0x06, /* Descriptor size */ - CY_U3P_SS_EP_COMPN_DESCR, /* SS endpoint companion descriptor type */ - (USB3_PACKETS_PER_BURST - 1), /* Max no. of packets in a burst : 0: burst 1 packet at a time */ - 0x00, /* Max streams for bulk EP = 0 (No streams) */ - 0x00,0x00, /* Service interval for the EP : 0 for bulk */ - - /* Endpoint descriptor for consumer EP */ - 0x07, /* Descriptor size */ - CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ - DATA_ENDPOINT_CONSUMER, /* Endpoint address and description */ - CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ - 0x00,0x04, /* Max packet size = 1024 bytes */ - 0x00, /* Servicing interval for data transfers : 0 for Bulk */ - - /* Super speed endpoint companion descriptor for consumer EP */ - 0x06, /* Descriptor size */ - CY_U3P_SS_EP_COMPN_DESCR, /* SS endpoint companion descriptor type */ - (USB3_PACKETS_PER_BURST - 1), /* Max no. of packets in a burst : 0: burst 1 packet at a time */ - 0x00, /* Max streams for bulk EP = 0 (No streams) */ - 0x00,0x00, /* Service interval for the EP : 0 for bulk */ - - /* Endpoint descriptor for producer EP */ - 0x07, /* Descriptor size */ - CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ - CTRL_ENDPOINT_PRODUCER, /* Endpoint address and description */ - CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ - 0x00,0x04, /* Max packet size = 1024 bytes */ - 0x00, /* Servicing interval for data transfers : 0 for bulk */ - - /* Super speed endpoint companion descriptor for producer EP */ - 0x06, /* Descriptor size */ - CY_U3P_SS_EP_COMPN_DESCR, /* SS endpoint companion descriptor type */ - (USB3_PACKETS_PER_BURST - 1), /* Max no. of packets in a burst : 0: burst 1 packet at a time */ - 0x00, /* Max streams for bulk EP = 0 (No streams) */ - 0x00,0x00, /* Service interval for the EP : 0 for bulk */ - - /* Endpoint descriptor for consumer EP */ - 0x07, /* Descriptor size */ - CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ - CTRL_ENDPOINT_CONSUMER, /* Endpoint address and description */ - CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ - 0x00,0x04, /* Max packet size = 1024 bytes */ - 0x00, /* Servicing interval for data transfers : 0 for Bulk */ - - /* Super speed endpoint companion descriptor for consumer EP */ - 0x06, /* Descriptor size */ - CY_U3P_SS_EP_COMPN_DESCR, /* SS endpoint companion descriptor type */ - (USB3_PACKETS_PER_BURST - 1), /* Max no. of packets in a burst : 0: burst 1 packet at a time */ - 0x00, /* Max streams for bulk EP = 0 (No streams) */ - 0x00,0x00 /* Service interval for the EP : 0 for bulk */ -}; - - -/* Standard Language ID String Descriptor */ -const uint8_t b200_string_lang_id_desc[] __attribute__ ((aligned (32))) = - { - 0x04, /* Descriptor Size */ - CY_U3P_USB_STRING_DESCR, /* Device Descriptor Type */ - 0x09,0x04 /* Language ID supported */ - }; - - -/* Standard Manufacturer String Descriptor */ -const uint8_t b200_usb_manufacture_desc[] __attribute__ ((aligned (32))) = - { - 0x26, /* Descriptor Size */ - CY_U3P_USB_STRING_DESCR, /* Device Descriptor Type */ - 'E',0x00, - 't',0x00, - 't',0x00, - 'u',0x00, - 's',0x00, - ' ',0x00, - 'R',0x00, - 'e',0x00, - 's',0x00, - 'e',0x00, - 'a',0x00, - 'r',0x00, - 'c',0x00, - 'h',0x00, - ' ',0x00, - 'L',0x00, - 'L',0x00, - 'C',0x00 - }; - -/* NI Manufacturer String Descriptor */ -const uint8_t niusrp_usb_manufacture_desc[] __attribute__ ((aligned (32))) = - { - 0x36, /* Descriptor Size */ - CY_U3P_USB_STRING_DESCR, /* Device Descriptor Type */ - 'N',0x00, - 'a',0x00, - 't',0x00, - 'i',0x00, - 'o',0x00, - 'n',0x00, - 'a',0x00, - 'l',0x00, - ' ',0x00, - 'I',0x00, - 'n',0x00, - 's',0x00, - 't',0x00, - 'r',0x00, - 'u',0x00, - 'm',0x00, - 'e',0x00, - 'n',0x00, - 't',0x00, - 's',0x00, - ' ',0x00, - 'C',0x00, - 'o',0x00, - 'r',0x00, - 'p',0x00, - '.',0x00 - }; - - -/* Standard Product String Descriptor */ -const uint8_t b200_usb_product_desc[] __attribute__ ((aligned (32))) = - { - 0x14, /* Descriptor Size */ - CY_U3P_USB_STRING_DESCR, /* Device Descriptor Type */ - 'U',0x00, - 'S',0x00, - 'R',0x00, - 'P',0x00, - ' ',0x00, - 'B',0x00, - '2',0x00, - '0',0x00, - '0',0x00 - }; - -/* NI-USRP 2900 Product String Descriptor */ -const uint8_t niusrp_2900_usb_product_desc[] __attribute__ ((aligned (32))) = - { - 0x1A, /* Descriptor Size */ - CY_U3P_USB_STRING_DESCR, /* Device Descriptor Type */ - 'N',0x00, - 'I',0x00, - ' ',0x00, - 'U',0x00, - 'S',0x00, - 'R',0x00, - 'P',0x00, - '-',0x00, - '2',0x00, - '9',0x00, - '0',0x00, - '0',0x00 - }; - -/* NI-USRP 2901 Product String Descriptor */ -const uint8_t niusrp_2901_usb_product_desc[] __attribute__ ((aligned (32))) = - { - 0x1A, /* Descriptor Size */ - CY_U3P_USB_STRING_DESCR, /* Device Descriptor Type */ - 'N',0x00, - 'I',0x00, - ' ',0x00, - 'U',0x00, - 'S',0x00, - 'R',0x00, - 'P',0x00, - '-',0x00, - '2',0x00, - '9',0x00, - '0',0x00, - '1',0x00 - }; - -const uint8_t unknown_desc[] __attribute__ ((aligned (32))) = - { - 0x10, /* Descriptor Size */ - CY_U3P_USB_STRING_DESCR, /* Device Descriptor Type */ - 'U',0x00, - 'n',0x00, - 'k',0x00, - 'n',0x00, - 'o',0x00, - 'w',0x00, - 'n',0x00 - }; - -/* Microsoft OS Descriptor. */ -const uint8_t CyFxUsbOSDscr[] __attribute__ ((aligned (32))) = -{ - 0x10, - CY_U3P_USB_STRING_DESCR, - 'O', 0x00, - 'S', 0x00, - ' ', 0x00, - 'D', 0x00, - 'e', 0x00, - 's', 0x00, - 'c', 0x00 -}; - -uint8_t dev_serial[20] __attribute__ ((aligned (32))) = -{ - 0x14, - CY_U3P_USB_STRING_DESCR, - '0', 0x00, - '0', 0x00, - '0', 0x00, - '0', 0x00, - '0', 0x00, - '0', 0x00, - '0', 0x00, - '0', 0x00, - '0', 0x00 -}; - -/* Place this buffer as the last buffer so that no other variable / code shares - * the same cache line. Do not add any other variables / arrays in this file. - * This will lead to variables sharing the same cache line. */ -const uint8_t CyFxUsbDscrAlignBuffer[32] __attribute__ ((aligned (32))); diff --git a/firmware/fx3/b200/bootloader/.gitignore b/firmware/fx3/b200/bootloader/.gitignore new file mode 100644 index 000000000..75d01c18d --- /dev/null +++ b/firmware/fx3/b200/bootloader/.gitignore @@ -0,0 +1,5 @@ +cyfx3.ld +cyfx_gcc_startup.S +elf2img +fx3_armgcc_config.mak +fx3_build_config.mak diff --git a/firmware/fx3/b200/bootloader/main.c b/firmware/fx3/b200/bootloader/main.c new file mode 100644 index 000000000..f46690813 --- /dev/null +++ b/firmware/fx3/b200/bootloader/main.c @@ -0,0 +1,55 @@ +// +// Copyright 2011-2012 Cypress Semiconductor Corporation +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#include "cyfx3usb.h" +#include "cyfx3device.h" + +extern void usbBoot (void); +extern uint8_t glCheckForDisconnect; +extern uint8_t glInCompliance; + +int main (void) +{ + CyFx3BootErrorCode_t status; + CyFx3BootIoMatrixConfig_t ioCfg = { + .isDQ32Bit = CyFalse, + .useUart = CyFalse, + .useI2C = CyTrue, + .useI2S = CyFalse, + .useSpi = CyFalse, + .gpioSimpleEn[0] = 0, + .gpioSimpleEn[1] = 0 + }; + + CyFx3BootDeviceInit(CyTrue); + + status = CyFx3BootDeviceConfigureIOMatrix(&ioCfg); + + if (status != CY_FX3_BOOT_SUCCESS) + { + return status; + } + + usbBoot(); + + while (1) + { + if (glCheckForDisconnect) + { + CyFx3BootUsbCheckUsb3Disconnect(); + glCheckForDisconnect = 0; + } + + if (glInCompliance) + { + CyFx3BootUsbSendCompliancePatterns(); + glInCompliance = 0; + } + } + return 0; +} + diff --git a/firmware/fx3/b200/bootloader/makefile b/firmware/fx3/b200/bootloader/makefile new file mode 100644 index 000000000..3dc7fcb80 --- /dev/null +++ b/firmware/fx3/b200/bootloader/makefile @@ -0,0 +1,92 @@ +# +# Copyright 2019 Ettus Research, a National Instruments Brand +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + +IMGOUT = usrp_b200_bl.img + +all:$(IMGOUT) + +BL_ROOT=../../boot_fw +BL_INC=$(BL_ROOT)/include +BL_LIB=$(BL_ROOT)/lib +BL_CYP_SRC=$(BL_ROOT)/src + +ELF2IMG_SRC=../../elf2img/elf2img.c +ELF2IMG=elf2img + +CYFXBUILD = gcc + +include fx3_build_config.mak + +MODULE = cyfx_boot_app + +APP_SOURCE = main.c usb_boot.c usb_descriptors.c ../common/common_descriptors.c ../common/common_helpers.c + +INCFLAGS = -I$(BL_INC) -I../common + +APP_OBJECT=$(APP_SOURCE:%.c=./%.o) + +APP_ASM_OBJECT=$(APP_ASM_SOURCE:%.S=./%.o) + +EXES = $(MODULE).$(EXEEXT) + +ifeq ($(CYFXBUILD), gcc) + +APP_ASM_SOURCE = cyfx_gcc_startup.S + +else + +APP_ASM_SOURCE = + +endif + +$(APP_ASM_OBJECT) : %.o : %.S + $(ASSEMBLE) + +$(APP_OBJECT) : %.o : %.c ../lib/cyfx3_boot.a cyfx3.ld + $(COMPILE) $(INCFLAGS) + +$(MODULE).$(EXEEXT): $(APP_OBJECT) $(APP_ASM_OBJECT) + $(LINK) + +$(ELF2IMG): + gcc -o $(ELF2IMG) $(ELF2IMG_SRC) + +fx3_build_config.mak: + cp $(BL_CYP_SRC)/fx3_build_config.mak . +fx3_armgcc_config.mak: + cp $(BL_CYP_SRC)/fx3_armgcc_config.mak . +cyfx_gcc_startup.S: + cp $(BL_CYP_SRC)/cyfx_gcc_startup.S . +cyfx3.ld: + cp $(BL_CYP_SRC)/cyfx3.ld . +../lib/cyfx3_boot.a: + mkdir -p ../lib + cp $(BL_LIB)/cyfx3_boot.a ../lib + + +clean: + rm -f ./$(MODULE).$(EXEEXT) + rm -f ./$(MODULE).map + rm -f ./$(IMGOUT) + rm -f ./fx3_build_config.mak + rm -f ./fx3_armgcc_config.mak + rm -f ./cyfx_gcc_startup.S + rm -f ./cyfx3.ld + rm -f ../lib/cyfx3_boot.a + rmdir ../lib --ignore-fail-on-non-empty + rm -f ./*.o + rm -f ../common/*.o + rm -f ./$(ELF2IMG) +ifeq ($(CYFXBUILD), gcc) + rm -f ./gcceclipse_files/*.o +endif + +compile: $(APP_OBJECT) $(APP_ASM_OBJECT) $(EXES) + +$(IMGOUT): compile $(EXES) $(ELF2IMG) + ./$(ELF2IMG) -i $(EXES) -o $(IMGOUT) -i2cconf 0x1A + +#[]# diff --git a/firmware/fx3/b200/bootloader/usb_boot.c b/firmware/fx3/b200/bootloader/usb_boot.c new file mode 100644 index 000000000..ba7eb9dfb --- /dev/null +++ b/firmware/fx3/b200/bootloader/usb_boot.c @@ -0,0 +1,807 @@ +// +// Copyright 2011-2012 Cypress Semiconductor Corporation +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#include "cyfx3usb.h" +#include "cyfx3device.h" +#include "cyfx3utils.h" +#include "cyfx3i2c.h" + +#include "common_helpers.h" +#include "common_descriptors.h" +#include "usb_descriptors.h" + +typedef enum +{ + eStall = 0, /* Send STALL */ + eDataIn, /* Data IN Stage */ + eDataOut, /* Data Out Stage */ + eStatus /* Status Stage */ +} eUsbStage; + +typedef int (*PFI)(); + +#define USB_SETUP_DIR (0x80) /* 0x80 = To Host */ +#define USB_SETUP_MASK (0x60) /* Used to mask off request type */ +#define USB_STANDARD_REQUEST (0x00) /* Standard Request */ +#define USB_VENDOR_REQUEST (0x40) /* Vendor Request */ +#define USB_REQ_MASK (0x3F) /* USB Request mask */ +#define USB_REQ_DEV (0) /* Device Request */ +#define USB_REQ_INTERFACE (1) /* Interface Request */ +#define USB_REQ_ENDPOINT (2) /* Endpoint Request */ +#define USB_SET_INTERFACE (11) +#define USB_SC_SET_SEL (0x30) /* Set system exit latency. */ +#define USB_SC_SET_ISOC_DELAY (0x31) + +#define SELF_POWERED (0x01) +#define REMOTE_WAKEUP (0x02) +#define U1_ENABLE (0x04) +#define U2_ENABLE (0x08) +#define LTM_ENABLE (0x10) + +uint8_t glUsbState = 0; +uint8_t gConfig = 0; /* Variable to hold the config info. */ +uint8_t gAltSetting = 0; /* Variable to hold the interface info. */ +uint8_t gUsbDevStatus = 0; +uint8_t glCheckForDisconnect = 0; +uint8_t glInCompliance = 0; + +/* 4KB of buffer area used for control endpoint transfers. */ +#define gpUSBData (uint8_t*)(0x40077000) +#define USB_DATA_BUF_SIZE (1024*4) + +CyU3PUsbDescrPtrs *gpUsbDescPtr; /* Pointer to the USB Descriptors */ +CyFx3BootUsbEp0Pkt_t gEP0; + +void myMemCopy(uint8_t* d, uint8_t* s, int32_t cnt) +{ + int32_t i; + for (i = 0; i < cnt; i++) { + *d++ = *s++; + } +} + +void myMemSet(uint8_t* d, uint8_t c, int32_t cnt) +{ + int32_t i; + for (i = 0; i < cnt; i++) { + *d++ = c; + } +} + +/************************************************ + * Request handlers + ***********************************************/ + +/* Function to handle the GET_STATUS Standard request. */ +int getStatus (void) +{ + uint16_t data = 0; + + switch (gEP0.bmReqType & USB_REQ_MASK) + { + case USB_REQ_DEV: + if (CyFx3BootUsbGetSpeed () == CY_FX3_BOOT_SUPER_SPEED) + { + data = (gpUsbDescPtr->usbSSConfigDesc_p[7] & 0x40) ? 1 : 0; + data |= gUsbDevStatus; + } + else + { + data = (gpUsbDescPtr->usbHSConfigDesc_p[7] & 0x40) ? 1 : 0; + data |= gUsbDevStatus; + } + break; + + case USB_REQ_INTERFACE: + if (!gConfig) + { + return eStall; + } + break; + + case USB_REQ_ENDPOINT: + if (CyFx3BootUsbGetEpCfg (gEP0.bIdx0, 0, (CyBool_t *)&data) != 0) + { + return eStall; + } + break; + default: + return eStall; + } + + *(uint16_t*)gEP0.pData = data; + return eDataIn; +} + +/* Function to handle the GET_DESCRIPTOR Standard request */ +int getDescriptor (void) +{ + uint32_t len = 0; + uint8_t *p = 0; + uint8_t *cfg_p = 0; + uint8_t usbSpeed; + + usbSpeed = CyFx3BootUsbGetSpeed(); + + gpUsbDescPtr->usbHSConfigDesc_p[1] = CY_U3P_USB_CONFIG_DESCR; + gpUsbDescPtr->usbFSConfigDesc_p[1] = CY_U3P_USB_CONFIG_DESCR; + + if (usbSpeed == CY_FX3_BOOT_HIGH_SPEED) + { + cfg_p = (uint8_t*)gpUsbDescPtr->usbHSConfigDesc_p; + len = ((gpUsbDescPtr->usbHSConfigDesc_p[3] << 8) | gpUsbDescPtr->usbHSConfigDesc_p[2]); + } + else if (usbSpeed == CY_FX3_BOOT_SUPER_SPEED) + { + cfg_p = (uint8_t*)gpUsbDescPtr->usbSSConfigDesc_p; + len = ((gpUsbDescPtr->usbSSConfigDesc_p[3] << 8) | gpUsbDescPtr->usbSSConfigDesc_p[2]); + } + else if (usbSpeed == CY_FX3_BOOT_FULL_SPEED) + { + cfg_p = (uint8_t*)gpUsbDescPtr->usbFSConfigDesc_p; + len = ((gpUsbDescPtr->usbFSConfigDesc_p[3] << 8) | gpUsbDescPtr->usbFSConfigDesc_p[2]); + } + + switch (gEP0.bVal1) + { + case CY_U3P_USB_DEVICE_DESCR: + { + if ((usbSpeed == CY_FX3_BOOT_HIGH_SPEED) || (usbSpeed == CY_FX3_BOOT_FULL_SPEED)) + { + p = (uint8_t*)gpUsbDescPtr->usbDevDesc_p; + len = gpUsbDescPtr->usbDevDesc_p[0]; + } + else if (usbSpeed == CY_FX3_BOOT_SUPER_SPEED) + { + p = (uint8_t*)gpUsbDescPtr->usbSSDevDesc_p; + len = gpUsbDescPtr->usbSSDevDesc_p[0]; + } + break; + } + case CY_U3P_BOS_DESCR: + { + p = (uint8_t *)gpUsbDescPtr->usbSSBOSDesc_p; + len = (gpUsbDescPtr->usbSSBOSDesc_p[3] << 8) | gpUsbDescPtr->usbSSBOSDesc_p[2]; + break; + } + case CY_U3P_USB_CONFIG_DESCR: + { + p = cfg_p; + break; + } + case CY_U3P_USB_DEVQUAL_DESCR: + { + if ((usbSpeed == CY_FX3_BOOT_HIGH_SPEED) || (usbSpeed == CY_FX3_BOOT_FULL_SPEED)) + { + p = (uint8_t*)gpUsbDescPtr->usbDevQualDesc_p; + len = gpUsbDescPtr->usbDevQualDesc_p[0]; + break; + } + return eStall; + } + case CY_U3P_USB_STRING_DESCR: + { + /* Ensure that we do not index past the limit of the array. */ + if (gEP0.bVal0 < CY_FX3_USB_MAX_STRING_DESC_INDEX) + { + p = (uint8_t*)gpUsbDescPtr->usbStringDesc_p[gEP0.bVal0]; + if (p != 0) + len = p[0]; + } + else + return eStall; + break; + } + case CY_U3P_USB_OTHERSPEED_DESCR: + { + if (usbSpeed == CY_FX3_BOOT_HIGH_SPEED) + { + gpUsbDescPtr->usbFSConfigDesc_p[1] = CY_U3P_USB_OTHERSPEED_DESCR; + p = (uint8_t*)gpUsbDescPtr->usbFSConfigDesc_p; + + len = ((gpUsbDescPtr->usbFSConfigDesc_p[3] < 8) | gpUsbDescPtr->usbFSConfigDesc_p[2]); + + if (len > gEP0.wLen) + { + len = gEP0.wLen; + } + } + else if (usbSpeed == CY_FX3_BOOT_FULL_SPEED) + { + gpUsbDescPtr->usbHSConfigDesc_p[1] = CY_U3P_USB_OTHERSPEED_DESCR; + p = (uint8_t*)gpUsbDescPtr->usbHSConfigDesc_p; + len = ((gpUsbDescPtr->usbHSConfigDesc_p[3] < 8) | gpUsbDescPtr->usbHSConfigDesc_p[2]); + + if (len > gEP0.wLen) + { + len = gEP0.wLen; + } + } + } + break; + default: + { + return eStall; + } + } + + if (p != 0) + { + myMemCopy (gpUSBData, p, len); + if (gEP0.wLen > len) + { + gEP0.wLen = len; + } + + return eDataIn; + } + else + /* Stall EP0 if the descriptor sought is not available. */ + return eStall; +} + +/* Function to handle the SET_CONFIG Standard request */ +int setConfig (void) +{ + uint8_t usbSpeed = 0; + uint32_t retVal = 0; + CyFx3BootUsbEpConfig_t epCfg; + + if ((gEP0.bVal0 == 0) || (gEP0.bVal0 == 1)) + { + glUsbState = gEP0.bVal0; + gConfig = gEP0.bVal0; + + /* Get the Bus speed */ + usbSpeed = CyFx3BootUsbGetSpeed(); + + epCfg.pcktSize = 512; + /* Based on the Bus Speed configure the endpoint packet size */ + if (usbSpeed == CY_FX3_BOOT_HIGH_SPEED) + { + epCfg.pcktSize = 512; + } + if (usbSpeed == CY_FX3_BOOT_SUPER_SPEED) + { + epCfg.pcktSize = 1024; + } + if (usbSpeed == CY_FX3_BOOT_FULL_SPEED) + { + epCfg.pcktSize = 64; + } + + /* Producer Endpoint configuration */ + epCfg.enable = 1; + epCfg.epType = CY_FX3_BOOT_USB_EP_BULK; + epCfg.burstLen = 1; + epCfg.streams = 0; + epCfg.isoPkts = 0; + + /* Configure the Endpoint */ + retVal = CyFx3BootUsbSetEpConfig(0x01, &epCfg); + if (retVal != 0) + { + /* TODO: Error Handling */ + return eStall; + } + + /* Consumer Endpoint configuration */ + epCfg.enable = 1; + epCfg.epType = CY_FX3_BOOT_USB_EP_BULK; + epCfg.burstLen = 1; + epCfg.streams = 0; + epCfg.isoPkts = 0; + + /* Configure the Endpoint */ + retVal = CyFx3BootUsbSetEpConfig (0x81, &epCfg); + if (retVal != 0) + { + /* TODO: Error Handling */ + return eStall; + } + + return eStatus; + } + + return eStall; +} + +/* Function to handle the GET_INTERFACE Standard request */ +int getInterface (void) +{ + if (gConfig == 0) + { + return eStall; + } + + gEP0.pData = (uint8_t *)&gAltSetting; + return eDataIn; +} + +/* Function to handle the SET_INTERFACE Standard request */ +int setInterface (void) +{ + gAltSetting = gEP0.bVal0; + return eStatus; +} + +/* This function returns stall for not supported requests. */ +int stall (void) +{ + return eStall; +} + +/* Function to handle the SET_ADDRESS Standard request. */ +int setAddress (void) +{ + return eStatus; +} + +/* Function to handle the CLEAR_FEATURE Standard request. */ +int clearFeature (void) +{ + /* All of the actual handling for the CLEAR_FEATURE request is done in the API. + We only need to update the device status flags here. + */ + if (CyFx3BootUsbSetClrFeature (0, (CyBool_t)glUsbState, &gEP0) != 0) + { + return eStall; + } + + if (gEP0.bmReqType == USB_REQ_DEV) + { + /* Update the device status flags as required. */ + if (CyFx3BootUsbGetSpeed () == CY_FX3_BOOT_SUPER_SPEED) + { + switch (gEP0.bVal0) + { + case 48: + gUsbDevStatus &= ~U1_ENABLE; + break; + case 49: + gUsbDevStatus &= ~U2_ENABLE; + break; + case 50: + gUsbDevStatus &= ~LTM_ENABLE; + break; + default: + break; + } + } + else + { + if (gEP0.bVal0 == 1) + { + gUsbDevStatus &= ~REMOTE_WAKEUP; + } + } + } + + return eStatus; +} + +/* Function to handle the SET_FEATURE Standard request. */ +int setFeature (void) +{ + /* All of the actual handling for the SET_FEATURE command is done in the API. + * We only need to update the device status flags here. + */ + if (CyFx3BootUsbSetClrFeature (1, (CyBool_t)glUsbState, &gEP0) != 0) + { + return eStall; + } + + if (gEP0.bmReqType == USB_REQ_DEV) + { + /* Update the device status flags as required. */ + if (CyFx3BootUsbGetSpeed () == CY_FX3_BOOT_SUPER_SPEED) + { + switch (gEP0.bVal0) + { + case 48: + gUsbDevStatus |= U1_ENABLE; + break; + case 49: + gUsbDevStatus |= U2_ENABLE; + break; + case 50: + gUsbDevStatus |= LTM_ENABLE; + break; + default: + break; + } + } + else + { + if (gEP0.bVal0 == 1) + { + gUsbDevStatus |= REMOTE_WAKEUP; + } + } + } + return eStatus; +} + +/* Function to handle the GET_CONFIG Standard request. */ +int getConfig (void) +{ + gEP0.pData = (uint8_t *)&gConfig; + return eDataIn; +} + +const PFI chapter9_cmds[] = +{ + getStatus, /* USB_GET_STATUS 0 */ + clearFeature, /* USB_CLEAR_FEATURE 1 */ + stall, /* Reserved 2 */ + setFeature, /* USB_SET_FEATURE 3 */ + stall, /* Reserved 4 */ + setAddress, /* USB_SET_ADDRESS 5 */ + getDescriptor, /* USB_GET_DESCRIPTOR 6 */ + stall, /* USB_SET_DESCRIPTOR 7 */ + getConfig, /* USB_GET_CONFIGURATION 8 */ + setConfig, /* USB_SET_CONFIGURATION 9 */ + getInterface, /* USB_GET_INTERFACE 10 */ + setInterface, /* USB_SET_INTERFACE 11 */ +}; + +/* This function validates the addresses being written to/read from + Return Value: + 0 - Address is valid + -1 - Address is not valid +*/ +int checkAddress (uint32_t address, uint32_t len) +{ + if (address & 3) + { + /* expect long word boundary */ + return -1; + } + + len += address; + + if ((address >= CY_FX3_BOOT_SYSMEM_BASE1) && (len <= CY_FX3_BOOT_SYSMEM_END)) + { + return 0; + } + + if (len <= CY_FX3_BOOT_ITCM_END) + { + return 0; + } + + return -1; +} + +/* Function to handle the vendor commands. */ +void vendorCmdHandler (void) +{ + int stage; + int status; + uint32_t address = ((gEP0.bIdx1 << 24) | (gEP0.bIdx0 << 16) | (gEP0.bVal1 << 8) | (gEP0.bVal0)); + uint16_t len = gEP0.wLen; + uint16_t bReq = gEP0.bReq; + uint16_t dir = gEP0.bmReqType & USB_SETUP_DIR; + + if (len > USB_DATA_BUF_SIZE) + { + CyFx3BootUsbStall (0, CyTrue, CyFalse); + return; + } + + if (dir) + { + stage = eDataIn; + } + else + { + stage = eDataOut; + } + + /* Vendor Command 0xA0 handling */ + if (bReq == 0xA0) + { + /* Note: This is a command issued by the CyControl Application to detect the legacy products. + As we are an FX3 device we stall the endpoint to indicate that this is not a legacy device. + */ + if (address == 0xE600) + { + /* Stall the Endpoint */ + CyFx3BootUsbStall (0, CyTrue, CyFalse); + return; + } + + status = checkAddress (address, len); + if (len == 0) + { + /* Mask the USB Interrupts and Disconnect the USB Phy. */ + CyFx3BootUsbConnect (CyFalse, CyTrue); + /* Transfer to Program Entry */ + CyFx3BootJumpToProgramEntry (address); + return; + } + + if (status < 0) + { + /* Stall the endpoint */ + CyFx3BootUsbStall (0, CyTrue, CyFalse); + return; + } + + /* Validate the SYSMEM address being accessed */ + if ((address >= CY_FX3_BOOT_SYSMEM_BASE1) && (address < CY_FX3_BOOT_SYSMEM_END)) + { + gEP0.pData = (uint8_t*)address; + } + + CyFx3BootUsbAckSetup (); + + if (eDataIn == stage) + { + if ((address + gEP0.wLen) <= CY_FX3_BOOT_ITCM_END) + { + myMemCopy(gEP0.pData, (uint8_t *)address , len); + } + + status = CyFx3BootUsbDmaXferData (0x80, (uint32_t)gEP0.pData, gEP0.wLen, CY_FX3_BOOT_WAIT_FOREVER); + if (status != CY_FX3_BOOT_SUCCESS) + { + /* USB DMA Transfer failed. Stall the Endpoint. */ + CyFx3BootUsbStall (0, CyTrue, CyFalse); + return; + } + } + else if (stage == eDataOut) + { + status = CyFx3BootUsbDmaXferData (0x00, (uint32_t)gEP0.pData, gEP0.wLen, CY_FX3_BOOT_WAIT_FOREVER); + if (status != CY_FX3_BOOT_SUCCESS) + { + /* USB DMA Transfer failed. Stall the Endpoint. */ + CyFx3BootUsbStall (0, CyTrue, CyFalse); + return; + } + + /* Validate ITCM Memory */ + if ((address + gEP0.wLen) <= CY_FX3_BOOT_ITCM_END) + { + /* Avoid writing to the interrupt table. */ + if (address < 0xFF) { + gEP0.pData += 0xFF-address; + gEP0.wLen -= 0xFF-address; + address = 0xFF; + } + myMemCopy((uint8_t *)address, gEP0.pData, gEP0.wLen); + } + } + return; + } + + /* Version request */ + if (dir && bReq == 0xB8) { + uint8_t version_info[] = {1, 21, 0, 0, 0, 0}; + + CyFx3BootUsbAckSetup (); + status = CyFx3BootUsbDmaXferData (0x80, (uint32_t)version_info, + sizeof(version_info), CY_FX3_BOOT_WAIT_FOREVER); + if (status != CY_FX3_BOOT_SUCCESS) { + /* USB DMA Transfer failed. Stall the Endpoint. */ + CyFx3BootUsbStall (0, CyTrue, CyFalse); + } + + return; + } + + /* Stall the Endpoint */ + CyFx3BootUsbStall (0, CyTrue, CyFalse); + return; +} + +/* Setup Data handler */ +void setupDataHandler (uint32_t setupDat0, uint32_t setupDat1) +{ + uint32_t *p; + int status = eStall; + + p = (uint32_t*)&gEP0; + p[0] = setupDat0; + p[1] = setupDat1; + + gEP0.pData = gpUSBData; + + switch (gEP0.bmReqType & USB_SETUP_MASK) + { + case USB_STANDARD_REQUEST: + if (gEP0.bReq <= USB_SET_INTERFACE) + { + status = (*chapter9_cmds[gEP0.bReq])(); + } + else + { + if (gEP0.bReq == USB_SC_SET_SEL) + { + if ((CyFx3BootUsbGetSpeed () == CY_FX3_BOOT_SUPER_SPEED) && (gEP0.bIdx0 == 0) && + (gEP0.bIdx1 == 0) && (gEP0.bVal0 == 0) && (gEP0.bVal1 == 0) && (gEP0.wLen == 6)) + { + gEP0.wLen = 32; + status = eDataOut; + } + else + { + status = eStall; + } + } + else if (gEP0.bReq == USB_SC_SET_ISOC_DELAY) + { + status = eStatus; + if ((CyFx3BootUsbGetSpeed () != CY_FX3_BOOT_SUPER_SPEED) || (gEP0.bIdx0 != 0) || + (gEP0.bIdx1 != 0) || (gEP0.wLen != 0)) + { + status = eStall; + } + } + else + { + status = eStall; + } + } + break; + + case USB_VENDOR_REQUEST: + vendorCmdHandler(); + return; + } + + switch (status) + { + case eDataIn: + CyFx3BootUsbAckSetup (); + status = CyFx3BootUsbDmaXferData (0x80, (uint32_t)gEP0.pData, gEP0.wLen, 1000); + if (status != CY_FX3_BOOT_SUCCESS) + { + CyFx3BootUsbStall (0, CyTrue, CyFalse); + } + break; + case eDataOut: + CyFx3BootUsbAckSetup (); + status = CyFx3BootUsbDmaXferData (0x00, (uint32_t)gEP0.pData, gEP0.wLen, CY_FX3_BOOT_WAIT_FOREVER); + if (status != CY_FX3_BOOT_SUCCESS) + { + CyFx3BootUsbStall (0, CyTrue, CyFalse); + } + break; + case eStatus: + CyFx3BootUsbAckSetup (); + break; + default: + CyFx3BootUsbStall (0, CyTrue, CyFalse); + return; + } + + return; +} + +/* USB Event Handler. This function is invoked from the USB ISR and as such MUST not be + blocked. +*/ +void usbEventCallback (CyFx3BootUsbEventType_t event) +{ + if (event == CY_FX3_BOOT_USB_RESET) + { + gConfig = 0; + gAltSetting = 0; + gUsbDevStatus = 0; + glUsbState = 0; + glInCompliance = 0; + } + + if ((event == CY_FX3_BOOT_USB_CONNECT) || + (event == CY_FX3_BOOT_USB_DISCONNECT)) + { + glUsbState = 0; + gUsbDevStatus = 0; + } + + if (event == CY_FX3_BOOT_USB_IN_SS_DISCONNECT) + { + glCheckForDisconnect = CyTrue; + } + + if (event == CY_FX3_BOOT_USB_COMPLIANCE) + { + glInCompliance = CyTrue; + } + + return; +} + +/* Function passed to common EEPROM functions to access the EEPROM */ +void eeprom_read(uint16_t addr, uint8_t* buffer, uint8_t length) +{ + CyFx3BootI2cPreamble_t preamble; + preamble.length = 4; + preamble.buffer[0] = 0xA0; + preamble.buffer[1] = addr >> 8; + preamble.buffer[2] = addr & 0xFF; + preamble.buffer[3] = 0xA1; + preamble.ctrlMask = 0x0004; + CyFx3BootI2cReceiveBytes(&preamble, buffer, length, 0); +} + +/* USB initialization */ +void usbBoot() +{ + /* Reset globals */ + gConfig = 0; + gAltSetting = 0; + gUsbDevStatus = 0; + glUsbState = 0; + glCheckForDisconnect = 0; + glInCompliance = 0; + + /* Init */ + CyFx3BootUsbStart (CyFalse, usbEventCallback); + + /* Run USB circuitry off of host power, not internal power. */ + CyFx3BootUsbVBattEnable (CyFalse); + + /* Register callbacks */ + CyFx3BootRegisterSetupCallback (setupDataHandler); + + /* Enable I2C for EEPROM access */ + CyFx3BootI2cInit(); + CyFx3BootI2cConfig_t i2cCfg = { + .bitRate = 100000, + .isDma = CyFalse, + .busTimeout = 0xFFFFFFFF, + .dmaTimeout = 0xFFFF}; + CyFx3BootI2cSetConfig(&i2cCfg); + + /* Retrieve VID and PID from EEPROM */ + const uint16_t vid = get_vid(&eeprom_read); + const uint16_t pid = get_pid(&eeprom_read); + + /* Power down I2C */ + CyFx3BootI2cDeInit(); + + /* Populate device descriptors with IDs */ + common_usb2_dev_desc[8] = vid & 0xFF; + common_usb2_dev_desc[9] = vid >> 8; + common_usb2_dev_desc[10] = pid & 0xFF; + common_usb2_dev_desc[11] = pid >> 8; + + common_usb3_dev_desc[8] = vid & 0xFF; + common_usb3_dev_desc[9] = vid >> 8; + common_usb3_dev_desc[10] = pid & 0xFF; + common_usb3_dev_desc[11] = pid >> 8; + + /* Copy all descriptors */ + CyFx3BootUsbSetDesc( + CY_U3P_USB_SET_HS_DEVICE_DESCR, 0, (uint8_t*)common_usb2_dev_desc); + CyFx3BootUsbSetDesc( + CY_U3P_USB_SET_SS_DEVICE_DESCR, 0, (uint8_t*)common_usb3_dev_desc); + + CyFx3BootUsbSetDesc(CY_U3P_USB_SET_DEVQUAL_DESCR, 0, (uint8_t*)common_dev_qual_desc); + + CyFx3BootUsbSetDesc(CY_U3P_USB_SET_HS_CONFIG_DESCR, 0, (uint8_t*)bl_hs_config_desc); + CyFx3BootUsbSetDesc(CY_U3P_USB_SET_FS_CONFIG_DESCR, 0, (uint8_t*)bl_fs_config_desc); + CyFx3BootUsbSetDesc(CY_U3P_USB_SET_SS_CONFIG_DESCR, 0, (uint8_t*)bl_ss_config_desc); + + CyFx3BootUsbSetDesc(CY_U3P_USB_SET_SS_BOS_DESCR, 0, (uint8_t*)common_usb_bos_desc); + + CyFx3BootUsbSetDesc( + CY_U3P_USB_SET_STRING_DESCR, 0, (uint8_t*)common_string_lang_id_desc); + + CyFx3BootUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 1, (uint8_t*)bl_manufacturer_desc); + CyFx3BootUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 2, (uint8_t*)bl_product_desc); + CyFx3BootUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 3, (uint8_t*)bl_dev_serial_desc); + + gpUsbDescPtr = CyFx3BootUsbGetDesc(); + + /* Connect! */ + CyFx3BootUsbConnect (CyTrue, CyTrue); +} + diff --git a/firmware/fx3/b200/bootloader/usb_descriptors.c b/firmware/fx3/b200/bootloader/usb_descriptors.c new file mode 100644 index 000000000..47d3175a8 --- /dev/null +++ b/firmware/fx3/b200/bootloader/usb_descriptors.c @@ -0,0 +1,187 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +/* Bootloader's unique config and string descriptors. */ + +/* Bootloader Full Speed Configuration Descriptor */ +const unsigned char bl_fs_config_desc[] = +{ + /* Configuration Descriptor Type */ + 0x09, /* Descriptor Size */ + 0x02, /* Configuration Descriptor Type */ + 0x20,0x00, /* Length of this descriptor and all sub descriptors */ + 0x01, /* Number of interfaces */ + 0x01, /* Configuration number */ + 0x00, /* COnfiguration string index */ + 0x80, /* Config characteristics - Bus powered */ + 0x32, /* Max power consumption of device (in 2mA unit) : 100mA */ + + /* Interface Descriptor */ + 0x09, /* Descriptor size */ + 0x04, /* Interface Descriptor type */ + 0x00, /* Interface number */ + 0x00, /* Alternate setting number */ + 0x02, /* Number of end points */ + 0xFF, /* Interface class */ + 0x00, /* Interface sub class */ + 0x00, /* Interface protocol code */ + 0x00, /* Interface descriptor string index */ + + /* Endpoint Descriptor for Producer EP */ + 0x07, /* Descriptor size */ + 0x05, /* Endpoint Descriptor Type */ + 0x01, /* Endpoint address and description */ + 0x02, /* Bulk End point Type */ + 0x40,0x00, /* Max packet size = 64 bytes */ + 0x00, /* Servicing interval for data transfers : NA for Bulk */ + + /* Endpoint Descriptor for Consumer EP */ + 0x07, /* Descriptor size */ + 0x05, /* Endpoint Descriptor Type */ + 0x81, /* Endpoint address and description */ + 0x02, /* Bulk End point Type */ + 0x40,0x00, /* Max packet size = 64 bytes */ + 0x00 /* Servicing interval for data transfers : NA for Bulk */ +}; + +/* Bootloader High Speed Configuration Descriptor */ +const unsigned char bl_hs_config_desc[] = +{ + 0x09, /* Descriptor Size */ + 0x02, /* Configuration Descriptor Type */ + 0x20,0x00, /* Length of this descriptor and all sub descriptors */ + 0x01, /* Number of interfaces */ + 0x01, /* Configuration number */ + 0x00, /* COnfiguration string index */ + 0x80, /* Config characteristics - Bus powered */ + 0x32, /* Max power consumption of device (in 2mA unit) : 100mA */ + + /* Interface Descriptor */ + 0x09, /* Descriptor size */ + 0x04, /* Interface Descriptor type */ + 0x00, /* Interface number */ + 0x00, /* Alternate setting number */ + 0x02, /* Number of end points */ + 0xFF, /* Interface class */ + 0x00, /* Interface sub class */ + 0x00, /* Interface protocol code */ + 0x00, /* Interface descriptor string index */ + + /* Endpoint Descriptor for Producer EP */ + 0x07, /* Descriptor size */ + 0x05, /* Endpoint Descriptor Type */ + 0x01, /* Endpoint address and description */ + 0x02, /* Bulk End point Type */ + 0x00, /* Max packet size = 512 bytes */ + 0x02, + 0x00, /* Servicing interval for data transfers : NA for Bulk */ + + /* Endpoint Descriptor for Consumer EP */ + 0x07, /* Descriptor size */ + 0x05, /* Endpoint Descriptor Type */ + 0x81, /* Endpoint address and description */ + 0x02, /* Bulk End point Type */ + 0x00, /* Max packet size = 512 bytes */ + 0x02, + 0x00 /* Servicing interval for data transfers : NA for Bulk */ +}; + +/* Bootloader Super Speed Configuration Descriptor */ +const unsigned char bl_ss_config_desc[] = +{ + /* Configuration Descriptor Type */ + 0x09, /* Descriptor Size */ + 0x02, /* Configuration Descriptor Type */ + 0x2C,0x00, /* Length of this descriptor and all sub descriptors */ + 0x01, /* Number of interfaces */ + 0x01, /* Configuration number */ + 0x00, /* COnfiguration string index */ + 0x80, /* Config characteristics - D6: Self power; D5: Remote Wakeup */ + 0x32, /* Max power consumption of device (in 8mA unit) : 400mA */ + + /* Interface Descriptor */ + 0x09, /* Descriptor size */ + 0x04, /* Interface Descriptor type */ + 0x00, /* Interface number */ + 0x00, /* Alternate setting number */ + 0x02, /* Number of end points */ + 0xFF, /* Interface class */ + 0x00, /* Interface sub class */ + 0x00, /* Interface protocol code */ + 0x00, /* Interface descriptor string index */ + + /* Endpoint Descriptor for Producer EP */ + 0x07, /* Descriptor size */ + 0x05, /* Endpoint Descriptor Type */ + 0x01, /* Endpoint address and description */ + 0x02, /* Bulk End point Type */ + 0x00,0x04, /* Max packet size = 1024 bytes */ + 0x00, /* Servicing interval for data transfers : NA for Bulk */ + + /* Super Speed Endpoint Companion Descriptor for Producer EP */ + 0x06, /* Descriptor size */ + 0x30, /* SS Endpoint Companion Descriptor Type */ + 0x00, /* Max no. of packets in a Burst : 0: Burst 1 packet at a time */ + 0x00, /* Max streams for Bulk EP = 0 (No streams)*/ + 0x00,0x00, /* Service interval for the EP : NA for Bulk */ + + /* Endpoint Descriptor for Consumer EP */ + 0x07, /* Descriptor size */ + 0x05, /* Endpoint Descriptor Type */ + 0x81, /* Endpoint address and description */ + 0x02, /* Bulk End point Type */ + 0x00,0x04, /* Max packet size = 1024 bytes */ + 0x00, /* Servicing interval for data transfers : NA for Bulk */ + + /* Super Speed Endpoint Companion Descriptor for Consumer EP */ + 0x06, /* Descriptor size */ + 0x30, /* SS Endpoint Companion Descriptor Type */ + 0x00, /* Max no. of packets in a Burst : 0: Burst 1 packet at a time */ + 0x00, /* Max streams for Bulk EP = 0 (No streams)*/ + 0x00,0x00 /* Service interval for the EP : NA for Bulk */ +}; + +/* Bootloader Product String Descriptor */ +const unsigned char bl_manufacturer_desc[] = +{ + 0x10, + 0x03, + 'C', 0x00, + 'y', 0x00, + 'p', 0x00, + 'r', 0x00, + 'e', 0x00, + 's', 0x00, + 's', 0x00 +}; + +/* Bootloader Manufacturer String Descriptor */ +const unsigned char bl_product_desc[] = +{ + 0x16, + 0x03, + 'W', 0x00, + 'e', 0x00, + 's', 0x00, + 't', 0x00, + 'B', 0x00, + 'r', 0x00, + 'i', 0x00, + 'd', 0x00, + 'g', 0x00, + 'e', 0x00 +}; + +/* Bootloader Device Serial String Descriptor */ +const unsigned char bl_dev_serial_desc [] = +{ + 0x1A, /* bLength */ + 0x03, /* bDescType */ + '0',0,'0',0,'0',0,'0',0,'0',0,'0',0, + '0',0,'0',0,'0',0,'4',0,'B',0,'E',0, + 0,0, /* long word align */ +}; + diff --git a/firmware/fx3/b200/bootloader/usb_descriptors.h b/firmware/fx3/b200/bootloader/usb_descriptors.h new file mode 100644 index 000000000..8a7942327 --- /dev/null +++ b/firmware/fx3/b200/bootloader/usb_descriptors.h @@ -0,0 +1,26 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +/* Bootloader's unique config and string descriptors. */ + +/* Bootloader Full Speed Configuration Descriptor */ +extern const unsigned char bl_fs_config_desc[]; + +/* Bootloader High Speed Configuration Descriptor */ +extern const unsigned char bl_hs_config_desc[]; + +/* Bootloader Super Speed Configuration Descriptor */ +extern const unsigned char bl_ss_config_desc[]; + +/* Bootloader Manufacturer String Descriptor */ +extern const unsigned char bl_manufacturer_desc[]; + +/* Bootloader Product String Descriptor */ +extern const unsigned char bl_product_desc[]; + +/* Bootloader Device Serial String Descriptor */ +extern const unsigned char bl_dev_serial_desc[]; + diff --git a/firmware/fx3/b200/common/common_const.h b/firmware/fx3/b200/common/common_const.h new file mode 100644 index 000000000..1b40a7fdd --- /dev/null +++ b/firmware/fx3/b200/common/common_const.h @@ -0,0 +1,51 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#ifndef _COMMON_CONST_H +#define _COMMON_CONST_H + +#define EEPROM_REV_UNRECOGNIZED -1 + +#define EEPROM_SIGNATURE_ADDR 0x0000 +#define EEPROM_SIGNATURE_LENGTH 4 + +#define EEPROM_REV0_SIGNATURE 0xB2145943 +#define EEPROM_REV1_OR_GREATER_SIGNATURE 0xB01A5943 + +#define EEPROM_REV0_VID_ADDR 0x0006 +#define EEPROM_REV1_VID_ADDR 0x7F06 +#define EEPROM_VID_LENGTH 2 + +#define VID_ETTUS_RESEARCH 0x2500 +#define VID_NATIONAL_INSTRUMENTS 0x3923 +#define VID_CYPRESS 0x04B4 + +#define EEPROM_REV0_PID_ADDR 0x0004 +#define EEPROM_REV1_PID_ADDR 0x7F08 +#define EEPROM_PID_LENGTH 2 + +#define PID_ETTUS_B200_B210 0x0020 +#define PID_NI_USRP_2900 0x7813 +#define PID_NI_USRP_2901 0x7814 +#define PID_CYPRESS_DEFAULT 0x00F0 + +#define EEPROM_REV0_SERIAL_ADDR 0x04F7 +#define EEPROM_REV1_SERIAL_ADDR 0x7F23 +#define EEPROM_SERIAL_LENGTH 9 + +#define EEPROM_REV1_MAGIC_ADDR 0x7F00 +#define EEPROM_MAGIC_LENGTH 2 +#define EEPROM_EXPECTED_MAGIC 0xB200 + +#define EEPROM_REV1_REV_ADDR 0x7F02 +#define EEPROM_REV_LENGTH 2 +#define EEPROM_EXPECTED_REV 1 + +#define EEPROM_REV1_COMPAT_ADDR 0x7F04 +#define EEPROM_COMPAT_LENGTH 2 +#define EEPROM_EXPECTED_COMPAT 1 + +#endif /* _COMMON_CONST_H */ diff --git a/firmware/fx3/b200/common/common_descriptors.c b/firmware/fx3/b200/common/common_descriptors.c new file mode 100644 index 000000000..7cb670a4a --- /dev/null +++ b/firmware/fx3/b200/common/common_descriptors.c @@ -0,0 +1,237 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +/* This file contains all descriptors that are common between the bootloader + and firmware code. Non-const descriptors are modified at runtime based on + information read from the EEPROM. */ + +/* Standard Device Descriptor for USB 2.0 */ +unsigned char common_usb2_dev_desc[] = +{ + 0x12, /* Descriptor size */ + 0x01,/* CY_U3P_USB_DEVICE_DESCR Device descriptor type */ + 0x10,0x02, /* USB 2.10 */ + 0xFF, /* Device class */ + 0x00, /* Device sub-class */ + 0x00, /* Device protocol */ + 0x40, /* Maxpacket size for EP0 : 64 bytes */ + 0xB4,0x04, /* Vendor ID */ + 0xF0,0x00, /* Product ID */ + 0x00,0x00, /* Device release number */ + 0x01, /* Manufacture string index */ + 0x02, /* Product string index */ + 0x03, /* Serial number string index */ + 0x01 /* Number of configurations */ +}; + +/* Standard Device Descriptor for USB 3.0 */ +unsigned char common_usb3_dev_desc[] = +{ + 0x12, /* Descriptor size */ + 0x01,/* CY_U3P_USB_DEVICE_DESCR Device descriptor type */ + 0x00,0x03, /* USB 3.0 */ + 0xFF, /* Device class */ + 0x00, /* Device sub-class */ + 0x00, /* Device protocol */ + 0x09, /* Maxpacket size for EP0 : 2^9 */ + 0xB4,0x04, /* Vendor ID */ + 0xF0,0x00, /* Product ID */ + 0x00,0x00, /* Device release number */ + 0x01, /* Manufacture string index */ + 0x02, /* Product string index */ + 0x03, /* Serial number string index */ + 0x01 /* Number of configurations */ +}; + +/* Standard Device Qualifier Descriptor */ +const unsigned char common_dev_qual_desc[] = +{ + 0x0A, /* Descriptor size */ + 0x06,/* CY_U3P_USB_DEVQUAL_DESCR Device qualifier descriptor type */ + 0x00,0x02, /* USB 2.0 */ + 0xFF, /* Device class */ + 0x00, /* Device sub-class */ + 0x00, /* Device protocol */ + 0x40, /* Maxpacket size for EP0 : 64 bytes */ + 0x01, /* Number of configurations */ + 0x00 /* Reserved */ +}; + +/* Standard Binary Device Object Store Descriptor */ +const unsigned char common_usb_bos_desc[] = +{ + 0x05, /* Descriptor size */ + 0x0F,/* CY_U3P_BOS_DESCR Device descriptor type */ + 0x16,0x00, /* Length of this descriptor and all sub descriptors */ + 0x02, /* Number of device capability descriptors */ + + /* USB 2.0 extension */ + 0x07, /* Descriptor size */ + 0x10,/* CY_U3P_DEVICE_CAPB_DESCR Device capability type descriptor */ + 0x02,/* CY_U3P_USB2_EXTN_CAPB_TYPE USB 2.0 extension capability type */ + 0x02,0x00,0x00,0x00, /* Supported device level features: LPM support */ + + /* SuperSpeed device capability */ + 0x0A, /* Descriptor size */ + 0x10,/* CY_U3P_DEVICE_CAPB_DESCR Device capability type descriptor */ + 0x03,/* CY_U3P_SS_USB_CAPB_TYPE SuperSpeed device capability type */ + 0x00, /* Supported device level features */ + 0x0E,0x00, /* Speeds supported by the device : SS, HS and FS */ + 0x03, /* Functionality support */ + 0x00, /* U1 Device Exit latency */ + 0x00,0x00 /* U2 Device Exit latency */ +}; + +/* Standard Language ID String Descriptor */ +const unsigned char common_string_lang_id_desc[] = +{ + 0x04, /* Descriptor Size */ + 0x03,/* CY_U3P_USB_STRING_DESCR Device Descriptor Type */ + 0x09,0x04 /* Language ID supported */ +}; + + +/* Ettus Manufacturer String Descriptor */ +const unsigned char common_ettus_manufacturer_desc[] = +{ + 0x26, /* Descriptor Size */ + 0x03,/* CY_U3P_USB_STRING_DESCR Device Descriptor Type */ + 'E',0x00, + 't',0x00, + 't',0x00, + 'u',0x00, + 's',0x00, + ' ',0x00, + 'R',0x00, + 'e',0x00, + 's',0x00, + 'e',0x00, + 'a',0x00, + 'r',0x00, + 'c',0x00, + 'h',0x00, + ' ',0x00, + 'L',0x00, + 'L',0x00, + 'C',0x00 +}; + +/* NI Manufacturer String Descriptor */ +const unsigned char common_ni_manufacturer_desc[] = +{ + 0x36, /* Descriptor Size */ + 0x03,/* CY_U3P_USB_STRING_DESCR Device Descriptor Type */ + 'N',0x00, + 'a',0x00, + 't',0x00, + 'i',0x00, + 'o',0x00, + 'n',0x00, + 'a',0x00, + 'l',0x00, + ' ',0x00, + 'I',0x00, + 'n',0x00, + 's',0x00, + 't',0x00, + 'r',0x00, + 'u',0x00, + 'm',0x00, + 'e',0x00, + 'n',0x00, + 't',0x00, + 's',0x00, + ' ',0x00, + 'C',0x00, + 'o',0x00, + 'r',0x00, + 'p',0x00, + '.',0x00 +}; + + +/* Ettus Product String Descriptor */ +const unsigned char common_b200_product_desc[] = +{ + 0x14, /* Descriptor Size */ + 0x03,/* CY_U3P_USB_STRING_DESCR Device Descriptor Type */ + 'U',0x00, + 'S',0x00, + 'R',0x00, + 'P',0x00, + ' ',0x00, + 'B',0x00, + '2',0x00, + '0',0x00, + '0',0x00 +}; + +/* NI-USRP 2900 Product String Descriptor */ +const unsigned char common_niusrp_2900_product_desc[] = +{ + 0x1A, /* Descriptor Size */ + 0x03,/* CY_U3P_USB_STRING_DESCR Device Descriptor Type */ + 'N',0x00, + 'I',0x00, + ' ',0x00, + 'U',0x00, + 'S',0x00, + 'R',0x00, + 'P',0x00, + '-',0x00, + '2',0x00, + '9',0x00, + '0',0x00, + '0',0x00 +}; + +/* NI-USRP 2901 Product String Descriptor */ +const unsigned char common_niusrp_2901_product_desc[] = +{ + 0x1A, /* Descriptor Size */ + 0x03,/* CY_U3P_USB_STRING_DESCR Device Descriptor Type */ + 'N',0x00, + 'I',0x00, + ' ',0x00, + 'U',0x00, + 'S',0x00, + 'R',0x00, + 'P',0x00, + '-',0x00, + '2',0x00, + '9',0x00, + '0',0x00, + '1',0x00 +}; + +/* Unknown Product String Descriptor */ +const unsigned char common_unknown_desc[] = +{ + 0x10, /* Descriptor Size */ + 0x03,/* CY_U3P_USB_STRING_DESCR Device Descriptor Type */ + 'U',0x00, + 'n',0x00, + 'k',0x00, + 'n',0x00, + 'o',0x00, + 'w',0x00, + 'n',0x00 +}; + +unsigned char common_dev_serial_desc[] = +{ + 0x14, /* Descriptor Size */ + 0x03,/* CY_U3P_USB_STRING_DESCR Device Descriptor Type */ + '0', 0x00, + '0', 0x00, + '0', 0x00, + '0', 0x00, + '0', 0x00, + '0', 0x00, + '0', 0x00, + '0', 0x00, + '0', 0x00 +}; diff --git a/firmware/fx3/b200/common/common_descriptors.h b/firmware/fx3/b200/common/common_descriptors.h new file mode 100644 index 000000000..15acac3fa --- /dev/null +++ b/firmware/fx3/b200/common/common_descriptors.h @@ -0,0 +1,50 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#ifndef _COMMON_DESCRIPTORS_H +#define _COMMON_DESCRIPTORS_H + +/* This file contains all descriptors that are common between the bootloader + and firmware code. Non-const descriptors are modified at runtime based on + information read from the EEPROM. */ + +/* Standard Device Descriptor for USB 2.0 */ +extern unsigned char common_usb2_dev_desc[]; + +/* Standard Device Descriptor for USB 3.0 */ +extern unsigned char common_usb3_dev_desc[]; + +/* Standard Device Qualifier Descriptor */ +extern const unsigned char common_dev_qual_desc[]; + +/* Standard Binary Device Object Store Descriptor */ +extern const unsigned char common_usb_bos_desc[]; + +/* Standard Language ID String Descriptor */ +extern const unsigned char common_string_lang_id_desc[]; + +/* Ettus Manufacturer String Descriptor */ +extern const unsigned char common_ettus_manufacturer_desc[]; + +/* NI Manufacturer String Descriptor */ +extern const unsigned char common_ni_manufacturer_desc[]; + +/* Ettus Product String Descriptor */ +extern const unsigned char common_b200_product_desc[]; + +/* NI-USRP 2900 Product String Descriptor */ +extern const unsigned char common_niusrp_2900_product_desc[]; + +/* NI-USRP 2901 Product String Descriptor */ +extern const unsigned char common_niusrp_2901_product_desc[]; + +/* Unknown Product String Descriptor */ +extern const unsigned char common_unknown_desc[]; + +/* Common Serial String Descriptor */ +extern unsigned char common_dev_serial_desc[]; + +#endif \ No newline at end of file diff --git a/firmware/fx3/b200/common/common_helpers.c b/firmware/fx3/b200/common/common_helpers.c new file mode 100644 index 000000000..5a21a2106 --- /dev/null +++ b/firmware/fx3/b200/common/common_helpers.c @@ -0,0 +1,199 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#include "common_helpers.h" +#include "common_const.h" +#include "common_descriptors.h" + +#define UNREAD 0xFFFF + +/* Check the rev, magic value, and eeprom compatibility field to determine if + our eeprom map is up-to-date with what is written on the device */ +int eeprom_is_readable(eeprom_read_t read_fn) { + /* Only check this once, then store that info */ + static int is_readable = UNREAD; + + if (is_readable != UNREAD) { + return is_readable; + } + + int rev = get_rev(read_fn); + + if (rev == EEPROM_REV_UNRECOGNIZED) + { + is_readable = 0; + return is_readable; + } + + + /* If rev is 0, there's no further checks available */ + if (rev == 0) + { + is_readable = 1; + return is_readable; + } + + /* For rev 1, check the EEPROM magic value and compat number */ + + if (rev == 1) { + { + uint8_t buffer[EEPROM_MAGIC_LENGTH]; + read_fn(EEPROM_REV1_MAGIC_ADDR, buffer, EEPROM_MAGIC_LENGTH); + if ((buffer[1] << 8 | buffer[0]) != EEPROM_EXPECTED_MAGIC) { + is_readable = 0; + return is_readable; + } + } + { + uint8_t buffer[EEPROM_COMPAT_LENGTH]; + read_fn(EEPROM_REV1_COMPAT_ADDR, buffer, EEPROM_COMPAT_LENGTH); + if ((buffer[1] << 8 | buffer[0]) > EEPROM_EXPECTED_COMPAT) { + is_readable = 0; + return is_readable; + } + } + is_readable = 1; + return is_readable; + } + + /* some other unrecognized rev */ + is_readable = 0; + return is_readable; +} + +/* Read the EEPROM layout revision number from EEPROM using the function + specified */ +int get_rev(eeprom_read_t read_fn) +{ + /* Only check the rev once, then store that info */ + static int rev = UNREAD; + + if (rev != UNREAD) { + return rev; + } + + uint8_t buffer[EEPROM_SIGNATURE_LENGTH]; + read_fn(EEPROM_SIGNATURE_ADDR, buffer, EEPROM_SIGNATURE_LENGTH); + + const uint32_t signature = buffer[3] << 24 | buffer[2] << 16 | buffer[1] << 8 + | buffer[0]; + if (signature == EEPROM_REV0_SIGNATURE) { + rev = 0; + } else if (signature == EEPROM_REV1_OR_GREATER_SIGNATURE) { + rev = 1; + } else { + rev = EEPROM_REV_UNRECOGNIZED; + } + return rev; +} + + + +/* Read the vendor ID from EEPROM using the function specified*/ +uint16_t get_vid(eeprom_read_t read_fn) +{ + static uint16_t vid = UNREAD; + + if (vid != UNREAD) { + return vid; + } + + if (!eeprom_is_readable(read_fn)) { + vid = VID_CYPRESS; + return vid; + } + + // eeprom_is_readable guarantees rev is valid + int rev = get_rev(read_fn); + + const uint16_t addr = (rev == 0) ? EEPROM_REV0_VID_ADDR : EEPROM_REV1_VID_ADDR; + + uint8_t buffer[EEPROM_VID_LENGTH]; + read_fn(addr, buffer, EEPROM_VID_LENGTH); + vid = buffer[1] << 8 | buffer[0]; + return vid; +} + +/* Read the product ID from EEPROM using the function specified*/ +uint16_t get_pid(eeprom_read_t read_fn) +{ + static uint16_t pid = UNREAD; + + if (pid != UNREAD) { + return pid; + } + + if (!eeprom_is_readable(read_fn)) { + pid = PID_CYPRESS_DEFAULT; + return pid; + } + + // eeprom_is_readable guarantees rev is valid + int rev = get_rev(read_fn); + + const uint16_t addr = (rev == 0) ? EEPROM_REV0_PID_ADDR : EEPROM_REV1_PID_ADDR; + + uint8_t buffer[EEPROM_PID_LENGTH]; + read_fn(addr, buffer, EEPROM_PID_LENGTH); + pid = buffer[1] << 8 | buffer[0]; + return pid; +} + +/* Read the vendor ID from EEPROM using the function specified */ +const uint8_t* get_serial_string_descriptor(eeprom_read_t read_fn) +{ + static uint8_t* serial_string_descriptor = 0; + if (serial_string_descriptor) { + return serial_string_descriptor; + } + + /* All code paths will eventually return this value, but some will modify + it beforehand */ + serial_string_descriptor = common_dev_serial_desc; + + if (!eeprom_is_readable(read_fn)) { + return serial_string_descriptor; + } + + // eeprom_is_readable guarantees rev is valid + int rev = get_rev(read_fn); + + const uint16_t addr = (rev == 0) ? EEPROM_REV0_SERIAL_ADDR : EEPROM_REV1_SERIAL_ADDR; + + uint8_t buffer[EEPROM_SERIAL_LENGTH]; + read_fn(addr, buffer, EEPROM_SERIAL_LENGTH); + int i; + for (i = 0; i < EEPROM_SERIAL_LENGTH; ++i) { + common_dev_serial_desc[2 + i * 2] = buffer[i]; + } + return serial_string_descriptor; +} + +/* Return the string descriptor based on the VID given */ +const uint8_t* get_manufacturer_string_descriptor(uint16_t vid) +{ + if (vid == VID_ETTUS_RESEARCH) { + return common_ettus_manufacturer_desc; + } else if (vid == VID_NATIONAL_INSTRUMENTS) { + return common_ni_manufacturer_desc; + } else { + return common_unknown_desc; + } +} + +/* Return the string descriptor based on the PID given */ +const uint8_t* get_product_string_descriptor(uint16_t pid) +{ + if (pid == PID_ETTUS_B200_B210) { + return common_b200_product_desc; + } else if (pid == PID_NI_USRP_2900) { + return common_niusrp_2900_product_desc; + } else if (pid == PID_NI_USRP_2901) { + return common_niusrp_2901_product_desc; + } else { + return common_unknown_desc; + } +} diff --git a/firmware/fx3/b200/common/common_helpers.h b/firmware/fx3/b200/common/common_helpers.h new file mode 100644 index 000000000..8ff28fb09 --- /dev/null +++ b/firmware/fx3/b200/common/common_helpers.h @@ -0,0 +1,34 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#ifndef _COMMON_HELPERS_H +#define _COMMON_HELPERS_H + +#include "cyu3types.h" + +typedef void (*eeprom_read_t)(uint16_t, uint8_t*, uint8_t); + +/* Read the EEPROM layout revision number from EEPROM using the function + specified */ +int get_rev(eeprom_read_t read_fn); + +/* Read the vendor ID from EEPROM using the function specified*/ +uint16_t get_vid(eeprom_read_t read_fn); + +/* Read the product ID from EEPROM using the function specified*/ +uint16_t get_pid(eeprom_read_t read_fn); + +/* Read the vendor ID from EEPROM using the function specified + Buffer must be at least length 20 */ +const uint8_t* get_serial_string_descriptor(eeprom_read_t read_fn); + +/* Return the string descriptor based on the VID given */ +const uint8_t* get_manufacturer_string_descriptor(uint16_t vid); + +/* Return the string descriptor based on the PID given */ +const uint8_t* get_product_string_descriptor(uint16_t pid); + +#endif /* _COMMON_HELPERS_H */ diff --git a/firmware/fx3/b200/firmware/b200_const.h b/firmware/fx3/b200/firmware/b200_const.h new file mode 100644 index 000000000..886643021 --- /dev/null +++ b/firmware/fx3/b200/firmware/b200_const.h @@ -0,0 +1,124 @@ +// +// Copyright 2013-2014 Ettus Research LLC +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#ifndef _B200_CONST_H +#define _B200_CONST_H + +#include "cyu3externcstart.h" + +#include "cyu3types.h" +#include "cyu3usbconst.h" + +#define FX3_COMPAT_MAJOR (uint8_t)(8) +#define FX3_COMPAT_MINOR (uint8_t)(0) + +/* GPIO Pins */ +#define GPIO_FPGA_RESET (uint32_t)(26) // CTL[9] +#define GPIO_DONE (uint32_t)(27) +#define GPIO_PROGRAM_B (uint32_t)(45) +#define GPIO_INIT_B (uint32_t)(50) +#define GPIO_AUX_PWR_ON (uint32_t)(51) +#define GPIO_SHDN_SW (uint32_t)(52) +#define GPIO_FX3_SCLK (uint32_t)(53) +#define GPIO_FX3_CE (uint32_t)(54) +#define GPIO_FX3_MISO (uint32_t)(55) +#define GPIO_FX3_MOSI (uint32_t)(56) +#define GPIO_FPGA_SB_SCL (uint32_t)(25) // CTL[8] +#define GPIO_FPGA_SB_SDA (uint32_t)(23) // CTL[6] + +/* Create the bit-shifts that define the above GPIOs for bitmaps. The bitshifts + * are relative to 32-bit masks, so shifts > 32 are adjusted accordingly. Note + * that GPIOs < 32 are configured without the use of masks. */ +#define MASK_GPIO_PROGRAM_B (uint32_t)(1 << (GPIO_PROGRAM_B - 32)) +#define MASK_GPIO_INIT_B (uint32_t)(1 << (GPIO_INIT_B - 32)) +#define MASK_GPIO_AUX_PWR_ON (uint32_t)(1 << (GPIO_AUX_PWR_ON - 32)) +#define MASK_GPIO_SHDN_SW (uint32_t)(1 << (GPIO_SHDN_SW - 32)) +#define MASK_GPIO_FX3_SCLK (uint32_t)(1 << (GPIO_FX3_SCLK - 32)) +#define MASK_GPIO_FX3_CE (uint32_t)(1 << (GPIO_FX3_CE - 32)) +#define MASK_GPIO_FX3_MISO (uint32_t)(1 << (GPIO_FX3_MISO - 32)) +#define MASK_GPIO_FX3_MOSI (uint32_t)(1 << (GPIO_FX3_MOSI - 32)) +#define MASK_GPIO_FPGA_SB_SCL (uint32_t)(1 << (GPIO_FPGA_SB_SCL - 0)) +#define MASK_GPIO_FPGA_SB_SDA (uint32_t)(1 << (GPIO_FPGA_SB_SDA - 0)) + +#define USB3_PACKETS_PER_BURST (8) // Optimized value from Cypress AN86947 +#define USB2_PACKETS_PER_BURST (1) +#define DMA_SIZE_INFINITE (0) + +#define APP_THREAD_STACK_SIZE (0x0800) +#define THREAD_PRIORITY (8) + +#define B200_VREQ_BITSTREAM_START (uint8_t)(0x02) +#define B200_VREQ_BITSTREAM_DATA (uint8_t)(0x12) +#define B200_VREQ_BITSTREAM_DATA_FILL (uint8_t)(0x13) +#define B200_VREQ_BITSTREAM_DATA_COMMIT (uint8_t)(0x14) +#define B200_VREQ_GET_COMPAT (uint8_t)(0x15) +#define B200_VREQ_SET_FPGA_HASH (uint8_t)(0x1C) +#define B200_VREQ_GET_FPGA_HASH (uint8_t)(0x1D) +#define B200_VREQ_SET_FW_HASH (uint8_t)(0x1E) +#define B200_VREQ_GET_FW_HASH (uint8_t)(0x1F) +#define B200_VREQ_LOOP_CODE (uint8_t)(0x22) +#define B200_VREQ_GET_LOG (uint8_t)(0x23) +#define B200_VREQ_GET_COUNTERS (uint8_t)(0x24) +#define B200_VREQ_CLEAR_COUNTERS (uint8_t)(0x25) +#define B200_VREQ_GET_USB_EVENT_LOG (uint8_t)(0x26) +#define B200_VREQ_SET_CONFIG (uint8_t)(0x27) +#define B200_VREQ_GET_CONFIG (uint8_t)(0x28) +#define B200_VREQ_WRITE_SB (uint8_t)(0x29) +#define B200_VREQ_SET_SB_BAUD_DIV (uint8_t)(0x30) +#define B200_VREQ_FLUSH_DATA_EPS (uint8_t)(0x31) +#define B200_VREQ_FPGA_CONFIG (uint8_t)(0x55) +#define B200_VREQ_TOGGLE_FPGA_RESET (uint8_t)(0x62) +#define B200_VREQ_TOGGLE_GPIF_RESET (uint8_t)(0x72) +#define B200_VREQ_GET_USB_SPEED (uint8_t)(0x80) +#define B200_VREQ_GET_STATUS (uint8_t)(0x83) +#define B200_VREQ_RESET_DEVICE (uint8_t)(0x99) +#define B200_VREQ_EEPROM_WRITE (uint8_t)(0xBA) +#define B200_VREQ_EEPROM_READ (uint8_t)(0xBB) + +#define EVENT_BITSTREAM_START (1 << 1) +#define EVENT_GPIO_DONE_HIGH (1 << 2) +#define EVENT_GPIO_INITB_RISE (1 << 3) +#define EVENT_FPGA_CONFIG (1 << 4) +#define EVENT_RE_ENUM (1 << 5) + + +/* FX3 States */ +#define STATE_UNDEFINED (0) +#define STATE_FPGA_READY (1) +#define STATE_CONFIGURING_FPGA (2) +#define STATE_BUSY (3) +#define STATE_RUNNING (4) +#define STATE_UNCONFIGURED (5) +#define STATE_ERROR (6) + + +/* Define the USB endpoints, sockets, and directions. The LSB is the socket + * number, and the MSB is the direction. For USB 2.0, sockets are mapped + * one-to-one since they must be uni-directional. */ +#define VREQ_ENDPOINT_PRODUCER 0x00 // OUT (host -> FX3) +#define VREQ_ENDPOINT_CONSUMER 0x80 // IN (FX3 -> host) + +#define DATA_ENDPOINT_PRODUCER 0x02 // OUT (host -> FX3), produces for FPGA +#define DATA_ENDPOINT_CONSUMER 0x86 // IN (FX3 -> host), consumes from FPGA + +#define CTRL_ENDPOINT_PRODUCER 0x04 // OUT (host -> FX3), produces for FPGA +#define CTRL_ENDPOINT_CONSUMER 0x88 // IN (FX3 -> host), consumes from FPGA + +#define PRODUCER_DATA_SOCKET CY_U3P_UIB_SOCKET_PROD_2 +#define CONSUMER_DATA_SOCKET CY_U3P_UIB_SOCKET_CONS_6 + +#define PRODUCER_CTRL_SOCKET CY_U3P_UIB_SOCKET_PROD_4 +#define CONSUMER_CTRL_SOCKET CY_U3P_UIB_SOCKET_CONS_8 + +#define DATA_TX_PPORT_SOCKET CY_U3P_PIB_SOCKET_0 +#define DATA_RX_PPORT_SOCKET CY_U3P_PIB_SOCKET_1 +#define CTRL_COMM_PPORT_SOCKET CY_U3P_PIB_SOCKET_2 +#define CTRL_RESP_PPORT_SOCKET CY_U3P_PIB_SOCKET_3 + +#include "cyu3externcend.h" + +#endif /* _B200_CONST_H */ diff --git a/firmware/fx3/b200/firmware/b200_gpifconfig.h b/firmware/fx3/b200/firmware/b200_gpifconfig.h new file mode 100644 index 000000000..aa1c36551 --- /dev/null +++ b/firmware/fx3/b200/firmware/b200_gpifconfig.h @@ -0,0 +1,176 @@ +/* + * Project Name: ssf2-edit.cyfx + * Time : 11/17/2014 13:01:01 + * Device Type: FX3 + * Project Type: GPIF2 + * + * + * + * + * This is a generated file and should not be modified + * This file need to be included only once in the firmware + * This file is generated by Gpif2 designer tool version - 1.0.837.1 + * + */ + +#ifndef _INCLUDED_CYFXGPIF2CONFIG_ +#define _INCLUDED_CYFXGPIF2CONFIG_ +#include "cyu3types.h" +#include "cyu3gpif.h" + +/* Summary + Number of states in the state machine + */ +#define CY_NUMBER_OF_STATES 7 + +/* Summary + Mapping of user defined state names to state indices + */ +#define RESET 0 +#define IDLE 1 +#define READ 2 +#define WRITE 3 +#define SHORT_PKT 4 +#define ZLP 5 +#define DSS_STATE 6 + + +/* Summary + Initial value of early outputs from the state machine. + */ +#define ALPHA_RESET 0xC + + +/* Summary + Transition function values used in the state machine. + */ +uint16_t CyFxGpifTransition[] = { + 0x0000, 0x8080, 0x2222, 0x5555, 0x7F7F, 0x1F1F, 0x8888 +}; + +/* Summary + Table containing the transition information for various states. + This table has to be stored in the WAVEFORM Registers. + This array consists of non-replicated waveform descriptors and acts as a + waveform table. + */ +CyU3PGpifWaveData CyFxGpifWavedata[] = { + {{0x1E086001,0x000302C4,0x80000000},{0x00000000,0x00000000,0x00000000}}, + {{0x4E080302,0x00000300,0x80000000},{0x1E086006,0x000302C4,0x80000000}}, + {{0x1E086001,0x000302C4,0x80000000},{0x4E040704,0x20000300,0xC0100000}}, + {{0x4E080302,0x00000300,0x80000000},{0x1E086001,0x000302C4,0x80000000}}, + {{0x00000000,0x00000000,0x00000000},{0x00000000,0x00000000,0x00000000}}, + {{0x00000000,0x00000000,0x00000000},{0x3E738705,0x00000300,0xC0100000}}, + {{0x00000000,0x00000000,0x00000000},{0x5E002703,0x2003030C,0x80000000}}, + {{0x00000000,0x00000000,0x00000000},{0x4E040704,0x20000300,0xC0100000}} +}; + +/* Summary + Table that maps state indices to the descriptor table indices. + */ +uint8_t CyFxGpifWavedataPosition[] = { + 0,1,0,2,0,0,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 0,5,0,2,0,0,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 0,6,0,2,0,0,6,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 0,7,0,2,0,0,7 +}; + +/* Summary + GPIF II configuration register values. + */ +uint32_t CyFxGpifRegValue[] = { + 0x80000380, /* CY_U3P_PIB_GPIF_CONFIG */ + 0x000010AC, /* CY_U3P_PIB_GPIF_BUS_CONFIG */ + 0x01070002, /* CY_U3P_PIB_GPIF_BUS_CONFIG2 */ + 0x00000044, /* CY_U3P_PIB_GPIF_AD_CONFIG */ + 0x00000000, /* CY_U3P_PIB_GPIF_STATUS */ + 0x00000000, /* CY_U3P_PIB_GPIF_INTR */ + 0x00000000, /* CY_U3P_PIB_GPIF_INTR_MASK */ + 0x00000082, /* CY_U3P_PIB_GPIF_SERIAL_IN_CONFIG */ + 0x00000782, /* CY_U3P_PIB_GPIF_SERIAL_OUT_CONFIG */ + 0x00000500, /* CY_U3P_PIB_GPIF_CTRL_BUS_DIRECTION */ + 0x0000FFCF, /* CY_U3P_PIB_GPIF_CTRL_BUS_DEFAULT */ + 0x000000BF, /* CY_U3P_PIB_GPIF_CTRL_BUS_POLARITY */ + 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_TOGGLE */ + 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ + 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ + 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ + 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ + 0x00000018, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ + 0x00000019, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ + 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ + 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ + 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ + 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ + 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ + 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ + 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ + 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ + 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ + 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_BUS_SELECT */ + 0x00000006, /* CY_U3P_PIB_GPIF_CTRL_COUNT_CONFIG */ + 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_COUNT_RESET */ + 0x0000FFFF, /* CY_U3P_PIB_GPIF_CTRL_COUNT_LIMIT */ + 0x0000010A, /* CY_U3P_PIB_GPIF_ADDR_COUNT_CONFIG */ + 0x00000000, /* CY_U3P_PIB_GPIF_ADDR_COUNT_RESET */ + 0x0000FFFF, /* CY_U3P_PIB_GPIF_ADDR_COUNT_LIMIT */ + 0x00000000, /* CY_U3P_PIB_GPIF_STATE_COUNT_CONFIG */ + 0x0000FFFF, /* CY_U3P_PIB_GPIF_STATE_COUNT_LIMIT */ + 0x0000010A, /* CY_U3P_PIB_GPIF_DATA_COUNT_CONFIG */ + 0x00000000, /* CY_U3P_PIB_GPIF_DATA_COUNT_RESET */ + 0x0000FFFF, /* CY_U3P_PIB_GPIF_DATA_COUNT_LIMIT */ + 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_COMP_VALUE */ + 0x00000000, /* CY_U3P_PIB_GPIF_CTRL_COMP_MASK */ + 0x00000000, /* CY_U3P_PIB_GPIF_DATA_COMP_VALUE */ + 0x00000000, /* CY_U3P_PIB_GPIF_DATA_COMP_MASK */ + 0x00000000, /* CY_U3P_PIB_GPIF_ADDR_COMP_VALUE */ + 0x00000000, /* CY_U3P_PIB_GPIF_ADDR_COMP_MASK */ + 0x00000000, /* CY_U3P_PIB_GPIF_DATA_CTRL */ + 0x00000000, /* CY_U3P_PIB_GPIF_INGRESS_DATA */ + 0x00000000, /* CY_U3P_PIB_GPIF_INGRESS_DATA */ + 0x00000000, /* CY_U3P_PIB_GPIF_INGRESS_DATA */ + 0x00000000, /* CY_U3P_PIB_GPIF_INGRESS_DATA */ + 0x00000000, /* CY_U3P_PIB_GPIF_EGRESS_DATA */ + 0x00000000, /* CY_U3P_PIB_GPIF_EGRESS_DATA */ + 0x00000000, /* CY_U3P_PIB_GPIF_EGRESS_DATA */ + 0x00000000, /* CY_U3P_PIB_GPIF_EGRESS_DATA */ + 0x00000000, /* CY_U3P_PIB_GPIF_INGRESS_ADDRESS */ + 0x00000000, /* CY_U3P_PIB_GPIF_INGRESS_ADDRESS */ + 0x00000000, /* CY_U3P_PIB_GPIF_INGRESS_ADDRESS */ + 0x00000000, /* CY_U3P_PIB_GPIF_INGRESS_ADDRESS */ + 0x00000000, /* CY_U3P_PIB_GPIF_EGRESS_ADDRESS */ + 0x00000000, /* CY_U3P_PIB_GPIF_EGRESS_ADDRESS */ + 0x00000000, /* CY_U3P_PIB_GPIF_EGRESS_ADDRESS */ + 0x00000000, /* CY_U3P_PIB_GPIF_EGRESS_ADDRESS */ + 0x80010400, /* CY_U3P_PIB_GPIF_THREAD_CONFIG */ + 0x80010401, /* CY_U3P_PIB_GPIF_THREAD_CONFIG */ + 0x80010402, /* CY_U3P_PIB_GPIF_THREAD_CONFIG */ + 0x80010403, /* CY_U3P_PIB_GPIF_THREAD_CONFIG */ + 0x00000000, /* CY_U3P_PIB_GPIF_LAMBDA_STAT */ + 0x00000000, /* CY_U3P_PIB_GPIF_ALPHA_STAT */ + 0x00000000, /* CY_U3P_PIB_GPIF_BETA_STAT */ + 0x000C0000, /* CY_U3P_PIB_GPIF_WAVEFORM_CTRL_STAT */ + 0x00000000, /* CY_U3P_PIB_GPIF_WAVEFORM_SWITCH */ + 0x00000000, /* CY_U3P_PIB_GPIF_WAVEFORM_SWITCH_TIMEOUT */ + 0x00000000, /* CY_U3P_PIB_GPIF_CRC_CONFIG */ + 0x00000000, /* CY_U3P_PIB_GPIF_CRC_DATA */ + 0xFFFFFFC1 /* CY_U3P_PIB_GPIF_BETA_DEASSERT */ +}; + +/* Summary + This structure holds all the configuration inputs for the GPIF II. + */ +const CyU3PGpifConfig_t CyFxGpifConfig = { + (uint16_t)(sizeof(CyFxGpifWavedataPosition)/sizeof(uint8_t)), + CyFxGpifWavedata, + CyFxGpifWavedataPosition, + (uint16_t)(sizeof(CyFxGpifTransition)/sizeof(uint16_t)), + CyFxGpifTransition, + (uint16_t)(sizeof(CyFxGpifRegValue)/sizeof(uint32_t)), + CyFxGpifRegValue +}; + +#endif /* _INCLUDED_CYFXGPIF2CONFIG_ */ diff --git a/firmware/fx3/b200/firmware/b200_i2c.c b/firmware/fx3/b200/firmware/b200_i2c.c new file mode 100644 index 000000000..c6fa67c77 --- /dev/null +++ b/firmware/fx3/b200/firmware/b200_i2c.c @@ -0,0 +1,82 @@ +// +// Copyright 2013-2014 Ettus Research LLC +// + +#include "b200_i2c.h" + +#include "cyu3i2c.h" + +/* I2c initialization for EEPROM programming. */ +void CyFxI2cInit (uint16_t pageLen) { + CyU3PI2cConfig_t i2cConfig; + + /* Initialize and configure the I2C master module. */ + CyU3PI2cInit (); + + /* Start the I2C master block. The bit rate is set at 100KHz. + * The data transfer is done via DMA. */ + CyU3PMemSet ((uint8_t *)&i2cConfig, 0, sizeof(i2cConfig)); + i2cConfig.bitRate = CY_FX_USBI2C_I2C_BITRATE; + i2cConfig.busTimeout = 0xFFFFFFFF; + i2cConfig.dmaTimeout = 0xFFFF; + i2cConfig.isDma = CyFalse; + + CyU3PI2cSetConfig (&i2cConfig, NULL); + glI2cPageSize = pageLen; +} + +/* I2C read / write for programmer application. */ +void CyFxUsbI2cTransfer ( + uint16_t byteAddress, + uint8_t devAddr, + uint16_t byteCount, + uint8_t *buffer, + CyBool_t isRead) +{ + CyU3PI2cPreamble_t preamble; + uint16_t pageCount = (byteCount / glI2cPageSize); + uint16_t resCount = glI2cPageSize; + + if (byteCount == 0) { + return; + } + + if ((byteCount % glI2cPageSize) != 0) { + pageCount ++; + resCount = byteCount % glI2cPageSize; + } + + while (pageCount != 0) { + if (isRead) { + /* Update the preamble information. */ + preamble.length = 4; + preamble.buffer[0] = devAddr; + preamble.buffer[1] = (uint8_t)(byteAddress >> 8); + preamble.buffer[2] = (uint8_t)(byteAddress & 0xFF); + preamble.buffer[3] = (devAddr | 0x01); + preamble.ctrlMask = 0x0004; + + CyU3PI2cReceiveBytes (&preamble, buffer, (pageCount == 1) ? resCount : glI2cPageSize, 0); + } else { + /* Write. Update the preamble information. */ + preamble.length = 3; + preamble.buffer[0] = devAddr; + preamble.buffer[1] = (uint8_t)(byteAddress >> 8); + preamble.buffer[2] = (uint8_t)(byteAddress & 0xFF); + preamble.ctrlMask = 0x0000; + + CyU3PI2cTransmitBytes (&preamble, buffer, (pageCount == 1) ? resCount : glI2cPageSize, 0); + /* Wait for the write to complete. */ + preamble.length = 1; + CyU3PI2cWaitForAck(&preamble, 200); + } + + /* An additional delay seems to be required after receiving an ACK. */ + CyU3PThreadSleep (1); + + /* Update the parameters */ + byteAddress += glI2cPageSize; + buffer += glI2cPageSize; + pageCount --; + } +} diff --git a/firmware/fx3/b200/firmware/b200_i2c.h b/firmware/fx3/b200/firmware/b200_i2c.h new file mode 100644 index 000000000..c5c781946 --- /dev/null +++ b/firmware/fx3/b200/firmware/b200_i2c.h @@ -0,0 +1,40 @@ +// +// Copyright 2013-2014 Ettus Research LLC +// + +#ifndef _B200_I2C_H +#define _B200_I2C_H + +#include "cyu3externcstart.h" + +#include "cyu3usbconst.h" +#include "cyu3types.h" + +/* Following two definitions made in b200_main.h for consistency. */ +/* define B200_VREQ_EEPROM_WRITE (uint8_t)(0xBA) */ +/* define B200_VREQ_EEPROM_READ (uint8_t)(0xBB) */ + +static uint16_t glI2cPageSize = 0x40; /* I2C Page size to be used for transfers. */ + +/* This application uses EEPROM as the slave I2C device. The I2C EEPROM + * part number used is 24LC256. The capacity of the EEPROM is 256K bits */ +#define CY_FX_USBI2C_I2C_MAX_CAPACITY (32 * 1024) /* Capacity in bytes */ + +/* The following constant is defined based on the page size that the I2C + * device support. 24LC256 support 64 byte page write access. */ +#define CY_FX_USBI2C_I2C_PAGE_SIZE (64) + +/* I2C Data rate */ +#define CY_FX_USBI2C_I2C_BITRATE (100000) + +/* Give a timeout value of 5s for any programming. */ +#define CY_FX_USB_I2C_TIMEOUT (5000) + +/* Function forward-declerations. */ +void CyFxI2cInit (uint16_t pageLen); +void CyFxUsbI2cTransfer (uint16_t byteAddress, uint8_t devAddr, + uint16_t byteCount, uint8_t *buffer, CyBool_t isRead); + +#include "cyu3externcend.h" + +#endif /* _B200_I2C_H */ diff --git a/firmware/fx3/b200/firmware/b200_main.c b/firmware/fx3/b200/firmware/b200_main.c new file mode 100644 index 000000000..26507dda7 --- /dev/null +++ b/firmware/fx3/b200/firmware/b200_main.c @@ -0,0 +1,3125 @@ +// +// Copyright 2013-2015 Ettus Research LLC +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +/* This file defines the application that runs on the Cypress FX3 device, and + * enables the user to program the FPGA with an FPGA image. Since the FPGA + * doesn't yet have a clock, the image must be bit-banged into the FPGA. + */ + +#include +#include + +#include "b200_const.h" +#include "b200_gpifconfig.h" +#include "b200_i2c.h" + +#include "common_helpers.h" +#include "common_descriptors.h" +#include "b200_usb_descriptors.h" + +#include "cyu3dma.h" +#include "cyu3error.h" +#include "cyu3gpif.h" +#include "cyu3gpio.h" +#include "cyu3spi.h" +#include "cyu3os.h" +#include "cyu3pib.h" +#include "cyu3system.h" +#include "cyu3usb.h" +#include "cyu3utils.h" +#include "cyfxversion.h" +#include "pib_regs.h" + +#define STATIC_SAVER static // Save stack space for variables in a non-re-entrant function (e.g. USB setup callback) + +/* + * WARNING: Before you enable any of the features below, please read the comments on the same line for that feature! + * Indented features must have the parent feature enabled as well. + */ + +#define HAS_HEAP // This requires memory to be set aside for the heap (e.g. required for printing floating-point numbers). You can apply the accompanying patch ('fx3_mem_map.patch') to fx3.ld & cyfxtx.c to create one. +#define ENABLE_MSG // This will cause the compiled code to exceed the default text memory area (SYS_MEM). You can apply the accompanying patch ('fx3_mem_map.patch') to fx3.ld & cyfxtx.c to resize the memory map so it will fit. +#define ENABLE_MANUAL_DMA_XFER // Allows us to set it from the host (using the side channel util), doesn't auto-enable it +//#define ENABLE_P2U_SUSP_EOP +#define ENABLE_MANUAL_DMA_XFER_FROM_HOST +#define ENABLE_MANUAL_DMA_XFER_TO_HOST +//#define ENABLE_DMA_BUFFER_PACKET_DEBUG +#define ENABLE_FPGA_SB // Be careful: this will add an ever-so-slight delay to some operations (e.g. AD3961 tune) +#define ENABLE_RE_ENUM_THREAD +#define ENABLE_USB_EVENT_LOGGING +//#define PREVENT_LOW_POWER_MODE +/*#define ENABLE_INIT_B_WORKAROUND // This should only be enabled if you have a board where the FPGA INIT_B line is broken, but the FPGA is known to work*/ +/*#define ENABLE_DONE_WORKAROUND // This should only be enabled if you have a board where the FPGA DONE line is broken, but the FPGA is known to work*/ + +#define WATCHDOG_TIMEOUT 1500 +#define CHECK_POWER_STATE_SLEEP_TIME 500 // Should be less than WATCHDOG_TIMEOUT + +#define FPGA_PROGRAMMING_POLL_SLEEP 10 // ticks +#define FPGA_PROGRAMMING_BITSTREAM_START_POLL_COUNT 250 // ~2.5 secs +#define FPGA_PROGRAMMING_INITB_POLL_COUNT 100 // ~1 sec +#define FPGA_PROGRAMMING_DONE_POLL_COUNT 250 // ~2.5 secs // This is the interval *after* no FPGA programming activity has been detected + +#define FPGA_RESET_SETTLING_TIME (1*10) // ~10ms (for SB to initialise) + +#define RE_ENUM_THREAD_SLEEP_TIME 100 +#define KEEP_ALIVE_LOOP_COUNT 200 + +#pragma message "----------------------" + +#ifdef ENABLE_MSG +#pragma message "msg enabled" +#else +#pragma message "msg disabled" +#endif // ENABLE_MSG + +#ifdef ENABLE_MANUAL_DMA_XFER +#pragma message "Manual DMA transfers" + +#ifdef ENABLE_MANUAL_DMA_XFER_FROM_HOST +#pragma message " -> From host" +#endif // ENABLE_MANUAL_DMA_XFER_FROM_HOST + +#ifdef ENABLE_MANUAL_DMA_XFER_TO_HOST +#pragma message " <- To host" +#endif // ENABLE_MANUAL_DMA_XFER_TO_HOST + +#ifdef ENABLE_DMA_BUFFER_PACKET_DEBUG +#pragma message " Packet debugging enabled" +#endif // ENABLE_DMA_BUFFER_PACKET_DEBUG + +#else +#pragma message "Auto DMA transfers" +#endif // ENABLE_MANUAL_DMA_XFER + +#ifdef ENABLE_FPGA_SB +#pragma message "FPGA Settings Bus enabled" +#else +#pragma message "FPGA Settings Bus disabled" +#endif // ENABLE_FPGA_SB + +#ifdef ENABLE_RE_ENUM_THREAD +#pragma message "Re-enumeration & statistics thread enabled" +#else +#pragma message "Re-enumeration & statistics thread disabled" +#endif // ENABLE_RE_ENUM_THREAD + +#ifdef ENABLE_USB_EVENT_LOGGING +#pragma message "USB event logging enabled" +#else +#pragma message "USB event logging disabled" +#endif // ENABLE_USB_EVENT_LOGGING + +#ifdef PREVENT_LOW_POWER_MODE +#pragma message "Preventing Low Power Mode" +#else +#pragma message "Allowing Low Power Mode" +#endif // PREVENT_LOW_POWER_MODE + +#ifdef HAS_HEAP +#pragma message "Heap enabled" +#else +#pragma message "Heap disabled" +#endif // HAS_HEAP + +#ifdef ENABLE_INIT_B_WORKAROUND +#pragma message "INIT_B workaround enabled" +#else +#pragma message "INIT_B workaround disabled" +#endif // ENABLE_INIT_B_WORKAROUND + +#ifdef ENABLE_DONE_WORKAROUND +#pragma message "DONE workaround enabled" +#else +#pragma message "DONE workaround disabled" +#endif // ENABLE_DONE_WORKAROUND + +#pragma message "----------------------" + +/* Declare global & static fields for our bit-bang application. */ +static CyU3PDmaChannel data_cons_to_prod_chan_handle; +static CyU3PDmaChannel data_prod_to_cons_chan_handle; + +static CyU3PDmaChannel ctrl_cons_to_prod_chan_handle; +static CyU3PDmaChannel ctrl_prod_to_cons_chan_handle; + +static CyU3PEvent g_event_usb_config; +static CyU3PThread thread_main_app; +static CyU3PThread thread_fpga_config; +#ifdef ENABLE_RE_ENUM_THREAD +static CyU3PThread thread_re_enum; +#endif // ENABLE_RE_ENUM_THREAD + +static CyBool_t g_app_running = CyFalse; +static uint8_t g_fx3_state = STATE_UNDEFINED; + +#define USB2_VREQ_BUF_SIZE 64 +#define USB3_VREQ_BUF_SIZE 512 +#define MIN_VREQ_BUF_SIZE USB2_VREQ_BUF_SIZE +#define MAX_VREQ_BUF_SIZE USB3_VREQ_BUF_SIZE + +static uint16_t g_vendor_req_buff_size = MIN_VREQ_BUF_SIZE; +static uint8_t g_vendor_req_buffer[MAX_VREQ_BUF_SIZE] __attribute__ ((aligned (32))); +static uint16_t g_vendor_req_read_count = 0; + +static uint8_t fpga_hash[4] __attribute__ ((aligned (32))); +static uint8_t fw_hash[4] __attribute__ ((aligned (32))); +static uint8_t compat_num[2]; +static uint32_t g_fpga_programming_write_count = 0; + +#define COUNTER_MAGIC 0x10024001 +#define LOG_BUFFER_SIZE /*MAX_VREQ_BUF_SIZE*/1024 // [Max vreq @ USB3 (64 @ USB2)] Can be larger +static char log_buffer[LOG_BUFFER_SIZE]; +static char log_contiguous_buffer[LOG_BUFFER_SIZE]; +static int log_buffer_idx = 0, log_buffer_len = 0; +#ifdef ENABLE_MSG +static int log_count = 0; +#endif // ENABLE_MSG + +#define USB_EVENT_LOG_SIZE 64 +static uint8_t g_usb_event_log[USB_EVENT_LOG_SIZE]; +static uint16_t g_last_usb_event_log_index = 0; +static uint8_t g_usb_event_log_contiguous_buf[USB_EVENT_LOG_SIZE]; + +#ifdef ENABLE_FPGA_SB +static CyBool_t g_fpga_sb_enabled = CyFalse; +//static uint16_t g_fpga_sb_uart_div = 434*2; +static uint16_t g_fpga_sb_last_usb_event_log_index = 0; +static CyU3PThread thread_fpga_sb_poll; +static CyU3PMutex g_suart_lock; +#endif // ENABLE_FPGA_SB + +static CyU3PMutex g_log_lock, g_counters_lock, g_counters_dma_from_host_lock, g_counters_dma_to_host_lock; + +#define FPGA_SB_UART_ADDR_BASE 0x00 + +enum UARTRegs +{ + SUART_CLKDIV, + SUART_TXLEVEL, + SUART_RXLEVEL, + SUART_TXCHAR, + SUART_RXCHAR +}; + +enum UARTPacketType +{ + UPT_NONE = '\0', + UPT_MSG = ' ', + UPT_COUNTERS = 'C', + UPT_USB_EVENTS = 'U', +}; + +enum ConfigFlags { + CF_NONE = 0, + CF_TX_SWING = 1 << 0, + CF_TX_DEEMPHASIS = 1 << 1, + CF_DISABLE_USB2 = 1 << 2, + CF_ENABLE_AS_SUPERSPEED = 1 << 3, + CF_PPORT_DRIVE_STRENGTH = 1 << 4, + CF_DMA_BUFFER_SIZE = 1 << 5, + CF_DMA_BUFFER_COUNT = 1 << 6, + CF_MANUAL_DMA = 1 << 7, + CF_SB_BAUD_DIV = 1 << 8, + + CF_RE_ENUM = 1 << 31 +}; + +typedef struct Config { + int tx_swing; // [90] [65] 45 + int tx_deemphasis; // 0x11 + int disable_usb2; // 0 + int enable_as_superspeed; // 1 + int pport_drive_strength; // CY_U3P_DS_THREE_QUARTER_STRENGTH + int dma_buffer_size; // [USB3] (max) + int dma_buffer_count; // [USB3] 2 + int manual_dma; // 0 + int sb_baud_div; // 434*2 +} CONFIG, *PCONFIG; + +typedef struct ConfigMod { + int flags; + CONFIG config; +} CONFIG_MOD, *PCONFIG_MOD; + +static CONFIG g_config = { + 65, // tx_swing + 0x11, // tx_deemphasis + 0, // disable_usb2 + 1, // enable_as_superspeed + CY_U3P_DS_THREE_QUARTER_STRENGTH, // pport_drive_strength + 16*1024, // dma_buffer_size - optimized value from Cypress AN86947 + 2, // dma_buffer_count - optimized value from Cypress AN86947 + 0, // manual_dma + 434*2 // sb_baud_div +}; +static CONFIG_MOD g_config_mod; + +#define REG_LNK_PHY_ERROR_STATUS 0xE0033044 + +enum PhyErrors { + PHYERR_PHY_LOCK_EV = 1 << 8, + PHYERR_TRAINING_ERROR_EV = 1 << 7, + PHYERR_RX_ERROR_CRC32_EV = 1 << 6, + PHYERR_RX_ERROR_CRC16_EV = 1 << 5, + PHYERR_RX_ERROR_CRC5_EV = 1 << 4, + PHYERR_PHY_ERROR_DISPARITY_EV = 1 << 3, + PHYERR_PHY_ERROR_EB_UND_EV = 1 << 2, + PHYERR_PHY_ERROR_EB_OVR_EV = 1 << 1, + PHYERR_PHY_ERROR_DECODE_EV = 1 << 0, + + PHYERR_MAX = PHYERR_PHY_LOCK_EV, + PHYERR_MASK = (PHYERR_MAX << 1) - 1 +}; + +typedef struct USBErrorCounters { + int phy_error_count; + int link_error_count; + + int PHY_LOCK_EV; + int TRAINING_ERROR_EV; + int RX_ERROR_CRC32_EV; + int RX_ERROR_CRC16_EV; + int RX_ERROR_CRC5_EV; + int PHY_ERROR_DISPARITY_EV; + int PHY_ERROR_EB_UND_EV; + int PHY_ERROR_EB_OVR_EV; + int PHY_ERROR_DECODE_EV; +} USB_ERROR_COUNTERS, *PUSB_ERROR_COUNTERS; + +typedef struct DMACounters { + int XFER_CPLT; + int SEND_CPLT; + int RECV_CPLT; + int PROD_EVENT; + int CONS_EVENT; + int ABORTED; + int ERROR; + int PROD_SUSP; + int CONS_SUSP; + + int BUFFER_MARKER; + int BUFFER_EOP; + int BUFFER_ERROR; + int BUFFER_OCCUPIED; + + int last_count; + int last_size; + + int last_sid; + int bad_sid_count; +} DMA_COUNTERS, *PDMA_COUNTERS; + +typedef struct PIBCounters +{ + int socket_inactive; // CYU3P_PIB_ERR_THR1_SCK_INACTIVE +} PIB_COUNTERS, *PPIB_COUNTERS; + +typedef struct Counters { + int magic; + + DMA_COUNTERS dma_to_host; + DMA_COUNTERS dma_from_host; + + int log_overrun_count; + + int usb_error_update_count; + USB_ERROR_COUNTERS usb_error_counters; + + int usb_ep_underrun_count; + + int heap_size; + + int resume_count; + + int state_transition_count; + int invalid_gpif_state; + + PIB_COUNTERS pib_counters[4]; +} COUNTERS, *PCOUNTERS; + +volatile static COUNTERS g_counters; + +#ifndef min +#define min(a,b) ((a)<(b)?(a):(b)) +#endif // min + +#define LOCKP(p) CyU3PMutexGet(p, CYU3P_WAIT_FOREVER) +#define UNLOCKP(p) CyU3PMutexPut(p) +#define LOCK(p) LOCKP(&p) +#define UNLOCK(p) UNLOCKP(&p) + +//////////////////////////////////////////////////////////////////////////////// + +char *heap_end = 0; +caddr_t _sbrk(int incr) +{ +#ifdef HAS_HEAP + extern char __heap_start; + extern char __heap_end; + char *prev_heap_end; + + if (heap_end == 0) + { + heap_end = (char *)&__heap_start; + } + prev_heap_end = heap_end; + + if (heap_end + incr > &__heap_end) + { + return (caddr_t) 0; + } + heap_end += incr; + g_counters.heap_size += incr; // Not sync'd + + return (caddr_t) prev_heap_end; +#else + return (caddr_t) -1; +#endif // HAS_HEAP +} + +//////////////////////////////////////////////////////////////////////////////// + +void b200_start_fpga_sb_gpio(void); +void sb_write(uint8_t reg, uint32_t val); +void _sb_write_string(const char* msg); + +void msg(const char* str, ...) { +#define msg_CHECK_USE_LOCK +//void _msgv(int use_lock, const char* str, va_list args) { +//#define msg_CHECK_USE_LOCK if (use_lock) +#ifdef ENABLE_MSG + va_list args; + static char buf[LOG_BUFFER_SIZE]; + int idx = 0; + + msg_CHECK_USE_LOCK + LOCK(g_log_lock); + + ++log_count; + log_count %= 10000; + + va_start(args, str); + + if (1) { // FIXME: Optional + uint32_t time_now = CyU3PGetTime(); + idx += sprintf(buf, "%08X %04i ", (uint)time_now, log_count); + } + else + idx += sprintf(buf, "%04i ", log_count); + idx += vsnprintf(buf + idx, LOG_BUFFER_SIZE - idx, str, args); + + va_end(args); + + if ((LOG_BUFFER_SIZE - log_buffer_len) < (idx + 1 + 1)) { + msg_CHECK_USE_LOCK + LOCK(g_counters_lock); + ++g_counters.log_overrun_count; + msg_CHECK_USE_LOCK + UNLOCK(g_counters_lock); + + goto msg_exit; + } + + // Circular buffer if we need it later, but currently won't wrap due to above condition + memcpy(log_buffer + log_buffer_len, buf, min(idx + 1, LOG_BUFFER_SIZE - log_buffer_len)); + if ((idx + 1) > (LOG_BUFFER_SIZE - log_buffer_len)) + { + memcpy(log_buffer, buf + (LOG_BUFFER_SIZE - log_buffer_len), (idx + 1) - (LOG_BUFFER_SIZE - log_buffer_len)); + log_buffer[(idx + 1) - (LOG_BUFFER_SIZE - log_buffer_len)] = '\0'; + } + else + log_buffer[log_buffer_len + idx + 1] = '\0'; + + log_buffer_len += (idx + 1); +msg_exit: + msg_CHECK_USE_LOCK + UNLOCK(g_log_lock); +#ifdef ENABLE_FPGA_SB + LOCK(g_suart_lock); + sb_write(SUART_TXCHAR, UPT_MSG); + _sb_write_string(buf); + _sb_write_string("\r\n"); + UNLOCK(g_suart_lock); +#endif // ENABLE_FPGA_SB +#endif // ENABLE_MSG +} +/* +void msg(const char* str, ...) +{ + va_list args; + va_start(args, str); + _msgv(1, str, args); + va_end(args); +} + +void msg_nl(const char* str, ...) +{ + va_list args; + va_start(args, str); + _msgv(0, str, args); + va_end(args); +} +*/ +void log_reset(void) { + //LOCK(g_log_lock); + + log_buffer_idx = 0; + log_buffer_len = 0; + log_buffer[0] = '\0'; + + //UNLOCK(g_log_lock); +} + +void counters_auto_reset(void) { + //LOCK(g_counters_lock); + + g_counters.log_overrun_count = 0; + + //UNLOCK(g_counters_lock); +} + +void counters_dma_reset(void) { + LOCK(g_counters_lock); + + LOCK(g_counters_dma_to_host_lock); + memset((void*)&g_counters.dma_to_host, 0x00, sizeof(DMA_COUNTERS)); + UNLOCK(g_counters_dma_to_host_lock); + + LOCK(g_counters_dma_from_host_lock); + memset((void*)&g_counters.dma_from_host, 0x00, sizeof(DMA_COUNTERS)); + UNLOCK(g_counters_dma_from_host_lock); + + UNLOCK(g_counters_lock); +} + +void counters_reset_usb_errors(void) { + LOCK(g_counters_lock); + + g_counters.usb_error_update_count = 0; + memset((void*)&g_counters.usb_error_counters, 0x00, sizeof(g_counters.usb_error_counters)); + + UNLOCK(g_counters_lock); +} + +#ifdef ENABLE_MANUAL_DMA_XFER +/* Callback funtion for the DMA event notification. */ +void dma_callback ( + CyU3PDmaChannel *chHandle, /* Handle to the DMA channel. */ + CyU3PDmaCbType_t type, /* Callback type. */ + CyU3PDmaCBInput_t *input, /* Callback status. */ + int from_host) +{ + CyU3PReturnStatus_t status = CY_U3P_SUCCESS; + + PDMA_COUNTERS cnt = (PDMA_COUNTERS)(from_host ? &g_counters.dma_from_host : &g_counters.dma_to_host); + CyU3PMutex* lock = (from_host ? &g_counters_dma_from_host_lock : &g_counters_dma_to_host_lock); + + uint16_t buffer_status = (input->buffer_p.status & CY_U3P_DMA_BUFFER_STATUS_MASK); + if (buffer_status & CY_U3P_DMA_BUFFER_MARKER) + { + cnt->BUFFER_MARKER++; + } + if (buffer_status & CY_U3P_DMA_BUFFER_EOP) + { + cnt->BUFFER_EOP++; + } + if (buffer_status & CY_U3P_DMA_BUFFER_ERROR) + { + cnt->BUFFER_ERROR++; + } + if (buffer_status & CY_U3P_DMA_BUFFER_OCCUPIED) + { + cnt->BUFFER_OCCUPIED++; + } + + if (type == CY_U3P_DMA_CB_PROD_EVENT) + { +#ifdef ENABLE_DMA_BUFFER_PACKET_DEBUG + LOCKP(lock); + int prod_cnt = cnt->PROD_EVENT++; + UNLOCKP(lock); + + //if (cnt->last_count != input->buffer_p.count) + // msg("[DMA%d %05d] buffer.count (%05d) != last_count (%05d)", from_host, prod_cnt, input->buffer_p.count, cnt->last_count); + cnt->last_count = input->buffer_p.count; + + if (cnt->last_size != input->buffer_p.size) + msg("[DMA%d %05d] buffer.size (%05d) != last_size (%05d)", from_host, prod_cnt, input->buffer_p.size, cnt->last_size); + cnt->last_size = input->buffer_p.size; + + uint32_t* p32 = input->buffer_p.buffer; + uint32_t sid = p32[1]; + cnt->last_sid = (int)sid; + if (((from_host == 0) && ((sid != 0xa0) && (sid != 0xb0))) || + ((from_host == 1) && ((sid != 0x50) && (sid != 0x60)))) + { + cnt->bad_sid_count++; + msg("[DMA%d %05d] Bad SID: 0x%08x", from_host, prod_cnt, sid); + } + + uint16_t* p16 = input->buffer_p.buffer; + + if (p32[0] & (((uint32_t)1) << 31)) + { + msg("[DMA%d %05d] Error code: 0x%x (packet len: %05d, buffer count: %05d, seq: %04d)", from_host, prod_cnt, p32[4], p16[0], input->buffer_p.count, (p16[1] & 0x0fff)); // Status + + //msg("[DMA%d] 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x", from_host, p32[0], p32[1], p32[2], p32[3], p32[4], p32[5]); + } + else + { + if (p16[1] & (((uint16_t)1) << 12)) + { + msg("[DMA%d %05d] EOB (packet len: %05d, buffer count: %05d)", from_host, prod_cnt, p16[0], input->buffer_p.count); // Comes with one sample + } + + if ((p16[0] != input->buffer_p.count) && + ((p16[0] + 4) != input->buffer_p.count)) // Case of overrun packet length being padded (being rounded up) + { + if (from_host == 0) + msg("[DMA%d %05d] Packet len (%05d) != buffer count (%05d), seq: %04d [0x%04x 0x%04x]", from_host, prod_cnt, p16[0], input->buffer_p.count, (p16[1] & 0x0fff), p16[0], p16[1]); + } + + //msg("[DMA%d] 0x%04x 0x%04x 0x%04x 0x%04x", from_host, p16[0], p16[1], p16[2], p16[3]); + + if (p16[1] & (((uint16_t)1) << 12)) + msg("[DMA%d %05d] 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x", from_host, prod_cnt, p32[0], p32[1], p32[2], p32[3], p32[4], p32[5]); + } +#endif // ENABLE_DMA_BUFFER_PACKET_DEBUG + status = CyU3PDmaChannelCommitBuffer (chHandle, input->buffer_p.count, 0); +#ifndef ENABLE_DMA_BUFFER_PACKET_DEBUG + LOCKP(lock); + cnt->PROD_EVENT++; + UNLOCKP(lock); +#endif // !ENABLE_DMA_BUFFER_PACKET_DEBUG + } + else if (type == CY_U3P_DMA_CB_CONS_EVENT) + { + LOCKP(lock); + cnt->CONS_EVENT++; + UNLOCKP(lock); + } + else if (type == CY_U3P_DMA_CB_XFER_CPLT) + { + LOCKP(lock); + cnt->XFER_CPLT++; + UNLOCKP(lock); + } + else if (type == CY_U3P_DMA_CB_SEND_CPLT) + { + LOCKP(lock); + cnt->SEND_CPLT++; + UNLOCKP(lock); + } + else if (type == CY_U3P_DMA_CB_RECV_CPLT) + { + LOCKP(lock); + cnt->RECV_CPLT++; + UNLOCKP(lock); + } + else if (type == CY_U3P_DMA_CB_ABORTED) + { + LOCKP(lock); + cnt->ABORTED++; + UNLOCKP(lock); + + msg("! Aborted %i", from_host); + } + else if (type == CY_U3P_DMA_CB_ERROR) + { + LOCKP(lock); + cnt->ERROR++; + UNLOCKP(lock); + + msg("! Error %i", from_host); + } + else if (type == CY_U3P_DMA_CB_PROD_SUSP) + { + LOCKP(lock); + cnt->PROD_SUSP++; + UNLOCKP(lock); + + msg("! Prod suspend %i", from_host); + } + else if (type == CY_U3P_DMA_CB_CONS_SUSP) + { + LOCKP(lock); + cnt->CONS_SUSP++; + UNLOCKP(lock); + + //msg("! Cons suspend %i", from_host); + + CyU3PDmaChannelResume (chHandle, CyFalse, CyTrue); + } +} + +void from_host_dma_callback ( + CyU3PDmaChannel *chHandle, /* Handle to the DMA channel. */ + CyU3PDmaCbType_t type, /* Callback type. */ + CyU3PDmaCBInput_t *input) /* Callback status. */ +{ + return dma_callback(chHandle, type, input, 1); +} + +void to_host_dma_callback ( + CyU3PDmaChannel *chHandle, /* Handle to the DMA channel. */ + CyU3PDmaCbType_t type, /* Callback type. */ + CyU3PDmaCBInput_t *input) /* Callback status. */ +{ + return dma_callback(chHandle, type, input, 0); +} +#endif // ENABLE_MANUAL_DMA_XFER + +/*! Interrupt callback for GPIOs. + * + * This function is invoked by the GPIO interrupt handler when pins configured + * as inputs with interrupts are triggered. */ +void gpio_interrupt_callback(uint8_t gpio_id) { + CyBool_t gpio_value; + + if ((gpio_id == GPIO_DONE) && (g_fx3_state == STATE_CONFIGURING_FPGA)) { // Only proceed if in the correct FX3 state + CyU3PGpioGetValue(gpio_id, &gpio_value); + + if(gpio_value == CyTrue) { + //msg("DONE HIGH"); + CyU3PEventSet(&g_event_usb_config, EVENT_GPIO_DONE_HIGH, CYU3P_EVENT_OR); + } + } else if ((gpio_id == GPIO_INIT_B) && (g_fx3_state == STATE_FPGA_READY)) { // Only proceed if in the correct FX3 state + CyU3PGpioGetValue(gpio_id, &gpio_value); + + if(gpio_value == CyTrue) { + //msg("INITB_RISE"); + CyU3PEventSet(&g_event_usb_config, EVENT_GPIO_INITB_RISE, CYU3P_EVENT_OR); + } + } +} + + +/*! Stops the application, and destroys transport data structures. + * + * This function is essentially a destructor for all transport configurations. + * It ensures that if the USB configuration is reset without a power reboot, + * everything will come back up properly. */ +void b200_fw_stop(void) { + msg("b200_fw_stop"); + + CyU3PEpConfig_t usb_endpoint_config; + + /* Update the flag. */ + g_app_running = CyFalse; + + /* Flush the endpoint memory */ + CyU3PUsbFlushEp(DATA_ENDPOINT_PRODUCER); + CyU3PUsbFlushEp(DATA_ENDPOINT_CONSUMER); + CyU3PUsbFlushEp(CTRL_ENDPOINT_PRODUCER); + CyU3PUsbFlushEp(CTRL_ENDPOINT_CONSUMER); + + /* Reset the DMA channels */ + // SDK 1.3 known issue #1 - probably not necessary since Destroy is next, but just in case + CyU3PDmaChannelReset(&data_cons_to_prod_chan_handle); + CyU3PDmaChannelReset(&data_prod_to_cons_chan_handle); + CyU3PDmaChannelReset(&ctrl_cons_to_prod_chan_handle); + CyU3PDmaChannelReset(&ctrl_prod_to_cons_chan_handle); + + /* Destroy the DMA channels */ + CyU3PDmaChannelDestroy(&data_cons_to_prod_chan_handle); + CyU3PDmaChannelDestroy(&data_prod_to_cons_chan_handle); + CyU3PDmaChannelDestroy(&ctrl_cons_to_prod_chan_handle); + CyU3PDmaChannelDestroy(&ctrl_prod_to_cons_chan_handle); + + /* Disable endpoints. */ + CyU3PMemSet((uint8_t *) &usb_endpoint_config, 0, \ + sizeof(usb_endpoint_config)); + usb_endpoint_config.enable = CyFalse; + + CyU3PSetEpConfig(DATA_ENDPOINT_PRODUCER, &usb_endpoint_config); + CyU3PSetEpConfig(DATA_ENDPOINT_CONSUMER, &usb_endpoint_config); + CyU3PSetEpConfig(CTRL_ENDPOINT_PRODUCER, &usb_endpoint_config); + CyU3PSetEpConfig(CTRL_ENDPOINT_CONSUMER, &usb_endpoint_config); +} + + +void reset_gpif(void) { + g_fx3_state = STATE_BUSY; + + // Put the FPGA into RESET + CyU3PGpioSetValue(GPIO_FPGA_RESET, CyTrue); + + // Bring down GPIF + CyU3PGpifDisable(/*CyTrue*/CyFalse); + + /* Reset the DMA channels */ + CyU3PDmaChannelReset(&data_cons_to_prod_chan_handle); + CyU3PDmaChannelReset(&data_prod_to_cons_chan_handle); + CyU3PDmaChannelReset(&ctrl_cons_to_prod_chan_handle); + CyU3PDmaChannelReset(&ctrl_prod_to_cons_chan_handle); + + /* Reset the DMA transfers */ + CyU3PDmaChannelSetXfer(&data_cons_to_prod_chan_handle, DMA_SIZE_INFINITE); + CyU3PDmaChannelSetXfer(&data_prod_to_cons_chan_handle, DMA_SIZE_INFINITE); + CyU3PDmaChannelSetXfer(&ctrl_cons_to_prod_chan_handle, DMA_SIZE_INFINITE); + CyU3PDmaChannelSetXfer(&ctrl_prod_to_cons_chan_handle, DMA_SIZE_INFINITE); + + /* Flush the USB endpoints */ + CyU3PUsbFlushEp(DATA_ENDPOINT_PRODUCER); + CyU3PUsbFlushEp(DATA_ENDPOINT_CONSUMER); + CyU3PUsbFlushEp(CTRL_ENDPOINT_PRODUCER); + CyU3PUsbFlushEp(CTRL_ENDPOINT_CONSUMER); + + /* Load the GPIF configuration for Slave FIFO sync mode. */ + //CyU3PGpifLoad(&CyFxGpifConfig); + + /* Start the state machine. */ + //if (CyU3PGpifSMStart(RESET, ALPHA_RESET) != CY_U3P_SUCCESS) + // msg("! CyU3PGpifSMStart"); + + /* Configure the watermarks for the slfifo-write buffers. */ + //CyU3PGpifSocketConfigure(0, DATA_TX_PPORT_SOCKET, 5, CyFalse, 1); + //CyU3PGpifSocketConfigure(1, DATA_RX_PPORT_SOCKET, 6, CyFalse, 1); + //CyU3PGpifSocketConfigure(2, CTRL_COMM_PPORT_SOCKET, 5, CyFalse, 1); + //CyU3PGpifSocketConfigure(3, CTRL_RESP_PPORT_SOCKET, 6, CyFalse, 1); + + CyU3PGpioSetValue(GPIO_FPGA_RESET, CyFalse); + + CyU3PThreadSleep(FPGA_RESET_SETTLING_TIME); + + if (CyU3PGpifSMStart(RESET, ALPHA_RESET) != CY_U3P_SUCCESS) + msg("! CyU3PGpifSMStart"); + + msg("GPIF reset"); + + b200_start_fpga_sb_gpio(); + + g_fx3_state = STATE_RUNNING; +} + +void eeprom_read(uint16_t addr, uint8_t* buffer, uint8_t length) +{ + CyFxUsbI2cTransfer(addr, 0xA0, length, buffer, CyTrue); +} + +CyU3PReturnStatus_t b200_set_io_matrix(CyBool_t fpga_config_mode) { + CyU3PIoMatrixConfig_t io_config_matrix; + CyU3PReturnStatus_t res; + + /* Configure the IO peripherals on the FX3. The gpioSimpleEn arrays are + * bitmaps, where each bit represents the GPIO of the matching index - the + * second array is index + 32. */ + CyU3PMemSet((uint8_t *) &io_config_matrix, 0, sizeof(io_config_matrix)); + io_config_matrix.isDQ32Bit = (fpga_config_mode == CyFalse); + io_config_matrix.lppMode = CY_U3P_IO_MATRIX_LPP_DEFAULT; + io_config_matrix.gpioSimpleEn[0] = 0 | MASK_GPIO_FPGA_SB_SCL | MASK_GPIO_FPGA_SB_SDA; + io_config_matrix.gpioSimpleEn[1] = MASK_GPIO_PROGRAM_B \ + | MASK_GPIO_INIT_B \ + | (fpga_config_mode ? 0 : \ + // Used once FPGA config is done to bit-bang SPI, etc. + MASK_GPIO_SHDN_SW \ + | MASK_GPIO_AUX_PWR_ON \ + | MASK_GPIO_FX3_SCLK \ + | MASK_GPIO_FX3_CE \ + | MASK_GPIO_FX3_MISO \ + | MASK_GPIO_FX3_MOSI); + io_config_matrix.gpioComplexEn[0] = 0; + io_config_matrix.gpioComplexEn[1] = 0; + io_config_matrix.useUart = CyFalse; + io_config_matrix.useI2C = CyTrue; + io_config_matrix.useI2S = CyFalse; + io_config_matrix.useSpi = fpga_config_mode; + + res = CyU3PDeviceConfigureIOMatrix(&io_config_matrix); + if (res != CY_U3P_SUCCESS) + msg("! ConfigureIOMatrix"); + + return res; +} + + +CyU3PReturnStatus_t b200_gpio_init(CyBool_t set_callback) { + CyU3PGpioClock_t gpio_clock_config; + CyU3PReturnStatus_t res; + + /* Since we are only using FX3's 'simple GPIO' functionality, these values + * must *NOT* change. Cypress says changing them will break stuff. */ + CyU3PMemSet((uint8_t *) &gpio_clock_config, 0, \ + sizeof(gpio_clock_config)); + gpio_clock_config.fastClkDiv = 2; + gpio_clock_config.slowClkDiv = 0; + gpio_clock_config.simpleDiv = CY_U3P_GPIO_SIMPLE_DIV_BY_2; + gpio_clock_config.clkSrc = CY_U3P_SYS_CLK; + gpio_clock_config.halfDiv = 0; + + res = CyU3PGpioInit(&gpio_clock_config, (set_callback ? gpio_interrupt_callback : NULL)); + if (res != CY_U3P_SUCCESS) + msg("! CyU3PGpioInit"); + + return res; +} + + +void sb_write(uint8_t reg, uint32_t val) { +#ifdef ENABLE_FPGA_SB + const int len = 32; + int i; + + if (g_fpga_sb_enabled == CyFalse) + return; + + reg += FPGA_SB_UART_ADDR_BASE; + + //CyU3PBusyWait(1); // Can be used after each SetValue to slow down bit changes + + // START + CyU3PGpioSetValue(GPIO_FPGA_SB_SCL, 1); // Should already be 1 + CyU3PGpioSetValue(GPIO_FPGA_SB_SDA, 0); + + // ADDR[8] + for (i = 7; i >= 0; i--) { + uint8_t bit = ((reg & (0x1 << i)) ? 0x01 : 0x00); + CyU3PGpioSetValue(GPIO_FPGA_SB_SCL, 0); + CyU3PGpioSetValue(GPIO_FPGA_SB_SDA, bit); + + CyU3PGpioSetValue(GPIO_FPGA_SB_SCL, 1); // FPGA reads bit + } + + // DATA[32] + for (i = (len-1); i >= 0; i--) { + uint8_t bit = ((val & (0x1 << i)) ? 0x01 : 0x00); + CyU3PGpioSetValue(GPIO_FPGA_SB_SCL, 0); + CyU3PGpioSetValue(GPIO_FPGA_SB_SDA, bit); + + CyU3PGpioSetValue(GPIO_FPGA_SB_SCL, 1); // FPGA reads bit + } + + // STOP + CyU3PGpioSetValue(GPIO_FPGA_SB_SDA, 0); + CyU3PGpioSetValue(GPIO_FPGA_SB_SCL, 0); + CyU3PGpioSetValue(GPIO_FPGA_SB_SCL, 1); // Actual stop + CyU3PGpioSetValue(GPIO_FPGA_SB_SDA, 1); // Xact occurs +#endif // ENABLE_FPGA_SB +} + + +void _sb_write_string(const char* msg) { +#ifdef ENABLE_FPGA_SB + while (*msg) { + sb_write(SUART_TXCHAR, (uint8_t)(*(msg++))); + } +#endif // ENABLE_FPGA_SB +} + + +void sb_write_string(const char* msg) { +#ifdef ENABLE_FPGA_SB + LOCK(g_suart_lock); + _sb_write_string(msg); + UNLOCK(g_suart_lock); +#endif // ENABLE_FPGA_SB +} + + +void b200_enable_fpga_sb_gpio(CyBool_t enable) { +#ifdef ENABLE_FPGA_SB + CyU3PGpioSimpleConfig_t gpio_config; + CyU3PReturnStatus_t res; + + if (enable == CyFalse) { + g_fpga_sb_enabled = CyFalse; + + return; + } + + gpio_config.outValue = CyFalse; + gpio_config.driveLowEn = CyTrue; + gpio_config.driveHighEn = CyTrue; + gpio_config.inputEn = CyFalse; + gpio_config.intrMode = CY_U3P_GPIO_NO_INTR; + + res = CyU3PGpioSetSimpleConfig(GPIO_FPGA_SB_SCL, &gpio_config); + if (res != CY_U3P_SUCCESS) { + msg("! GpioSetSimpleConfig GPIO_FPGA_SB_SCL"); + } + res = CyU3PGpioSetSimpleConfig(GPIO_FPGA_SB_SDA, &gpio_config); + if (res != CY_U3P_SUCCESS) { + msg("! GpioSetSimpleConfig GPIO_FPGA_SB_SDA"); + } + + CyU3PGpioSetValue(GPIO_FPGA_SB_SCL, 1); + CyU3PGpioSetValue(GPIO_FPGA_SB_SDA, 1); + + g_fpga_sb_enabled = CyTrue; + + msg("Debug SB OK"); +#endif // ENABLE_FPGA_SB +} + + +void b200_start_fpga_sb_gpio(void) { +#ifdef ENABLE_FPGA_SB + LOCK(g_suart_lock); + sb_write(SUART_CLKDIV, /*g_fpga_sb_uart_div*/g_config.sb_baud_div); // 16-bit reg, master clock = 100 MHz (434*2x = 230400/2) + _sb_write_string("\r\n B2x0 FPGA reset\r\n"); + UNLOCK(g_suart_lock); + + msg("Compat: %d.%d", FX3_COMPAT_MAJOR, FX3_COMPAT_MINOR); + msg("FX3 SDK: %d.%d.%d (build %d)", CYFX_VERSION_MAJOR, CYFX_VERSION_MINOR, CYFX_VERSION_PATCH, CYFX_VERSION_BUILD); +#endif // ENABLE_FPGA_SB +} + + +/*! Initialize and configure the GPIO module for FPGA programming. + * + * This function initializes the FX3 GPIO module, creating a configuration that + * allows us to program the FPGA. After the FPGA has been programmed, the + * application thread will re-configure some of the pins. */ +void b200_gpios_pre_fpga_config(void) { + CyU3PGpioSimpleConfig_t gpio_config; + + //b200_enable_fpga_sb_gpio(CyFalse); + + //CyU3PGpioDeInit(); + + b200_set_io_matrix(CyTrue); + + //b200_gpio_init(CyTrue); // This now done once during startup + + //////////////////////////////////// + + /* GPIO[0:32] must be set with the DeviceOverride function, instead of the + * SimpleEn array configuration. */ + CyU3PDeviceGpioOverride(GPIO_FPGA_RESET, CyTrue); + CyU3PDeviceGpioOverride(GPIO_DONE, CyTrue); + + /* Configure GPIOs: + * Outputs: + * driveLowEn = True + * driveHighEn = True + * inputEn = False + * Inputs: + * driveLowEn = False + * driveHighEn = False + * outValue = Ignored + */ + gpio_config.outValue = CyFalse; + gpio_config.driveLowEn = CyTrue; + gpio_config.driveHighEn = CyTrue; + gpio_config.inputEn = CyFalse; + gpio_config.intrMode = CY_U3P_GPIO_NO_INTR; + + CyU3PGpioSetSimpleConfig(GPIO_FPGA_RESET, &gpio_config); + CyU3PGpioSetSimpleConfig(GPIO_PROGRAM_B, &gpio_config); + + /* Reconfigure the GPIO configure struct for inputs that DO require + * interrupts attached to them. */ + gpio_config.outValue = CyTrue; + gpio_config.inputEn = CyTrue; + gpio_config.driveLowEn = CyFalse; + gpio_config.driveHighEn = CyFalse; + gpio_config.intrMode = CY_U3P_GPIO_INTR_POS_EDGE; + + CyU3PGpioSetSimpleConfig(GPIO_DONE, &gpio_config); + CyU3PGpioSetSimpleConfig(GPIO_INIT_B, &gpio_config); + + /* Initialize GPIO output values. */ + CyU3PGpioSetValue(GPIO_FPGA_RESET, 0); + CyU3PGpioSetValue(GPIO_PROGRAM_B, 1); + + b200_enable_fpga_sb_gpio(CyTrue); // So SCL/SDA are already high when SB state machine activates +} + + +void b200_slfifo_mode_gpio_config(void) { + CyU3PGpioSimpleConfig_t gpio_config; + + //b200_enable_fpga_sb_gpio(CyFalse); + + //CyU3PGpioDeInit(); + + b200_set_io_matrix(CyFalse); + + //b200_gpio_init(CyFalse); // This now done once during startup + + //////////////////////////////////// + + /* GPIO[0:32] must be set with the DeviceOverride function, instead of the + * SimpleEn array configuration. */ + CyU3PDeviceGpioOverride(GPIO_FPGA_RESET, CyTrue); + CyU3PDeviceGpioOverride(GPIO_DONE, CyTrue); + CyU3PDeviceGpioOverride(GPIO_FX3_SCLK, CyTrue); + CyU3PDeviceGpioOverride(GPIO_FX3_CE, CyTrue); + CyU3PDeviceGpioOverride(GPIO_FX3_MISO, CyTrue); + CyU3PDeviceGpioOverride(GPIO_FX3_MOSI, CyTrue); + + /* Configure GPIOs: + * Outputs: + * driveLowEn = True + * driveHighEn = True + * inputEn = False + * Inputs: + * driveLowEn = False + * driveHighEn = False + * outValue = Ignored + */ + gpio_config.outValue = CyFalse; + gpio_config.driveLowEn = CyTrue; + gpio_config.driveHighEn = CyTrue; + gpio_config.inputEn = CyFalse; + gpio_config.intrMode = CY_U3P_GPIO_NO_INTR; + + CyU3PGpioSetSimpleConfig(GPIO_FPGA_RESET, &gpio_config); + CyU3PGpioSetSimpleConfig(GPIO_SHDN_SW, &gpio_config); + CyU3PGpioSetSimpleConfig(GPIO_FX3_SCLK, &gpio_config); + CyU3PGpioSetSimpleConfig(GPIO_FX3_CE, &gpio_config); + CyU3PGpioSetSimpleConfig(GPIO_FX3_MOSI, &gpio_config); + + /* Reconfigure the GPIO configure struct for inputs that do NOT require + * interrupts attached to them. */ + gpio_config.outValue = CyFalse; + gpio_config.inputEn = CyTrue; + gpio_config.driveLowEn = CyFalse; + gpio_config.driveHighEn = CyFalse; + gpio_config.intrMode = CY_U3P_GPIO_NO_INTR; + + CyU3PGpioSetSimpleConfig(GPIO_FX3_MISO, &gpio_config); + CyU3PGpioSetSimpleConfig(GPIO_AUX_PWR_ON, &gpio_config); + CyU3PGpioSetSimpleConfig(GPIO_PROGRAM_B, &gpio_config); + CyU3PGpioSetSimpleConfig(GPIO_INIT_B, &gpio_config); + CyU3PGpioSetSimpleConfig(GPIO_DONE, &gpio_config); + + /* Initialize GPIO output values. */ + CyU3PGpioSetValue(GPIO_FPGA_RESET, 0); + CyU3PGpioSetValue(GPIO_SHDN_SW, 1); + CyU3PGpioSetValue(GPIO_FX3_SCLK, 0); + CyU3PGpioSetValue(GPIO_FX3_CE, 1); + CyU3PGpioSetValue(GPIO_FX3_MOSI, 0); + + // Disabled here as only useful once FPGA has been programmed + //b200_enable_fpga_sb_gpio(CyTrue); + //b200_start_fpga_sb_gpio(); // Set up SB USART +} + + +/*! Initializes and configures USB, and DMA. + * + * This function creates and connects the USB endpoints, and sets up the DMA + * channels. After this is done, everything is 'running' on the FX3 chip, and + * ready to receive data from the host. */ +void b200_fw_start(void) { + msg("b200_fw_start"); + + CyU3PDmaChannelConfig_t dma_channel_config; + CyU3PEpConfig_t usb_endpoint_config; + CyU3PUSBSpeed_t usb_speed; + uint16_t max_packet_size = 0; + uint16_t data_buffer_count = 0; + uint16_t data_buffer_size = 0; + uint16_t data_buffer_size_to_host = 0; + uint16_t data_buffer_size_from_host = 0; + uint8_t num_packets_per_burst = 0; + CyU3PReturnStatus_t apiRetStatus = CY_U3P_SUCCESS; + + /* Based on the USB bus speed, configure the endpoint packet size + * and the DMA buffer size */ + usb_speed = CyU3PUsbGetSpeed(); + switch(usb_speed) { + case CY_U3P_FULL_SPEED: + case CY_U3P_HIGH_SPEED: + max_packet_size = 512; + data_buffer_count = g_config.dma_buffer_count; + data_buffer_size = g_config.dma_buffer_size; + g_vendor_req_buff_size = USB2_VREQ_BUF_SIZE; // Max 64 + num_packets_per_burst = USB2_PACKETS_PER_BURST; // 1 + + data_buffer_size_to_host = data_buffer_size_from_host = data_buffer_size; + + break; + + case CY_U3P_SUPER_SPEED: +//#ifdef PREVENT_LOW_POWER_MODE + apiRetStatus = CyU3PUsbLPMDisable(); // This still allows my laptop to sleep + + if (apiRetStatus != CY_U3P_SUCCESS) + msg("! LPMDisable failed (%d)", apiRetStatus); + else + msg("LPMDisable OK"); +//#endif // PREVENT_LOW_POWER_MODE + max_packet_size = 1024; // Per USB3 spec + + // SDK ver: total available buffer memory + // 1.2.3: 204KB + // 1.3.1: 188KB + + // These options should be ignored - data_buffer_count *MUST* be 1 + // They follow is kept for future testing + + // 1K + //data_buffer_count = 64; + //data_buffer_size = 1024; + + // 4K + //data_buffer_count = 8; + //data_buffer_size = 4096; + + // 8K + //data_buffer_count = 4; + //data_buffer_size = 4096*2; + + // 16K + //data_buffer_count = 2*2; + //data_buffer_size = 16384; // Default 16K + + // 32K + //data_buffer_count = 2; + //data_buffer_size = 16384*2; + + //data_buffer_count = 1; + //data_buffer_size = ((1 << 16) - 1); + //data_buffer_size = 16384; + //data_buffer_size -= (data_buffer_size % 1024); // Align to 1K boundary + + data_buffer_count = g_config.dma_buffer_count; + data_buffer_size = g_config.dma_buffer_size; + + data_buffer_size_to_host = data_buffer_size; + data_buffer_size_from_host = data_buffer_size; + + g_vendor_req_buff_size = USB3_VREQ_BUF_SIZE; // Max 512 + num_packets_per_burst = USB3_PACKETS_PER_BURST; // 8 + break; + + case CY_U3P_NOT_CONNECTED: + msg("! CY_U3P_NOT_CONNECTED"); + return; + + default: + return; + } + + msg("[DMA] to host: %d, from host: %d, depth: %d, burst size: %d", data_buffer_size_to_host, data_buffer_size_from_host, data_buffer_count, num_packets_per_burst); + +#ifdef ENABLE_MANUAL_DMA_XFER + msg("[DMA] Callback enabled"); + +#ifdef ENABLE_P2U_SUSP_EOP + msg("[DMA] P2U_SUSP_EOP enabled"); +#endif // ENABLE_P2U_SUSP_EOP +#ifdef ENABLE_MANUAL_DMA_XFER_FROM_HOST + msg("[DMA] Manual transfers from host"); +#endif // ENABLE_MANUAL_DMA_XFER_FROM_HOST +#ifdef ENABLE_MANUAL_DMA_XFER_TO_HOST + msg("[DMA] Manual transfers to host"); +#endif // ENABLE_MANUAL_DMA_XFER_TO_HOST +#ifdef ENABLE_DMA_BUFFER_PACKET_DEBUG + msg("[DMA] Packet debugging enabled"); +#endif // ENABLE_DMA_BUFFER_PACKET_DEBUG + +#else + msg("[DMA] AUTO transfer mode"); +#endif // ENABLE_MANUAL_DMA_XFER + + msg("[DMA] Transfer override: %s", (g_config.manual_dma ? "manual" : "auto")); + + /************************************************************************* + * Slave FIFO Data DMA Channel Configuration + *************************************************************************/ + + /* Wipe out any old config. */ + CyU3PMemSet((uint8_t *) &usb_endpoint_config, 0, \ + sizeof(usb_endpoint_config)); + + /* This is the configuration for the USB Producer and Consumer endpoints. + * + * The Producer endpoint is actually the endpoint on the FX3 that is + * sending data BACK to the host. This endpoint enumerates as the + * 'BULK IN' endpoint. + + * The Consumer endpoint is the endpoint on the FX3 that is + * receiving data from the host. This endpoint enumerates as the + * 'BULK OUT' endpoint. + * + * Note that this is opposite of what you might expect!. */ + usb_endpoint_config.enable = CyTrue; + usb_endpoint_config.epType = CY_U3P_USB_EP_BULK; + usb_endpoint_config.burstLen = num_packets_per_burst; + usb_endpoint_config.streams = 0; + usb_endpoint_config.pcktSize = max_packet_size; + + /* Configure the endpoints that we are using for slave FIFO transfers. */ + CyU3PSetEpConfig(DATA_ENDPOINT_PRODUCER, &usb_endpoint_config); + CyU3PSetEpConfig(DATA_ENDPOINT_CONSUMER, &usb_endpoint_config); + + /* Create a DMA AUTO channel for U2P transfer. + * DMA size is set based on the USB speed. */ + //dma_channel_config.size = data_buffer_size; + dma_channel_config.size = data_buffer_size_from_host; + dma_channel_config.count = data_buffer_count; + dma_channel_config.prodSckId = PRODUCER_DATA_SOCKET; + dma_channel_config.consSckId = DATA_TX_PPORT_SOCKET; + dma_channel_config.dmaMode = CY_U3P_DMA_MODE_BYTE; + dma_channel_config.notification = 0 | +#if defined(ENABLE_MANUAL_DMA_XFER) && defined(ENABLE_MANUAL_DMA_XFER_FROM_HOST) +CY_U3P_DMA_CB_XFER_CPLT | +CY_U3P_DMA_CB_SEND_CPLT | +CY_U3P_DMA_CB_RECV_CPLT | +CY_U3P_DMA_CB_PROD_EVENT | +CY_U3P_DMA_CB_CONS_EVENT | +CY_U3P_DMA_CB_ABORTED | +CY_U3P_DMA_CB_ERROR | +CY_U3P_DMA_CB_PROD_SUSP | +CY_U3P_DMA_CB_CONS_SUSP | +#endif // ENABLE_MANUAL_DMA_XFER + 0; + //if (g_config.manual_dma == 0) + // dma_channel_config.notification = 0; // Force all off is manual is disabled + dma_channel_config.cb = +#if defined(ENABLE_MANUAL_DMA_XFER) && defined(ENABLE_MANUAL_DMA_XFER_FROM_HOST) + from_host_dma_callback; +#else + NULL; +#endif // ENABLE_MANUAL_DMA_XFER + dma_channel_config.prodHeader = 0; + dma_channel_config.prodFooter = 0; + dma_channel_config.consHeader = 0; + dma_channel_config.prodAvailCount = 0; + + CyU3PDmaChannelCreate (&data_cons_to_prod_chan_handle, +#if defined(ENABLE_MANUAL_DMA_XFER) && defined(ENABLE_MANUAL_DMA_XFER_FROM_HOST) + (g_config.manual_dma ? /*CY_U3P_DMA_TYPE_AUTO_SIGNAL*/CY_U3P_DMA_TYPE_MANUAL : CY_U3P_DMA_TYPE_AUTO), +#else + CY_U3P_DMA_TYPE_AUTO, +#endif // ENABLE_MANUAL_DMA_XFER + &dma_channel_config); + + // By default these will adopt 'usb_endpoint_config.pcktSize' + //CyU3PSetEpPacketSize(DATA_ENDPOINT_PRODUCER, 16384); + //CyU3PSetEpPacketSize(DATA_ENDPOINT_CONSUMER, 16384); + + /* Create a DMA AUTO channel for P2U transfer. */ + dma_channel_config.size = data_buffer_size_to_host; + dma_channel_config.prodSckId = DATA_RX_PPORT_SOCKET; + dma_channel_config.consSckId = CONSUMER_DATA_SOCKET; + dma_channel_config.notification = 0 | +#if defined(ENABLE_MANUAL_DMA_XFER) && defined(ENABLE_MANUAL_DMA_XFER_TO_HOST) +CY_U3P_DMA_CB_XFER_CPLT | +CY_U3P_DMA_CB_SEND_CPLT | +CY_U3P_DMA_CB_RECV_CPLT | +CY_U3P_DMA_CB_PROD_EVENT | +CY_U3P_DMA_CB_CONS_EVENT | +CY_U3P_DMA_CB_ABORTED | +CY_U3P_DMA_CB_ERROR | +CY_U3P_DMA_CB_PROD_SUSP | +CY_U3P_DMA_CB_CONS_SUSP | +#endif // ENABLE_MANUAL_DMA_XFER +#if defined(ENABLE_MANUAL_DMA_XFER) && defined(ENABLE_P2U_SUSP_EOP) +CY_U3P_DMA_CB_CONS_SUSP | // For 'CyU3PDmaChannelSetSuspend' below +#endif // ENABLE_P2U_SUSP_EOP + 0; + //if (g_config.manual_dma == 0) + // dma_channel_config.notification = 0; // Force all off is manual is disabled + dma_channel_config.cb = +#if defined(ENABLE_MANUAL_DMA_XFER) && (defined(ENABLE_MANUAL_DMA_XFER_TO_HOST) || defined(ENABLE_P2U_SUSP_EOP)) + to_host_dma_callback; +#else + NULL; +#endif // ENABLE_MANUAL_DMA_XFER + CyU3PDmaChannelCreate (&data_prod_to_cons_chan_handle, +#if defined(ENABLE_MANUAL_DMA_XFER) && defined(ENABLE_MANUAL_DMA_XFER_TO_HOST) + (g_config.manual_dma ? /*CY_U3P_DMA_TYPE_AUTO_SIGNAL*/CY_U3P_DMA_TYPE_MANUAL : CY_U3P_DMA_TYPE_AUTO), +#else + CY_U3P_DMA_TYPE_AUTO, +#endif // ENABLE_MANUAL_DMA_XFER + &dma_channel_config); +#ifdef ENABLE_P2U_SUSP_EOP + CyU3PDmaChannelSetSuspend(&data_prod_to_cons_chan_handle, CY_U3P_DMA_SCK_SUSP_NONE, CY_U3P_DMA_SCK_SUSP_EOP); +#endif // ENABLE_P2U_SUSP_EOP + /* Flush the Endpoint memory */ + CyU3PUsbFlushEp(DATA_ENDPOINT_PRODUCER); + CyU3PUsbFlushEp(DATA_ENDPOINT_CONSUMER); + + /* Set DMA channel transfer size. */ + CyU3PDmaChannelSetXfer(&data_cons_to_prod_chan_handle, DMA_SIZE_INFINITE); + CyU3PDmaChannelSetXfer(&data_prod_to_cons_chan_handle, DMA_SIZE_INFINITE); + + + /************************************************************************* + * Slave FIFO Control DMA Channel Configuration + *************************************************************************/ + + /* Wipe out any old config. */ + CyU3PMemSet((uint8_t *) &usb_endpoint_config, 0, \ + sizeof(usb_endpoint_config)); + + /* This is the configuration for the USB Producer and Consumer endpoints. + * + * The Producer endpoint is actually the endpoint on the FX3 that is + * sending data BACK to the host. This endpoint enumerates as the + * 'BULK IN' endpoint. + + * The Consumer endpoint is the endpoint on the FX3 that is + * receiving data from the host. This endpoint enumerates as the + * 'BULK OUT' endpoint. + * + * Note that this is opposite of what you might expect!. */ + usb_endpoint_config.enable = CyTrue; + usb_endpoint_config.epType = CY_U3P_USB_EP_BULK; + usb_endpoint_config.burstLen = num_packets_per_burst; + usb_endpoint_config.streams = 0; + usb_endpoint_config.pcktSize = max_packet_size; + + /* Configure the endpoints that we are using for slave FIFO transfers. */ + CyU3PSetEpConfig(CTRL_ENDPOINT_PRODUCER, &usb_endpoint_config); + CyU3PSetEpConfig(CTRL_ENDPOINT_CONSUMER, &usb_endpoint_config); + + /* Create a DMA AUTO channel for U2P transfer. + * DMA size is set based on the USB speed. */ + dma_channel_config.size = max_packet_size; + dma_channel_config.count = 2; + dma_channel_config.prodSckId = PRODUCER_CTRL_SOCKET; + dma_channel_config.consSckId = CTRL_COMM_PPORT_SOCKET; + dma_channel_config.dmaMode = CY_U3P_DMA_MODE_BYTE; + dma_channel_config.notification = 0; + dma_channel_config.cb = NULL; + dma_channel_config.prodHeader = 0; + dma_channel_config.prodFooter = 0; + dma_channel_config.consHeader = 0; + dma_channel_config.prodAvailCount = 0; + + CyU3PDmaChannelCreate (&ctrl_cons_to_prod_chan_handle, + CY_U3P_DMA_TYPE_AUTO, &dma_channel_config); + + /* Create a DMA AUTO channel for P2U transfer. */ + dma_channel_config.prodSckId = CTRL_RESP_PPORT_SOCKET; + dma_channel_config.consSckId = CONSUMER_CTRL_SOCKET; + dma_channel_config.cb = NULL; + CyU3PDmaChannelCreate (&ctrl_prod_to_cons_chan_handle, + CY_U3P_DMA_TYPE_AUTO, &dma_channel_config); + + /* Flush the Endpoint memory */ + CyU3PUsbFlushEp(CTRL_ENDPOINT_PRODUCER); + CyU3PUsbFlushEp(CTRL_ENDPOINT_CONSUMER); + + /* Set DMA channel transfer size. */ + CyU3PDmaChannelSetXfer(&ctrl_cons_to_prod_chan_handle, DMA_SIZE_INFINITE); + CyU3PDmaChannelSetXfer(&ctrl_prod_to_cons_chan_handle, DMA_SIZE_INFINITE); + + //CyU3PUsbEnableEPPrefetch(); // To address USB_EVENT_EP_UNDERRUN on EP 0x86 (didn't fix it though) + + /* Update the application status flag. */ + g_app_running = CyTrue; +} + + +/*! This callback is invoked when the FX3 detects a USB event. + * + * We currently handle SETCONF, RESET, and DISCONNECT. + * + * We are _not_ handling SUSPEND or CONNECT. + */ +void event_usb_callback (CyU3PUsbEventType_t event_type, uint16_t event_data) { + + switch(event_type) { + case CY_U3P_USB_EVENT_SETCONF: + msg("USB_EVENT_SETCONF (#%d)", event_data); //evData provides the configuration number that is selected by the host. + if(g_app_running) { + b200_fw_stop(); + } + + b200_fw_start(); + break; + + case CY_U3P_USB_EVENT_RESET: + case CY_U3P_USB_EVENT_DISCONNECT: + if (event_type == CY_U3P_USB_EVENT_RESET) + msg("USB_EVENT_RESET"); + else + msg("USB_EVENT_DISCONNECT"); + if(g_app_running) { + b200_fw_stop(); + } + break; + + case CY_U3P_USB_EVENT_CONNECT: + msg("USB_EVENT_CONNECT"); + break; + + case CY_U3P_USB_EVENT_SUSPEND: + msg("USB_EVENT_SUSPEND"); + break; + + case CY_U3P_USB_EVENT_RESUME: // Known issue: this is called repeatedly after a resume + //msg("USB_EVENT_RESUME"); + g_counters.resume_count++; // Not locked + break; + + case CY_U3P_USB_EVENT_SPEED: + msg("USB_EVENT_SPEED"); + break; + + case CY_U3P_USB_EVENT_SETINTF: + msg("USB_EVENT_SETINTF"); + break; + + case CY_U3P_USB_EVENT_SET_SEL: + msg("USB_EVENT_SET_SEL"); + break; + + case CY_U3P_USB_EVENT_SOF_ITP: // CyU3PUsbEnableITPEvent + //msg("USB_EVENT_SOF_ITP"); + break; + + case CY_U3P_USB_EVENT_EP0_STAT_CPLT: + //msg("USB_EVENT_EP0_STAT_CPLT"); // Occurs each time there's a control transfer + break; + + case CY_U3P_USB_EVENT_VBUS_VALID: + msg("USB_EVENT_VBUS_VALID"); + break; + + case CY_U3P_USB_EVENT_VBUS_REMOVED: + msg("USB_EVENT_VBUS_REMOVED"); + break; + + case CY_U3P_USB_EVENT_HOST_CONNECT: + msg("USB_EVENT_HOST_CONNECT"); + break; + + case CY_U3P_USB_EVENT_HOST_DISCONNECT: + msg("USB_EVENT_HOST_DISCONNECT"); + break; + + case CY_U3P_USB_EVENT_OTG_CHANGE: + msg("USB_EVENT_OTG_CHANGE"); + break; + + case CY_U3P_USB_EVENT_OTG_VBUS_CHG: + msg("USB_EVENT_OTG_VBUS_CHG"); + break; + + case CY_U3P_USB_EVENT_OTG_SRP: + msg("USB_EVENT_OTG_SRP"); + break; + + case CY_U3P_USB_EVENT_EP_UNDERRUN: // See SDK 1.3 known issues 17 if this happens (can probably ignore first logged occurence) + LOCK(g_counters_lock); + ++g_counters.usb_ep_underrun_count; + UNLOCK(g_counters_lock); + + msg("! USB_EVENT_EP_UNDERRUN on EP 0x%02x", event_data); + break; + + case CY_U3P_USB_EVENT_LNK_RECOVERY: + msg("USB_EVENT_LNK_RECOVERY"); + break; +#if (CYFX_VERSION_MAJOR >= 1) && (CYFX_VERSION_MINOR >= 3) + case CY_U3P_USB_EVENT_USB3_LNKFAIL: + msg("USB_EVENT_USB3_LNKFAIL"); + break; + + case CY_U3P_USB_EVENT_SS_COMP_ENTRY: + msg("USB_EVENT_SS_COMP_ENTRY"); + break; + + case CY_U3P_USB_EVENT_SS_COMP_EXIT: + msg("USB_EVENT_SS_COMP_EXIT"); + break; +#endif // (CYFX_VERSION_MAJOR >= 1) && (CYFX_VERSION_MINOR >= 3) + + default: + msg("! Unhandled USB event"); + break; + } +} + + +/*! Callback function that is invoked when a USB setup event occurs. + * + * We aren't actually handling the USB setup ourselves, but rather letting the + * USB driver take care of it since the default options work fine. The purpose + * of this function is to register that the event happened at all, so that the + * application thread knows it can proceed. + * + * This function is also responsible for receiving vendor requests, and triggering + * the appropriate RTOS event to wake up the vendor request handler thread. + */ +CyBool_t usb_setup_callback(uint32_t data0, uint32_t data1) { + STATIC_SAVER uint8_t bRequestType, bRequest, bType, bTarget, i2cAddr; + STATIC_SAVER uint16_t wValue, wIndex, wLength; + + CyBool_t handled = CyFalse; + + /* Decode the fields from the setup request. */ + bRequestType = (uint8_t)(data0 & CY_U3P_USB_REQUEST_TYPE_MASK); + bType = (uint8_t)(bRequestType & CY_U3P_USB_TYPE_MASK); + bTarget = (uint8_t)(bRequestType & CY_U3P_USB_TARGET_MASK); + bRequest = (uint8_t)((data0 & CY_U3P_USB_REQUEST_MASK) >> CY_U3P_USB_REQUEST_POS); + wValue = (uint16_t)((data0 & CY_U3P_USB_VALUE_MASK) >> CY_U3P_USB_VALUE_POS); + wIndex = (uint16_t)((data1 & CY_U3P_USB_INDEX_MASK) >> CY_U3P_USB_INDEX_POS); + wLength = (uint16_t)((data1 & CY_U3P_USB_LENGTH_MASK) >> CY_U3P_USB_LENGTH_POS); + + if(bType == CY_U3P_USB_STANDARD_RQT) { + /* Handle SET_FEATURE(FUNCTION_SUSPEND) and CLEAR_FEATURE(FUNCTION_SUSPEND) + * requests here. It should be allowed to pass if the device is in configured + * state and failed otherwise. */ + if((bTarget == CY_U3P_USB_TARGET_INTF) \ + && ((bRequest == CY_U3P_USB_SC_SET_FEATURE) \ + || (bRequest == CY_U3P_USB_SC_CLEAR_FEATURE)) && (wValue == 0)) { + + if(g_app_running) { + CyU3PUsbAckSetup(); + msg("ACK set/clear"); + } else { + CyU3PUsbStall(0, CyTrue, CyFalse); + msg("! STALL set/clear"); + } + + handled = CyTrue; + } + + /* Handle Microsoft OS String Descriptor request. */ + if((bTarget == CY_U3P_USB_TARGET_DEVICE) \ + && (bRequest == CY_U3P_USB_SC_GET_DESCRIPTOR) \ + && (wValue == ((CY_U3P_USB_STRING_DESCR << 8) | 0xEE))) { + /* Make sure we do not send more data than requested. */ + const uint8_t* product_desc = get_product_string_descriptor( + get_pid(&eeprom_read)); + if (wLength > product_desc[0]) + { + wLength = product_desc[0]; + } + + //msg("MS string desc"); + + CyU3PUsbSendEP0Data(wLength, ((uint8_t*)product_desc)); + handled = CyTrue; + } + + /* CLEAR_FEATURE request for endpoint is always passed to the setup callback + * regardless of the enumeration model used. When a clear feature is received, + * the previous transfer has to be flushed and cleaned up. This is done at the + * protocol level. Since this is just a loopback operation, there is no higher + * level protocol. So flush the EP memory and reset the DMA channel associated + * with it. If there are more than one EP associated with the channel reset both + * the EPs. The endpoint stall and toggle / sequence number is also expected to be + * reset. Return CyFalse to make the library clear the stall and reset the endpoint + * toggle. Or invoke the CyU3PUsbStall (ep, CyFalse, CyTrue) and return CyTrue. + * Here we are clearing the stall. */ + if((bTarget == CY_U3P_USB_TARGET_ENDPT) \ + && (bRequest == CY_U3P_USB_SC_CLEAR_FEATURE) + && (wValue == CY_U3P_USBX_FS_EP_HALT)) { + if(g_app_running) { + if(wIndex == DATA_ENDPOINT_PRODUCER) { + CyU3PDmaChannelReset(&data_cons_to_prod_chan_handle); + CyU3PUsbFlushEp(DATA_ENDPOINT_PRODUCER); + CyU3PUsbResetEp(DATA_ENDPOINT_PRODUCER); + CyU3PDmaChannelSetXfer(&data_cons_to_prod_chan_handle, \ + DMA_SIZE_INFINITE); + CyU3PUsbStall(wIndex, CyFalse, CyTrue); + handled = CyTrue; + CyU3PUsbAckSetup(); + + msg("Clear DATA_ENDPOINT_PRODUCER"); + } + + if(wIndex == DATA_ENDPOINT_CONSUMER) { + CyU3PDmaChannelReset(&data_prod_to_cons_chan_handle); + CyU3PUsbFlushEp(DATA_ENDPOINT_CONSUMER); + CyU3PUsbResetEp(DATA_ENDPOINT_CONSUMER); + CyU3PDmaChannelSetXfer(&data_prod_to_cons_chan_handle, \ + DMA_SIZE_INFINITE); + CyU3PUsbStall(wIndex, CyFalse, CyTrue); + handled = CyTrue; + CyU3PUsbAckSetup(); + + msg("Clear DATA_ENDPOINT_CONSUMER"); + } + + if(wIndex == CTRL_ENDPOINT_PRODUCER) { + CyU3PDmaChannelReset(&ctrl_cons_to_prod_chan_handle); + CyU3PUsbFlushEp(CTRL_ENDPOINT_PRODUCER); + CyU3PUsbResetEp(CTRL_ENDPOINT_PRODUCER); + CyU3PDmaChannelSetXfer(&ctrl_cons_to_prod_chan_handle, \ + DMA_SIZE_INFINITE); + CyU3PUsbStall(wIndex, CyFalse, CyTrue); + handled = CyTrue; + CyU3PUsbAckSetup(); + + msg("Clear CTRL_ENDPOINT_PRODUCER"); + } + + if(wIndex == CTRL_ENDPOINT_CONSUMER) { + CyU3PDmaChannelReset(&ctrl_prod_to_cons_chan_handle); + CyU3PUsbFlushEp(CTRL_ENDPOINT_CONSUMER); + CyU3PUsbResetEp(CTRL_ENDPOINT_CONSUMER); + CyU3PDmaChannelSetXfer(&ctrl_prod_to_cons_chan_handle, \ + DMA_SIZE_INFINITE); + CyU3PUsbStall(wIndex, CyFalse, CyTrue); + handled = CyTrue; + CyU3PUsbAckSetup(); + + msg("Clear CTRL_ENDPOINT_CONSUMER"); + } + } + } + } + /* This must be & and not == so that we catch VREQs that are both 'IN' and + * 'OUT' in direction. */ + else if(bRequestType & CY_U3P_USB_VENDOR_RQT) { + + handled = CyTrue; + uint16_t read_count = 0; + + switch(bRequest) { + case B200_VREQ_BITSTREAM_START: { + CyU3PUsbGetEP0Data(1, g_vendor_req_buffer, &read_count); + + g_fpga_programming_write_count = 0; + + CyU3PEventSet(&g_event_usb_config, EVENT_BITSTREAM_START, \ + CYU3P_EVENT_OR); + break; + } + + case B200_VREQ_BITSTREAM_DATA: { + CyU3PUsbGetEP0Data(g_vendor_req_buff_size, g_vendor_req_buffer, \ + &read_count); + + if (g_fx3_state == STATE_CONFIGURING_FPGA) { + ++g_fpga_programming_write_count; + CyU3PSpiTransmitWords(g_vendor_req_buffer, read_count); + CyU3PThreadSleep(1); // Newer controllers don't have an issue when this short sleep here + } + break; + } + + case B200_VREQ_BITSTREAM_DATA_FILL: { + CyU3PUsbGetEP0Data(g_vendor_req_buff_size, g_vendor_req_buffer, &g_vendor_req_read_count); + break; + } + + case B200_VREQ_BITSTREAM_DATA_COMMIT: { + /*CyU3PReturnStatus_t*/int spi_result = -1; + if (g_fx3_state == STATE_CONFIGURING_FPGA) { + ++g_fpga_programming_write_count; + spi_result = CyU3PSpiTransmitWords(g_vendor_req_buffer, g_vendor_req_read_count); + CyU3PThreadSleep(1); // 20 MHz, 512 bytes + } + CyU3PUsbSendEP0Data(sizeof(spi_result), (uint8_t*)&spi_result); + break; + } + + case B200_VREQ_FPGA_CONFIG: { + CyU3PUsbGetEP0Data(1, g_vendor_req_buffer, &read_count); + + CyU3PEventSet(&g_event_usb_config, EVENT_FPGA_CONFIG, CYU3P_EVENT_OR); + break; + } + + case B200_VREQ_GET_COMPAT: { + CyU3PUsbSendEP0Data(/*2*/sizeof(compat_num), compat_num); + break; + } + + case B200_VREQ_SET_FPGA_HASH: { + CyU3PUsbGetEP0Data(4, fpga_hash, &read_count); + break; + } + + case B200_VREQ_GET_FPGA_HASH: { + CyU3PUsbSendEP0Data(/*4*/sizeof(fpga_hash), fpga_hash); + break; + } + + case B200_VREQ_SET_FW_HASH: { + CyU3PUsbGetEP0Data(4, fw_hash, &read_count); + break; + } + + case B200_VREQ_GET_FW_HASH: { + CyU3PUsbSendEP0Data(/*4*/sizeof(fw_hash), fw_hash); + break; + } + + case B200_VREQ_LOOP_CODE: { + CyU3PUsbSendEP0Data(g_vendor_req_buff_size, g_vendor_req_buffer); + break; + } + + case B200_VREQ_GET_LOG: { + LOCK(g_log_lock); + + if (log_buffer_len == 0) { + log_buffer[0] = '\0'; + CyU3PUsbSendEP0Data(1, (uint8_t*)log_buffer); + //CyU3PUsbSendEP0Data(0, NULL); + //CyU3PUsbAckSetup(); + } + else if (log_buffer_idx == 0) + CyU3PUsbSendEP0Data(log_buffer_len, (uint8_t*)log_buffer); + else { + int len1 = min(LOG_BUFFER_SIZE - log_buffer_idx, log_buffer_len); + memcpy(log_contiguous_buffer, log_buffer + log_buffer_idx, len1); + //if ((log_buffer_idx + log_buffer_len) > LOG_BUFFER_SIZE) + if (len1 < log_buffer_len) + memcpy(log_contiguous_buffer + len1, log_buffer, log_buffer_len - len1); + CyU3PUsbSendEP0Data(log_buffer_len, (uint8_t*)log_contiguous_buffer); + } + + // FIXME: Necessary? Not used in the other ones + //CyU3PUsbSendEP0Data(0, NULL); // Send ZLP since previous send has resulted in an integral # of packets + + log_reset(); + + UNLOCK(g_log_lock); + + //log_reset(); + + break; + } + + case B200_VREQ_GET_COUNTERS: { + LOCK(g_counters_lock); + + CyU3PUsbSendEP0Data(sizeof(COUNTERS), (uint8_t*)&g_counters); + + counters_auto_reset(); + + UNLOCK(g_counters_lock); + + //counters_auto_reset(); + + break; + } + + case B200_VREQ_CLEAR_COUNTERS: { + CyU3PUsbAckSetup(); + //CyU3PUsbGetEP0Data(g_vendor_req_buff_size, g_vendor_req_buffer, &read_count); // Dummy + + counters_dma_reset(); + + break; + } + + case B200_VREQ_GET_USB_EVENT_LOG: { + uint16_t idx = CyU3PUsbGetEventLogIndex(); // Current *write* pointer + if (idx > (USB_EVENT_LOG_SIZE-1)) { + msg("! USB event log idx = %i", (int)idx); + break; + } + // Assuming logging won't wrap around between get calls (i.e. buffer should be long enough) + uint16_t len = 0; + if (idx < g_last_usb_event_log_index) { + uint16_t len1 = (USB_EVENT_LOG_SIZE - g_last_usb_event_log_index); + if (len1 > (USB_EVENT_LOG_SIZE-1)) { + msg("! USB event log len 2.1 = %i", (int)len1); + break; + } + len = len1 + idx; + if (len > (USB_EVENT_LOG_SIZE-1)) { + msg("! USB event log len 2.2 = %i", (int)len); + break; + } + memcpy(g_usb_event_log_contiguous_buf, g_usb_event_log + g_last_usb_event_log_index, len1); + memcpy(g_usb_event_log_contiguous_buf + len1, g_usb_event_log, idx); + //msg("USB event log [2] %i %i", (int)len1, (int)len); + } else { + len = idx - g_last_usb_event_log_index; + if (len > (USB_EVENT_LOG_SIZE-1)) { + msg("! USB event log len 1 = %i", (int)len); + break; + } + if (len > 0) { // ZLP should be OK + memcpy(g_usb_event_log_contiguous_buf, g_usb_event_log + g_last_usb_event_log_index, len); + //msg("USB event log [1] %i", (int)len); + } + } + + //if (len > 0) // Send a ZLP, otherwise it'll timeout + CyU3PUsbSendEP0Data(len, g_usb_event_log_contiguous_buf); + + g_last_usb_event_log_index = idx; + break; + } + + case B200_VREQ_SET_CONFIG: { + CyU3PUsbGetEP0Data(sizeof(CONFIG_MOD), (uint8_t*)g_vendor_req_buffer, &read_count); + if (read_count == sizeof(CONFIG_MOD)) { + memcpy(&g_config_mod, g_vendor_req_buffer, sizeof(CONFIG_MOD)); + CyU3PEventSet(&g_event_usb_config, EVENT_RE_ENUM, CYU3P_EVENT_OR); + } + break; + } + + case B200_VREQ_GET_CONFIG: { + CyU3PUsbSendEP0Data(sizeof(g_config), (uint8_t*)&g_config); + break; + } + + case B200_VREQ_WRITE_SB: { + CyU3PUsbGetEP0Data(g_vendor_req_buff_size, (uint8_t*)g_vendor_req_buffer, &read_count); +#ifdef ENABLE_FPGA_SB + uint16_t i; + LOCK(g_suart_lock); + for (i = 0; i < read_count; ++i) + sb_write(SUART_TXCHAR, g_vendor_req_buffer[i]); + UNLOCK(g_suart_lock); + + msg("Wrote %d SB chars", read_count); +#else + msg("SB is disabled"); +#endif // ENABLE_FPGA_SB + break; + } + + case B200_VREQ_SET_SB_BAUD_DIV: { + uint16_t div; + CyU3PUsbGetEP0Data(sizeof(div), (uint8_t*)&div, &read_count); + + if (read_count == sizeof(div)) { +#ifdef ENABLE_FPGA_SB + LOCK(g_suart_lock); + sb_write(SUART_CLKDIV, div); + UNLOCK(g_suart_lock); + msg("SUART_CLKDIV = %d", div); + /*g_fpga_sb_uart_div*/g_config.sb_baud_div = div; // Store for GPIF (FPGA) reset +#else + msg("SB is disabled"); +#endif // ENABLE_FPGA_SB + } + else + msg("! SUART_CLKDIV received %d bytes", read_count); + + break; + } + + case B200_VREQ_FLUSH_DATA_EPS: { + //msg("Flushing data EPs..."); + + //CyU3PUsbAckSetup(); + + //CyU3PUsbResetEndpointMemories(); + + // From host + //CyU3PDmaChannelReset(&data_cons_to_prod_chan_handle); + //CyU3PUsbFlushEp(DATA_ENDPOINT_PRODUCER); + //CyU3PUsbResetEp(DATA_ENDPOINT_PRODUCER); + //CyU3PDmaChannelSetXfer(&data_cons_to_prod_chan_handle, DMA_SIZE_INFINITE); + + //CyU3PDmaSocketDisable(DATA_RX_PPORT_SOCKET); + + //CyU3PDmaChannelReset(&data_cons_to_prod_chan_handle); + if (CyU3PDmaChannelReset(&data_prod_to_cons_chan_handle) != CY_U3P_SUCCESS) + { + msg("! CyU3PDmaChannelReset"); + } + //CyU3PUsbFlushEp(DATA_ENDPOINT_PRODUCER); + CyU3PUsbFlushEp(DATA_ENDPOINT_CONSUMER); + //CyU3PUsbResetEp(DATA_ENDPOINT_PRODUCER); +// CyU3PUsbResetEp(DATA_ENDPOINT_CONSUMER); + //CyU3PUsbStall(DATA_ENDPOINT_CONSUMER, CyFalse, CyTrue); + //CyU3PDmaChannelSetXfer(&data_cons_to_prod_chan_handle, DMA_SIZE_INFINITE); + //CyU3PDmaSocketEnable(DATA_RX_PPORT_SOCKET); + CyU3PDmaChannelSetXfer(&data_prod_to_cons_chan_handle, DMA_SIZE_INFINITE); + + //CyU3PUsbResetEndpointMemories(); + + // To host + //CyU3PDmaChannelReset(&data_prod_to_cons_chan_handle); + //CyU3PUsbFlushEp(DATA_ENDPOINT_CONSUMER); + //CyU3PUsbResetEp(DATA_ENDPOINT_CONSUMER); + //CyU3PDmaChannelSetXfer(&data_prod_to_cons_chan_handle, DMA_SIZE_INFINITE); + + CyU3PUsbAckSetup(); + + break; + } + + case B200_VREQ_EEPROM_WRITE: { + i2cAddr = 0xA0 | ((wValue & 0x0007) << 1); + CyU3PUsbGetEP0Data(((wLength + 15) & 0xFFF0), g_vendor_req_buffer, NULL); + + CyFxUsbI2cTransfer (wIndex, i2cAddr, wLength, + g_vendor_req_buffer, CyFalse); + break; + } + + case B200_VREQ_EEPROM_READ: { + i2cAddr = 0xA0 | ((wValue & 0x0007) << 1); + CyU3PMemSet (g_vendor_req_buffer, 0, sizeof (g_vendor_req_buffer)); + CyFxUsbI2cTransfer (wIndex, i2cAddr, wLength, + g_vendor_req_buffer, CyTrue); + + CyU3PUsbSendEP0Data(wLength, g_vendor_req_buffer); + break; + } + + case B200_VREQ_TOGGLE_FPGA_RESET: { + CyU3PUsbGetEP0Data(g_vendor_req_buff_size, g_vendor_req_buffer, \ + &read_count); + + /* CyBool_t value = (g_vendor_req_buffer[0] & 0x01) ? CyTrue : CyFalse; + CyU3PGpioSetValue(GPIO_FPGA_RESET, value); */ + break; + } + + case B200_VREQ_TOGGLE_GPIF_RESET: { + CyU3PUsbGetEP0Data(g_vendor_req_buff_size, g_vendor_req_buffer, \ + &read_count); + + reset_gpif(); + break; + } + + case B200_VREQ_RESET_DEVICE: { + CyU3PUsbGetEP0Data(4, g_vendor_req_buffer, &read_count); + + CyU3PDeviceReset(CyFalse); // FIXME: If CyTrue, this will *not* call static initialisers for global variables - must do this manually + break; + } + + case B200_VREQ_GET_USB_SPEED: { + CyU3PUSBSpeed_t usb_speed = CyU3PUsbGetSpeed(); + switch(usb_speed) { + case CY_U3P_SUPER_SPEED: + g_vendor_req_buffer[0] = 3; + break; + + case CY_U3P_FULL_SPEED: + case CY_U3P_HIGH_SPEED: + g_vendor_req_buffer[0] = 2; + break; + + default: + g_vendor_req_buffer[0] = 1; + break; + } + + CyU3PUsbSendEP0Data(1, g_vendor_req_buffer); + break; + } + + case B200_VREQ_GET_STATUS: { + g_vendor_req_buffer[0] = g_fx3_state; + CyU3PUsbSendEP0Data(1, g_vendor_req_buffer); + break; + } + + default: + msg("! Unknown VREQ %02X", (uint32_t)bRequest); + handled = CyFalse; + } + + /* After processing the vendor request, flush the endpoints. */ + CyU3PUsbFlushEp(VREQ_ENDPOINT_PRODUCER); + CyU3PUsbFlushEp(VREQ_ENDPOINT_CONSUMER); + } + + return handled; +} + + +/* Callback function to handle LPM requests from the USB 3.0 host. This function + * is invoked by the API whenever a state change from U0 -> U1 or U0 -> U2 + * happens. + * + * If we return CyTrue from this function, the FX3 device is retained + * in the low power state. If we return CyFalse, the FX3 device immediately + * tries to trigger an exit back to U0. + */ +CyBool_t lpm_request_callback(CyU3PUsbLinkPowerMode link_mode) { + msg("! lpm_request_callback = %i", link_mode); + return +//#ifdef PREVENT_LOW_POWER_MODE + CyFalse; // This still allows my laptop to sleep +//#else +// CyTrue; +//#endif // PREVENT_LOW_POWER_MODE +} + + +/* Callback function to check for PIB ERROR*/ +void gpif_error_cb(CyU3PPibIntrType cbType, uint16_t cbArg) +{ + if (cbType==CYU3P_PIB_INTR_ERROR) + { + switch (CYU3P_GET_PIB_ERROR_TYPE(cbArg)) + { + case CYU3P_PIB_ERR_NONE: + break; + case CYU3P_PIB_ERR_THR0_WR_OVERRUN: + msg("CYU3P_PIB_ERR_THR0_WR_OVERRUN"); + break; + case CYU3P_PIB_ERR_THR1_WR_OVERRUN: + msg("CYU3P_PIB_ERR_THR1_WR_OVERRUN"); + break; + case CYU3P_PIB_ERR_THR2_WR_OVERRUN: + msg("CYU3P_PIB_ERR_THR2_WR_OVERRUN"); + break; + case CYU3P_PIB_ERR_THR3_WR_OVERRUN: + msg("CYU3P_PIB_ERR_THR3_WR_OVERRUN"); + break; + case CYU3P_PIB_ERR_THR0_RD_UNDERRUN: + msg("CYU3P_PIB_ERR_THR0_RD_UNDERRUN"); + break; + case CYU3P_PIB_ERR_THR1_RD_UNDERRUN: + msg("CYU3P_PIB_ERR_THR1_RD_UNDERRUN"); + break; + case CYU3P_PIB_ERR_THR2_RD_UNDERRUN: + msg("CYU3P_PIB_ERR_THR2_RD_UNDERRUN"); + break; + case CYU3P_PIB_ERR_THR3_RD_UNDERRUN: + msg("CYU3P_PIB_ERR_THR3_RD_UNDERRUN"); + break; + case CYU3P_PIB_ERR_THR0_ADAP_UNDERRUN: + msg("CYU3P_PIB_ERR_THR0_ADAP_UNDERRUN"); + break; + case CYU3P_PIB_ERR_THR1_ADAP_OVERRUN: + msg("CYU3P_PIB_ERR_THR1_ADAP_OVERRUN"); + break; + // FIXME: Other threads + case CYU3P_PIB_ERR_THR1_SCK_INACTIVE: + //msg("CYU3P_PIB_ERR_THR1_SCK_INACTIVE"); + ++g_counters.pib_counters[1].socket_inactive; // UNSYNC'd + break; + default: + msg("Unknown CYU3P_PIB_ERR %i", CYU3P_GET_PIB_ERROR_TYPE(cbArg)); + break; + } + + switch (CYU3P_GET_GPIF_ERROR_TYPE(cbArg)) + { + case CYU3P_GPIF_ERR_NONE: /**< No GPIF state machine errors. */ + //msg("CYU3P_GPIF_ERR_NONE"); + break; + case CYU3P_GPIF_ERR_INADDR_OVERWRITE: /**< Content of INGRESS_ADDR register is overwritten before read. */ + msg("CYU3P_GPIF_ERR_INADDR_OVERWRITE"); + break; + case CYU3P_GPIF_ERR_EGADDR_INVALID: /**< Attempt to read EGRESS_ADDR register before it is written to. */ + msg("CYU3P_GPIF_ERR_EGADDR_INVALID"); + break; + case CYU3P_GPIF_ERR_DATA_READ_ERR: /**< Read from DMA data thread which is not ready. */ + msg("CYU3P_GPIF_ERR_DATA_READ_ERR"); + break; + case CYU3P_GPIF_ERR_DATA_WRITE_ERR: /**< Write to DMA data thread which is not ready. */ + msg("CYU3P_GPIF_ERR_DATA_WRITE_ERR"); + break; + case CYU3P_GPIF_ERR_ADDR_READ_ERR: /**< Read from DMA address thread which is not ready. */ + msg("CYU3P_GPIF_ERR_ADDR_READ_ERR"); + break; + case CYU3P_GPIF_ERR_ADDR_WRITE_ERR: /**< Write to DMA address thread which is not ready. */ + msg("CYU3P_GPIF_ERR_ADDR_WRITE_ERR"); + break; + case CYU3P_GPIF_ERR_INVALID_STATE: /**< GPIF state machine has reached an invalid state. */ + //msg("CYU3P_GPIF_ERR_INVALID_STATE"); + ++g_counters.invalid_gpif_state; // UNSYNC'd + break; + default: + msg("Unknown CYU3P_GPIF_ERR %i", CYU3P_GET_GPIF_ERROR_TYPE(cbArg)); + break; + } + } +} + + +void GpifStateChangeCb(uint8_t stateId) +{ + //msg("%d", stateId); + ++g_counters.state_transition_count; +} + + +/*! Initialize and start the GPIF state machine. + * + * This function starts the GPIF Slave FIFO state machine on the FX3. Because on + * of the GPIF pins is used for FPGA configuration, this cannot be done until + * after FPGA configuration is complete. */ +void b200_gpif_init(void) { + msg("b200_gpif_init"); + + CyU3PPibClock_t pib_clock_config; + + /* Initialize the p-port block; disable DLL for sync GPIF. */ + pib_clock_config.clkDiv = 2; + pib_clock_config.clkSrc = CY_U3P_SYS_CLK; + pib_clock_config.isHalfDiv = CyFalse; + pib_clock_config.isDllEnable = CyFalse; + if (CyU3PPibInit(CyTrue, &pib_clock_config) != CY_U3P_SUCCESS) + msg("! CyU3PPibInit"); + + /* Load the GPIF configuration for Slave FIFO sync mode. */ + if (CyU3PGpifLoad(&CyFxGpifConfig) != CY_U3P_SUCCESS) + msg("! CyU3PGpifLoad"); + + msg("GPIF loaded"); + + //CyU3PGpifRegisterSMIntrCallback(GpifStateChangeCb); + + /* Start the state machine. */ + //CyU3PGpifSMStart(RESET, ALPHA_RESET); + + /* Configure the watermarks for the slfifo-write buffers. */ + if (CyU3PGpifSocketConfigure(0, DATA_TX_PPORT_SOCKET, 5, CyFalse, 1) != CY_U3P_SUCCESS) + msg("! CyU3PGpifSocketConfigure 0"); + if (CyU3PGpifSocketConfigure(1, DATA_RX_PPORT_SOCKET, 6, CyFalse, 1) != CY_U3P_SUCCESS) + msg("! CyU3PGpifSocketConfigure 1"); + if (CyU3PGpifSocketConfigure(2, CTRL_COMM_PPORT_SOCKET, 5, CyFalse, 1) != CY_U3P_SUCCESS) + msg("! CyU3PGpifSocketConfigure 2"); + if (CyU3PGpifSocketConfigure(3, CTRL_RESP_PPORT_SOCKET, 6, CyFalse, 1) != CY_U3P_SUCCESS) + msg("! CyU3PGpifSocketConfigure 3"); + + //CyU3PGpifSMStart(RESET, ALPHA_RESET); + + /* Register a callback for notification of PIB interrupts*/ + CyU3PPibRegisterCallback(gpif_error_cb, CYU3P_PIB_INTR_ERROR); +} + +/*! Start and configure the FX3's SPI module. + * + * This module is used for programming the FPGA. After the FPGA is configured, + * the SPI module is disabled, as it cannot be used while we are using GPIF + * 32-bit mode. */ +CyU3PReturnStatus_t b200_spi_init(void) { + msg("b200_spi_init"); + + CyU3PSpiConfig_t spiConfig; + + /* Start the SPI module and configure the master. */ + CyU3PSpiInit(); + + /* Start the SPI master block. Run the SPI clock at 8MHz + * and configure the word length to 8 bits. Also configure + * the slave select using FW. */ + CyU3PMemSet ((uint8_t *)&spiConfig, 0, sizeof(spiConfig)); + spiConfig.isLsbFirst = CyFalse; + spiConfig.cpol = CyFalse; + spiConfig.cpha = CyFalse; + spiConfig.ssnPol = CyTrue; + spiConfig.leadTime = CY_U3P_SPI_SSN_LAG_LEAD_HALF_CLK; + spiConfig.lagTime = CY_U3P_SPI_SSN_LAG_LEAD_HALF_CLK; + spiConfig.ssnCtrl = CY_U3P_SPI_SSN_CTRL_FW; + spiConfig.clock = 20000000; + spiConfig.wordLen = 8; + + CyU3PReturnStatus_t res = CyU3PSpiSetConfig(&spiConfig, NULL); + + if (res != CY_U3P_SUCCESS) + msg("! CyU3PSpiSetConfig"); + + return res; +} + + +/*! Initialize the USB module of the FX3 chip. + * + * This function handles USB initialization, re-enumeration (and thus coming up + * as a USRP B200 device), configures USB endpoints and the DMA module. + */ +void b200_usb_init(void) { + //msg("b200_usb_init"); + + /* Initialize the I2C interface for the EEPROM of page size 64 bytes. */ + CyFxI2cInit(CY_FX_USBI2C_I2C_PAGE_SIZE); + + /* Start the USB system! */ + CyU3PUsbStart(); + + /* Register our USB Setup callback. The boolean parameter indicates whether + * or not we are using FX3's 'Fast Enumeration' mode, which relies on the + * USB driver auto-detecting the connection speed and setting the correct + * descriptors. */ + CyU3PUsbRegisterSetupCallback(usb_setup_callback, CyTrue); + + CyU3PUsbRegisterEventCallback(event_usb_callback); + + CyU3PUsbRegisterLPMRequestCallback(lpm_request_callback); + + /* Check to see if a VID/PID is in the EEPROM that we should use. */ + const uint16_t vid = get_vid(&eeprom_read); + const uint16_t pid = get_pid(&eeprom_read); + + common_usb2_dev_desc[8] = vid & 0xFF; + common_usb2_dev_desc[9] = vid >> 8; + common_usb2_dev_desc[10] = pid & 0xFF; + common_usb2_dev_desc[11] = pid >> 8; + + common_usb3_dev_desc[8] = vid & 0xFF; + common_usb3_dev_desc[9] = vid >> 8; + common_usb3_dev_desc[10] = pid & 0xFF; + common_usb3_dev_desc[11] = pid >> 8; + + const uint8_t *mfr_string = get_manufacturer_string_descriptor(vid); + const uint8_t *product_string = get_product_string_descriptor(pid); + const uint8_t *serial_string = get_serial_string_descriptor(&eeprom_read); + + /* Set our USB enumeration descriptors! Note that there are different + * function calls for each USB speed: FS, HS, SS. */ + + /* Device descriptors */ + CyU3PUsbSetDesc(CY_U3P_USB_SET_HS_DEVICE_DESCR, 0, + (uint8_t *)common_usb2_dev_desc); + + CyU3PUsbSetDesc(CY_U3P_USB_SET_SS_DEVICE_DESCR, 0, + (uint8_t *)common_usb3_dev_desc); + + /* Device qualifier descriptors */ + CyU3PUsbSetDesc(CY_U3P_USB_SET_DEVQUAL_DESCR, 0, + (uint8_t *)common_dev_qual_desc); + + /* Configuration descriptors */ + CyU3PUsbSetDesc(CY_U3P_USB_SET_HS_CONFIG_DESCR, 0, + (uint8_t *)b200_usb_hs_config_desc); + + CyU3PUsbSetDesc(CY_U3P_USB_SET_FS_CONFIG_DESCR, 0, + (uint8_t *)b200_usb_fs_config_desc); + + CyU3PUsbSetDesc(CY_U3P_USB_SET_SS_CONFIG_DESCR, 0, + (uint8_t *)b200_usb_ss_config_desc); + + /* BOS Descriptor */ + CyU3PUsbSetDesc(CY_U3P_USB_SET_SS_BOS_DESCR, 0, + (uint8_t *)common_usb_bos_desc); + + /* String descriptors */ + CyU3PUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 0, + (uint8_t *)common_string_lang_id_desc); + + CyU3PUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 1, + (uint8_t *)mfr_string); + + CyU3PUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 2, + (uint8_t *)product_string); + + CyU3PUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 3, + (uint8_t *)serial_string); + + //////////////////////////////////////////////////////// + + const uint32_t tx_swing = g_config.tx_swing/*65*//*45*/; // 65 & 45 are OK, 120 causes much link recovery. <128. 1.2V is USB3 limit. + if (CyU3PUsbSetTxSwing(tx_swing) == CY_U3P_SUCCESS) + msg("CyU3PUsbSetTxSwing: %d", tx_swing); + else + msg("! CyU3PUsbSetTxSwing: %d", tx_swing); + + //////////////////////////////////////////////////////// + + /* Connect the USB pins, and enable SuperSpeed (USB 3.0). */ + if (CyU3PConnectState(CyTrue, (g_config.enable_as_superspeed != 0 ? CyTrue : CyFalse)) == CY_U3P_SUCCESS) { // connect, ssEnable + CyU3PUSBSpeed_t usb_speed = CyU3PUsbGetSpeed(); + msg("Link up (speed: USB %d)", (int)usb_speed); // MAGIC: Values happen to map + } + else + msg("! Failed to establish link"); +} + + +void b200_restore_gpio_for_fpga_config(void) { + CyU3PDeviceGpioRestore(GPIO_FPGA_RESET); + CyU3PDeviceGpioRestore(GPIO_DONE); + + CyU3PDeviceGpioRestore(GPIO_FX3_SCLK); + CyU3PDeviceGpioRestore(GPIO_FX3_CE); + CyU3PDeviceGpioRestore(GPIO_FX3_MISO); + CyU3PDeviceGpioRestore(GPIO_FX3_MOSI); + + //CyU3PGpioDeInit(); // Moved to just before init +} + +void thread_fpga_config_entry(uint32_t input) { + uint32_t event_flag; + + //msg("thread_fpga_config_entry"); + + for(;;) { + + // Event is set through VREQ + if(CyU3PEventGet(&g_event_usb_config, \ + (EVENT_FPGA_CONFIG), CYU3P_EVENT_AND_CLEAR, \ + &event_flag, CYU3P_WAIT_FOREVER) == CY_U3P_SUCCESS) { + + //uint8_t old_state = g_fx3_state; + uint32_t old_fpga_programming_write_count = 0; + + if(g_fx3_state == STATE_ERROR) { + CyU3PThreadRelinquish(); + continue; + } + + if(g_fx3_state == STATE_RUNNING) { + /* The FX3 is currently configured for SLFIFO mode. We need to tear down + * this configuration and re-configure to program the FPGA. */ + b200_restore_gpio_for_fpga_config(); + CyU3PGpifDisable(CyTrue); + } + + CyU3PSysWatchDogClear(); + + g_fx3_state = STATE_BUSY; + + /* Configure the device GPIOs for FPGA programming. */ + b200_gpios_pre_fpga_config(); + + CyU3PSysWatchDogClear(); + + /* Initialize the SPI module that will be used for FPGA programming. */ + b200_spi_init(); // This must be done *after* 'b200_gpios_pre_fpga_config' + + CyU3PSysWatchDogClear(); + + /* Wait for the signal from the host that the bitstream is starting. */ + uint32_t wait_count = 0; + + /* We can now begin configuring the FPGA. */ + g_fx3_state = STATE_FPGA_READY; + + msg("Begin FPGA"); + + // Event is set through VREQ + while(CyU3PEventGet(&g_event_usb_config, \ + (EVENT_BITSTREAM_START), CYU3P_EVENT_AND_CLEAR, \ + &event_flag, CYU3P_NO_WAIT) != CY_U3P_SUCCESS) { + + if(wait_count >= FPGA_PROGRAMMING_BITSTREAM_START_POLL_COUNT) { + msg("! Bitstream didn't start"); + g_fx3_state = STATE_UNCONFIGURED; // Since IO configuration has changed, leave it in the unconfigured state (rather than the previous one, which might have been running) + CyU3PThreadRelinquish(); + break; + } + + wait_count++; + CyU3PThreadSleep(FPGA_PROGRAMMING_POLL_SLEEP); + CyU3PSysWatchDogClear(); + } + + if (wait_count >= FPGA_PROGRAMMING_BITSTREAM_START_POLL_COUNT) + continue; + + /* Pull PROGRAM_B low and then release it. */ + CyU3PGpioSetValue(GPIO_PROGRAM_B, 0); + CyU3PThreadSleep(20); + CyU3PGpioSetValue(GPIO_PROGRAM_B, 1); + + /* Wait for INIT_B to fall and rise. */ + wait_count = 0; + + msg("Wait FPGA"); + + while(CyU3PEventGet(&g_event_usb_config, \ + (EVENT_GPIO_INITB_RISE), CYU3P_EVENT_AND_CLEAR, \ + &event_flag, CYU3P_NO_WAIT) != CY_U3P_SUCCESS) { + + if(wait_count >= FPGA_PROGRAMMING_INITB_POLL_COUNT) { + msg("! INITB didn't rise"); + g_fx3_state = STATE_UNCONFIGURED; // Safer to call it unconfigured than the previous state + CyU3PThreadRelinquish(); + break; + } + + wait_count++; + CyU3PThreadSleep(FPGA_PROGRAMMING_POLL_SLEEP); + CyU3PSysWatchDogClear(); + } +#ifdef ENABLE_INIT_B_WORKAROUND + if (wait_count >= FPGA_PROGRAMMING_INITB_POLL_COUNT) + { + CyBool_t gpio_init_b; + CyU3PGpioGetValue(GPIO_INIT_B, &gpio_init_b); + if (gpio_init_b == CyTrue) + { + wait_count = 0; + } + else + { + msg("! INIT_B still not high"); + } + } +#endif // ENABLE_INIT_B_WORKAROUND + if (wait_count >= FPGA_PROGRAMMING_INITB_POLL_COUNT) + continue; + + /* We are ready to accept the FPGA bitstream! */ + wait_count = 0; + g_fx3_state = STATE_CONFIGURING_FPGA; + + msg("Configuring FPGA"); + + // g_fpga_programming_write_count is zero'd by VREQ triggering EVENT_BITSTREAM_START + + while(CyU3PEventGet(&g_event_usb_config, \ + (EVENT_GPIO_DONE_HIGH), CYU3P_EVENT_AND_CLEAR, \ + &event_flag, CYU3P_NO_WAIT) != CY_U3P_SUCCESS) { + + /* Wait for the configuration to complete, which will be indicated + * by the DONE pin going high and triggering the associated + * interrupt. */ + + if(wait_count >= FPGA_PROGRAMMING_DONE_POLL_COUNT) { + msg("! DONE didn't go high"); + g_fx3_state = STATE_UNCONFIGURED; + CyU3PThreadRelinquish(); + break; + } + + if (old_fpga_programming_write_count == g_fpga_programming_write_count) // Only increment wait count if we haven't written anything + wait_count++; + else { + wait_count = 0; + old_fpga_programming_write_count = g_fpga_programming_write_count; + } + + CyU3PThreadSleep(FPGA_PROGRAMMING_POLL_SLEEP); + CyU3PSysWatchDogClear(); + } +#ifdef ENABLE_DONE_WORKAROUND + if (wait_count >= FPGA_PROGRAMMING_DONE_POLL_COUNT) + { + CyBool_t gpio_done; + CyU3PGpioGetValue(GPIO_DONE, &gpio_done); + if (gpio_done == CyTrue) + { + wait_count = 0; + } + else + { + msg("! DONE still not high"); + } + } +#endif // ENABLE_DONE_WORKAROUND + if (wait_count >= FPGA_PROGRAMMING_DONE_POLL_COUNT) + continue; + + msg("FPGA done"); + + /* Tell the host that we are ignoring it for a while. */ + g_fx3_state = STATE_BUSY; + + CyU3PSysWatchDogClear(); + + /* Now that the FPGA is configured, we need to tear down the current SPI and + * GPIO configs, and re-config for GPIF & bit-banged SPI operation. */ + CyU3PSpiDeInit(); + b200_restore_gpio_for_fpga_config(); + + CyU3PSysWatchDogClear(); + + /* Load the GPIO configuration for normal SLFIFO use. */ + b200_slfifo_mode_gpio_config(); + + /* Tone down the drive strength on the P-port. */ + //CyU3PSetPportDriveStrength(CY_U3P_DS_HALF_STRENGTH); + + CyU3PSysWatchDogClear(); + + /* FPGA configuration is complete! Time to get the GPIF state machine + * running for Slave FIFO. */ + b200_gpif_init(); + + CyU3PThreadSleep(1); + b200_start_fpga_sb_gpio(); // Moved here to give SB time to init + + /* RUN, BABY, RUN! */ + g_fx3_state = STATE_RUNNING; + + msg("Running"); + } + + CyU3PThreadRelinquish(); + } +} + + +/*! The primary program thread. + * + * This is the primary application thread running on the FX3 device. It is + * responsible for initializing much of the chip, and then bit-banging the FPGA + * image, as it is sent from the host, into the FPGA. It then re-configures the + * FX3 for slave-fifo, and enters an infinite loop where it simply updates the + * watchdog timer and does some minor power management state checking. + */ +void thread_main_app_entry(uint32_t input) { + //msg("thread_main_app_entry"); + + /* In your spectrum, stealing your Hz. */ + for(;;) { + CyU3PSysWatchDogClear(); + CyU3PThreadSleep(CHECK_POWER_STATE_SLEEP_TIME); +#ifdef PREVENT_LOW_POWER_MODE + /* Once data transfer has started, we keep trying to get the USB + * link to stay in U0. If this is done + * before data transfers have started, there is a likelihood of + * failing the TD 9.24 U1/U2 test. */ + { + CyU3PUsbLinkPowerMode current_state; + + if((CyU3PUsbGetSpeed () == CY_U3P_SUPER_SPEED)) { + + /* If the link is in U1/U2 states, try to get back to U0. */ + CyU3PUsbGetLinkPowerState(¤t_state); + + if (current_state > CyU3PUsbLPM_U3) + msg("Power state %i", current_state); + + while((current_state >= CyU3PUsbLPM_U1) \ + && (current_state <= CyU3PUsbLPM_U3)) { + + msg("! LPS = %i", current_state); + + CyU3PUsbSetLinkPowerState(CyU3PUsbLPM_U0); // This will wake up the host if it's trying to sleep + CyU3PThreadSleep(1); + + if (CyU3PUsbGetSpeed () != CY_U3P_SUPER_SPEED) + break; + + CyU3PUsbGetLinkPowerState (¤t_state); + } + } + } +#endif // PREVENT_LOW_POWER_MODE + } +} + +static uint16_t g_poll_last_phy_error_count = 0, g_poll_last_link_error_count = 0; +static uint32_t g_poll_last_phy_error_status = 0; + +void update_error_counters(void) { + if (CyU3PUsbGetSpeed () != CY_U3P_SUPER_SPEED) + return; + + uvint32_t reg = REG_LNK_PHY_ERROR_STATUS; + uint32_t val = 0; + if (CyU3PReadDeviceRegisters((uvint32_t*)reg, 1, &val) == CY_U3P_SUCCESS) { + g_poll_last_phy_error_status |= (val & PHYERR_MASK); + + // Reset after read + uint32_t zero = PHYERR_MASK; + if (CyU3PWriteDeviceRegisters((uvint32_t*)reg, 1, &zero) != CY_U3P_SUCCESS) + msg("! CyU3PWriteDeviceRegisters"); + } + else { + // FIXME: Log once + msg("! Reg read fail"); + } + + // Equivalent code: + //uint32_t* p = (uint32_t*)REG_LNK_PHY_ERROR_STATUS; + //val = (*p); + //(*p) = PHYERR_MASK; + + uint16_t phy_error_count = 0, link_error_count = 0; + if (CyU3PUsbGetErrorCounts(&phy_error_count, &link_error_count) == CY_U3P_SUCCESS) { // Resets internal counters after call + g_poll_last_phy_error_count += phy_error_count; + g_poll_last_link_error_count += link_error_count; + } + else { + // FIXME: Log once + msg("! CyU3PUsbGetErrorCounts"); + } + + LOCK(g_counters_lock); + g_counters.usb_error_update_count++; + g_counters.usb_error_counters.phy_error_count += phy_error_count; + g_counters.usb_error_counters.link_error_count += link_error_count; + if (val & PHYERR_MASK) { + if (val & PHYERR_PHY_LOCK_EV) g_counters.usb_error_counters.PHY_LOCK_EV++; + if (val & PHYERR_TRAINING_ERROR_EV) g_counters.usb_error_counters.TRAINING_ERROR_EV++; + if (val & PHYERR_RX_ERROR_CRC32_EV) g_counters.usb_error_counters.RX_ERROR_CRC32_EV++; + if (val & PHYERR_RX_ERROR_CRC16_EV) g_counters.usb_error_counters.RX_ERROR_CRC16_EV++; + if (val & PHYERR_RX_ERROR_CRC5_EV) g_counters.usb_error_counters.RX_ERROR_CRC5_EV++; + if (val & PHYERR_PHY_ERROR_DISPARITY_EV)g_counters.usb_error_counters.PHY_ERROR_DISPARITY_EV++; + if (val & PHYERR_PHY_ERROR_EB_UND_EV) g_counters.usb_error_counters.PHY_ERROR_EB_UND_EV++; + if (val & PHYERR_PHY_ERROR_EB_OVR_EV) g_counters.usb_error_counters.PHY_ERROR_EB_OVR_EV++; + if (val & PHYERR_PHY_ERROR_DECODE_EV) g_counters.usb_error_counters.PHY_ERROR_DECODE_EV++; + } + UNLOCK(g_counters_lock); // FIXME: Read/write regs +} + + +void thread_re_enum_entry(uint32_t input) { + uint32_t event_flag; + + //msg("thread_re_enum_entry"); + + int keep_alive = 0; + + while (1) { + if (CyU3PEventGet(&g_event_usb_config, \ + (EVENT_RE_ENUM), CYU3P_EVENT_AND_CLEAR, \ + &event_flag, RE_ENUM_THREAD_SLEEP_TIME) == CY_U3P_SUCCESS) { + msg("Re-config"); + + // FIXME: This section is not finished + + // Not locking this since we only expect one write in VREQ and read afterward here + + int re_enum = g_config_mod.flags & (CF_RE_ENUM | CF_TX_SWING | CF_TX_DEEMPHASIS | CF_DISABLE_USB2 | CF_ENABLE_AS_SUPERSPEED); + + CyU3PThreadSleep(100); // Wait for EP0 xaction to complete + + //b200_fw_stop(); + +/* + int tx_swing; // [90] [65] 45 + int tx_deemphasis; // 0x11 + int disable_usb2; // 0 + int enable_as_superspeed; // 1 + int pport_drive_strength; // CY_U3P_DS_THREE_QUARTER_STRENGTH + int dma_buffer_size; // [USB3] (max) + int dma_buffer_count; // [USB3] 1 + int manual_dma; // 0 + int sb_baud_div; // 434*2 +*/ + + if (re_enum) { + if (CyU3PConnectState(CyFalse, (g_config.enable_as_superspeed != 0 ? CyTrue : CyFalse)) == CY_U3P_SUCCESS) + msg("Link down"); + else + msg("! Failed to bring link down"); + } + + if (g_config_mod.flags & CF_TX_DEEMPHASIS) { +#if (CYFX_VERSION_MAJOR >= 1) && (CYFX_VERSION_MINOR >= 3) + if ((g_config_mod.config.tx_deemphasis < 0x1F) && (CyU3PUsbSetTxDeemphasis(g_config_mod.config.tx_deemphasis) == CY_U3P_SUCCESS)) { + msg("TX deemphasis now: %d (was: %d)", g_config_mod.config.tx_deemphasis, g_config.tx_deemphasis); + g_config.tx_deemphasis = g_config_mod.config.tx_deemphasis; + } + else +#endif // #if (CYFX_VERSION_MAJOR >= 1) && (CYFX_VERSION_MINOR >= 3) + msg("! Failed to set TX deemphasis: %d (still: %d)", g_config_mod.config.tx_deemphasis, g_config.tx_deemphasis); + } + + if (g_config_mod.flags & CF_TX_SWING) { + if ((g_config_mod.config.tx_swing < 128) && (CyU3PUsbSetTxSwing(g_config_mod.config.tx_swing) == CY_U3P_SUCCESS)) { + msg("TX swing now: %d (was: %d)", g_config_mod.config.tx_swing, g_config.tx_swing); + g_config.tx_swing = g_config_mod.config.tx_swing; + } + else + msg("! Failed to set TX swing: %d (still: %d)", g_config_mod.config.tx_swing, g_config.tx_swing); + } + + if (g_config_mod.flags & CF_DISABLE_USB2) { + if (CyU3PUsbControlUsb2Support((g_config_mod.config.disable_usb2 != 0 ? CyTrue : CyFalse)) == CY_U3P_SUCCESS) { + msg("USB 2 support now: %s (was: %d)", (g_config_mod.config.disable_usb2 ? "disabled" : "enabled"), (g_config.disable_usb2 ? "disabled" : "enabled")); + g_config.disable_usb2 = g_config_mod.config.disable_usb2; + } + else + msg("! Failed to change USB 2 support to: %s (still: %s)", (g_config_mod.config.disable_usb2 ? "enabled" : "disabled"), (g_config.disable_usb2 ? "enabled" : "disabled")); + } + + if (g_config_mod.flags & CF_PPORT_DRIVE_STRENGTH) { + // CY_U3P_DS_QUARTER_STRENGTH,CY_U3P_DS_HALF_STRENGTH,CY_U3P_DS_THREE_QUARTER_STRENGTH,CY_U3P_DS_FULL_STRENGTH + if ((g_config_mod.config.pport_drive_strength >= CY_U3P_DS_QUARTER_STRENGTH) && + (g_config_mod.config.pport_drive_strength <= CY_U3P_DS_FULL_STRENGTH) && + (CyU3PSetPportDriveStrength(g_config_mod.config.pport_drive_strength) == CY_U3P_SUCCESS)) { + msg("PPort drive strength now: %d (was: %d)", g_config_mod.config.pport_drive_strength, g_config.pport_drive_strength); + g_config.pport_drive_strength = g_config_mod.config.pport_drive_strength; + } + else + msg("! Failed to set PPort drive strength: %d (still: %d)", g_config_mod.config.pport_drive_strength, g_config.pport_drive_strength); + } + + int reinit_dma = g_config_mod.flags & (CF_MANUAL_DMA | CF_DMA_BUFFER_COUNT | CF_DMA_BUFFER_SIZE); + if (re_enum) + reinit_dma = 0; // Don't need to if re-enumerating + + if (g_config_mod.flags & CF_MANUAL_DMA) { +#ifdef ENABLE_MANUAL_DMA_XFER + msg("DMA transfers will be: %s (was: %s)", (g_config_mod.config.manual_dma ? "manual" : "auto"), (g_config.manual_dma ? "manual" : "auto")); + g_config.manual_dma = g_config_mod.config.manual_dma; +#else + msg("! Manual DMA transfers not compiled into FW"); +#endif // ENABLE_MANUAL_DMA_XFER + } + + if (g_config_mod.flags & CF_DMA_BUFFER_COUNT) { + msg("DMA buffer count will be: %d (was: %d)", g_config_mod.config.dma_buffer_count, g_config.dma_buffer_count); + g_config.dma_buffer_count = g_config_mod.config.dma_buffer_count; + } + + if (g_config_mod.flags & CF_DMA_BUFFER_SIZE) { + msg("DMA buffer size will be: %d (was: %d)", g_config_mod.config.dma_buffer_size, g_config.dma_buffer_size); + g_config.dma_buffer_size = g_config_mod.config.dma_buffer_size; + } + + if (g_config_mod.flags & CF_SB_BAUD_DIV) { +#ifdef ENABLE_FPGA_SB + LOCK(g_suart_lock); + sb_write(SUART_CLKDIV, g_config_mod.config.sb_baud_div); + UNLOCK(g_suart_lock); + msg("SUART_CLKDIV now: %d (was: %d)", g_config_mod.config.sb_baud_div, g_config.sb_baud_div); + g_config.sb_baud_div = g_config_mod.config.sb_baud_div; +#else + msg("! Failed to set SUART_CLKDIV: SB is disabled (still: %d)", g_config.sb_baud_div); +#endif // ENABLE_FPGA_SB + } + + //b200_fw_start() + + if (g_config_mod.flags & CF_ENABLE_AS_SUPERSPEED) { + msg("Enable SuperSpeed: %s (was: %s)", (g_config_mod.config.enable_as_superspeed ? "yes" : "no"), (g_config.enable_as_superspeed ? "yes" : "no")); + g_config.enable_as_superspeed = g_config_mod.config.enable_as_superspeed; + } + + if (reinit_dma) { + if (g_app_running) { + msg("Stopping FW..."); + + b200_fw_stop(); + } + + msg("Starting FW..."); + + b200_fw_start(); + } + else // Shouldn't be re-init'ing AND re-enum'ing + /* Connect the USB pins, and enable SuperSpeed (USB 3.0). */ + if (re_enum) { + msg("Connecting... (as SuperSpeed: %d)", g_config.enable_as_superspeed); + + if (CyU3PConnectState(CyTrue, (g_config.enable_as_superspeed != 0 ? CyTrue : CyFalse)) == CY_U3P_SUCCESS) { // CHECK: Assuming all other important state will persist + CyU3PUSBSpeed_t usb_speed = CyU3PUsbGetSpeed(); + msg("Link up (speed: USB %d)", (int)usb_speed); // MAGIC: Values happen to map + } + else + msg("! Failed to bring link up"); + } + + counters_reset_usb_errors(); + } + else { + if (++keep_alive == KEEP_ALIVE_LOOP_COUNT) { + msg("Keep-alive"); + keep_alive = 0; + } +#ifndef ENABLE_FPGA_SB + update_error_counters(); +#endif // !ENABLE_FPGA_SB + } + + CyU3PThreadRelinquish(); + } +} + + +void base16_encode(uint8_t v, char out[2], char first) { + out[0] = first + (v >> 4); + out[1] = first + (v & 0x0F); +} + + +#ifdef ENABLE_FPGA_SB +void thread_fpga_sb_poll_entry(uint32_t input) { + //msg("thread_fpga_sb_poll_entry"); + + while (1) { + uint16_t i; + uint8_t has_change = 0; + + update_error_counters(); + + /*if (g_poll_last_phy_error_count > 0) + has_change = 1; + if (g_poll_last_link_error_count > 0) + has_change = 1;*/ + if (g_poll_last_phy_error_status != 0) + has_change = 1; + + uint16_t idx = CyU3PUsbGetEventLogIndex(); // Current *write* pointer + if (idx > (USB_EVENT_LOG_SIZE-1)) { + msg("! USB event log idx = %i", (int)idx); + break; + } + + uint8_t has_usb_events = 0; + // Assuming logging won't wrap around between get calls (i.e. buffer should be long enough) + if (g_fpga_sb_last_usb_event_log_index != idx) { + if (idx < g_fpga_sb_last_usb_event_log_index) { + for (i = g_fpga_sb_last_usb_event_log_index; i < USB_EVENT_LOG_SIZE; i++) { + if (g_usb_event_log[i] != 0x14 && g_usb_event_log[i] != 0x15 && g_usb_event_log[i] != 0x16) { // CTRL, STATUS, ACKSETUP + has_usb_events = 1; + break; + } + } + + if (has_usb_events == 0) { + for (i = 0; i < idx; i++) { + if (g_usb_event_log[i] != 0x14 && g_usb_event_log[i] != 0x15 && g_usb_event_log[i] != 0x16) { // CTRL, STATUS, ACKSETUP + has_usb_events = 1; + break; + } + } + } + } + else { + for (i = g_fpga_sb_last_usb_event_log_index; i < idx; i++) { + if (g_usb_event_log[i] != 0x14 && g_usb_event_log[i] != 0x15 && g_usb_event_log[i] != 0x16) { // CTRL, STATUS, ACKSETUP + has_usb_events = 1; + break; + } + } + } + } + + if (has_change || has_usb_events) { + LOCK(g_suart_lock); + + sb_write(SUART_TXCHAR, UPT_USB_EVENTS); + + char out[3]; + out[2] = '\0'; + + if (has_usb_events) { + if (idx < g_fpga_sb_last_usb_event_log_index) { + for (i = g_fpga_sb_last_usb_event_log_index; i < USB_EVENT_LOG_SIZE; i++) { + if (g_usb_event_log[i] == 0x14 || g_usb_event_log[i] == 0x15 || g_usb_event_log[i] == 0x16) // CTRL, STATUS, ACKSETUP + continue; + base16_encode(g_usb_event_log[i], out, 'A'); + _sb_write_string(out); + } + + for (i = 0; i < idx; i++) { + if (g_usb_event_log[i] == 0x14 || g_usb_event_log[i] == 0x15 || g_usb_event_log[i] == 0x16) // CTRL, STATUS, ACKSETUP + continue; + base16_encode(g_usb_event_log[i], out, 'A'); + _sb_write_string(out); + } + } + else { + for (i = g_fpga_sb_last_usb_event_log_index; i < idx; i++) { + if (g_usb_event_log[i] == 0x14 || g_usb_event_log[i] == 0x15 || g_usb_event_log[i] == 0x16) // CTRL, STATUS, ACKSETUP + continue; + base16_encode(g_usb_event_log[i], out, 'A'); + _sb_write_string(out); + } + } + } + + // USB events: A-P,A-P + // PHY error status: a,a-i + + if (g_poll_last_phy_error_status != 0) { + uint32_t mask; + size_t offset; + for (mask = PHYERR_MAX, offset = 0; mask != 0; mask >>= 1, ++offset) { + if ((g_poll_last_phy_error_status & mask) != 0) { + sb_write(SUART_TXCHAR, 'a'); + sb_write(SUART_TXCHAR, 'a' + offset); + } + } + } + + /*char buf[6]; + + if (g_poll_last_phy_error_count > 0) { + sb_write(SUART_TXCHAR, 'b'); + snprintf(buf, sizeof(buf)-1, "%d", g_poll_last_phy_error_count); + _sb_write_string(buf); + } + + if (g_poll_last_link_error_count > 0) { + sb_write(SUART_TXCHAR, 'c'); + snprintf(buf, sizeof(buf)-1, "%d", g_poll_last_link_error_count); + _sb_write_string(buf); + }*/ + + _sb_write_string("\r\n"); + + UNLOCK(g_suart_lock); + } + + g_poll_last_phy_error_count = 0; + g_poll_last_link_error_count = 0; + g_poll_last_phy_error_status = 0; + + g_fpga_sb_last_usb_event_log_index = idx; + + CyU3PThreadRelinquish(); + } +} +#endif // ENABLE_FPGA_SB + +/*! Application define function which creates the threads. + * + * The name of this application cannot be changed, as it is called from the + * tx_application _define function, referenced in the rest of the FX3 build + * system. + * + * If thread creation fails, lock the system and force a power reset. + */ +void CyFxApplicationDefine(void) { + void *app_thread_ptr, *fpga_thread_ptr; +#ifdef ENABLE_RE_ENUM_THREAD + void *re_enum_thread_ptr; +#endif // ENABLE_RE_ENUM_THREAD +#ifdef ENABLE_FPGA_SB + void *fpga_sb_poll_thread_ptr; +#endif // ENABLE_FPGA_SB + + g_counters.magic = COUNTER_MAGIC; + //memset(&g_config, 0xFF, sizeof(g_config)); // Initialise to -1 + + CyU3PMutexCreate(&g_log_lock, CYU3P_NO_INHERIT); + CyU3PMutexCreate(&g_counters_lock, CYU3P_NO_INHERIT); + CyU3PMutexCreate(&g_counters_dma_from_host_lock, CYU3P_NO_INHERIT); + CyU3PMutexCreate(&g_counters_dma_to_host_lock, CYU3P_NO_INHERIT); +#ifdef ENABLE_FPGA_SB + CyU3PMutexCreate(&g_suart_lock, CYU3P_NO_INHERIT); +#endif // ENABLE_FPGA_SB +#ifdef ENABLE_USB_EVENT_LOGGING + CyU3PUsbInitEventLog(g_usb_event_log, USB_EVENT_LOG_SIZE); +#endif // ENABLE_USB_EVENT_LOGGING + + //////////////////////////////////////////////////////// + + /* Tell the host that we are ignoring it for a while. */ + g_fx3_state = STATE_BUSY; + + /* Set the FX3 compatibility number. */ + compat_num[0] = FX3_COMPAT_MAJOR; + compat_num[1] = FX3_COMPAT_MINOR; + + /* Initialize the USB system. */ + b200_usb_init(); + + /* Turn on the Watchdog Timer. */ + CyU3PSysWatchDogConfigure(CyTrue, WATCHDOG_TIMEOUT); + + /* Go do something. Probably not useful, because you aren't configured. */ + g_fx3_state = STATE_UNCONFIGURED; + + //////////////////////////////////////////////////////// + + b200_gpio_init(CyTrue); + + b200_enable_fpga_sb_gpio(CyTrue); + + msg("Compat: %d.%d", FX3_COMPAT_MAJOR, FX3_COMPAT_MINOR); + msg("FX3 SDK: %d.%d.%d (build %d)", CYFX_VERSION_MAJOR, CYFX_VERSION_MINOR, CYFX_VERSION_PATCH, CYFX_VERSION_BUILD); + msg("FW built: %s %s", __TIME__, __DATE__); + + //////////////////////////////////////////////////////// + + /* Create the USB event group that we will use to track USB events from the + * application thread. */ + CyU3PEventCreate(&g_event_usb_config); + + /* Allocate memory for the application thread. */ + app_thread_ptr = CyU3PMemAlloc(APP_THREAD_STACK_SIZE); + + /* Allocate memory for the FPGA configuration thread. */ + fpga_thread_ptr = CyU3PMemAlloc(APP_THREAD_STACK_SIZE); +#ifdef ENABLE_RE_ENUM_THREAD + re_enum_thread_ptr = CyU3PMemAlloc(APP_THREAD_STACK_SIZE); +#endif // ENABLE_RE_ENUM_THREAD +#ifdef ENABLE_FPGA_SB + fpga_sb_poll_thread_ptr = CyU3PMemAlloc(APP_THREAD_STACK_SIZE); +#endif // ENABLE_FPGA_SB + //////////////////////////////////////////////////////// + + /* Create the thread for the application */ + if (app_thread_ptr != NULL) + CyU3PThreadCreate(&thread_main_app, + "200:B200 Main", + thread_main_app_entry, + 0, + app_thread_ptr, + APP_THREAD_STACK_SIZE, + THREAD_PRIORITY, + THREAD_PRIORITY, + CYU3P_NO_TIME_SLICE, + CYU3P_AUTO_START); + + /* Create the thread for FPGA configuration. */ + if (fpga_thread_ptr != NULL) + CyU3PThreadCreate(&thread_fpga_config, + "300:B200 FPGA", + thread_fpga_config_entry, + 0, + fpga_thread_ptr, + APP_THREAD_STACK_SIZE, + THREAD_PRIORITY, + THREAD_PRIORITY, + CYU3P_NO_TIME_SLICE, + CYU3P_AUTO_START); +#ifdef ENABLE_RE_ENUM_THREAD + /* Create the thread for stats collection and re-enumeration/configuration */ + if (re_enum_thread_ptr != NULL) + CyU3PThreadCreate(&thread_re_enum, + "400:B200 Re-enum", + thread_re_enum_entry, + 0, + re_enum_thread_ptr, + APP_THREAD_STACK_SIZE, + THREAD_PRIORITY, + THREAD_PRIORITY, + CYU3P_NO_TIME_SLICE, + CYU3P_AUTO_START); +#endif // ENABLE_RE_ENUM_THREAD +#ifdef ENABLE_FPGA_SB + /* Create thread to handling Settings Bus logging/transactions */ + if (fpga_sb_poll_thread_ptr != NULL) + CyU3PThreadCreate(&thread_fpga_sb_poll, + "600:B200 FPGA SB poll", + thread_fpga_sb_poll_entry, + 0, + fpga_sb_poll_thread_ptr, + APP_THREAD_STACK_SIZE, + THREAD_PRIORITY, + THREAD_PRIORITY, + CYU3P_NO_TIME_SLICE, + CYU3P_AUTO_START); +#endif // ENABLE_FPGA_SB +} + + +int main(void) { + CyU3PReturnStatus_t status = CY_U3P_SUCCESS; + CyU3PSysClockConfig_t clock_config; + + /* Configure the FX3 Clocking scheme: + * CPU Divider: 2 (~200 MHz) + * DMA Divider: 2 (~100 MHz) + * MMIO Divider: 2 (~100 MHz) + * 32 kHz Standby Clock: Disabled + * System Clock Divider: 1 */ + clock_config.cpuClkDiv = 2; + clock_config.dmaClkDiv = 2; + clock_config.mmioClkDiv = 2; + clock_config.useStandbyClk = CyFalse; + clock_config.clkSrc = CY_U3P_SYS_CLK; + clock_config.setSysClk400 = CyTrue; + + status = CyU3PDeviceInit(&clock_config); + if(status != CY_U3P_SUCCESS) + goto handle_fatal_error; + + /* Initialize the caches. Enable instruction cache and keep data cache disabled. + * The data cache is useful only when there is a large amount of CPU based memory + * accesses. When used in simple cases, it can decrease performance due to large + * number of cache flushes and cleans and also it adds to the complexity of the + * code. */ + status = CyU3PDeviceCacheControl(CyTrue, CyFalse, CyFalse); // Icache, Dcache, DMAcache + if (status != CY_U3P_SUCCESS) + goto handle_fatal_error; + + /* Configure the IO peripherals on the FX3. The gpioSimpleEn arrays are + * bitmaps, where each bit represents the GPIO of the matching index - the + * second array is index + 32. */ + status = b200_set_io_matrix(CyTrue); + if(status != CY_U3P_SUCCESS) + goto handle_fatal_error; + + /* This function calls starts the RTOS kernel. + * + * ABANDON ALL HOPE, YE WHO ENTER HERE */ + CyU3PKernelEntry(); + + /* Although we will never make it here, this has to be here to make the + * compiler happy. */ + return 0; + + /* If an error occurs before the launch of the kernel, it is unrecoverable. + * Once you go down this hole, you aren't coming back out without a power + * reset. */ + handle_fatal_error: + while(1); +} diff --git a/firmware/fx3/b200/firmware/b200_usb_descriptors.c b/firmware/fx3/b200/firmware/b200_usb_descriptors.c new file mode 100644 index 000000000..30e6d876c --- /dev/null +++ b/firmware/fx3/b200/firmware/b200_usb_descriptors.c @@ -0,0 +1,359 @@ +// +// Copyright 2013-2015 Ettus Research LLC +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +/* Firmware's unique config and string descriptors */ + +#include "b200_const.h" + +/* Firmware Full Speed Configuration Descriptor */ +const uint8_t b200_usb_fs_config_desc[] = +{ + /* Configuration descriptor */ + 0x09, /* Descriptor size */ + CY_U3P_USB_CONFIG_DESCR, /* Configuration descriptor type */ + 0x52,0x00, /* Length of this descriptor and all sub descriptors */ + 0x05, /* Number of interfaces */ + 0x01, /* Configuration number */ + 0x00, /* Configuration string index */ + 0x80, /* Config characteristics - bus powered */ + 0x01, /* Lie about the max power consumption (in 2mA unit) : 2mA */ + + /* Interface descriptor */ + 0x09, /* Descriptor size */ + CY_U3P_USB_INTRFC_DESCR, /* Interface descriptor type */ + 0x00, /* Interface number */ + 0x00, /* Alternate setting number */ + 0x00, /* Number of endpoints */ + 0xFF, /* Interface class */ + 0x00, /* Interface sub class */ + 0x00, /* Interface protocol code */ + 0x02, /* Interface descriptor string index */ + + /* Interface descriptor */ + 0x09, /* Descriptor size */ + CY_U3P_USB_INTRFC_DESCR, /* Interface descriptor type */ + 0x01, /* Interface number */ + 0x00, /* Alternate setting number */ + 0x01, /* Number of endpoints */ + 0xFF, /* Interface class */ + 0x00, /* Interface sub class */ + 0x00, /* Interface protocol code */ + 0x02, /* Interface descriptor string index */ + + /* Endpoint descriptor for producer EP */ + 0x07, /* Descriptor size */ + CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ + DATA_ENDPOINT_PRODUCER, /* Endpoint address and description */ + CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ + 0x40,0x00, /* Max packet size = 64 bytes */ + 0x00, /* Servicing interval for data transfers : 0 for bulk */ + + /* Interface descriptor */ + 0x09, /* Descriptor size */ + CY_U3P_USB_INTRFC_DESCR, /* Interface descriptor type */ + 0x02, /* Interface number */ + 0x00, /* Alternate setting number */ + 0x01, /* Number of endpoints */ + 0xFF, /* Interface class */ + 0x00, /* Interface sub class */ + 0x00, /* Interface protocol code */ + 0x02, /* Interface descriptor string index */ + + /* Endpoint descriptor for consumer EP */ + 0x07, /* Descriptor size */ + CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ + DATA_ENDPOINT_CONSUMER, /* Endpoint address and description */ + CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ + 0x40,0x00, /* Max packet size = 64 bytes */ + 0x00, /* Servicing interval for data transfers : 0 for bulk */ + + /* Interface descriptor */ + 0x09, /* Descriptor size */ + CY_U3P_USB_INTRFC_DESCR, /* Interface descriptor type */ + 0x03, /* Interface number */ + 0x00, /* Alternate setting number */ + 0x01, /* Number of endpoints */ + 0xFF, /* Interface class */ + 0x00, /* Interface sub class */ + 0x00, /* Interface protocol code */ + 0x02, /* Interface descriptor string index */ + + /* Endpoint descriptor for producer EP */ + 0x07, /* Descriptor size */ + CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ + CTRL_ENDPOINT_PRODUCER, /* Endpoint address and description */ + CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ + 0x40,0x00, /* Max packet size = 64 bytes */ + 0x00, /* Servicing interval for data transfers : 0 for bulk */ + + /* Interface descriptor */ + 0x09, /* Descriptor size */ + CY_U3P_USB_INTRFC_DESCR, /* Interface descriptor type */ + 0x04, /* Interface number */ + 0x00, /* Alternate setting number */ + 0x01, /* Number of endpoints */ + 0xFF, /* Interface class */ + 0x00, /* Interface sub class */ + 0x00, /* Interface protocol code */ + 0x02, /* Interface descriptor string index */ + + /* Endpoint descriptor for consumer EP */ + 0x07, /* Descriptor size */ + CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ + CTRL_ENDPOINT_CONSUMER, /* Endpoint address and description */ + CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ + 0x40,0x00, /* Max packet size = 64 bytes */ + 0x00 /* Servicing interval for data transfers : 0 for bulk */ +}; + + +/* Firmware High Speed Configuration Descriptor */ +const uint8_t b200_usb_hs_config_desc[] = +{ + /* Configuration descriptor */ + 0x09, /* Descriptor size */ + CY_U3P_USB_CONFIG_DESCR, /* Configuration descriptor type */ + 0x52,0x00, /* Length of this descriptor and all sub descriptors */ + 0x05, /* Number of interfaces */ + 0x01, /* Configuration number */ + 0x00, /* COnfiguration string index */ + 0x80, /* Config characteristics - bus powered */ + 0x01, /* Lie about the max power consumption (in 2mA unit) : 2mA */ + + /* Interface descriptor */ + 0x09, /* Descriptor size */ + CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ + 0x00, /* Interface number */ + 0x00, /* Alternate setting number */ + 0x00, /* Number of endpoints */ + 0xFF, /* Interface class */ + 0x00, /* Interface sub class */ + 0x00, /* Interface protocol code */ + 0x02, /* Interface descriptor string index */ + + /* Interface descriptor */ + 0x09, /* Descriptor size */ + CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ + 0x01, /* Interface number */ + 0x00, /* Alternate setting number */ + 0x01, /* Number of endpoints */ + 0xFF, /* Interface class */ + 0x00, /* Interface sub class */ + 0x00, /* Interface protocol code */ + 0x02, /* Interface descriptor string index */ + + /* Endpoint descriptor for producer EP */ + 0x07, /* Descriptor size */ + CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ + DATA_ENDPOINT_PRODUCER, /* Endpoint address and description */ + CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ + 0x00,0x02, /* Max packet size = 512 bytes */ + 0x00, /* Servicing interval for data transfers : 0 for bulk */ + + /* Interface descriptor */ + 0x09, /* Descriptor size */ + CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ + 0x02, /* Interface number */ + 0x00, /* Alternate setting number */ + 0x01, /* Number of endpoints */ + 0xFF, /* Interface class */ + 0x00, /* Interface sub class */ + 0x00, /* Interface protocol code */ + 0x02, /* Interface descriptor string index */ + + /* Endpoint descriptor for consumer EP */ + 0x07, /* Descriptor size */ + CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ + DATA_ENDPOINT_CONSUMER, /* Endpoint address and description */ + CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ + 0x00,0x02, /* Max packet size = 512 bytes */ + 0x00, /* Servicing interval for data transfers : 0 for bulk */ + + /* Interface descriptor */ + 0x09, /* Descriptor size */ + CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ + 0x03, /* Interface number */ + 0x00, /* Alternate setting number */ + 0x01, /* Number of endpoints */ + 0xFF, /* Interface class */ + 0x00, /* Interface sub class */ + 0x00, /* Interface protocol code */ + 0x02, /* Interface descriptor string index */ + + /* Endpoint descriptor for producer EP */ + 0x07, /* Descriptor size */ + CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ + CTRL_ENDPOINT_PRODUCER, /* Endpoint address and description */ + CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ + 0x00,0x02, /* Max packet size = 512 bytes */ + 0x00, /* Servicing interval for data transfers : 0 for bulk */ + + /* Interface descriptor */ + 0x09, /* Descriptor size */ + CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ + 0x04, /* Interface number */ + 0x00, /* Alternate setting number */ + 0x01, /* Number of endpoints */ + 0xFF, /* Interface class */ + 0x00, /* Interface sub class */ + 0x00, /* Interface protocol code */ + 0x02, /* Interface descriptor string index */ + + /* Endpoint descriptor for consumer EP */ + 0x07, /* Descriptor size */ + CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ + CTRL_ENDPOINT_CONSUMER, /* Endpoint address and description */ + CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ + 0x00,0x02, /* Max packet size = 512 bytes */ + 0x00 /* Servicing interval for data transfers : 0 for bulk */ +}; + + +/* Firmware Super Speed Configuration Descriptor */ +const uint8_t b200_usb_ss_config_desc[] = +{ + /* Configuration descriptor */ + 0x09, /* Descriptor size */ + CY_U3P_USB_CONFIG_DESCR, /* Configuration descriptor type */ + 0x6A,0x00, /* Length of this descriptor and all sub descriptors */ + 0x05, /* Number of interfaces */ + 0x01, /* Configuration number */ + 0x00, /* Configuration string index */ + 0x80, /* Config characteristics - D6: Self power; D5: Remote wakeup */ + 0x01, /* Lie about the max power consumption (in 8mA unit) : 8mA */ + + /* Interface descriptor */ + 0x09, /* Descriptor size */ + CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ + 0x00, /* Interface number */ + 0x00, /* Alternate setting number */ + 0x00, /* Number of end points */ + 0xFF, /* Interface class */ + 0x00, /* Interface sub class */ + 0x00, /* Interface protocol code */ + 0x02, /* Interface descriptor string index */ + + /* Interface descriptor */ + 0x09, /* Descriptor size */ + CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ + 0x01, /* Interface number */ + 0x00, /* Alternate setting number */ + 0x01, /* Number of end points */ + 0xFF, /* Interface class */ + 0x00, /* Interface sub class */ + 0x00, /* Interface protocol code */ + 0x02, /* Interface descriptor string index */ + + /* Endpoint descriptor for producer EP */ + 0x07, /* Descriptor size */ + CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ + DATA_ENDPOINT_PRODUCER, /* Endpoint address and description */ + CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ + 0x00,0x04, /* Max packet size = 1024 bytes */ + 0x00, /* Servicing interval for data transfers : 0 for bulk */ + + /* Super speed endpoint companion descriptor for producer EP */ + 0x06, /* Descriptor size */ + CY_U3P_SS_EP_COMPN_DESCR, /* SS endpoint companion descriptor type */ + (USB3_PACKETS_PER_BURST - 1), /* Max no. of packets in a burst : 0: burst 1 packet at a time */ + 0x00, /* Max streams for bulk EP = 0 (No streams) */ + 0x00,0x00, /* Service interval for the EP : 0 for bulk */ + + /* Interface descriptor */ + 0x09, /* Descriptor size */ + CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ + 0x02, /* Interface number */ + 0x00, /* Alternate setting number */ + 0x01, /* Number of end points */ + 0xFF, /* Interface class */ + 0x00, /* Interface sub class */ + 0x00, /* Interface protocol code */ + 0x02, /* Interface descriptor string index */ + + /* Endpoint descriptor for consumer EP */ + 0x07, /* Descriptor size */ + CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ + DATA_ENDPOINT_CONSUMER, /* Endpoint address and description */ + CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ + 0x00,0x04, /* Max packet size = 1024 bytes */ + 0x00, /* Servicing interval for data transfers : 0 for Bulk */ + + /* Super speed endpoint companion descriptor for consumer EP */ + 0x06, /* Descriptor size */ + CY_U3P_SS_EP_COMPN_DESCR, /* SS endpoint companion descriptor type */ + (USB3_PACKETS_PER_BURST - 1), /* Max no. of packets in a burst : 0: burst 1 packet at a time */ + 0x00, /* Max streams for bulk EP = 0 (No streams) */ + 0x00,0x00, /* Service interval for the EP : 0 for bulk */ + + /* Interface descriptor */ + 0x09, /* Descriptor size */ + CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ + 0x03, /* Interface number */ + 0x00, /* Alternate setting number */ + 0x01, /* Number of end points */ + 0xFF, /* Interface class */ + 0x00, /* Interface sub class */ + 0x00, /* Interface protocol code */ + 0x02, /* Interface descriptor string index */ + + /* Endpoint descriptor for producer EP */ + 0x07, /* Descriptor size */ + CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ + CTRL_ENDPOINT_PRODUCER, /* Endpoint address and description */ + CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ + 0x00,0x04, /* Max packet size = 1024 bytes */ + 0x00, /* Servicing interval for data transfers : 0 for bulk */ + + /* Super speed endpoint companion descriptor for producer EP */ + 0x06, /* Descriptor size */ + CY_U3P_SS_EP_COMPN_DESCR, /* SS endpoint companion descriptor type */ + (USB3_PACKETS_PER_BURST - 1), /* Max no. of packets in a burst : 0: burst 1 packet at a time */ + 0x00, /* Max streams for bulk EP = 0 (No streams) */ + 0x00,0x00, /* Service interval for the EP : 0 for bulk */ + + /* Interface descriptor */ + 0x09, /* Descriptor size */ + CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ + 0x04, /* Interface number */ + 0x00, /* Alternate setting number */ + 0x01, /* Number of end points */ + 0xFF, /* Interface class */ + 0x00, /* Interface sub class */ + 0x00, /* Interface protocol code */ + 0x02, /* Interface descriptor string index */ + + /* Endpoint descriptor for consumer EP */ + 0x07, /* Descriptor size */ + CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ + CTRL_ENDPOINT_CONSUMER, /* Endpoint address and description */ + CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ + 0x00,0x04, /* Max packet size = 1024 bytes */ + 0x00, /* Servicing interval for data transfers : 0 for Bulk */ + + /* Super speed endpoint companion descriptor for consumer EP */ + 0x06, /* Descriptor size */ + CY_U3P_SS_EP_COMPN_DESCR, /* SS endpoint companion descriptor type */ + (USB3_PACKETS_PER_BURST - 1), /* Max no. of packets in a burst : 0: burst 1 packet at a time */ + 0x00, /* Max streams for bulk EP = 0 (No streams) */ + 0x00,0x00 /* Service interval for the EP : 0 for bulk */ +}; + +/* Firmware Device Serial String Descriptor */ +uint8_t b200_dev_serial_desc[20] = +{ + 0x14, + 0x03,/* CY_U3P_USB_STRING_DESCR Device Descriptor Type */ + '0', 0x00, + '0', 0x00, + '0', 0x00, + '0', 0x00, + '0', 0x00, + '0', 0x00, + '0', 0x00, + '0', 0x00, + '0', 0x00 +}; \ No newline at end of file diff --git a/firmware/fx3/b200/firmware/b200_usb_descriptors.h b/firmware/fx3/b200/firmware/b200_usb_descriptors.h new file mode 100644 index 000000000..f3889b9af --- /dev/null +++ b/firmware/fx3/b200/firmware/b200_usb_descriptors.h @@ -0,0 +1,21 @@ +// +// Copyright 2013-2014 Ettus Research LLC +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#ifndef _B200_USB_DESCRIPTORS_H +#define _B200_USB_DESCRIPTORS_H + +#include "cyu3externcstart.h" + +/* Descriptor definitions for USB enumerations. */ +extern uint8_t b200_usb_fs_config_desc[]; +extern uint8_t b200_usb_hs_config_desc[]; +extern uint8_t b200_usb_ss_config_desc[]; +extern uint8_t b200_dev_serial_desc[]; + +#include "cyu3externcend.h" + +#endif /* _B200_USB_DESCRIPTORS_H */ diff --git a/firmware/fx3/b200/firmware/makefile b/firmware/fx3/b200/firmware/makefile new file mode 100644 index 000000000..53d423dfb --- /dev/null +++ b/firmware/fx3/b200/firmware/makefile @@ -0,0 +1,53 @@ +# +# Copyright 2013-2014 Ettus Research LLC +# Copyright 2019 Ettus Research, a National Instruments Brand +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + +HEX_OUT = usrp_b200_fw.hex + +all:$(HEX_OUT) + +# Pull in the Cypress SDK files to build the firmware +FX3FWROOT=../.. +FX3PFWROOT=../../u3p_firmware +include $(FX3FWROOT)/common/fx3_build_config.mak + +ifndef OC + OC = arm-none-eabi-objcopy +endif + +MODULE = b200_main + +SOURCE += $(MODULE).c b200_i2c.c b200_usb_descriptors.c ../common/common_helpers.c ../common/common_descriptors.c + +INCFLAGS = -I../common + +LDLIBS += \ + "$$ARMGCC_INSTALL_PATH"/arm-none-eabi/lib/libm.a + +C_OBJECT=$(SOURCE:%.c=./%.o) +A_OBJECT=$(SOURCE_ASM:%.S=./%.o) + +EXES = $(MODULE).$(EXEEXT) + +$(MODULE).$(EXEEXT): $(A_OBJECT) $(C_OBJECT) + $(LINK) $(LINKFLAGS) + +$(C_OBJECT) : %.o : %.c + $(COMPILE) $(INCFLAGS) + +$(A_OBJECT) : %.o : %.S + $(ASSEMBLE) + +clean: + rm -f ./$(MODULE).$(EXEEXT) + rm -f ./$(MODULE).map + rm -f ./*.o + rm -f ../common/*.o + +$(HEX_OUT): $(C_OBJECT) $(A_OBJECT) $(EXES) + $(OC) -O ihex $(EXES) $@ + +#[]# diff --git a/firmware/fx3/b200/fx3_mem_map.patch b/firmware/fx3/b200/fx3_mem_map.patch index 37d704ace..df9ff0e7a 100644 --- a/firmware/fx3/b200/fx3_mem_map.patch +++ b/firmware/fx3/b200/fx3_mem_map.patch @@ -66,3 +66,26 @@ diff -ur 1.2.3-orig/common/fx3.ld 1.2.3/common/fx3.ld + PROVIDE(__heap_size = __heap_end - __heap_start); } +diff -ur 1.2.3-orig/boot_fw/src/cyfx3.ld 1.2.3/boot_fw/src/cyfx3.ld +--- 1.2.3-orig/boot_fw/src/cyfx3.ld 2019-02-12 16:40:48.000000000 -0800 ++++ 1.2.3/boot_fw/src/cyfx3.ld 2019-03-20 14:36:18.992529192 -0700 +@@ -34,12 +34,18 @@ + + MEMORY + { ++ BLANK : ORIGIN = 0x40070000 LENGTH = 0x0100 + SYS_MEM : ORIGIN = 0x40078000 LENGTH = 0x7000 + DATA : ORIGIN = 0x4007F000 LENGTH = 0x1000 + } + + SECTIONS + { ++ . = 0x40070000; ++ .blank : ++ { ++ . += 0x100; ++ } > BLANK + . = 0x40078000; + .text : + { + diff --git a/firmware/fx3/b200/makefile b/firmware/fx3/b200/makefile deleted file mode 100644 index 22eb1bbcc..000000000 --- a/firmware/fx3/b200/makefile +++ /dev/null @@ -1,51 +0,0 @@ -# -# Copyright 2013-2014 Ettus Research LLC -# - -HEX_OUT = usrp_b200_fw.hex - -all:$(HEX_OUT) - -# Pull in the Cypress SDK files to build the firmware -FX3FWROOT=.. -FX3PFWROOT=../u3p_firmware -include $(FX3FWROOT)/common/fx3_build_config.mak - -ifndef OC - OC = arm-none-eabi-objcopy -endif - -MODULE = b200_main - -SOURCE += $(MODULE).c -SOURCE += b200_usb_descriptors.c -SOURCE += b200_i2c.c - -INCLUDES = b200_main.h b200_gpifconfig.h b200_i2c.h - -LDLIBS += \ - "$$ARMGCC_INSTALL_PATH"/arm-none-eabi/lib/libm.a - -C_OBJECT=$(SOURCE:%.c=./%.o) -A_OBJECT=$(SOURCE_ASM:%.S=./%.o) - -EXES = $(MODULE).$(EXEEXT) - -$(MODULE).$(EXEEXT): $(A_OBJECT) $(C_OBJECT) - $(LINK) $(LINKFLAGS) - -$(C_OBJECT) : %.o : %.c $(INCLUDES) - $(COMPILE) $(INCFLAGS) - -$(A_OBJECT) : %.o : %.S - $(ASSEMBLE) - -clean: - rm -f ./$(MODULE).$(EXEEXT) - rm -f ./$(MODULE).map - rm -f ./*.o - -$(HEX_OUT): $(C_OBJECT) $(A_OBJECT) $(EXES) - $(OC) -O ihex $(EXES) $@ - -#[]# -- cgit v1.2.3