booster: foboot-2 compatibility

Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
Sean Cross 2019-11-24 15:14:07 +08:00
parent 95e6e8c211
commit ea04c290eb
8 changed files with 1194 additions and 796 deletions

File diff suppressed because it is too large Load Diff

244
booster/include/usb-eptri.h Normal file
View File

@ -0,0 +1,244 @@
#ifndef __USB_EPTRI_H_
#define __USB_EPTRI_H_
#ifdef CSR_ACCESSORS_DEFINED
extern void csr_writeb(uint8_t value, unsigned long addr);
extern uint8_t csr_readb(unsigned long addr);
extern void csr_writew(uint16_t value, unsigned long addr);
extern uint16_t csr_readw(unsigned long addr);
extern void csr_writel(uint32_t value, unsigned long addr);
extern uint32_t csr_readl(unsigned long addr);
#else /* ! CSR_ACCESSORS_DEFINED */
#include <hw/common.h>
#endif /* ! CSR_ACCESSORS_DEFINED */
#define CSR_USB_BASE 0xe0004800L
#define CSR_USB_PULLUP_OUT_ADDR 0xe0004800L
#define CSR_USB_PULLUP_OUT_SIZE 1
static inline unsigned char usb_pullup_out_read(void) {
unsigned char r = csr_readl(0xe0004800L);
return r;
}
static inline void usb_pullup_out_write(unsigned char value) {
csr_writel(value, 0xe0004800L);
}
#define CSR_USB_ADDRESS_ADDR 0xe0004804L
#define CSR_USB_ADDRESS_SIZE 1
static inline unsigned char usb_address_read(void) {
unsigned char r = csr_readl(0xe0004804L);
return r;
}
static inline void usb_address_write(unsigned char value) {
csr_writel(value, 0xe0004804L);
}
#define CSR_USB_ADDRESS_ADDR_OFFSET 0
#define CSR_USB_ADDRESS_ADDR_SIZE 7
#define CSR_USB_NEXT_EV_ADDR 0xe0004808L
#define CSR_USB_NEXT_EV_SIZE 1
static inline unsigned char usb_next_ev_read(void) {
unsigned char r = csr_readl(0xe0004808L);
return r;
}
#define CSR_USB_NEXT_EV_IN_OFFSET 0
#define CSR_USB_NEXT_EV_IN_SIZE 1
#define CSR_USB_NEXT_EV_OUT_OFFSET 1
#define CSR_USB_NEXT_EV_OUT_SIZE 1
#define CSR_USB_NEXT_EV_SETUP_OFFSET 2
#define CSR_USB_NEXT_EV_SETUP_SIZE 1
#define CSR_USB_NEXT_EV_RESET_OFFSET 3
#define CSR_USB_NEXT_EV_RESET_SIZE 1
#define CSR_USB_SETUP_DATA_ADDR 0xe000480cL
#define CSR_USB_SETUP_DATA_SIZE 1
static inline unsigned char usb_setup_data_read(void) {
unsigned char r = csr_readl(0xe000480cL);
return r;
}
#define CSR_USB_SETUP_DATA_DATA_OFFSET 0
#define CSR_USB_SETUP_DATA_DATA_SIZE 8
#define CSR_USB_SETUP_CTRL_ADDR 0xe0004810L
#define CSR_USB_SETUP_CTRL_SIZE 1
static inline unsigned char usb_setup_ctrl_read(void) {
unsigned char r = csr_readl(0xe0004810L);
return r;
}
static inline void usb_setup_ctrl_write(unsigned char value) {
csr_writel(value, 0xe0004810L);
}
#define CSR_USB_SETUP_CTRL_RESET_OFFSET 5
#define CSR_USB_SETUP_CTRL_RESET_SIZE 1
#define CSR_USB_SETUP_STATUS_ADDR 0xe0004814L
#define CSR_USB_SETUP_STATUS_SIZE 1
static inline unsigned char usb_setup_status_read(void) {
unsigned char r = csr_readl(0xe0004814L);
return r;
}
#define CSR_USB_SETUP_STATUS_EPNO_OFFSET 0
#define CSR_USB_SETUP_STATUS_EPNO_SIZE 4
#define CSR_USB_SETUP_STATUS_HAVE_OFFSET 4
#define CSR_USB_SETUP_STATUS_HAVE_SIZE 1
#define CSR_USB_SETUP_STATUS_PEND_OFFSET 5
#define CSR_USB_SETUP_STATUS_PEND_SIZE 1
#define CSR_USB_SETUP_STATUS_IS_IN_OFFSET 6
#define CSR_USB_SETUP_STATUS_IS_IN_SIZE 1
#define CSR_USB_SETUP_STATUS_DATA_OFFSET 7
#define CSR_USB_SETUP_STATUS_DATA_SIZE 1
#define CSR_USB_SETUP_EV_STATUS_ADDR 0xe0004818L
#define CSR_USB_SETUP_EV_STATUS_SIZE 1
static inline unsigned char usb_setup_ev_status_read(void) {
unsigned char r = csr_readl(0xe0004818L);
return r;
}
static inline void usb_setup_ev_status_write(unsigned char value) {
csr_writel(value, 0xe0004818L);
}
#define CSR_USB_SETUP_EV_PENDING_ADDR 0xe000481cL
#define CSR_USB_SETUP_EV_PENDING_SIZE 1
static inline unsigned char usb_setup_ev_pending_read(void) {
unsigned char r = csr_readl(0xe000481cL);
return r;
}
static inline void usb_setup_ev_pending_write(unsigned char value) {
csr_writel(value, 0xe000481cL);
}
#define CSR_USB_SETUP_EV_ENABLE_ADDR 0xe0004820L
#define CSR_USB_SETUP_EV_ENABLE_SIZE 1
static inline unsigned char usb_setup_ev_enable_read(void) {
unsigned char r = csr_readl(0xe0004820L);
return r;
}
static inline void usb_setup_ev_enable_write(unsigned char value) {
csr_writel(value, 0xe0004820L);
}
#define CSR_USB_IN_DATA_ADDR 0xe0004824L
#define CSR_USB_IN_DATA_SIZE 1
static inline unsigned char usb_in_data_read(void) {
unsigned char r = csr_readl(0xe0004824L);
return r;
}
static inline void usb_in_data_write(unsigned char value) {
csr_writel(value, 0xe0004824L);
}
#define CSR_USB_IN_DATA_DATA_OFFSET 0
#define CSR_USB_IN_DATA_DATA_SIZE 8
#define CSR_USB_IN_CTRL_ADDR 0xe0004828L
#define CSR_USB_IN_CTRL_SIZE 1
static inline unsigned char usb_in_ctrl_read(void) {
unsigned char r = csr_readl(0xe0004828L);
return r;
}
static inline void usb_in_ctrl_write(unsigned char value) {
csr_writel(value, 0xe0004828L);
}
#define CSR_USB_IN_CTRL_EPNO_OFFSET 0
#define CSR_USB_IN_CTRL_EPNO_SIZE 4
#define CSR_USB_IN_CTRL_RESET_OFFSET 5
#define CSR_USB_IN_CTRL_RESET_SIZE 1
#define CSR_USB_IN_CTRL_STALL_OFFSET 6
#define CSR_USB_IN_CTRL_STALL_SIZE 1
#define CSR_USB_IN_STATUS_ADDR 0xe000482cL
#define CSR_USB_IN_STATUS_SIZE 1
static inline unsigned char usb_in_status_read(void) {
unsigned char r = csr_readl(0xe000482cL);
return r;
}
#define CSR_USB_IN_STATUS_IDLE_OFFSET 0
#define CSR_USB_IN_STATUS_IDLE_SIZE 1
#define CSR_USB_IN_STATUS_HAVE_OFFSET 4
#define CSR_USB_IN_STATUS_HAVE_SIZE 1
#define CSR_USB_IN_STATUS_PEND_OFFSET 5
#define CSR_USB_IN_STATUS_PEND_SIZE 1
#define CSR_USB_IN_EV_STATUS_ADDR 0xe0004830L
#define CSR_USB_IN_EV_STATUS_SIZE 1
static inline unsigned char usb_in_ev_status_read(void) {
unsigned char r = csr_readl(0xe0004830L);
return r;
}
static inline void usb_in_ev_status_write(unsigned char value) {
csr_writel(value, 0xe0004830L);
}
#define CSR_USB_IN_EV_PENDING_ADDR 0xe0004834L
#define CSR_USB_IN_EV_PENDING_SIZE 1
static inline unsigned char usb_in_ev_pending_read(void) {
unsigned char r = csr_readl(0xe0004834L);
return r;
}
static inline void usb_in_ev_pending_write(unsigned char value) {
csr_writel(value, 0xe0004834L);
}
#define CSR_USB_IN_EV_ENABLE_ADDR 0xe0004838L
#define CSR_USB_IN_EV_ENABLE_SIZE 1
static inline unsigned char usb_in_ev_enable_read(void) {
unsigned char r = csr_readl(0xe0004838L);
return r;
}
static inline void usb_in_ev_enable_write(unsigned char value) {
csr_writel(value, 0xe0004838L);
}
#define CSR_USB_OUT_DATA_ADDR 0xe000483cL
#define CSR_USB_OUT_DATA_SIZE 1
static inline unsigned char usb_out_data_read(void) {
unsigned char r = csr_readl(0xe000483cL);
return r;
}
#define CSR_USB_OUT_DATA_DATA_OFFSET 0
#define CSR_USB_OUT_DATA_DATA_SIZE 8
#define CSR_USB_OUT_CTRL_ADDR 0xe0004840L
#define CSR_USB_OUT_CTRL_SIZE 1
static inline unsigned char usb_out_ctrl_read(void) {
unsigned char r = csr_readl(0xe0004840L);
return r;
}
static inline void usb_out_ctrl_write(unsigned char value) {
csr_writel(value, 0xe0004840L);
}
#define CSR_USB_OUT_CTRL_EPNO_OFFSET 0
#define CSR_USB_OUT_CTRL_EPNO_SIZE 4
#define CSR_USB_OUT_CTRL_ENABLE_OFFSET 4
#define CSR_USB_OUT_CTRL_ENABLE_SIZE 1
#define CSR_USB_OUT_CTRL_RESET_OFFSET 5
#define CSR_USB_OUT_CTRL_RESET_SIZE 1
#define CSR_USB_OUT_CTRL_STALL_OFFSET 6
#define CSR_USB_OUT_CTRL_STALL_SIZE 1
#define CSR_USB_OUT_STATUS_ADDR 0xe0004844L
#define CSR_USB_OUT_STATUS_SIZE 1
static inline unsigned char usb_out_status_read(void) {
unsigned char r = csr_readl(0xe0004844L);
return r;
}
#define CSR_USB_OUT_STATUS_EPNO_OFFSET 0
#define CSR_USB_OUT_STATUS_EPNO_SIZE 4
#define CSR_USB_OUT_STATUS_HAVE_OFFSET 4
#define CSR_USB_OUT_STATUS_HAVE_SIZE 1
#define CSR_USB_OUT_STATUS_PEND_OFFSET 5
#define CSR_USB_OUT_STATUS_PEND_SIZE 1
#define CSR_USB_OUT_EV_STATUS_ADDR 0xe0004848L
#define CSR_USB_OUT_EV_STATUS_SIZE 1
static inline unsigned char usb_out_ev_status_read(void) {
unsigned char r = csr_readl(0xe0004848L);
return r;
}
static inline void usb_out_ev_status_write(unsigned char value) {
csr_writel(value, 0xe0004848L);
}
#define CSR_USB_OUT_EV_PENDING_ADDR 0xe000484cL
#define CSR_USB_OUT_EV_PENDING_SIZE 1
static inline unsigned char usb_out_ev_pending_read(void) {
unsigned char r = csr_readl(0xe000484cL);
return r;
}
static inline void usb_out_ev_pending_write(unsigned char value) {
csr_writel(value, 0xe000484cL);
}
#define CSR_USB_OUT_EV_ENABLE_ADDR 0xe0004850L
#define CSR_USB_OUT_EV_ENABLE_SIZE 1
static inline unsigned char usb_out_ev_enable_read(void) {
unsigned char r = csr_readl(0xe0004850L);
return r;
}
static inline void usb_out_ev_enable_write(unsigned char value) {
csr_writel(value, 0xe0004850L);
}
#define USB_INTERRUPT 3
#endif /* __USB_EPTRI_H_ */

View File

@ -15,14 +15,17 @@ void usb_connect(void);
void usb_idle(void);
void usb_disconnect(void);
void usb_setup(const struct usb_setup_request *setup, uint32_t size);
void usb_set_address(uint8_t address);
void usb_ack_in(uint8_t epno);
void usb_ack_out(uint8_t epno);
void usb_err_in(uint8_t epno);
void usb_err_out(uint8_t epno);
void usb_ack_in(void);
void usb_ack_out(void);
void usb_err(void);
void usb_send(const void *data, int total_count);
#ifdef __cplusplus
}
#endif
#endif
#endif

30
booster/src/accessors.c Normal file
View File

@ -0,0 +1,30 @@
#include <stdint.h>
void csr_writeb(uint8_t value, uint32_t addr)
{
*((volatile uint8_t *)addr) = value;
}
uint8_t csr_readb(uint32_t addr)
{
return *(volatile uint8_t *)addr;
}
void csr_writew(uint16_t value, uint32_t addr)
{
*((volatile uint16_t *)addr) = value;
}
uint16_t csr_readw(uint32_t addr)
{
return *(volatile uint16_t *)addr;
}
void csr_writel(uint32_t value, uint32_t addr)
{
*((volatile uint32_t *)addr) = value;
}
uint32_t csr_readl(uint32_t addr)
{
return *(volatile uint32_t *)addr;
}

View File

@ -1,131 +1,145 @@
#include <stdint.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <csr.h>
#define SP_MOSI_PIN 0
#define SP_MISO_PIN 1
#define SP_WP_PIN 2
#define SP_HOLD_PIN 3
#define SP_CLK_PIN 4
#define SP_CS_PIN 5
#define SP_D0_PIN 0
#define SP_D1_PIN 1
#define SP_D2_PIN 2
#define SP_D3_PIN 3
#include "spi.h"
#define PI_OUTPUT 1
#define PI_INPUT 0
static void gpioWrite(int pin, int val) {
static uint8_t do_mirror;
if (val)
do_mirror |= 1 << pin;
else
do_mirror &= ~(1 << pin);
picorvspi_cfg1_write(do_mirror);
}
static int gpioRead(int pin) {
return !!(picorvspi_stat1_read() & (1 << pin));
}
enum pin {
PIN_MOSI = 0,
PIN_CLK = 1,
PIN_CS = 2,
PIN_MISO_EN = 3,
PIN_MISO = 4, // Value is ignored
};
void spiBegin(void) {
gpioWrite(SP_WP_PIN, 1);
gpioWrite(SP_HOLD_PIN, 1);
gpioWrite(SP_CS_PIN, 0);
lxspi_bitbang_write((0 << PIN_CLK) | (0 << PIN_CS));
}
void spiEnd(void) {
gpioWrite(SP_CS_PIN, 1);
lxspi_bitbang_write((0 << PIN_CLK) | (1 << PIN_CS));
}
void spiPause(void) {
return;
}
static uint8_t spiXfer(uint8_t out) {
static void spi_single_tx(uint8_t out) {
int bit;
uint8_t in = 0;
for (bit = 7; bit >= 0; bit--) {
if (out & (1 << bit)) {
gpioWrite(SP_MOSI_PIN, 1);
lxspi_bitbang_write((0 << PIN_CLK) | (1 << PIN_MOSI));
lxspi_bitbang_write((1 << PIN_CLK) | (1 << PIN_MOSI));
lxspi_bitbang_write((0 << PIN_CLK) | (1 << PIN_MOSI));
} else {
lxspi_bitbang_write((0 << PIN_CLK) | (0 << PIN_MOSI));
lxspi_bitbang_write((1 << PIN_CLK) | (0 << PIN_MOSI));
lxspi_bitbang_write((0 << PIN_CLK) | (0 << PIN_MOSI));
}
else {
gpioWrite(SP_MOSI_PIN, 0);
}
gpioWrite(SP_CLK_PIN, 1);
spiPause();
in |= ((!!gpioRead(SP_MISO_PIN)) << bit);
gpioWrite(SP_CLK_PIN, 0);
spiPause();
}
}
static uint8_t spi_single_rx(void) {
int bit = 0;
uint8_t in = 0;
lxspi_bitbang_write((1 << PIN_MISO_EN) | (0 << PIN_CLK));
while (bit++ < 8) {
lxspi_bitbang_write((1 << PIN_MISO_EN) | (1 << PIN_CLK));
in = (in << 1) | lxspi_miso_read();
lxspi_bitbang_write((1 << PIN_MISO_EN) | (0 << PIN_CLK));
}
return in;
}
void spiCommand(uint8_t cmd) {
spiXfer(cmd);
static uint8_t spi_read_status(void) {
uint8_t val;
spiBegin();
spi_single_tx(0x05);
val = spi_single_rx();
spiEnd();
return val;
}
uint8_t spiCommandRx(void) {
return spiXfer(0xff);
int spiIsBusy(void) {
return spi_read_status() & (1 << 0);
}
uint8_t spiReadStatus(void) {
uint8_t val = 0xff;
spiBegin();
spiCommand(0x05);
val = spiCommandRx();
spiEnd();
return val;
__attribute__((used))
uint32_t spi_id;
__attribute__((used))
uint32_t spiId(void) {
spi_id = 0;
spiBegin();
spi_single_tx(0x90); // Read manufacturer ID
spi_single_tx(0x00); // Dummy byte 1
spi_single_tx(0x00); // Dummy byte 2
spi_single_tx(0x00); // Dummy byte 3
spi_id = (spi_id << 8) | spi_single_rx(); // Manufacturer ID
spi_id = (spi_id << 8) | spi_single_rx(); // Device ID
spiEnd();
spiBegin();
spi_single_tx(0x9f); // Read device id
(void)spi_single_rx(); // Manufacturer ID (again)
spi_id = (spi_id << 8) | spi_single_rx(); // Memory Type
spi_id = (spi_id << 8) | spi_single_rx(); // Memory Size
spiEnd();
return spi_id;
}
void spiBeginErase4(uint32_t erase_addr) {
// Enable Write-Enable Latch (WEL)
spiBegin();
spiCommand(0x06);
spi_single_tx(0x06);
spiEnd();
spiBegin();
spiCommand(0x20);
spiCommand(erase_addr >> 16);
spiCommand(erase_addr >> 8);
spiCommand(erase_addr >> 0);
spi_single_tx(0x20);
spi_single_tx(erase_addr >> 16);
spi_single_tx(erase_addr >> 8);
spi_single_tx(erase_addr >> 0);
spiEnd();
}
void spiBeginErase32(uint32_t erase_addr) {
// Enable Write-Enable Latch (WEL)
spiBegin();
spiCommand(0x06);
spi_single_tx(0x06);
spiEnd();
spiBegin();
spiCommand(0x52);
spiCommand(erase_addr >> 16);
spiCommand(erase_addr >> 8);
spiCommand(erase_addr >> 0);
spi_single_tx(0x52);
spi_single_tx(erase_addr >> 16);
spi_single_tx(erase_addr >> 8);
spi_single_tx(erase_addr >> 0);
spiEnd();
}
void spiBeginErase64(uint32_t erase_addr) {
// Enable Write-Enable Latch (WEL)
spiBegin();
spiCommand(0x06);
spi_single_tx(0x06);
spiEnd();
spiBegin();
spiCommand(0xD8);
spiCommand(erase_addr >> 16);
spiCommand(erase_addr >> 8);
spiCommand(erase_addr >> 0);
spi_single_tx(0xD8);
spi_single_tx(erase_addr >> 16);
spi_single_tx(erase_addr >> 8);
spi_single_tx(erase_addr >> 0);
spiEnd();
}
int spiIsBusy(void) {
return spiReadStatus() & (1 << 0);
}
void spiBeginWrite(uint32_t addr, const void *v_data, unsigned int count) {
const uint8_t write_cmd = 0x02;
const uint8_t *data = v_data;
@ -133,37 +147,67 @@ void spiBeginWrite(uint32_t addr, const void *v_data, unsigned int count) {
// Enable Write-Enable Latch (WEL)
spiBegin();
spiCommand(0x06);
spi_single_tx(0x06);
spiEnd();
spiBegin();
spiCommand(write_cmd);
spiCommand(addr >> 16);
spiCommand(addr >> 8);
spiCommand(addr >> 0);
spi_single_tx(write_cmd);
spi_single_tx(addr >> 16);
spi_single_tx(addr >> 8);
spi_single_tx(addr >> 0);
for (i = 0; (i < count) && (i < 256); i++)
spiCommand(*data++);
spi_single_tx(*data++);
spiEnd();
}
uint32_t spiId(void) {
uint32_t id = 0;
uint8_t spiReset(void) {
// Writing 0xff eight times is equivalent to exiting QPI mode,
// or if CFM mode is enabled it will terminate CFM and return
// to idle.
unsigned int i;
spiBegin();
spiCommand(0x90); // Read manufacturer ID
spiCommand(0x00); // Dummy byte 1
spiCommand(0x00); // Dummy byte 2
spiCommand(0x00); // Dummy byte 3
id = (id << 8) | spiCommandRx(); // Manufacturer ID
id = (id << 8) | spiCommandRx(); // Device ID
for (i = 0; i < 8; i++)
spi_single_tx(0xff);
spiEnd();
// Some SPI parts require this to wake up
spiBegin();
spiCommand(0x9f); // Read device id
(void)spiCommandRx(); // Manufacturer ID (again)
id = (id << 8) | spiCommandRx(); // Memory Type
id = (id << 8) | spiCommandRx(); // Memory Size
spi_single_tx(0xab); // Read electronic signature
spiEnd();
return id;
}
return 0;
}
int spiInit(void) {
// Ensure CS is deasserted and the clock is high
lxspi_bitbang_write((0 << PIN_CLK) | (1 << PIN_CS));
// Disable memory-mapped mode and enable bit-bang mode
lxspi_bitbang_en_write(1);
// Reset the SPI flash, which will return it to SPI mode even
// if it's in QPI mode, and ensure the chip is accepting commands.
spiReset();
spiId();
return 0;
}
void spiHold(void) {
spiBegin();
spi_single_tx(0xb9);
spiEnd();
}
void spiUnhold(void) {
spiBegin();
spi_single_tx(0xab);
spiEnd();
}
void spiFree(void) {
// Re-enable memory-mapped mode
lxspi_bitbang_en_write(0);
}

View File

@ -1,5 +1,6 @@
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <usb.h>
struct usb_setup_request {
@ -67,16 +68,23 @@ static const uint8_t usb_string_microsoft[18] = {
static uint8_t reply_buffer[8];
static uint8_t usb_configuration = 0;
static uint8_t data_buffer[64];
__attribute__((section(".ramtext")))
void usb_setup(const struct usb_setup_request *setup, uint32_t size)
{
const uint8_t *data = NULL;
uint32_t datalen = 0;
uint8_t ep_dir_is_in = setup->bmRequestType >> 7;
(void)size;
switch (setup->wRequestAndType)
{
case 0x0500: // SET_ADDRESS
usb_set_address(setup->wValue);
break;
case 0x0b01: // SET_INTERFACE
break;
@ -100,7 +108,7 @@ void usb_setup(const struct usb_setup_request *setup, uint32_t size)
case 0x0082: // GET_STATUS (endpoint)
if (setup->wIndex > 0)
{
usb_err();
usb_err_in(0);
return;
}
reply_buffer[0] = 0;
@ -112,8 +120,7 @@ void usb_setup(const struct usb_setup_request *setup, uint32_t size)
case 0x0102: // CLEAR_FEATURE (endpoint)
if (setup->wIndex > 0 || setup->wValue != 0)
{
// TODO: do we need to handle IN vs OUT here?
usb_err();
usb_err_out(0);
return;
}
break;
@ -121,8 +128,7 @@ void usb_setup(const struct usb_setup_request *setup, uint32_t size)
case 0x0302: // SET_FEATURE (endpoint)
if (setup->wIndex > 0 || setup->wValue != 0)
{
// TODO: do we need to handle IN vs OUT here?
usb_err();
usb_err_out(0);
return;
}
break;
@ -138,7 +144,7 @@ void usb_setup(const struct usb_setup_request *setup, uint32_t size)
CASE_VALUE(0x0302, usb_string2_descriptor);
CASE_VALUE(0x03ee, usb_string_microsoft);
CASE_VALUE(0x0f00, usb_bos_descriptor);
default: usb_err(); return;
default: usb_err_in(0); return;
}
#undef CASE_VALUE
goto send;
@ -152,7 +158,7 @@ void usb_setup(const struct usb_setup_request *setup, uint32_t size)
datalen = sizeof(usb_ms_compat_id_descriptor);
break;
}
usb_err();
usb_err_in(0);
return;
#ifdef LANDING_PAGE_URL
@ -165,12 +171,12 @@ void usb_setup(const struct usb_setup_request *setup, uint32_t size)
break;
}
}
usb_err();
usb_err_in(0);
return;
#endif
default:
usb_err();
usb_err_in(0);
return;
}
@ -178,9 +184,18 @@ send:
if (data && datalen) {
if (datalen > setup->wLength)
datalen = setup->wLength;
usb_send(data, datalen);
if (datalen > sizeof(data_buffer))
datalen = sizeof(data_buffer);
memcpy(data_buffer, data, datalen);
usb_send(data_buffer, datalen);
usb_ack_out(0);
}
else {
// Ack the opposite endpoint type
if (ep_dir_is_in)
usb_ack_out(0);
else
usb_ack_in(0);
}
else
usb_ack_in();
return;
}

View File

@ -1,237 +0,0 @@
#include <csr.h>
#include <irq.h>
#include <string.h>
#include <usb.h>
// #ifdef CSR_USB_EP_0_OUT_EV_PENDING_ADDR
#if 1
#define EP0OUT_BUFFERS 8
__attribute__((aligned(4)))
static uint8_t volatile usb_ep0out_buffer_len[EP0OUT_BUFFERS];
static uint8_t volatile usb_ep0out_buffer[EP0OUT_BUFFERS][128];
static uint8_t volatile usb_ep0out_last_tok[EP0OUT_BUFFERS];
static volatile uint8_t usb_ep0out_wr_ptr;
static volatile uint8_t usb_ep0out_rd_ptr;
static const int max_byte_length = 64;
static const uint8_t * volatile current_data;
static volatile int current_length;
static volatile int data_offset;
static volatile int data_to_send;
static int next_packet_is_empty;
// Note that our PIDs are only bits 2 and 3 of the token,
// since all other bits are effectively redundant at this point.
enum USB_PID {
USB_PID_OUT = 0,
USB_PID_SOF = 1,
USB_PID_IN = 2,
USB_PID_SETUP = 3,
};
enum epfifo_response {
EPF_ACK = 0,
EPF_NAK = 1,
EPF_NONE = 2,
EPF_STALL = 3,
};
#define USB_EV_ERROR 1
#define USB_EV_PACKET 2
void usb_idle(void) {
usb_ep_0_out_ev_enable_write(0);
usb_ep_0_in_ev_enable_write(0);
// Reject all incoming data, since there is no handler anymore
usb_ep_0_out_respond_write(EPF_NAK);
// Reject outgoing data, since we don't have any to give.
usb_ep_0_in_respond_write(EPF_NAK);
irq_setmask(irq_getmask() & ~(1 << USB_INTERRUPT));
}
void usb_disconnect(void) {
usb_ep_0_out_ev_enable_write(0);
usb_ep_0_in_ev_enable_write(0);
irq_setmask(irq_getmask() & ~(1 << USB_INTERRUPT));
usb_pullup_out_write(0);
}
void usb_connect(void) {
usb_ep_0_out_ev_pending_write(usb_ep_0_out_ev_enable_read());
usb_ep_0_in_ev_pending_write(usb_ep_0_in_ev_pending_read());
usb_ep_0_out_ev_enable_write(USB_EV_PACKET | USB_EV_ERROR);
usb_ep_0_in_ev_enable_write(USB_EV_PACKET | USB_EV_ERROR);
// Accept incoming data by default.
usb_ep_0_out_respond_write(EPF_ACK);
// Reject outgoing data, since we have none to give yet.
usb_ep_0_in_respond_write(EPF_NAK);
usb_pullup_out_write(1);
irq_setmask(irq_getmask() | (1 << USB_INTERRUPT));
}
void usb_init(void) {
usb_ep0out_wr_ptr = 0;
usb_ep0out_rd_ptr = 0;
usb_pullup_out_write(0);
}
static void process_tx(void) {
// Don't allow requeueing -- only queue more data if we're
// currently set up to respond NAK.
if (usb_ep_0_in_respond_read() != EPF_NAK) {
return;
}
// Prevent us from double-filling the buffer.
if (!usb_ep_0_in_ibuf_empty_read()) {
return;
}
if (!current_data || !current_length) {
return;
}
data_offset += data_to_send;
data_to_send = current_length - data_offset;
// Clamp the data to the maximum packet length
if (data_to_send > max_byte_length) {
data_to_send = max_byte_length;
next_packet_is_empty = 0;
}
else if (data_to_send == max_byte_length) {
next_packet_is_empty = 1;
}
else if (next_packet_is_empty) {
next_packet_is_empty = 0;
data_to_send = 0;
}
else if (current_data == NULL || data_to_send <= 0) {
next_packet_is_empty = 0;
current_data = NULL;
current_length = 0;
data_offset = 0;
data_to_send = 0;
return;
}
int this_offset;
for (this_offset = data_offset; this_offset < (data_offset + data_to_send); this_offset++) {
usb_ep_0_in_ibuf_head_write(current_data[this_offset]);
}
usb_ep_0_in_respond_write(EPF_ACK);
return;
}
void usb_send(const void *data, int total_count) {
while ((current_length || current_data))// && usb_ep_0_in_respond_read() != EPF_NAK)
;
current_data = (uint8_t *)data;
current_length = total_count;
data_offset = 0;
data_to_send = 0;
process_tx();
}
void usb_wait_for_send_done(void) {
while (current_data && current_length)
;
while ((usb_ep_0_in_dtb_read() & 1) == 1)
;
}
void usb_isr(void) {
uint8_t ep0o_pending = usb_ep_0_out_ev_pending_read();
uint8_t ep0i_pending = usb_ep_0_in_ev_pending_read();
// We got an OUT or a SETUP packet. Copy it to usb_ep0out_buffer
// and clear the "pending" bit.
if (ep0o_pending) {
uint8_t last_tok = usb_ep_0_out_last_tok_read();
uint32_t obuf_len = 0;
static uint8_t obuf[128];
if (!usb_ep_0_out_obuf_empty_read()) {
while (!usb_ep_0_out_obuf_empty_read()) {
obuf[obuf_len++] = usb_ep_0_out_obuf_head_read();
usb_ep_0_out_obuf_head_write(0);
}
}
if (obuf_len >= 2)
obuf_len -= 2 /* Strip off CRC16 */;
if (last_tok == USB_PID_SETUP) {
usb_ep_0_in_dtb_write(1);
data_offset = 0;
current_length = 0;
current_data = NULL;
usb_setup((const void *)obuf, obuf_len);
}
usb_ep_0_out_ev_pending_write(ep0o_pending);
usb_ep_0_out_respond_write(EPF_ACK);
}
// We just got an "IN" token. Send data if we have it.
if (ep0i_pending) {
usb_ep_0_in_respond_write(EPF_NAK);
usb_ep_0_in_ev_pending_write(ep0i_pending);
}
return;
}
void usb_ack_in(void) {
while (usb_ep_0_in_respond_read() == EPF_ACK)
;
usb_ep_0_in_respond_write(EPF_ACK);
}
void usb_ack_out(void) {
while (usb_ep_0_out_respond_read() == EPF_ACK)
;
usb_ep_0_out_respond_write(EPF_ACK);
}
void usb_err(void) {
usb_ep_0_out_respond_write(EPF_STALL);
usb_ep_0_in_respond_write(EPF_STALL);
}
int usb_recv(void *buffer, unsigned int buffer_len) {
// Set the OUT response to ACK, since we are in a position to receive data now.
usb_ep_0_out_respond_write(EPF_ACK);
while (1) {
if (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
if (usb_ep0out_last_tok[usb_ep0out_rd_ptr] == USB_PID_OUT) {
unsigned int ep0_buffer_len = usb_ep0out_buffer_len[usb_ep0out_rd_ptr];
if (ep0_buffer_len < buffer_len)
buffer_len = ep0_buffer_len;
// usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0;
memcpy(buffer, (void *)&usb_ep0out_buffer[usb_ep0out_rd_ptr], buffer_len);
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
return buffer_len;
}
else if (usb_ep0out_last_tok[usb_ep0out_rd_ptr] == USB_PID_SETUP) {
return -1;
}
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
}
}
return 0;
}
#endif /* CSR_USB_EP_0_OUT_EV_PENDING_ADDR */

314
booster/src/usb-eptri.c Normal file
View File

@ -0,0 +1,314 @@
#include <usb.h>
#include <irq.h>
#include <string.h>
#include <usb.h>
#include <usb-eptri.h>
__attribute__((aligned(4)))
//__attribute__((used, aligned(4)))
//static uint8_t volatile previous_setup_packet[10];
//__attribute__((used))
//volatile uint32_t previous_setup_length;
static uint8_t volatile out_buffer_length;
static uint8_t volatile out_buffer[128];
static uint8_t volatile out_ep;
static uint8_t volatile out_have;
static const int max_byte_length = 64;
static const uint8_t * volatile current_data;
static volatile int current_length;
static volatile uint8_t current_epno;
static volatile int data_offset;
static volatile int data_to_send;
static int next_packet_is_empty;
__attribute__((used))
const uint8_t * last_data;
__attribute__((used))
int last_length;
__attribute__((used))
int last_epno;
__attribute__((used))
int last_data_offset;
__attribute__((used))
int last_data_to_send;
__attribute__((used))
int last_packet_was_empty;
static uint8_t next_address = 0;
#define USB_EV_ERROR 1
#define USB_EV_PACKET 2
void eptri_usb_idle(void) {
irq_setmask(irq_getmask() & ~(1 << USB_INTERRUPT));
}
void eptri_usb_disconnect(void) {
irq_setmask(irq_getmask() & ~(1 << USB_INTERRUPT));
usb_pullup_out_write(0);
}
void usb_connect(void) {
usb_setup_ev_pending_write(usb_setup_ev_pending_read());
usb_in_ev_pending_write(usb_in_ev_pending_read());
usb_out_ev_pending_write(usb_out_ev_pending_read());
usb_setup_ev_enable_write(3);
usb_in_ev_enable_write(1);
usb_out_ev_enable_write(1);
// Reset the IN handler
usb_in_ctrl_write(1 << CSR_USB_IN_CTRL_RESET_OFFSET);
// Reset the SETUP handler
usb_setup_ctrl_write(1 << CSR_USB_SETUP_CTRL_RESET_OFFSET);
// Reset the OUT handler
usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_RESET_OFFSET);
// Accept incoming data by default.
usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_ENABLE_OFFSET);
usb_address_write(0);
// Turn on the external pullup
usb_pullup_out_write(1);
// Unmask the interrupt so we can respond to interrupts
irq_setmask(irq_getmask() | (1 << USB_INTERRUPT));
}
void usb_init(void) {
out_buffer_length = 0;
usb_pullup_out_write(0);
usb_address_write(0);
usb_out_ctrl_write(0);
usb_setup_ev_enable_write(0);
usb_in_ev_enable_write(0);
usb_out_ev_enable_write(0);
// Reset the IN handler
usb_in_ctrl_write(1 << CSR_USB_IN_CTRL_RESET_OFFSET);
// Reset the SETUP handler
usb_setup_ctrl_write(1 << CSR_USB_SETUP_CTRL_RESET_OFFSET);
// Reset the OUT handler
usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_RESET_OFFSET);
return;
}
static void process_tx(void) {
// Don't allow requeueing -- only queue more data if the system is idle.
if (!(usb_in_status_read() & (1 << CSR_USB_IN_STATUS_IDLE_OFFSET))) {
return;
}
// Don't send empty data
if (!current_data || !current_length) {
return;
}
last_data_offset = data_offset;
data_offset += data_to_send;
last_data_to_send = data_to_send;
data_to_send = current_length - data_offset;
// Clamp the data to the maximum packet length
if (data_to_send > max_byte_length) {
last_data_to_send = data_to_send;
data_to_send = max_byte_length;
last_packet_was_empty = next_packet_is_empty;
next_packet_is_empty = 0;
}
else if (data_to_send == max_byte_length) {
last_packet_was_empty = next_packet_is_empty;
next_packet_is_empty = 1;
}
else if (next_packet_is_empty) {
last_packet_was_empty = next_packet_is_empty;
next_packet_is_empty = 0;
last_data_to_send = data_to_send;
data_to_send = 0;
}
else if (current_data == NULL || data_to_send <= 0) {
last_packet_was_empty = next_packet_is_empty;
next_packet_is_empty = 0;
last_data = current_data;
last_length = current_length;
last_data_offset = data_offset;
last_data_to_send = data_to_send;
current_data = NULL;
current_length = 0;
data_offset = 0;
data_to_send = 0;
return;
}
// We have more data to send, so fill the buffer
int this_offset;
for (this_offset = data_offset; this_offset < (data_offset + data_to_send); this_offset++) {
usb_in_data_write(current_data[this_offset]);
}
// Updating the epno queues the data
usb_in_ctrl_write(current_epno & 0xf);
return;
}
static void process_rx(void) {
// If we already have data in our buffer, don't do anything.
if (out_have)
return;
// If there isn't any data in the FIFO, don't do anything.
if (!(usb_out_status_read() & (1 << CSR_USB_OUT_STATUS_HAVE_OFFSET)))
return;
out_have = 1;
out_ep = (usb_out_status_read() >> CSR_USB_OUT_STATUS_EPNO_OFFSET) & 0xf;
out_buffer_length = 0;
while (usb_out_status_read() & (1 << CSR_USB_OUT_STATUS_HAVE_OFFSET)) {
out_buffer[out_buffer_length++] = usb_out_data_read();
}
// Strip off the CRC16 that's at the end of the buffer
if (out_buffer_length >= 2)
out_buffer_length -= 2;
}
void usb_send(const void *data, int total_count) {
uint8_t epno = 0;
while ((current_length || current_data) && !(usb_in_status_read() & 2))
process_tx();
last_epno = current_epno;
current_data = (uint8_t *)data;
current_length = total_count;
current_epno = epno;
data_offset = 0;
data_to_send = 0;
process_tx();
}
void eptri_usb_wait_for_send_done(void) {
while (current_data && current_length)
;
while (usb_in_status_read() & (1 << CSR_USB_IN_STATUS_HAVE_OFFSET))
;
}
void usb_isr(void) {
uint8_t setup_packet[10];
uint32_t setup_length;
uint8_t setup_pending = usb_setup_ev_pending_read();
uint8_t in_pending = usb_in_ev_pending_read();
uint8_t out_pending = usb_out_ev_pending_read();
// Clear all interrupts before we handle them
usb_setup_ev_pending_write(setup_pending);
usb_in_ev_pending_write(in_pending);
usb_out_ev_pending_write(out_pending);
// USB reset event
if (setup_pending & 2) {
out_buffer_length = 0;
out_have = 0;
current_data = NULL;
current_length = 0;
usb_connect();
return;
}
// We got a SETUP packet. Copy it to the setup buffer and clear
// the "pending" bit.
if (setup_pending & 1) {
// previous_setup_length = setup_length;
// memcpy((void *)previous_setup_packet, (void *)setup_packet, sizeof(setup_packet));
setup_length = 0;
memset((void *)setup_packet, 0, sizeof(setup_packet));
while (usb_setup_status_read() & (1 << CSR_USB_SETUP_STATUS_HAVE_OFFSET)) {
setup_packet[setup_length++] = usb_setup_data_read();
}
// If we have 8 bytes, that's a full SETUP packet.
// Otherwise, it was an RX error.
if (setup_length == 10) {
usb_setup((const struct usb_setup_request *)setup_packet, 8);
}
}
// An "IN" transaction just completed.
if (in_pending) {
// Process more data to send, if we have any.
process_tx();
// If next_address is nonzero, then this is the completion of
// the IN packet that follows as the final ACK. This means
// we're free to set our address now.
if (next_address) {
usb_address_write(next_address);
next_address = 0;
}
}
// An "OUT" transaction just completed so we have new data.
// (But only if we can accept the data)
if (out_pending) {
process_rx();
}
return;
}
void usb_ack_in(uint8_t ep) {
(void)ep;
// Writing to this register queues a transfer
usb_in_ctrl_write(0);
}
void usb_ack_out(uint8_t ep) {
(void)ep;
out_have = 0;
usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_ENABLE_OFFSET);
}
void usb_err_in(uint8_t ep) {
(void)ep;
usb_in_ctrl_write(1 << CSR_USB_IN_CTRL_STALL_OFFSET);
}
void usb_err_out(uint8_t ep) {
(void)ep;
usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_STALL_OFFSET);
}
int eptri_usb_recv(void *buffer, int buffer_len) {
// Set the OUT response to ACK, since we are in a position to receive data now.
if (out_have) {
usb_ack_out(0);
}
while (1) {
if (out_have) {
if (buffer_len > out_buffer_length)
buffer_len = out_buffer_length;
memcpy(buffer, (void *)out_buffer, buffer_len);
usb_ack_out(0);
return buffer_len;
}
}
}
void usb_set_address(uint8_t new_address) {
next_address = new_address;
}