sw: first software commit
The software is untested, but it builds. Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
		
							
								
								
									
										131
									
								
								sw/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								sw/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,131 @@
 | 
			
		||||
GIT_VERSION := $(shell git describe --tags)
 | 
			
		||||
 | 
			
		||||
# There is no 64-bit gcc on Raspberry Pi, so use the 32-bit version
 | 
			
		||||
ifneq (,$(wildcard /etc/rpi-issue))
 | 
			
		||||
TRGT       ?= riscv32-unknown-elf-
 | 
			
		||||
else
 | 
			
		||||
TRGT       ?= riscv64-unknown-elf-
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
CC         := $(TRGT)gcc
 | 
			
		||||
CXX        := $(TRGT)g++
 | 
			
		||||
OBJCOPY    := $(TRGT)objcopy
 | 
			
		||||
 | 
			
		||||
RM         := rm -rf
 | 
			
		||||
COPY       := cp -a
 | 
			
		||||
PATH_SEP   := /
 | 
			
		||||
 | 
			
		||||
ifeq ($(OS),Windows_NT)
 | 
			
		||||
COPY       := copy
 | 
			
		||||
RM         := del
 | 
			
		||||
PATH_SEP   := \\
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ($(LITEX),1)
 | 
			
		||||
BASE_DIR   := ../../../../sw
 | 
			
		||||
LDSCRIPT   := $(BASE_DIR)/ld/linker.ld
 | 
			
		||||
LD_DIR     := ../include/generated
 | 
			
		||||
ADD_CFLAGS := -I../include -I$(BASE_DIR)/include
 | 
			
		||||
ADD_LFLAGS := 
 | 
			
		||||
PACKAGE    := bios
 | 
			
		||||
else
 | 
			
		||||
BASE_DIR   := .
 | 
			
		||||
LD_DIR     := $(BASE_DIR)/ld
 | 
			
		||||
LDSCRIPT   := $(BASE_DIR)/ld/linker.ld
 | 
			
		||||
ADD_CFLAGS := -I$(BASE_DIR)/include
 | 
			
		||||
ADD_LFLAGS := 
 | 
			
		||||
PACKAGE    := factory-test
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
LDSCRIPTS  := $(LDSCRIPT) $(LD_DIR)/output_format.ld $(LD_DIR)/regions.ld
 | 
			
		||||
SRC_DIR    := $(BASE_DIR)/src
 | 
			
		||||
THIRD_PARTY := $(BASE_DIR)/third_party
 | 
			
		||||
DBG_CFLAGS := -ggdb -g -DDEBUG -Wall
 | 
			
		||||
DBG_LFLAGS := -ggdb -g -Wall
 | 
			
		||||
CFLAGS     := $(ADD_CFLAGS) \
 | 
			
		||||
			  -D__vexriscv__ -march=rv32i  -mabi=ilp32 \
 | 
			
		||||
			  -Wall -Wextra \
 | 
			
		||||
			  -flto \
 | 
			
		||||
			  -ffunction-sections -fdata-sections -fno-common \
 | 
			
		||||
			  -fomit-frame-pointer -Os \
 | 
			
		||||
			  -march=rv32i \
 | 
			
		||||
			  -DGIT_VERSION=u\"$(GIT_VERSION)\" -std=gnu11
 | 
			
		||||
CXXFLAGS   := $(CFLAGS) -std=c++11 -fno-rtti -fno-exceptions
 | 
			
		||||
LFLAGS     := $(CFLAGS) $(ADD_LFLAGS) -L$(LD_DIR) \
 | 
			
		||||
			  -nostartfiles \
 | 
			
		||||
			  -nostdlib \
 | 
			
		||||
			  -Wl,--gc-sections \
 | 
			
		||||
			  -Wl,--no-warn-mismatch \
 | 
			
		||||
			  -Wl,--script=$(LDSCRIPT) \
 | 
			
		||||
			  -Wl,--build-id=none
 | 
			
		||||
 | 
			
		||||
OBJ_DIR    := .obj
 | 
			
		||||
 | 
			
		||||
CSOURCES   := $(wildcard $(SRC_DIR)/*.c)
 | 
			
		||||
CPPSOURCES := $(wildcard $(SRC_DIR)/*.cpp)
 | 
			
		||||
ASOURCES   := $(wildcard $(SRC_DIR)/*.S)
 | 
			
		||||
COBJS      := $(addprefix $(OBJ_DIR)/, $(notdir $(CSOURCES:.c=.o)))
 | 
			
		||||
CXXOBJS    := $(addprefix $(OBJ_DIR)/, $(notdir $(CPPSOURCES:.cpp=.o)))
 | 
			
		||||
AOBJS      := $(addprefix $(OBJ_DIR)/, $(notdir $(ASOURCES:.S=.o)))
 | 
			
		||||
OBJECTS    := $(COBJS) $(CXXOBJS) $(AOBJS)
 | 
			
		||||
VPATH      := $(SRC_DIR)
 | 
			
		||||
 | 
			
		||||
QUIET      := @
 | 
			
		||||
 | 
			
		||||
ALL        := all
 | 
			
		||||
TARGET     := $(PACKAGE).elf
 | 
			
		||||
CLEAN      := clean
 | 
			
		||||
 | 
			
		||||
$(ALL): $(TARGET) $(PACKAGE).bin $(PACKAGE).ihex
 | 
			
		||||
 | 
			
		||||
$(OBJECTS): | $(OBJ_DIR)
 | 
			
		||||
 | 
			
		||||
$(TARGET): $(OBJECTS) $(LDSCRIPTS)
 | 
			
		||||
	$(QUIET) echo "  LD       $@"
 | 
			
		||||
	$(QUIET) $(CC) $(OBJECTS) $(LFLAGS) -o $@
 | 
			
		||||
 | 
			
		||||
$(PACKAGE).bin: $(TARGET)
 | 
			
		||||
	$(QUIET) echo "  OBJCOPY  $@"
 | 
			
		||||
	$(QUIET) $(OBJCOPY) -O binary $(TARGET) $@
 | 
			
		||||
 | 
			
		||||
$(PACKAGE).dfu: $(TARGET)
 | 
			
		||||
	$(QUIET) echo "  DFU      $@"
 | 
			
		||||
	$(QUIET) $(COPY) $(PACKAGE).bin $@
 | 
			
		||||
	$(QUIET) dfu-suffix -v 1209 -p 70b1 -a $@
 | 
			
		||||
 | 
			
		||||
$(PACKAGE).ihex: $(TARGET)
 | 
			
		||||
	$(QUIET) echo "  IHEX     $(PACKAGE).ihex"
 | 
			
		||||
	$(QUIET) $(OBJCOPY) -O ihex $(TARGET) $@
 | 
			
		||||
 | 
			
		||||
$(DEBUG): CFLAGS += $(DBG_CFLAGS)
 | 
			
		||||
$(DEBUG): LFLAGS += $(DBG_LFLAGS)
 | 
			
		||||
CFLAGS += $(DBG_CFLAGS)
 | 
			
		||||
LFLAGS += $(DBG_LFLAGS)
 | 
			
		||||
$(DEBUG): $(TARGET)
 | 
			
		||||
 | 
			
		||||
$(OBJ_DIR):
 | 
			
		||||
	$(QUIET) mkdir $(OBJ_DIR)
 | 
			
		||||
 | 
			
		||||
$(COBJS) : $(OBJ_DIR)/%.o : %.c $(BASE_DIR)/Makefile
 | 
			
		||||
	$(QUIET) echo "  CC       $<	$(notdir $@)"
 | 
			
		||||
	$(QUIET) $(CC) -c $< $(CFLAGS) -o $@ -MMD
 | 
			
		||||
 | 
			
		||||
$(OBJ_DIR)/%.o: %.cpp
 | 
			
		||||
	$(QUIET) echo "  CXX      $<	$(notdir $@)"
 | 
			
		||||
	$(QUIET) $(CXX) -c $< $(CXXFLAGS) -o $@ -MMD
 | 
			
		||||
 | 
			
		||||
$(OBJ_DIR)/%.o: %.S
 | 
			
		||||
	$(QUIET) echo "  AS       $<	$(notdir $@)"
 | 
			
		||||
	$(QUIET) $(CC) -x assembler-with-cpp -c $< $(CFLAGS) -o $@ -MMD
 | 
			
		||||
 | 
			
		||||
.PHONY: clean
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	$(QUIET) echo "  RM      $(subst /,$(PATH_SEP),$(wildcard $(OBJ_DIR)/*.d))"
 | 
			
		||||
	-$(QUIET) $(RM) $(subst /,$(PATH_SEP),$(wildcard $(OBJ_DIR)/*.d))
 | 
			
		||||
	$(QUIET) echo "  RM      $(subst /,$(PATH_SEP),$(wildcard $(OBJ_DIR)/*.d))"
 | 
			
		||||
	-$(QUIET) $(RM) $(subst /,$(PATH_SEP),$(wildcard $(OBJ_DIR)/*.o))
 | 
			
		||||
	$(QUIET) echo "  RM      $(TARGET) $(PACKAGE).bin $(PACKAGE).symbol $(PACKAGE).ihex $(PACKAGE).dfu"
 | 
			
		||||
	-$(QUIET) $(RM) $(TARGET) $(PACKAGE).bin $(PACKAGE).symbol $(PACKAGE).ihex $(PACKAGE).dfu
 | 
			
		||||
 | 
			
		||||
include $(wildcard $(OBJ_DIR)/*.d)
 | 
			
		||||
							
								
								
									
										903
									
								
								sw/include/fomu/csr.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										903
									
								
								sw/include/fomu/csr.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,903 @@
 | 
			
		||||
#ifndef __GENERATED_CSR_H
 | 
			
		||||
#define __GENERATED_CSR_H
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#ifdef CSR_ACCESSORS_DEFINED
 | 
			
		||||
extern void csr_writeb(uint8_t value, uint32_t addr);
 | 
			
		||||
extern uint8_t csr_readb(uint32_t addr);
 | 
			
		||||
extern void csr_writew(uint16_t value, uint32_t addr);
 | 
			
		||||
extern uint16_t csr_readw(uint32_t addr);
 | 
			
		||||
extern void csr_writel(uint32_t value, uint32_t addr);
 | 
			
		||||
extern uint32_t csr_readl(uint32_t addr);
 | 
			
		||||
#else /* ! CSR_ACCESSORS_DEFINED */
 | 
			
		||||
static inline void csr_writeb(uint8_t value, uint32_t addr)
 | 
			
		||||
{
 | 
			
		||||
	*((volatile uint8_t *)addr) = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline uint8_t csr_readb(uint32_t addr)
 | 
			
		||||
{
 | 
			
		||||
	return *(volatile uint8_t *)addr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void csr_writew(uint16_t value, uint32_t addr)
 | 
			
		||||
{
 | 
			
		||||
	*((volatile uint16_t *)addr) = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline uint16_t csr_readw(uint32_t addr)
 | 
			
		||||
{
 | 
			
		||||
	return *(volatile uint16_t *)addr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void csr_writel(uint32_t value, uint32_t addr)
 | 
			
		||||
{
 | 
			
		||||
	*((volatile uint32_t *)addr) = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline uint32_t csr_readl(uint32_t addr)
 | 
			
		||||
{
 | 
			
		||||
	return *(volatile uint32_t *)addr;
 | 
			
		||||
}
 | 
			
		||||
#endif /* ! CSR_ACCESSORS_DEFINED */
 | 
			
		||||
 | 
			
		||||
/* ctrl */
 | 
			
		||||
#define CSR_CTRL_BASE 0xe0000000
 | 
			
		||||
#define CSR_CTRL_RESET_ADDR 0xe0000000
 | 
			
		||||
#define CSR_CTRL_RESET_SIZE 1
 | 
			
		||||
	static inline unsigned char
 | 
			
		||||
	ctrl_reset_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0000000);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void ctrl_reset_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0000000);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_CTRL_SCRATCH_ADDR 0xe0000004
 | 
			
		||||
#define CSR_CTRL_SCRATCH_SIZE 4
 | 
			
		||||
static inline unsigned int ctrl_scratch_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int r = csr_readl(0xe0000004);
 | 
			
		||||
	r <<= 8;
 | 
			
		||||
	r |= csr_readl(0xe0000008);
 | 
			
		||||
	r <<= 8;
 | 
			
		||||
	r |= csr_readl(0xe000000c);
 | 
			
		||||
	r <<= 8;
 | 
			
		||||
	r |= csr_readl(0xe0000010);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void ctrl_scratch_write(unsigned int value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value >> 24, 0xe0000004);
 | 
			
		||||
	csr_writel(value >> 16, 0xe0000008);
 | 
			
		||||
	csr_writel(value >> 8, 0xe000000c);
 | 
			
		||||
	csr_writel(value, 0xe0000010);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_CTRL_BUS_ERRORS_ADDR 0xe0000014
 | 
			
		||||
#define CSR_CTRL_BUS_ERRORS_SIZE 4
 | 
			
		||||
static inline unsigned int ctrl_bus_errors_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int r = csr_readl(0xe0000014);
 | 
			
		||||
	r <<= 8;
 | 
			
		||||
	r |= csr_readl(0xe0000018);
 | 
			
		||||
	r <<= 8;
 | 
			
		||||
	r |= csr_readl(0xe000001c);
 | 
			
		||||
	r <<= 8;
 | 
			
		||||
	r |= csr_readl(0xe0000020);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* picorvspi */
 | 
			
		||||
#define CSR_PICORVSPI_BASE 0xe0005000
 | 
			
		||||
#define CSR_PICORVSPI_CFG1_ADDR 0xe0005000
 | 
			
		||||
#define CSR_PICORVSPI_CFG1_SIZE 1
 | 
			
		||||
static inline unsigned char picorvspi_cfg1_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0005000);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void picorvspi_cfg1_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0005000);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_PICORVSPI_CFG2_ADDR 0xe0005004
 | 
			
		||||
#define CSR_PICORVSPI_CFG2_SIZE 1
 | 
			
		||||
static inline unsigned char picorvspi_cfg2_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0005004);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void picorvspi_cfg2_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0005004);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_PICORVSPI_CFG3_ADDR 0xe0005008
 | 
			
		||||
#define CSR_PICORVSPI_CFG3_SIZE 1
 | 
			
		||||
static inline unsigned char picorvspi_cfg3_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0005008);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void picorvspi_cfg3_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0005008);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_PICORVSPI_CFG4_ADDR 0xe000500c
 | 
			
		||||
#define CSR_PICORVSPI_CFG4_SIZE 1
 | 
			
		||||
static inline unsigned char picorvspi_cfg4_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe000500c);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void picorvspi_cfg4_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe000500c);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_PICORVSPI_STAT1_ADDR 0xe0005010
 | 
			
		||||
#define CSR_PICORVSPI_STAT1_SIZE 1
 | 
			
		||||
static inline unsigned char picorvspi_stat1_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0005010);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
#define CSR_PICORVSPI_STAT2_ADDR 0xe0005014
 | 
			
		||||
#define CSR_PICORVSPI_STAT2_SIZE 1
 | 
			
		||||
static inline unsigned char picorvspi_stat2_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0005014);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
#define CSR_PICORVSPI_STAT3_ADDR 0xe0005018
 | 
			
		||||
#define CSR_PICORVSPI_STAT3_SIZE 1
 | 
			
		||||
static inline unsigned char picorvspi_stat3_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0005018);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
#define CSR_PICORVSPI_STAT4_ADDR 0xe000501c
 | 
			
		||||
#define CSR_PICORVSPI_STAT4_SIZE 1
 | 
			
		||||
static inline unsigned char picorvspi_stat4_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe000501c);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* reboot */
 | 
			
		||||
#define CSR_REBOOT_BASE 0xe0006000
 | 
			
		||||
#define CSR_REBOOT_CTRL_ADDR 0xe0006000
 | 
			
		||||
#define CSR_REBOOT_CTRL_SIZE 1
 | 
			
		||||
static inline unsigned char reboot_ctrl_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0006000);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void reboot_ctrl_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0006000);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_REBOOT_ADDR_ADDR 0xe0006004
 | 
			
		||||
#define CSR_REBOOT_ADDR_SIZE 4
 | 
			
		||||
static inline unsigned int reboot_addr_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int r = csr_readl(0xe0006004);
 | 
			
		||||
	r <<= 8;
 | 
			
		||||
	r |= csr_readl(0xe0006008);
 | 
			
		||||
	r <<= 8;
 | 
			
		||||
	r |= csr_readl(0xe000600c);
 | 
			
		||||
	r <<= 8;
 | 
			
		||||
	r |= csr_readl(0xe0006010);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void reboot_addr_write(unsigned int value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value >> 24, 0xe0006004);
 | 
			
		||||
	csr_writel(value >> 16, 0xe0006008);
 | 
			
		||||
	csr_writel(value >> 8, 0xe000600c);
 | 
			
		||||
	csr_writel(value, 0xe0006010);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* rgb */
 | 
			
		||||
#define CSR_RGB_BASE 0xe0006800
 | 
			
		||||
#define CSR_RGB_DAT_ADDR 0xe0006800
 | 
			
		||||
#define CSR_RGB_DAT_SIZE 1
 | 
			
		||||
static inline unsigned char rgb_dat_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0006800);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void rgb_dat_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0006800);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_RGB_ADDR_ADDR 0xe0006804
 | 
			
		||||
#define CSR_RGB_ADDR_SIZE 1
 | 
			
		||||
static inline unsigned char rgb_addr_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0006804);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void rgb_addr_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0006804);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_RGB_CTRL_ADDR 0xe0006808
 | 
			
		||||
#define CSR_RGB_CTRL_SIZE 1
 | 
			
		||||
static inline unsigned char rgb_ctrl_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0006808);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void rgb_ctrl_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0006808);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* timer0 */
 | 
			
		||||
#define CSR_TIMER0_BASE 0xe0002800
 | 
			
		||||
#define CSR_TIMER0_LOAD_ADDR 0xe0002800
 | 
			
		||||
#define CSR_TIMER0_LOAD_SIZE 4
 | 
			
		||||
static inline unsigned int timer0_load_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int r = csr_readl(0xe0002800);
 | 
			
		||||
	r <<= 8;
 | 
			
		||||
	r |= csr_readl(0xe0002804);
 | 
			
		||||
	r <<= 8;
 | 
			
		||||
	r |= csr_readl(0xe0002808);
 | 
			
		||||
	r <<= 8;
 | 
			
		||||
	r |= csr_readl(0xe000280c);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void timer0_load_write(unsigned int value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value >> 24, 0xe0002800);
 | 
			
		||||
	csr_writel(value >> 16, 0xe0002804);
 | 
			
		||||
	csr_writel(value >> 8, 0xe0002808);
 | 
			
		||||
	csr_writel(value, 0xe000280c);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_TIMER0_RELOAD_ADDR 0xe0002810
 | 
			
		||||
#define CSR_TIMER0_RELOAD_SIZE 4
 | 
			
		||||
static inline unsigned int timer0_reload_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int r = csr_readl(0xe0002810);
 | 
			
		||||
	r <<= 8;
 | 
			
		||||
	r |= csr_readl(0xe0002814);
 | 
			
		||||
	r <<= 8;
 | 
			
		||||
	r |= csr_readl(0xe0002818);
 | 
			
		||||
	r <<= 8;
 | 
			
		||||
	r |= csr_readl(0xe000281c);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void timer0_reload_write(unsigned int value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value >> 24, 0xe0002810);
 | 
			
		||||
	csr_writel(value >> 16, 0xe0002814);
 | 
			
		||||
	csr_writel(value >> 8, 0xe0002818);
 | 
			
		||||
	csr_writel(value, 0xe000281c);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_TIMER0_EN_ADDR 0xe0002820
 | 
			
		||||
#define CSR_TIMER0_EN_SIZE 1
 | 
			
		||||
static inline unsigned char timer0_en_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0002820);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void timer0_en_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0002820);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_TIMER0_UPDATE_VALUE_ADDR 0xe0002824
 | 
			
		||||
#define CSR_TIMER0_UPDATE_VALUE_SIZE 1
 | 
			
		||||
static inline unsigned char timer0_update_value_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0002824);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void timer0_update_value_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0002824);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_TIMER0_VALUE_ADDR 0xe0002828
 | 
			
		||||
#define CSR_TIMER0_VALUE_SIZE 4
 | 
			
		||||
static inline unsigned int timer0_value_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int r = csr_readl(0xe0002828);
 | 
			
		||||
	r <<= 8;
 | 
			
		||||
	r |= csr_readl(0xe000282c);
 | 
			
		||||
	r <<= 8;
 | 
			
		||||
	r |= csr_readl(0xe0002830);
 | 
			
		||||
	r <<= 8;
 | 
			
		||||
	r |= csr_readl(0xe0002834);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
#define CSR_TIMER0_EV_STATUS_ADDR 0xe0002838
 | 
			
		||||
#define CSR_TIMER0_EV_STATUS_SIZE 1
 | 
			
		||||
static inline unsigned char timer0_ev_status_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0002838);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void timer0_ev_status_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0002838);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_TIMER0_EV_PENDING_ADDR 0xe000283c
 | 
			
		||||
#define CSR_TIMER0_EV_PENDING_SIZE 1
 | 
			
		||||
static inline unsigned char timer0_ev_pending_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe000283c);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void timer0_ev_pending_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe000283c);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_TIMER0_EV_ENABLE_ADDR 0xe0002840
 | 
			
		||||
#define CSR_TIMER0_EV_ENABLE_SIZE 1
 | 
			
		||||
static inline unsigned char timer0_ev_enable_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0002840);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void timer0_ev_enable_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0002840);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* touch */
 | 
			
		||||
#define CSR_TOUCH_BASE 0xe0005800
 | 
			
		||||
#define CSR_TOUCH_O_ADDR 0xe0005800
 | 
			
		||||
#define CSR_TOUCH_O_SIZE 1
 | 
			
		||||
static inline unsigned char touch_o_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0005800);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void touch_o_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0005800);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_TOUCH_OE_ADDR 0xe0005804
 | 
			
		||||
#define CSR_TOUCH_OE_SIZE 1
 | 
			
		||||
static inline unsigned char touch_oe_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0005804);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void touch_oe_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0005804);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_TOUCH_I_ADDR 0xe0005808
 | 
			
		||||
#define CSR_TOUCH_I_SIZE 1
 | 
			
		||||
static inline unsigned char touch_i_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0005808);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* usb */
 | 
			
		||||
#define CSR_USB_BASE 0xe0004800
 | 
			
		||||
#define CSR_USB_PULLUP_OUT_ADDR 0xe0004800
 | 
			
		||||
#define CSR_USB_PULLUP_OUT_SIZE 1
 | 
			
		||||
static inline unsigned char usb_pullup_out_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004800);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_pullup_out_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0004800);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_0_OUT_EV_STATUS_ADDR 0xe0004804
 | 
			
		||||
#define CSR_USB_EP_0_OUT_EV_STATUS_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_0_out_ev_status_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004804);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_0_out_ev_status_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0004804);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_0_OUT_EV_PENDING_ADDR 0xe0004808
 | 
			
		||||
#define CSR_USB_EP_0_OUT_EV_PENDING_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_0_out_ev_pending_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004808);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_0_out_ev_pending_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0004808);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_0_OUT_EV_ENABLE_ADDR 0xe000480c
 | 
			
		||||
#define CSR_USB_EP_0_OUT_EV_ENABLE_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_0_out_ev_enable_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe000480c);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_0_out_ev_enable_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe000480c);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_0_OUT_LAST_TOK_ADDR 0xe0004810
 | 
			
		||||
#define CSR_USB_EP_0_OUT_LAST_TOK_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_0_out_last_tok_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004810);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_0_OUT_RESPOND_ADDR 0xe0004814
 | 
			
		||||
#define CSR_USB_EP_0_OUT_RESPOND_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_0_out_respond_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004814);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_0_out_respond_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0004814);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_0_OUT_DTB_ADDR 0xe0004818
 | 
			
		||||
#define CSR_USB_EP_0_OUT_DTB_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_0_out_dtb_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004818);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_0_out_dtb_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0004818);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_0_OUT_OBUF_HEAD_ADDR 0xe000481c
 | 
			
		||||
#define CSR_USB_EP_0_OUT_OBUF_HEAD_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_0_out_obuf_head_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe000481c);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_0_out_obuf_head_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe000481c);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_0_OUT_OBUF_EMPTY_ADDR 0xe0004820
 | 
			
		||||
#define CSR_USB_EP_0_OUT_OBUF_EMPTY_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_0_out_obuf_empty_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004820);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_0_IN_EV_STATUS_ADDR 0xe0004824
 | 
			
		||||
#define CSR_USB_EP_0_IN_EV_STATUS_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_0_in_ev_status_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004824);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_0_in_ev_status_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0004824);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_0_IN_EV_PENDING_ADDR 0xe0004828
 | 
			
		||||
#define CSR_USB_EP_0_IN_EV_PENDING_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_0_in_ev_pending_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004828);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_0_in_ev_pending_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0004828);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_0_IN_EV_ENABLE_ADDR 0xe000482c
 | 
			
		||||
#define CSR_USB_EP_0_IN_EV_ENABLE_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_0_in_ev_enable_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe000482c);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_0_in_ev_enable_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe000482c);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_0_IN_LAST_TOK_ADDR 0xe0004830
 | 
			
		||||
#define CSR_USB_EP_0_IN_LAST_TOK_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_0_in_last_tok_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004830);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_0_IN_RESPOND_ADDR 0xe0004834
 | 
			
		||||
#define CSR_USB_EP_0_IN_RESPOND_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_0_in_respond_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004834);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_0_in_respond_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0004834);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_0_IN_DTB_ADDR 0xe0004838
 | 
			
		||||
#define CSR_USB_EP_0_IN_DTB_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_0_in_dtb_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004838);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_0_in_dtb_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0004838);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_0_IN_IBUF_HEAD_ADDR 0xe000483c
 | 
			
		||||
#define CSR_USB_EP_0_IN_IBUF_HEAD_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_0_in_ibuf_head_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe000483c);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_0_in_ibuf_head_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe000483c);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_0_IN_IBUF_EMPTY_ADDR 0xe0004840
 | 
			
		||||
#define CSR_USB_EP_0_IN_IBUF_EMPTY_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_0_in_ibuf_empty_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004840);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_1_IN_EV_STATUS_ADDR 0xe0004844
 | 
			
		||||
#define CSR_USB_EP_1_IN_EV_STATUS_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_1_in_ev_status_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004844);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_1_in_ev_status_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0004844);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_1_IN_EV_PENDING_ADDR 0xe0004848
 | 
			
		||||
#define CSR_USB_EP_1_IN_EV_PENDING_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_1_in_ev_pending_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004848);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_1_in_ev_pending_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0004848);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_1_IN_EV_ENABLE_ADDR 0xe000484c
 | 
			
		||||
#define CSR_USB_EP_1_IN_EV_ENABLE_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_1_in_ev_enable_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe000484c);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_1_in_ev_enable_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe000484c);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_1_IN_LAST_TOK_ADDR 0xe0004850
 | 
			
		||||
#define CSR_USB_EP_1_IN_LAST_TOK_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_1_in_last_tok_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004850);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_1_IN_RESPOND_ADDR 0xe0004854
 | 
			
		||||
#define CSR_USB_EP_1_IN_RESPOND_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_1_in_respond_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004854);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_1_in_respond_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0004854);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_1_IN_DTB_ADDR 0xe0004858
 | 
			
		||||
#define CSR_USB_EP_1_IN_DTB_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_1_in_dtb_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004858);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_1_in_dtb_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0004858);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_1_IN_IBUF_HEAD_ADDR 0xe000485c
 | 
			
		||||
#define CSR_USB_EP_1_IN_IBUF_HEAD_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_1_in_ibuf_head_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe000485c);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_1_in_ibuf_head_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe000485c);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_1_IN_IBUF_EMPTY_ADDR 0xe0004860
 | 
			
		||||
#define CSR_USB_EP_1_IN_IBUF_EMPTY_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_1_in_ibuf_empty_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004860);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_2_OUT_EV_STATUS_ADDR 0xe0004864
 | 
			
		||||
#define CSR_USB_EP_2_OUT_EV_STATUS_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_2_out_ev_status_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004864);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_2_out_ev_status_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0004864);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_2_OUT_EV_PENDING_ADDR 0xe0004868
 | 
			
		||||
#define CSR_USB_EP_2_OUT_EV_PENDING_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_2_out_ev_pending_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004868);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_2_out_ev_pending_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0004868);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_2_OUT_EV_ENABLE_ADDR 0xe000486c
 | 
			
		||||
#define CSR_USB_EP_2_OUT_EV_ENABLE_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_2_out_ev_enable_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe000486c);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_2_out_ev_enable_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe000486c);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_2_OUT_LAST_TOK_ADDR 0xe0004870
 | 
			
		||||
#define CSR_USB_EP_2_OUT_LAST_TOK_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_2_out_last_tok_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004870);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_2_OUT_RESPOND_ADDR 0xe0004874
 | 
			
		||||
#define CSR_USB_EP_2_OUT_RESPOND_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_2_out_respond_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004874);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_2_out_respond_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0004874);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_2_OUT_DTB_ADDR 0xe0004878
 | 
			
		||||
#define CSR_USB_EP_2_OUT_DTB_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_2_out_dtb_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004878);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_2_out_dtb_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0004878);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_2_OUT_OBUF_HEAD_ADDR 0xe000487c
 | 
			
		||||
#define CSR_USB_EP_2_OUT_OBUF_HEAD_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_2_out_obuf_head_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe000487c);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_2_out_obuf_head_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe000487c);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_2_OUT_OBUF_EMPTY_ADDR 0xe0004880
 | 
			
		||||
#define CSR_USB_EP_2_OUT_OBUF_EMPTY_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_2_out_obuf_empty_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004880);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_2_IN_EV_STATUS_ADDR 0xe0004884
 | 
			
		||||
#define CSR_USB_EP_2_IN_EV_STATUS_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_2_in_ev_status_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004884);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_2_in_ev_status_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0004884);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_2_IN_EV_PENDING_ADDR 0xe0004888
 | 
			
		||||
#define CSR_USB_EP_2_IN_EV_PENDING_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_2_in_ev_pending_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004888);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_2_in_ev_pending_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0004888);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_2_IN_EV_ENABLE_ADDR 0xe000488c
 | 
			
		||||
#define CSR_USB_EP_2_IN_EV_ENABLE_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_2_in_ev_enable_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe000488c);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_2_in_ev_enable_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe000488c);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_2_IN_LAST_TOK_ADDR 0xe0004890
 | 
			
		||||
#define CSR_USB_EP_2_IN_LAST_TOK_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_2_in_last_tok_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004890);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_2_IN_RESPOND_ADDR 0xe0004894
 | 
			
		||||
#define CSR_USB_EP_2_IN_RESPOND_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_2_in_respond_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004894);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_2_in_respond_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0004894);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_2_IN_DTB_ADDR 0xe0004898
 | 
			
		||||
#define CSR_USB_EP_2_IN_DTB_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_2_in_dtb_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0004898);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_2_in_dtb_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe0004898);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_2_IN_IBUF_HEAD_ADDR 0xe000489c
 | 
			
		||||
#define CSR_USB_EP_2_IN_IBUF_HEAD_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_2_in_ibuf_head_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe000489c);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static inline void usb_ep_2_in_ibuf_head_write(unsigned char value)
 | 
			
		||||
{
 | 
			
		||||
	csr_writel(value, 0xe000489c);
 | 
			
		||||
}
 | 
			
		||||
#define CSR_USB_EP_2_IN_IBUF_EMPTY_ADDR 0xe00048a0
 | 
			
		||||
#define CSR_USB_EP_2_IN_IBUF_EMPTY_SIZE 1
 | 
			
		||||
static inline unsigned char usb_ep_2_in_ibuf_empty_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe00048a0);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* version */
 | 
			
		||||
#define CSR_VERSION_BASE 0xe0007000
 | 
			
		||||
#define CSR_VERSION_MAJOR_ADDR 0xe0007000
 | 
			
		||||
#define CSR_VERSION_MAJOR_SIZE 1
 | 
			
		||||
static inline unsigned char version_major_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0007000);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
#define CSR_VERSION_MINOR_ADDR 0xe0007004
 | 
			
		||||
#define CSR_VERSION_MINOR_SIZE 1
 | 
			
		||||
static inline unsigned char version_minor_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0007004);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
#define CSR_VERSION_REVISION_ADDR 0xe0007008
 | 
			
		||||
#define CSR_VERSION_REVISION_SIZE 1
 | 
			
		||||
static inline unsigned char version_revision_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0007008);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
#define CSR_VERSION_GITREV_ADDR 0xe000700c
 | 
			
		||||
#define CSR_VERSION_GITREV_SIZE 4
 | 
			
		||||
static inline unsigned int version_gitrev_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int r = csr_readl(0xe000700c);
 | 
			
		||||
	r <<= 8;
 | 
			
		||||
	r |= csr_readl(0xe0007010);
 | 
			
		||||
	r <<= 8;
 | 
			
		||||
	r |= csr_readl(0xe0007014);
 | 
			
		||||
	r <<= 8;
 | 
			
		||||
	r |= csr_readl(0xe0007018);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
#define CSR_VERSION_GITEXTRA_ADDR 0xe000701c
 | 
			
		||||
#define CSR_VERSION_GITEXTRA_SIZE 2
 | 
			
		||||
static inline unsigned short int version_gitextra_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned short int r = csr_readl(0xe000701c);
 | 
			
		||||
	r <<= 8;
 | 
			
		||||
	r |= csr_readl(0xe0007020);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
#define CSR_VERSION_DIRTY_ADDR 0xe0007024
 | 
			
		||||
#define CSR_VERSION_DIRTY_SIZE 1
 | 
			
		||||
static inline unsigned char version_dirty_read(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char r = csr_readl(0xe0007024);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* constants */
 | 
			
		||||
#define NMI_INTERRUPT 0
 | 
			
		||||
static inline int nmi_interrupt_read(void)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
#define TIMER0_INTERRUPT 1
 | 
			
		||||
static inline int timer0_interrupt_read(void)
 | 
			
		||||
{
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
#define UART_INTERRUPT 2
 | 
			
		||||
static inline int uart_interrupt_read(void)
 | 
			
		||||
{
 | 
			
		||||
	return 2;
 | 
			
		||||
}
 | 
			
		||||
#define USB_INTERRUPT 3
 | 
			
		||||
static inline int usb_interrupt_read(void)
 | 
			
		||||
{
 | 
			
		||||
	return 3;
 | 
			
		||||
}
 | 
			
		||||
#define CSR_DATA_WIDTH 8
 | 
			
		||||
static inline int csr_data_width_read(void)
 | 
			
		||||
{
 | 
			
		||||
	return 8;
 | 
			
		||||
}
 | 
			
		||||
#define SYSTEM_CLOCK_FREQUENCY 12000000
 | 
			
		||||
static inline int system_clock_frequency_read(void)
 | 
			
		||||
{
 | 
			
		||||
	return 12000000;
 | 
			
		||||
}
 | 
			
		||||
#define CONFIG_CLOCK_FREQUENCY 12000000
 | 
			
		||||
static inline int config_clock_frequency_read(void)
 | 
			
		||||
{
 | 
			
		||||
	return 12000000;
 | 
			
		||||
}
 | 
			
		||||
#define CONFIG_CPU_RESET_ADDR 0
 | 
			
		||||
static inline int config_cpu_reset_addr_read(void)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
#define CONFIG_CPU_TYPE "VEXRISCV"
 | 
			
		||||
static inline const char *config_cpu_type_read(void)
 | 
			
		||||
{
 | 
			
		||||
	return "VEXRISCV";
 | 
			
		||||
}
 | 
			
		||||
#define CONFIG_CPU_VARIANT "VEXRISCV"
 | 
			
		||||
static inline const char *config_cpu_variant_read(void)
 | 
			
		||||
{
 | 
			
		||||
	return "VEXRISCV";
 | 
			
		||||
}
 | 
			
		||||
#define CONFIG_CSR_DATA_WIDTH 8
 | 
			
		||||
static inline int config_csr_data_width_read(void)
 | 
			
		||||
{
 | 
			
		||||
	return 8;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										16
									
								
								sw/include/fomu/mem.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								sw/include/fomu/mem.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
#ifndef __GENERATED_MEM_H
 | 
			
		||||
#define __GENERATED_MEM_H
 | 
			
		||||
 | 
			
		||||
#define VEXRISCV_DEBUG_BASE 0xf00f0000
 | 
			
		||||
#define VEXRISCV_DEBUG_SIZE 0x00000010
 | 
			
		||||
 | 
			
		||||
#define SRAM_BASE 0x10000000
 | 
			
		||||
#define SRAM_SIZE 0x00020000
 | 
			
		||||
 | 
			
		||||
#define ROM_BASE 0x00000000
 | 
			
		||||
#define ROM_SIZE 0x00002000
 | 
			
		||||
 | 
			
		||||
#define SPIFLASH_BASE 0x20000000
 | 
			
		||||
#define SPIFLASH_SIZE 0x00200000
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										145
									
								
								sw/include/irq.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								sw/include/irq.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,145 @@
 | 
			
		||||
#ifndef __IRQ_H
 | 
			
		||||
#define __IRQ_H
 | 
			
		||||
 | 
			
		||||
#include <riscv.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef __picorv32__
 | 
			
		||||
// PicoRV32 has a very limited interrupt support, implemented via custom
 | 
			
		||||
// instructions. It also doesn't have a global interrupt enable/disable, so
 | 
			
		||||
// we have to emulate it via saving and restoring a mask and using 0/~1 as a
 | 
			
		||||
// hardware mask.
 | 
			
		||||
// Due to all this somewhat low-level mess, all of the glue is implemented in
 | 
			
		||||
// the RiscV crt0, and this header is kept as a thin wrapper. Since interrupts
 | 
			
		||||
// managed by this layer, do not call interrupt instructions directly, as the
 | 
			
		||||
// state will go out of sync with the hardware.
 | 
			
		||||
 | 
			
		||||
// Read only.
 | 
			
		||||
extern unsigned int _irq_pending;
 | 
			
		||||
// Read only.
 | 
			
		||||
extern unsigned int _irq_mask;
 | 
			
		||||
// Read only.
 | 
			
		||||
extern unsigned int _irq_enabled;
 | 
			
		||||
extern void _irq_enable(void);
 | 
			
		||||
extern void _irq_disable(void);
 | 
			
		||||
extern void _irq_setmask(unsigned int);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static inline unsigned int irq_getie(void)
 | 
			
		||||
{
 | 
			
		||||
#if defined (__lm32__)
 | 
			
		||||
	unsigned int ie;
 | 
			
		||||
	__asm__ __volatile__("rcsr %0, IE" : "=r" (ie));
 | 
			
		||||
	return ie;
 | 
			
		||||
#elif defined (__or1k__)
 | 
			
		||||
	return !!(mfspr(SPR_SR) & SPR_SR_IEE);
 | 
			
		||||
#elif defined (__picorv32__)
 | 
			
		||||
	return _irq_enabled != 0;
 | 
			
		||||
#elif defined (__vexriscv__)
 | 
			
		||||
	return (csrr(mstatus) & CSR_MSTATUS_MIE) != 0;
 | 
			
		||||
#elif defined (__minerva__)
 | 
			
		||||
	return (csrr(mstatus) & CSR_MSTATUS_MIE) != 0;
 | 
			
		||||
#else
 | 
			
		||||
#error Unsupported architecture
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void irq_setie(unsigned int ie)
 | 
			
		||||
{
 | 
			
		||||
#if defined (__lm32__)
 | 
			
		||||
	__asm__ __volatile__("wcsr IE, %0" : : "r" (ie));
 | 
			
		||||
#elif defined (__or1k__)
 | 
			
		||||
	if (ie & 0x1)
 | 
			
		||||
		mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_IEE);
 | 
			
		||||
	else
 | 
			
		||||
		mtspr(SPR_SR, mfspr(SPR_SR) & ~SPR_SR_IEE);
 | 
			
		||||
#elif defined (__picorv32__)
 | 
			
		||||
    if (ie & 0x1)
 | 
			
		||||
        _irq_enable();
 | 
			
		||||
    else
 | 
			
		||||
        _irq_disable();
 | 
			
		||||
#elif defined (__vexriscv__)
 | 
			
		||||
	if(ie) csrs(mstatus,CSR_MSTATUS_MIE); else csrc(mstatus,CSR_MSTATUS_MIE);
 | 
			
		||||
#elif defined (__minerva__)
 | 
			
		||||
	if(ie) csrs(mstatus,CSR_MSTATUS_MIE); else csrc(mstatus,CSR_MSTATUS_MIE);
 | 
			
		||||
#else
 | 
			
		||||
#error Unsupported architecture
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline unsigned int irq_getmask(void)
 | 
			
		||||
{
 | 
			
		||||
#if defined (__lm32__)
 | 
			
		||||
	unsigned int mask;
 | 
			
		||||
	__asm__ __volatile__("rcsr %0, IM" : "=r" (mask));
 | 
			
		||||
	return mask;
 | 
			
		||||
#elif defined (__or1k__)
 | 
			
		||||
	return mfspr(SPR_PICMR);
 | 
			
		||||
#elif defined (__picorv32__)
 | 
			
		||||
    // PicoRV32 interrupt mask bits are high-disabled. This is the inverse of how
 | 
			
		||||
    // LiteX sees things.
 | 
			
		||||
    return ~_irq_mask;
 | 
			
		||||
#elif defined (__vexriscv__)
 | 
			
		||||
	unsigned int mask;
 | 
			
		||||
	asm volatile ("csrr %0, %1" : "=r"(mask) : "i"(CSR_IRQ_MASK));
 | 
			
		||||
	return mask;
 | 
			
		||||
#elif defined (__minerva__)
 | 
			
		||||
	unsigned int mask;
 | 
			
		||||
	asm volatile ("csrr %0, %1" : "=r"(mask) : "i"(CSR_IRQ_MASK));
 | 
			
		||||
	return mask;
 | 
			
		||||
#else
 | 
			
		||||
#error Unsupported architecture
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void irq_setmask(unsigned int mask)
 | 
			
		||||
{
 | 
			
		||||
#if defined (__lm32__)
 | 
			
		||||
	__asm__ __volatile__("wcsr IM, %0" : : "r" (mask));
 | 
			
		||||
#elif defined (__or1k__)
 | 
			
		||||
	mtspr(SPR_PICMR, mask);
 | 
			
		||||
#elif defined (__picorv32__)
 | 
			
		||||
    // PicoRV32 interrupt mask bits are high-disabled. This is the inverse of how
 | 
			
		||||
    // LiteX sees things.
 | 
			
		||||
    _irq_setmask(~mask);
 | 
			
		||||
#elif defined (__vexriscv__)
 | 
			
		||||
	asm volatile ("csrw %0, %1" :: "i"(CSR_IRQ_MASK), "r"(mask));
 | 
			
		||||
#elif defined (__minerva__)
 | 
			
		||||
	asm volatile ("csrw %0, %1" :: "i"(CSR_IRQ_MASK), "r"(mask));
 | 
			
		||||
#else
 | 
			
		||||
#error Unsupported architecture
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline unsigned int irq_pending(void)
 | 
			
		||||
{
 | 
			
		||||
#if defined (__lm32__)
 | 
			
		||||
	unsigned int pending;
 | 
			
		||||
	__asm__ __volatile__("rcsr %0, IP" : "=r" (pending));
 | 
			
		||||
	return pending;
 | 
			
		||||
#elif defined (__or1k__)
 | 
			
		||||
	return mfspr(SPR_PICSR);
 | 
			
		||||
#elif defined (__picorv32__)
 | 
			
		||||
	return _irq_pending;
 | 
			
		||||
#elif defined (__vexriscv__)
 | 
			
		||||
	unsigned int pending;
 | 
			
		||||
	asm volatile ("csrr %0, %1" : "=r"(pending) : "i"(CSR_IRQ_PENDING));
 | 
			
		||||
	return pending;
 | 
			
		||||
#elif defined (__minerva__)
 | 
			
		||||
	unsigned int pending;
 | 
			
		||||
	asm volatile ("csrr %0, %1" : "=r"(pending) : "i"(CSR_IRQ_PENDING));
 | 
			
		||||
	return pending;
 | 
			
		||||
#else
 | 
			
		||||
#error Unsupported architecture
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __IRQ_H */
 | 
			
		||||
							
								
								
									
										10
									
								
								sw/include/rgb.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								sw/include/rgb.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
#ifndef _RGB_H_
 | 
			
		||||
#define _RGB_H_
 | 
			
		||||
 | 
			
		||||
void rgb_init(void);
 | 
			
		||||
void rgb_mode_idle(void);
 | 
			
		||||
void rgb_mode_done(void);
 | 
			
		||||
void rgb_mode_writing(void);
 | 
			
		||||
void rgb_mode_error(void);
 | 
			
		||||
 | 
			
		||||
#endif /* _RGB_H_ */
 | 
			
		||||
							
								
								
									
										54
									
								
								sw/include/riscv.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								sw/include/riscv.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
#ifndef RISCV_DEFS_H__
 | 
			
		||||
#define RISCV_DEFS_H__
 | 
			
		||||
 | 
			
		||||
#include <fomu/csr.h>
 | 
			
		||||
 | 
			
		||||
#define CSR_MSTATUS_MIE 0x8
 | 
			
		||||
 | 
			
		||||
#define CSR_IRQ_MASK 0xBC0
 | 
			
		||||
#define CSR_IRQ_PENDING 0xFC0
 | 
			
		||||
 | 
			
		||||
#define CSR_DCACHE_INFO 0xCC0
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void flush_cpu_icache(void);
 | 
			
		||||
void flush_cpu_dcache(void);
 | 
			
		||||
void flush_l2_cache(void);
 | 
			
		||||
 | 
			
		||||
#define csrr(reg) ({ unsigned long __tmp; \
 | 
			
		||||
  asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \
 | 
			
		||||
  __tmp; })
 | 
			
		||||
 | 
			
		||||
#define csrw(reg, val) ({ \
 | 
			
		||||
  if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \
 | 
			
		||||
	asm volatile ("csrw " #reg ", %0" :: "i"(val)); \
 | 
			
		||||
  else \
 | 
			
		||||
	asm volatile ("csrw " #reg ", %0" :: "r"(val)); })
 | 
			
		||||
 | 
			
		||||
#define csrs(reg, bit) ({ \
 | 
			
		||||
  if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \
 | 
			
		||||
	asm volatile ("csrrs x0, " #reg ", %0" :: "i"(bit)); \
 | 
			
		||||
  else \
 | 
			
		||||
	asm volatile ("csrrs x0, " #reg ", %0" :: "r"(bit)); })
 | 
			
		||||
 | 
			
		||||
#define csrc(reg, bit) ({ \
 | 
			
		||||
  if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \
 | 
			
		||||
	asm volatile ("csrrc x0, " #reg ", %0" :: "i"(bit)); \
 | 
			
		||||
  else \
 | 
			
		||||
	asm volatile ("csrrc x0, " #reg ", %0" :: "r"(bit)); })
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
__attribute__((noreturn)) void reboot(void);
 | 
			
		||||
 | 
			
		||||
__attribute__((noreturn)) static inline void warmboot_to_image(uint8_t image_index) {
 | 
			
		||||
	reboot_ctrl_write(0xac | (image_index & 3) << 0);
 | 
			
		||||
	while (1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif	/* RISCV_DEFS_H__ */
 | 
			
		||||
							
								
								
									
										94
									
								
								sw/include/spi.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								sw/include/spi.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,94 @@
 | 
			
		||||
#ifndef BB_SPI_H_
 | 
			
		||||
#define BB_SPI_H_
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
enum spi_state {
 | 
			
		||||
	SS_UNCONFIGURED = 0,
 | 
			
		||||
	SS_SINGLE,
 | 
			
		||||
	SS_DUAL_RX,
 | 
			
		||||
	SS_DUAL_TX,
 | 
			
		||||
	SS_QUAD_RX,
 | 
			
		||||
	SS_QUAD_TX,
 | 
			
		||||
	SS_HARDWARE,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum spi_type {
 | 
			
		||||
	ST_UNCONFIGURED,
 | 
			
		||||
	ST_SINGLE,
 | 
			
		||||
	ST_DUAL,
 | 
			
		||||
	ST_QUAD,
 | 
			
		||||
	ST_QPI,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum spi_pin {
 | 
			
		||||
	SP_MOSI,
 | 
			
		||||
	SP_MISO,
 | 
			
		||||
	SP_HOLD,
 | 
			
		||||
	SP_WP,
 | 
			
		||||
	SP_CS,
 | 
			
		||||
	SP_CLK,
 | 
			
		||||
	SP_D0,
 | 
			
		||||
	SP_D1,
 | 
			
		||||
	SP_D2,
 | 
			
		||||
	SP_D3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct spi_id {
 | 
			
		||||
	uint8_t manufacturer_id;	// Result from 0x90
 | 
			
		||||
	uint8_t device_id;		// Result from 0x90
 | 
			
		||||
	uint8_t _manufacturer_id;	// Result from 0x9f
 | 
			
		||||
	uint8_t memory_type;		// Result from 0x9f
 | 
			
		||||
	uint8_t memory_size;		// Result from 0x9f
 | 
			
		||||
	uint8_t signature;		// Result from 0xab
 | 
			
		||||
	uint8_t serial[4];		// Result from 0x4b
 | 
			
		||||
	int bytes;			// -1 if unknown
 | 
			
		||||
	const char *manufacturer;
 | 
			
		||||
	const char *model;
 | 
			
		||||
	const char *capacity;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ff_spi;
 | 
			
		||||
 | 
			
		||||
void spiPause(struct ff_spi *spi);
 | 
			
		||||
void spiBegin(struct ff_spi *spi);
 | 
			
		||||
void spiEnd(struct ff_spi *spi);
 | 
			
		||||
 | 
			
		||||
//void spiSingleTx(struct ff_spi *spi, uint8_t out);
 | 
			
		||||
//uint8_t spiSingleRx(struct ff_spi *spi);
 | 
			
		||||
//void spiDualTx(struct ff_spi *spi, uint8_t out);
 | 
			
		||||
//void spiQuadTx(struct ff_spi *spi, uint8_t out);
 | 
			
		||||
void spiCommand(struct ff_spi *spi, uint8_t cmd);
 | 
			
		||||
//uint8_t spiDualRx(struct ff_spi *spi);
 | 
			
		||||
//uint8_t spiQuadRx(struct ff_spi *spi);
 | 
			
		||||
int spiTx(struct ff_spi *spi, uint8_t word);
 | 
			
		||||
uint8_t spiRx(struct ff_spi *spi);
 | 
			
		||||
uint8_t spiReadStatus(struct ff_spi *spi, uint8_t sr);
 | 
			
		||||
void spiWriteStatus(struct ff_spi *spi, uint8_t sr, uint8_t val);
 | 
			
		||||
void spiReadSecurity(struct ff_spi *spi, uint8_t sr, uint8_t security[256]);
 | 
			
		||||
void spiWriteSecurity(struct ff_spi *spi, uint8_t sr, uint8_t security[256]);
 | 
			
		||||
int spiSetType(struct ff_spi *spi, enum spi_type type);
 | 
			
		||||
int spiRead(struct ff_spi *spi, uint32_t addr, uint8_t *data, unsigned int count);
 | 
			
		||||
int spiIsBusy(struct ff_spi *spi);
 | 
			
		||||
int spiBeginErase32(struct ff_spi *spi, uint32_t erase_addr);
 | 
			
		||||
int spiBeginErase64(struct ff_spi *spi, uint32_t erase_addr);
 | 
			
		||||
int spiBeginWrite(struct ff_spi *spi, uint32_t addr, const void *data, unsigned int count);
 | 
			
		||||
void spiEnableQuad(void);
 | 
			
		||||
 | 
			
		||||
struct spi_id spiId(struct ff_spi *spi);
 | 
			
		||||
void spiOverrideSize(struct ff_spi *spi, uint32_t new_size);
 | 
			
		||||
 | 
			
		||||
//int spi_wait_for_not_busy(struct ff_spi *spi);
 | 
			
		||||
int spiWrite(struct ff_spi *spi, uint32_t addr, const uint8_t *data, unsigned int count);
 | 
			
		||||
uint8_t spiReset(struct ff_spi *spi);
 | 
			
		||||
int spiInit(struct ff_spi *spi);
 | 
			
		||||
 | 
			
		||||
void spiHold(struct ff_spi *spi);
 | 
			
		||||
void spiUnhold(struct ff_spi *spi);
 | 
			
		||||
void spiSwapTxRx(struct ff_spi *spi);
 | 
			
		||||
 | 
			
		||||
struct ff_spi *spiAlloc(void);
 | 
			
		||||
void spiSetPin(struct ff_spi *spi, enum spi_pin pin, int val);
 | 
			
		||||
void spiFree(void);
 | 
			
		||||
 | 
			
		||||
#endif /* BB_SPI_H_ */
 | 
			
		||||
							
								
								
									
										16
									
								
								sw/include/time.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								sw/include/time.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
#ifndef __TIME_H
 | 
			
		||||
#define __TIME_H
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void time_init(void);
 | 
			
		||||
int elapsed(int *last_event, int period);
 | 
			
		||||
void msleep(int ms);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __TIME_H */
 | 
			
		||||
							
								
								
									
										162
									
								
								sw/include/usb-cdc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								sw/include/usb-cdc.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,162 @@
 | 
			
		||||
/** @defgroup usb_cdc_defines USB CDC Type Definitions
 | 
			
		||||
 | 
			
		||||
@brief <b>Defined Constants and Types for the USB CDC Type Definitions</b>
 | 
			
		||||
 | 
			
		||||
@ingroup USB_defines
 | 
			
		||||
 | 
			
		||||
@version 1.0.0
 | 
			
		||||
 | 
			
		||||
@author @htmlonly © @endhtmlonly 2010
 | 
			
		||||
Gareth McMullin <gareth@blacksphere.co.nz>
 | 
			
		||||
 | 
			
		||||
@date 10 March 2013
 | 
			
		||||
 | 
			
		||||
LGPL License Terms @ref lgpl_license
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This file is part of the libopencm3 project.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with this library.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**@{*/
 | 
			
		||||
 | 
			
		||||
#ifndef __CDC_H
 | 
			
		||||
#define __CDC_H
 | 
			
		||||
 | 
			
		||||
/* Definitions of Communications Device Class from
 | 
			
		||||
 * "Universal Serial Bus Class Definitions for Communications Devices
 | 
			
		||||
 * Revision 1.2"
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* Table 2: Communications Device Class Code */
 | 
			
		||||
#define USB_CLASS_CDC			0x02
 | 
			
		||||
 | 
			
		||||
/* Table 4: Class Subclass Code */
 | 
			
		||||
#define USB_CDC_SUBCLASS_DLCM		0x01
 | 
			
		||||
#define USB_CDC_SUBCLASS_ACM		0x02
 | 
			
		||||
/* ... */
 | 
			
		||||
 | 
			
		||||
/* Table 5 Communications Interface Class Control Protocol Codes */
 | 
			
		||||
#define USB_CDC_PROTOCOL_NONE		0x00
 | 
			
		||||
#define USB_CDC_PROTOCOL_AT		0x01
 | 
			
		||||
/* ... */
 | 
			
		||||
 | 
			
		||||
/* Table 6: Data Interface Class Code */
 | 
			
		||||
#define USB_CLASS_DATA			0x0A
 | 
			
		||||
 | 
			
		||||
/* Table 12: Type Values for the bDescriptorType Field */
 | 
			
		||||
#define CS_INTERFACE			0x24
 | 
			
		||||
#define CS_ENDPOINT			0x25
 | 
			
		||||
 | 
			
		||||
/* Table 13: bDescriptor SubType in Communications Class Functional
 | 
			
		||||
 * Descriptors */
 | 
			
		||||
#define USB_CDC_TYPE_HEADER		0x00
 | 
			
		||||
#define USB_CDC_TYPE_CALL_MANAGEMENT	0x01
 | 
			
		||||
#define USB_CDC_TYPE_ACM		0x02
 | 
			
		||||
/* ... */
 | 
			
		||||
#define USB_CDC_TYPE_UNION		0x06
 | 
			
		||||
/* ... */
 | 
			
		||||
 | 
			
		||||
/* Table 15: Class-Specific Descriptor Header Format */
 | 
			
		||||
struct usb_cdc_header_descriptor {
 | 
			
		||||
	uint8_t bFunctionLength;
 | 
			
		||||
	uint8_t bDescriptorType;
 | 
			
		||||
	uint8_t bDescriptorSubtype;
 | 
			
		||||
	uint16_t bcdCDC;
 | 
			
		||||
} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
/* Table 16: Union Interface Functional Descriptor */
 | 
			
		||||
struct usb_cdc_union_descriptor {
 | 
			
		||||
	uint8_t bFunctionLength;
 | 
			
		||||
	uint8_t bDescriptorType;
 | 
			
		||||
	uint8_t bDescriptorSubtype;
 | 
			
		||||
	uint8_t bControlInterface;
 | 
			
		||||
	uint8_t bSubordinateInterface0;
 | 
			
		||||
	/* ... */
 | 
			
		||||
} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Definitions for Abstract Control Model devices from:
 | 
			
		||||
 * "Universal Serial Bus Communications Class Subclass Specification for
 | 
			
		||||
 * PSTN Devices"
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* Table 3: Call Management Functional Descriptor */
 | 
			
		||||
struct usb_cdc_call_management_descriptor {
 | 
			
		||||
	uint8_t bFunctionLength;
 | 
			
		||||
	uint8_t bDescriptorType;
 | 
			
		||||
	uint8_t bDescriptorSubtype;
 | 
			
		||||
	uint8_t bmCapabilities;
 | 
			
		||||
	uint8_t bDataInterface;
 | 
			
		||||
} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
/* Table 4: Abstract Control Management Functional Descriptor */
 | 
			
		||||
struct usb_cdc_acm_descriptor {
 | 
			
		||||
	uint8_t bFunctionLength;
 | 
			
		||||
	uint8_t bDescriptorType;
 | 
			
		||||
	uint8_t bDescriptorSubtype;
 | 
			
		||||
	uint8_t bmCapabilities;
 | 
			
		||||
} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
/* Table 13: Class-Specific Request Codes for PSTN subclasses */
 | 
			
		||||
/* ... */
 | 
			
		||||
#define USB_CDC_REQ_SET_LINE_CODING		0x20
 | 
			
		||||
/* ... */
 | 
			
		||||
#define USB_CDC_REQ_SET_CONTROL_LINE_STATE	0x22
 | 
			
		||||
/* ... */
 | 
			
		||||
 | 
			
		||||
/* Table 17: Line Coding Structure */
 | 
			
		||||
struct usb_cdc_line_coding {
 | 
			
		||||
	uint32_t dwDTERate;
 | 
			
		||||
	uint8_t bCharFormat;
 | 
			
		||||
	uint8_t bParityType;
 | 
			
		||||
	uint8_t bDataBits;
 | 
			
		||||
} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
enum usb_cdc_line_coding_bCharFormat {
 | 
			
		||||
	USB_CDC_1_STOP_BITS			= 0,
 | 
			
		||||
	USB_CDC_1_5_STOP_BITS			= 1,
 | 
			
		||||
	USB_CDC_2_STOP_BITS			= 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum usb_cdc_line_coding_bParityType {
 | 
			
		||||
	USB_CDC_NO_PARITY			= 0,
 | 
			
		||||
	USB_CDC_ODD_PARITY			= 1,
 | 
			
		||||
	USB_CDC_EVEN_PARITY			= 2,
 | 
			
		||||
	USB_CDC_MARK_PARITY			= 3,
 | 
			
		||||
	USB_CDC_SPACE_PARITY			= 4,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Table 30: Class-Specific Notification Codes for PSTN subclasses */
 | 
			
		||||
/* ... */
 | 
			
		||||
#define USB_CDC_NOTIFY_SERIAL_STATE		0x20
 | 
			
		||||
/* ... */
 | 
			
		||||
 | 
			
		||||
/* Notification Structure */
 | 
			
		||||
struct usb_cdc_notification {
 | 
			
		||||
	uint8_t bmRequestType;
 | 
			
		||||
	uint8_t bNotification;
 | 
			
		||||
	uint16_t wValue;
 | 
			
		||||
	uint16_t wIndex;
 | 
			
		||||
	uint16_t wLength;
 | 
			
		||||
} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**@}*/
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										101
									
								
								sw/include/usb-desc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								sw/include/usb-desc.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
			
		||||
/* Teensyduino Core Library
 | 
			
		||||
 * http://www.pjrc.com/teensy/
 | 
			
		||||
 * Copyright (c) 2013 PJRC.COM, LLC.
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining
 | 
			
		||||
 * a copy of this software and associated documentation files (the
 | 
			
		||||
 * "Software"), to deal in the Software without restriction, including
 | 
			
		||||
 * without limitation the rights to use, copy, modify, merge, publish,
 | 
			
		||||
 * distribute, sublicense, and/or sell copies of the Software, and to
 | 
			
		||||
 * permit persons to whom the Software is furnished to do so, subject to
 | 
			
		||||
 * the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * 1. The above copyright notice and this permission notice shall be 
 | 
			
		||||
 * included in all copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * 2. If the Software is incorporated into a build system that allows 
 | 
			
		||||
 * selection among a list of target devices, then similar target
 | 
			
		||||
 * devices manufactured by PJRC.COM must be included in the list of
 | 
			
		||||
 * target devices and selectable in the same manner.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | 
			
		||||
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | 
			
		||||
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | 
			
		||||
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 | 
			
		||||
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 | 
			
		||||
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 | 
			
		||||
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _usb_desc_h_
 | 
			
		||||
#define _usb_desc_h_
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
 | 
			
		||||
struct usb_setup_request {
 | 
			
		||||
    union {
 | 
			
		||||
        struct {
 | 
			
		||||
            uint8_t bmRequestType;
 | 
			
		||||
            uint8_t bRequest;
 | 
			
		||||
        };
 | 
			
		||||
        uint16_t wRequestAndType;
 | 
			
		||||
    };
 | 
			
		||||
    uint16_t wValue;
 | 
			
		||||
    uint16_t wIndex;
 | 
			
		||||
    uint16_t wLength;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct usb_string_descriptor_struct {
 | 
			
		||||
    uint8_t bLength;
 | 
			
		||||
    uint8_t bDescriptorType;
 | 
			
		||||
    uint16_t wString[];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define NUM_USB_BUFFERS           8
 | 
			
		||||
#define VENDOR_ID                 0x1209    // pid.codes
 | 
			
		||||
#define PRODUCT_ID                0x5bf0    // Assigned to Fomu project
 | 
			
		||||
#define DEVICE_VER                0x0101    // Bootloader version
 | 
			
		||||
#define MANUFACTURER_NAME         u"Foosn"
 | 
			
		||||
#define MANUFACTURER_NAME_LEN     sizeof(MANUFACTURER_NAME)
 | 
			
		||||
#define PRODUCT_NAME              u"Fomu Factory Test " GIT_VERSION
 | 
			
		||||
#define PRODUCT_NAME_LEN          sizeof(PRODUCT_NAME)
 | 
			
		||||
#define EP0_SIZE                  64
 | 
			
		||||
#define NUM_INTERFACE             1
 | 
			
		||||
#define CONFIG_DESC_SIZE          67
 | 
			
		||||
#define USB_DT_INTERFACE_SIZE			9
 | 
			
		||||
 | 
			
		||||
/* USB Descriptor Types - Table 9-5 */
 | 
			
		||||
#define USB_DT_DEVICE				1
 | 
			
		||||
#define USB_DT_CONFIGURATION			2
 | 
			
		||||
#define USB_DT_STRING				3
 | 
			
		||||
#define USB_DT_INTERFACE			4
 | 
			
		||||
#define USB_DT_ENDPOINT				5
 | 
			
		||||
#define USB_DT_DEVICE_QUALIFIER			6
 | 
			
		||||
#define USB_DT_OTHER_SPEED_CONFIGURATION	7
 | 
			
		||||
#define USB_DT_INTERFACE_POWER			8
 | 
			
		||||
/* From ECNs */
 | 
			
		||||
#define USB_DT_OTG				9
 | 
			
		||||
#define USB_DT_DEBUG				10
 | 
			
		||||
#define USB_DT_INTERFACE_ASSOCIATION		11
 | 
			
		||||
 | 
			
		||||
#define USB_DT_ENDPOINT_SIZE		7
 | 
			
		||||
 | 
			
		||||
/* USB Endpoint Descriptor bmAttributes bit definitions - Table 9-13 */
 | 
			
		||||
/* bits 1..0 : transfer type */
 | 
			
		||||
#define USB_ENDPOINT_ATTR_CONTROL		0x00
 | 
			
		||||
#define USB_ENDPOINT_ATTR_ISOCHRONOUS		0x01
 | 
			
		||||
#define USB_ENDPOINT_ATTR_BULK			0x02
 | 
			
		||||
#define USB_ENDPOINT_ATTR_INTERRUPT		0x03
 | 
			
		||||
#define USB_ENDPOINT_ATTR_TYPE		0x03
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint16_t  wValue;
 | 
			
		||||
    uint16_t  length;
 | 
			
		||||
    const uint8_t *addr;
 | 
			
		||||
} usb_descriptor_list_t;
 | 
			
		||||
 | 
			
		||||
extern const usb_descriptor_list_t usb_descriptor_list[];
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										30
									
								
								sw/include/usb.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								sw/include/usb.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
#ifndef __USB_H
 | 
			
		||||
#define __USB_H
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct usb_setup_request;
 | 
			
		||||
 | 
			
		||||
void usb_isr(void);
 | 
			
		||||
void usb_init(void);
 | 
			
		||||
void usb_connect(void);
 | 
			
		||||
void usb_idle(void);
 | 
			
		||||
void usb_disconnect(void);
 | 
			
		||||
 | 
			
		||||
int usb_irq_happened(void);
 | 
			
		||||
void usb_setup(const struct usb_setup_request *setup);
 | 
			
		||||
void usb_send(const void *data, int total_count);
 | 
			
		||||
void usb_ack_in(void);
 | 
			
		||||
void usb_ack_out(void);
 | 
			
		||||
void usb_err(void);
 | 
			
		||||
int usb_recv(void *buffer, unsigned int buffer_len);
 | 
			
		||||
void usb_poll(void);
 | 
			
		||||
void usb_wait_for_send_done(void);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										55
									
								
								sw/ld/linker.ld
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								sw/ld/linker.ld
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
INCLUDE output_format.ld
 | 
			
		||||
ENTRY(_start)
 | 
			
		||||
 | 
			
		||||
__DYNAMIC = 0;
 | 
			
		||||
 | 
			
		||||
INCLUDE regions.ld
 | 
			
		||||
 | 
			
		||||
SECTIONS
 | 
			
		||||
{
 | 
			
		||||
	.text :
 | 
			
		||||
	{
 | 
			
		||||
		_ftext = .;
 | 
			
		||||
		*(.text.start)
 | 
			
		||||
		*(.text .stub .text.* .gnu.linkonce.t.*)
 | 
			
		||||
		_etext = .;
 | 
			
		||||
	} > rom
 | 
			
		||||
 | 
			
		||||
	.rodata :
 | 
			
		||||
	{
 | 
			
		||||
		. = ALIGN(4);
 | 
			
		||||
		_frodata = .;
 | 
			
		||||
		*(.rodata .rodata.* .gnu.linkonce.r.*)
 | 
			
		||||
		*(.rodata1)
 | 
			
		||||
		*(.srodata)
 | 
			
		||||
		_erodata = .;
 | 
			
		||||
	} > rom
 | 
			
		||||
 | 
			
		||||
	.data : AT (ADDR(.rodata) + SIZEOF (.rodata))
 | 
			
		||||
	{
 | 
			
		||||
		. = ALIGN(4);
 | 
			
		||||
		_fdata = .;
 | 
			
		||||
		*(.data .data.* .gnu.linkonce.d.*)
 | 
			
		||||
		*(.data1)
 | 
			
		||||
		_gp = ALIGN(16);
 | 
			
		||||
		*(.sdata .sdata.* .gnu.linkonce.s.* .sdata2 .sdata2.*)
 | 
			
		||||
		_edata = ALIGN(16); /* Make sure _edata is >= _gp. */
 | 
			
		||||
	} > sram
 | 
			
		||||
 | 
			
		||||
	.bss :
 | 
			
		||||
	{
 | 
			
		||||
		. = ALIGN(4);
 | 
			
		||||
		_fbss = .;
 | 
			
		||||
		*(.dynsbss)
 | 
			
		||||
		*(.sbss .sbss.* .gnu.linkonce.sb.*)
 | 
			
		||||
		*(.scommon)
 | 
			
		||||
		*(.dynbss)
 | 
			
		||||
		*(.bss .bss.* .gnu.linkonce.b.*)
 | 
			
		||||
		*(COMMON)
 | 
			
		||||
		. = ALIGN(4);
 | 
			
		||||
		_ebss = .;
 | 
			
		||||
		_end = .;
 | 
			
		||||
	} > sram
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PROVIDE(_fstack = ORIGIN(sram) + LENGTH(sram) - 4);
 | 
			
		||||
							
								
								
									
										1
									
								
								sw/ld/output_format.ld
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								sw/ld/output_format.ld
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
OUTPUT_FORMAT("elf32-littleriscv")
 | 
			
		||||
							
								
								
									
										4
									
								
								sw/ld/regions.ld
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								sw/ld/regions.ld
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
MEMORY {
 | 
			
		||||
	sram : ORIGIN = 0x10000000, LENGTH = 4096
 | 
			
		||||
	rom : ORIGIN = 0x00000000, LENGTH = 0x00002000
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										91
									
								
								sw/src/crt0-vexriscv.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								sw/src/crt0-vexriscv.S
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,91 @@
 | 
			
		||||
.global main
 | 
			
		||||
.global isr
 | 
			
		||||
 | 
			
		||||
.section .text.start
 | 
			
		||||
.global _start
 | 
			
		||||
 | 
			
		||||
_start:
 | 
			
		||||
  j crt_init
 | 
			
		||||
  nop
 | 
			
		||||
  nop
 | 
			
		||||
  nop
 | 
			
		||||
  nop
 | 
			
		||||
  nop
 | 
			
		||||
  nop
 | 
			
		||||
  nop
 | 
			
		||||
 | 
			
		||||
.section .text
 | 
			
		||||
.global  trap_entry
 | 
			
		||||
trap_entry:
 | 
			
		||||
  sw x1,  - 1*4(sp)
 | 
			
		||||
  sw x5,  - 2*4(sp)
 | 
			
		||||
  sw x6,  - 3*4(sp)
 | 
			
		||||
  sw x7,  - 4*4(sp)
 | 
			
		||||
  sw x10, - 5*4(sp)
 | 
			
		||||
  sw x11, - 6*4(sp)
 | 
			
		||||
  sw x12, - 7*4(sp)
 | 
			
		||||
  sw x13, - 8*4(sp)
 | 
			
		||||
  sw x14, - 9*4(sp)
 | 
			
		||||
  sw x15, -10*4(sp)
 | 
			
		||||
  sw x16, -11*4(sp)
 | 
			
		||||
  sw x17, -12*4(sp)
 | 
			
		||||
  sw x28, -13*4(sp)
 | 
			
		||||
  sw x29, -14*4(sp)
 | 
			
		||||
  sw x30, -15*4(sp)
 | 
			
		||||
  sw x31, -16*4(sp)
 | 
			
		||||
  addi sp,sp,-16*4
 | 
			
		||||
  call isr
 | 
			
		||||
  lw x1 , 15*4(sp)
 | 
			
		||||
  lw x5,  14*4(sp)
 | 
			
		||||
  lw x6,  13*4(sp)
 | 
			
		||||
  lw x7,  12*4(sp)
 | 
			
		||||
  lw x10, 11*4(sp)
 | 
			
		||||
  lw x11, 10*4(sp)
 | 
			
		||||
  lw x12,  9*4(sp)
 | 
			
		||||
  lw x13,  8*4(sp)
 | 
			
		||||
  lw x14,  7*4(sp)
 | 
			
		||||
  lw x15,  6*4(sp)
 | 
			
		||||
  lw x16,  5*4(sp)
 | 
			
		||||
  lw x17,  4*4(sp)
 | 
			
		||||
  lw x28,  3*4(sp)
 | 
			
		||||
  lw x29,  2*4(sp)
 | 
			
		||||
  lw x30,  1*4(sp)
 | 
			
		||||
  lw x31,  0*4(sp)
 | 
			
		||||
  addi sp,sp,16*4
 | 
			
		||||
  mret
 | 
			
		||||
  .text
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
crt_init:
 | 
			
		||||
  la sp, _fstack + 4
 | 
			
		||||
  la a0, trap_entry
 | 
			
		||||
  csrw mtvec, a0
 | 
			
		||||
 | 
			
		||||
bss_init:
 | 
			
		||||
  la a0, _fbss
 | 
			
		||||
  la a1, _ebss
 | 
			
		||||
bss_loop:
 | 
			
		||||
  beq a0,a1,bss_done
 | 
			
		||||
  sw zero,0(a0)
 | 
			
		||||
  add a0,a0,4
 | 
			
		||||
  j bss_loop
 | 
			
		||||
bss_done:
 | 
			
		||||
 | 
			
		||||
  /* Load DATA */
 | 
			
		||||
  la t0, _erodata
 | 
			
		||||
  la t1, _fdata
 | 
			
		||||
  la t2, _edata
 | 
			
		||||
3:
 | 
			
		||||
  lw t3, 0(t0)
 | 
			
		||||
  sw t3, 0(t1)
 | 
			
		||||
  /* _edata is aligned to 16 bytes. Use word-xfers. */
 | 
			
		||||
  addi t0, t0, 4
 | 
			
		||||
  addi t1, t1, 4
 | 
			
		||||
  bltu t1, t2, 3b
 | 
			
		||||
 | 
			
		||||
  li a0, 0x880  //880 enable timer + external interrupt sources (until mstatus.MIE is set, they will never trigger an interrupt)
 | 
			
		||||
  csrw mie,a0
 | 
			
		||||
 | 
			
		||||
  call main
 | 
			
		||||
infinit_loop:
 | 
			
		||||
  j infinit_loop
 | 
			
		||||
							
								
								
									
										46
									
								
								sw/src/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								sw/src/main.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <irq.h>
 | 
			
		||||
#include <usb.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <rgb.h>
 | 
			
		||||
#include <spi.h>
 | 
			
		||||
#include <fomu/csr.h>
 | 
			
		||||
 | 
			
		||||
struct ff_spi *spi;
 | 
			
		||||
 | 
			
		||||
void isr(void)
 | 
			
		||||
{
 | 
			
		||||
    unsigned int irqs;
 | 
			
		||||
 | 
			
		||||
    irqs = irq_pending() & irq_getmask();
 | 
			
		||||
 | 
			
		||||
    if (irqs & (1 << USB_INTERRUPT))
 | 
			
		||||
        usb_isr();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void init(void)
 | 
			
		||||
{
 | 
			
		||||
    rgb_init();
 | 
			
		||||
    spi = spiAlloc();
 | 
			
		||||
    spiInit(spi);
 | 
			
		||||
    irq_setmask(0);
 | 
			
		||||
    irq_setie(1);
 | 
			
		||||
    usb_init();
 | 
			
		||||
    time_init();
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
    (void)argc;
 | 
			
		||||
    (void)argv;
 | 
			
		||||
 | 
			
		||||
    init();
 | 
			
		||||
 | 
			
		||||
    usb_connect();
 | 
			
		||||
    while (1)
 | 
			
		||||
    {
 | 
			
		||||
        usb_poll();
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										89
									
								
								sw/src/rgb.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								sw/src/rgb.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
#include <rgb.h>
 | 
			
		||||
#include <fomu/csr.h>
 | 
			
		||||
 | 
			
		||||
enum led_registers {
 | 
			
		||||
    LEDDCR0 = 8,
 | 
			
		||||
    LEDDBR = 9,
 | 
			
		||||
    LEDDONR = 10,
 | 
			
		||||
    LEDDOFR = 11,
 | 
			
		||||
    LEDDBCRR = 5,
 | 
			
		||||
    LEDDBCFR = 6,
 | 
			
		||||
    LEDDPWRR = 1,
 | 
			
		||||
    LEDDPWRG = 2,
 | 
			
		||||
    LEDDPWRB = 3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define BREATHE_ENABLE (1 << 7)
 | 
			
		||||
#define BREATHE_EDGE_ON (0 << 6)
 | 
			
		||||
#define BREATHE_EDGE_BOTH (1 << 6)
 | 
			
		||||
#define BREATHE_MODE_MODULATE (1 << 5)
 | 
			
		||||
#define BREATHE_RATE(x) ((x & 7) << 0)
 | 
			
		||||
 | 
			
		||||
#define RGB_SWITCH_MODE(x) do { \
 | 
			
		||||
    if (rgb_mode == x) \
 | 
			
		||||
        return; \
 | 
			
		||||
    rgb_mode = x; \
 | 
			
		||||
    /* Toggle LEDD_EXE to force the mode to switch */ \
 | 
			
		||||
    rgb_ctrl_write(           (1 << 1) | (1 << 2)); \
 | 
			
		||||
    rgb_ctrl_write((1 << 0) | (1 << 1) | (1 << 2)); \
 | 
			
		||||
} while(0)
 | 
			
		||||
 | 
			
		||||
static enum {
 | 
			
		||||
    INVALID = 0,
 | 
			
		||||
    IDLE,
 | 
			
		||||
    WRITING,
 | 
			
		||||
    ERROR,
 | 
			
		||||
    DONE,
 | 
			
		||||
} rgb_mode;
 | 
			
		||||
 | 
			
		||||
static void rgb_write(uint8_t value, uint8_t addr) {
 | 
			
		||||
    rgb_addr_write(addr);
 | 
			
		||||
    rgb_dat_write(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rgb_init(void) {
 | 
			
		||||
    // Turn on the RGB block and current enable, as well as enabling led control
 | 
			
		||||
    rgb_ctrl_write((1 << 0) | (1 << 1) | (1 << 2));
 | 
			
		||||
 | 
			
		||||
    // Enable the LED driver, and set 250 Hz mode.
 | 
			
		||||
    // Also set quick stop, which we'll use to switch patterns quickly.
 | 
			
		||||
    rgb_write((1 << 7) | (1 << 6) | (1 << 3), LEDDCR0);
 | 
			
		||||
 | 
			
		||||
    // Set clock register to 12 MHz / 64 kHz - 1
 | 
			
		||||
    rgb_write((12000000/64000)-1, LEDDBR);
 | 
			
		||||
 | 
			
		||||
    rgb_mode_idle();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rgb_switch_mode(uint8_t mode,
 | 
			
		||||
        uint8_t onr, uint8_t ofr,
 | 
			
		||||
        uint8_t onrate, uint8_t offrate,
 | 
			
		||||
        uint8_t r, uint8_t g, uint8_t b) {
 | 
			
		||||
    RGB_SWITCH_MODE(mode);
 | 
			
		||||
    rgb_write(onr, LEDDONR);
 | 
			
		||||
    rgb_write(ofr, LEDDOFR);
 | 
			
		||||
 | 
			
		||||
    rgb_write(BREATHE_ENABLE | BREATHE_EDGE_BOTH
 | 
			
		||||
            | BREATHE_MODE_MODULATE | BREATHE_RATE(onrate), LEDDBCRR);
 | 
			
		||||
    rgb_write(BREATHE_ENABLE | BREATHE_MODE_MODULATE | BREATHE_RATE(offrate), LEDDBCFR);
 | 
			
		||||
 | 
			
		||||
    rgb_write(r, LEDDPWRG); // Red
 | 
			
		||||
    rgb_write(g, LEDDPWRB); // Green
 | 
			
		||||
    rgb_write(b, LEDDPWRR); // Blue
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rgb_mode_idle(void) {
 | 
			
		||||
    rgb_switch_mode(IDLE, 12, 14, 2, 3, 0x00/4, 0x4a/4, 0xe1/4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rgb_mode_writing(void) {
 | 
			
		||||
    rgb_switch_mode(WRITING, 1, 2, 1, 3, 0x00/4, 0x7a/4, 0x51/4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rgb_mode_error(void) {
 | 
			
		||||
    rgb_switch_mode(ERROR, 3, 3, 2, 3, 0xf0/4, 0x0a/4, 0x01/4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rgb_mode_done(void) {
 | 
			
		||||
    rgb_switch_mode(DONE, 8, 8, 2, 3, 0x14/4, 0xff/4, 0x44/4);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										824
									
								
								sw/src/spi.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										824
									
								
								sw/src/spi.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,824 @@
 | 
			
		||||
#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 <fomu/csr.h>
 | 
			
		||||
 | 
			
		||||
#include "spi.h"
 | 
			
		||||
 | 
			
		||||
#define fprintf(...) do {} while(0)
 | 
			
		||||
 | 
			
		||||
static uint8_t do_mirror;
 | 
			
		||||
static uint8_t oe_mirror;
 | 
			
		||||
 | 
			
		||||
#define PI_OUTPUT 1
 | 
			
		||||
#define PI_INPUT 0
 | 
			
		||||
#define PI_ALT0 PI_INPUT
 | 
			
		||||
static void gpioSetMode(int pin, int mode) {
 | 
			
		||||
    if (mode)
 | 
			
		||||
        oe_mirror |= 1 << pin;
 | 
			
		||||
    else
 | 
			
		||||
        oe_mirror &= ~(1 << pin);
 | 
			
		||||
    picorvspi_cfg2_write(oe_mirror);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gpioWrite(int pin, int val) {
 | 
			
		||||
    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));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gpioSync(void) {
 | 
			
		||||
    // bbspi_do_write(do_mirror);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define SPI_ONLY_SINGLE
 | 
			
		||||
 | 
			
		||||
enum ff_spi_quirks {
 | 
			
		||||
	// There is no separate "Write SR 2" command.  Instead,
 | 
			
		||||
	// you must write SR2 after writing SR1
 | 
			
		||||
	SQ_SR2_FROM_SR1    = (1 << 0),
 | 
			
		||||
 | 
			
		||||
	// Don't issue a "Write Enable" command prior to writing
 | 
			
		||||
	// a status register
 | 
			
		||||
	SQ_SKIP_SR_WEL     = (1 << 1),
 | 
			
		||||
 | 
			
		||||
	// Security registers are shifted up by 4 bits
 | 
			
		||||
	SQ_SECURITY_NYBBLE_SHIFT = (1 << 2),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ff_spi {
 | 
			
		||||
	enum spi_state state;
 | 
			
		||||
	enum spi_type type;
 | 
			
		||||
	enum spi_type desired_type;
 | 
			
		||||
	struct spi_id id;
 | 
			
		||||
	enum ff_spi_quirks quirks;
 | 
			
		||||
	int size_override;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		int clk;
 | 
			
		||||
		int d0;
 | 
			
		||||
		int d1;
 | 
			
		||||
		int d2;
 | 
			
		||||
		int d3;
 | 
			
		||||
		int wp;
 | 
			
		||||
		int hold;
 | 
			
		||||
		int cs;
 | 
			
		||||
		int miso;
 | 
			
		||||
		int mosi;
 | 
			
		||||
	} pins;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void spi_get_id(struct ff_spi *spi);
 | 
			
		||||
 | 
			
		||||
static void spi_set_state(struct ff_spi *spi, enum spi_state state) {
 | 
			
		||||
	return;
 | 
			
		||||
	if (spi->state == state)
 | 
			
		||||
		return;
 | 
			
		||||
#ifndef SPI_ONLY_SINGLE
 | 
			
		||||
	switch (state) {
 | 
			
		||||
	case SS_SINGLE:
 | 
			
		||||
#endif
 | 
			
		||||
		gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
 | 
			
		||||
		gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
 | 
			
		||||
		gpioSetMode(spi->pins.mosi, PI_OUTPUT); // MOSI
 | 
			
		||||
		gpioSetMode(spi->pins.miso, PI_INPUT); // MISO
 | 
			
		||||
		gpioSetMode(spi->pins.hold, PI_OUTPUT);
 | 
			
		||||
		gpioSetMode(spi->pins.wp, PI_OUTPUT);
 | 
			
		||||
#ifndef SPI_ONLY_SINGLE
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case SS_DUAL_RX:
 | 
			
		||||
		gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
 | 
			
		||||
		gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
 | 
			
		||||
		gpioSetMode(spi->pins.mosi, PI_INPUT); // MOSI
 | 
			
		||||
		gpioSetMode(spi->pins.miso, PI_INPUT); // MISO
 | 
			
		||||
		gpioSetMode(spi->pins.hold, PI_OUTPUT);
 | 
			
		||||
		gpioSetMode(spi->pins.wp, PI_OUTPUT);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case SS_DUAL_TX:
 | 
			
		||||
		gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
 | 
			
		||||
		gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
 | 
			
		||||
		gpioSetMode(spi->pins.mosi, PI_OUTPUT); // MOSI
 | 
			
		||||
		gpioSetMode(spi->pins.miso, PI_OUTPUT); // MISO
 | 
			
		||||
		gpioSetMode(spi->pins.hold, PI_OUTPUT);
 | 
			
		||||
		gpioSetMode(spi->pins.wp, PI_OUTPUT);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case SS_QUAD_RX:
 | 
			
		||||
		gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
 | 
			
		||||
		gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
 | 
			
		||||
		gpioSetMode(spi->pins.mosi, PI_INPUT); // MOSI
 | 
			
		||||
		gpioSetMode(spi->pins.miso, PI_INPUT); // MISO
 | 
			
		||||
		gpioSetMode(spi->pins.hold, PI_INPUT);
 | 
			
		||||
		gpioSetMode(spi->pins.wp, PI_INPUT);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case SS_QUAD_TX:
 | 
			
		||||
		gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
 | 
			
		||||
		gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
 | 
			
		||||
		gpioSetMode(spi->pins.mosi, PI_OUTPUT); // MOSI
 | 
			
		||||
		gpioSetMode(spi->pins.miso, PI_OUTPUT); // MISO
 | 
			
		||||
		gpioSetMode(spi->pins.hold, PI_OUTPUT);
 | 
			
		||||
		gpioSetMode(spi->pins.wp, PI_OUTPUT);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case SS_HARDWARE:
 | 
			
		||||
		gpioSetMode(spi->pins.clk, PI_ALT0); // CLK
 | 
			
		||||
		gpioSetMode(spi->pins.cs, PI_ALT0); // CE0#
 | 
			
		||||
		gpioSetMode(spi->pins.mosi, PI_ALT0); // MOSI
 | 
			
		||||
		gpioSetMode(spi->pins.miso, PI_ALT0); // MISO
 | 
			
		||||
		gpioSetMode(spi->pins.hold, PI_OUTPUT);
 | 
			
		||||
		gpioSetMode(spi->pins.wp, PI_OUTPUT);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		fprintf(stderr, "Unrecognized spi state\n");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	spi->state = state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void spiPause(struct ff_spi *spi) {
 | 
			
		||||
	(void)spi;
 | 
			
		||||
	gpioSync();
 | 
			
		||||
//	usleep(1);
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void spiBegin(struct ff_spi *spi) {
 | 
			
		||||
	spi_set_state(spi, SS_SINGLE);
 | 
			
		||||
	if ((spi->type == ST_SINGLE) || (spi->type == ST_DUAL)) {
 | 
			
		||||
		gpioWrite(spi->pins.wp, 1);
 | 
			
		||||
		gpioWrite(spi->pins.hold, 1);
 | 
			
		||||
	}
 | 
			
		||||
	gpioWrite(spi->pins.cs, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void spiEnd(struct ff_spi *spi) {
 | 
			
		||||
	(void)spi;
 | 
			
		||||
	gpioWrite(spi->pins.cs, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint8_t spiXfer(struct ff_spi *spi, uint8_t out) {
 | 
			
		||||
	int bit;
 | 
			
		||||
	uint8_t in = 0;
 | 
			
		||||
 | 
			
		||||
	for (bit = 7; bit >= 0; bit--) {
 | 
			
		||||
		if (out & (1 << bit)) {
 | 
			
		||||
			gpioWrite(spi->pins.mosi, 1);
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			gpioWrite(spi->pins.mosi, 0);
 | 
			
		||||
		}
 | 
			
		||||
		gpioWrite(spi->pins.clk, 1);
 | 
			
		||||
		spiPause(spi);
 | 
			
		||||
		in |= ((!!gpioRead(spi->pins.miso)) << bit);
 | 
			
		||||
		gpioWrite(spi->pins.clk, 0);
 | 
			
		||||
		spiPause(spi);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return in;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void spiSingleTx(struct ff_spi *spi, uint8_t out) {
 | 
			
		||||
	spi_set_state(spi, SS_SINGLE);
 | 
			
		||||
	spiXfer(spi, out);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint8_t spiSingleRx(struct ff_spi *spi) {
 | 
			
		||||
	spi_set_state(spi, SS_SINGLE);
 | 
			
		||||
	return spiXfer(spi, 0xff);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void spiDualTx(struct ff_spi *spi, uint8_t out) {
 | 
			
		||||
 | 
			
		||||
	int bit;
 | 
			
		||||
	spi_set_state(spi, SS_DUAL_TX);
 | 
			
		||||
	for (bit = 7; bit >= 0; bit -= 2) {
 | 
			
		||||
		if (out & (1 << (bit - 1))) {
 | 
			
		||||
			gpioWrite(spi->pins.d0, 1);
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			gpioWrite(spi->pins.d0, 0);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (out & (1 << (bit - 0))) {
 | 
			
		||||
			gpioWrite(spi->pins.d1, 1);
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			gpioWrite(spi->pins.d1, 0);
 | 
			
		||||
		}
 | 
			
		||||
		gpioWrite(spi->pins.clk, 1);
 | 
			
		||||
		spiPause(spi);
 | 
			
		||||
		gpioWrite(spi->pins.clk, 0);
 | 
			
		||||
		spiPause(spi);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void spiQuadTx(struct ff_spi *spi, uint8_t out) {
 | 
			
		||||
	int bit;
 | 
			
		||||
	spi_set_state(spi, SS_QUAD_TX);
 | 
			
		||||
	for (bit = 7; bit >= 0; bit -= 4) {
 | 
			
		||||
		if (out & (1 << (bit - 3))) {
 | 
			
		||||
			gpioWrite(spi->pins.d0, 1);
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			gpioWrite(spi->pins.d0, 0);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (out & (1 << (bit - 2))) {
 | 
			
		||||
			gpioWrite(spi->pins.d1, 1);
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			gpioWrite(spi->pins.d1, 0);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (out & (1 << (bit - 1))) {
 | 
			
		||||
			gpioWrite(spi->pins.d2, 1);
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			gpioWrite(spi->pins.d2, 0);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (out & (1 << (bit - 0))) {
 | 
			
		||||
			gpioWrite(spi->pins.d3, 1);
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			gpioWrite(spi->pins.d3, 0);
 | 
			
		||||
		}
 | 
			
		||||
		gpioWrite(spi->pins.clk, 1);
 | 
			
		||||
		spiPause(spi);
 | 
			
		||||
		gpioWrite(spi->pins.clk, 0);
 | 
			
		||||
		spiPause(spi);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint8_t spiDualRx(struct ff_spi *spi) {
 | 
			
		||||
	int bit;
 | 
			
		||||
	uint8_t in = 0;
 | 
			
		||||
 | 
			
		||||
	spi_set_state(spi, SS_QUAD_RX);
 | 
			
		||||
	for (bit = 7; bit >= 0; bit -= 2) {
 | 
			
		||||
		gpioWrite(spi->pins.clk, 1);
 | 
			
		||||
		spiPause(spi);
 | 
			
		||||
		in |= ((!!gpioRead(spi->pins.d0)) << (bit - 1));
 | 
			
		||||
		in |= ((!!gpioRead(spi->pins.d1)) << (bit - 0));
 | 
			
		||||
		gpioWrite(spi->pins.clk, 0);
 | 
			
		||||
		spiPause(spi);
 | 
			
		||||
	}
 | 
			
		||||
	return in;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint8_t spiQuadRx(struct ff_spi *spi) {
 | 
			
		||||
	int bit;
 | 
			
		||||
	uint8_t in = 0;
 | 
			
		||||
 | 
			
		||||
	spi_set_state(spi, SS_QUAD_RX);
 | 
			
		||||
	for (bit = 7; bit >= 0; bit -= 4) {
 | 
			
		||||
		gpioWrite(spi->pins.clk, 1);
 | 
			
		||||
		spiPause(spi);
 | 
			
		||||
		in |= ((!!gpioRead(spi->pins.d0)) << (bit - 3));
 | 
			
		||||
		in |= ((!!gpioRead(spi->pins.d1)) << (bit - 2));
 | 
			
		||||
		in |= ((!!gpioRead(spi->pins.d2)) << (bit - 1));
 | 
			
		||||
		in |= ((!!gpioRead(spi->pins.d3)) << (bit - 0));
 | 
			
		||||
		gpioWrite(spi->pins.clk, 0);
 | 
			
		||||
		spiPause(spi);
 | 
			
		||||
	}
 | 
			
		||||
	return in;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int spiTx(struct ff_spi *spi, uint8_t word) {
 | 
			
		||||
	switch (spi->type) {
 | 
			
		||||
	case ST_SINGLE:
 | 
			
		||||
		spiSingleTx(spi, word);
 | 
			
		||||
		break;
 | 
			
		||||
	case ST_DUAL:
 | 
			
		||||
		spiDualTx(spi, word);
 | 
			
		||||
		break;
 | 
			
		||||
	case ST_QUAD:
 | 
			
		||||
	case ST_QPI:
 | 
			
		||||
		spiQuadTx(spi, word);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t spiRx(struct ff_spi *spi) {
 | 
			
		||||
	switch (spi->type) {
 | 
			
		||||
	case ST_SINGLE:
 | 
			
		||||
		return spiSingleRx(spi);
 | 
			
		||||
	case ST_DUAL:
 | 
			
		||||
		return spiDualRx(spi);
 | 
			
		||||
	case ST_QUAD:
 | 
			
		||||
	case ST_QPI:
 | 
			
		||||
		return spiQuadRx(spi);
 | 
			
		||||
	default:
 | 
			
		||||
		return 0xff;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void spiCommand(struct ff_spi *spi, uint8_t cmd) {
 | 
			
		||||
	if (spi->type == ST_QPI)
 | 
			
		||||
		spiQuadTx(spi, cmd);
 | 
			
		||||
	else
 | 
			
		||||
		spiSingleTx(spi, cmd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t spiCommandRx(struct ff_spi *spi) {
 | 
			
		||||
	if (spi->type == ST_QPI)
 | 
			
		||||
		return spiQuadRx(spi);
 | 
			
		||||
	else
 | 
			
		||||
		return spiSingleRx(spi);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t spiReadStatus(struct ff_spi *spi, uint8_t sr) {
 | 
			
		||||
	uint8_t val = 0xff;
 | 
			
		||||
	(void)sr;
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
	switch (sr) {
 | 
			
		||||
	case 1:
 | 
			
		||||
#endif
 | 
			
		||||
		spiBegin(spi);
 | 
			
		||||
		spiCommand(spi, 0x05);
 | 
			
		||||
		val = spiCommandRx(spi);
 | 
			
		||||
		spiEnd(spi);
 | 
			
		||||
#if 0
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case 2:
 | 
			
		||||
		spiBegin(spi);
 | 
			
		||||
		spiCommand(spi, 0x35);
 | 
			
		||||
		val = spiCommandRx(spi);
 | 
			
		||||
		spiEnd(spi);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case 3:
 | 
			
		||||
		spiBegin(spi);
 | 
			
		||||
		spiCommand(spi, 0x15);
 | 
			
		||||
		val = spiCommandRx(spi);
 | 
			
		||||
		spiEnd(spi);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		fprintf(stderr, "unrecognized status register: %d\n", sr);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	return val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void spiWriteSecurity(struct ff_spi *spi, uint8_t sr, uint8_t security[256]) {
 | 
			
		||||
 | 
			
		||||
	if (spi->quirks & SQ_SECURITY_NYBBLE_SHIFT)
 | 
			
		||||
		sr <<= 4;
 | 
			
		||||
 | 
			
		||||
	spiBegin(spi);
 | 
			
		||||
	spiCommand(spi, 0x06);
 | 
			
		||||
	spiEnd(spi);
 | 
			
		||||
 | 
			
		||||
	// erase the register
 | 
			
		||||
	spiBegin(spi);
 | 
			
		||||
	spiCommand(spi, 0x44);
 | 
			
		||||
	spiCommand(spi, 0x00); // A23-16
 | 
			
		||||
	spiCommand(spi, sr);   // A15-8
 | 
			
		||||
	spiCommand(spi, 0x00); // A0-7
 | 
			
		||||
	spiEnd(spi);
 | 
			
		||||
 | 
			
		||||
	spi_get_id(spi);
 | 
			
		||||
	sleep(1);
 | 
			
		||||
 | 
			
		||||
	// write enable
 | 
			
		||||
	spiBegin(spi);
 | 
			
		||||
	spiCommand(spi, 0x06);
 | 
			
		||||
	spiEnd(spi);
 | 
			
		||||
 | 
			
		||||
	spiBegin(spi);
 | 
			
		||||
	spiCommand(spi, 0x42);
 | 
			
		||||
	spiCommand(spi, 0x00); // A23-16
 | 
			
		||||
	spiCommand(spi, sr);   // A15-8
 | 
			
		||||
	spiCommand(spi, 0x00); // A0-7
 | 
			
		||||
	int i;
 | 
			
		||||
	for (i = 0; i < 256; i++)
 | 
			
		||||
		spiCommand(spi, security[i]);
 | 
			
		||||
	spiEnd(spi);
 | 
			
		||||
 | 
			
		||||
	spi_get_id(spi);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void spiReadSecurity(struct ff_spi *spi, uint8_t sr, uint8_t security[256]) {
 | 
			
		||||
	if (spi->quirks & SQ_SECURITY_NYBBLE_SHIFT)
 | 
			
		||||
		sr <<= 4;
 | 
			
		||||
 | 
			
		||||
	spiBegin(spi);
 | 
			
		||||
	spiCommand(spi, 0x48);	// Read security registers
 | 
			
		||||
	spiCommand(spi, 0x00);  // A23-16
 | 
			
		||||
	spiCommand(spi, sr);    // A15-8
 | 
			
		||||
	spiCommand(spi, 0x00);  // A0-7
 | 
			
		||||
	int i;
 | 
			
		||||
	for (i = 0; i < 256; i++)
 | 
			
		||||
		security[i] = spiCommandRx(spi);
 | 
			
		||||
	spiEnd(spi);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void spiWriteStatus(struct ff_spi *spi, uint8_t sr, uint8_t val) {
 | 
			
		||||
 | 
			
		||||
	switch (sr) {
 | 
			
		||||
	case 1:
 | 
			
		||||
		if (!(spi->quirks & SQ_SKIP_SR_WEL)) {
 | 
			
		||||
			spiBegin(spi);
 | 
			
		||||
			spiCommand(spi, 0x06);
 | 
			
		||||
			spiEnd(spi);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		spiBegin(spi);
 | 
			
		||||
		spiCommand(spi, 0x50);
 | 
			
		||||
		spiEnd(spi);
 | 
			
		||||
 | 
			
		||||
		spiBegin(spi);
 | 
			
		||||
		spiCommand(spi, 0x01);
 | 
			
		||||
		spiCommand(spi, val);
 | 
			
		||||
		spiEnd(spi);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case 2: {
 | 
			
		||||
		uint8_t sr1 = 0x00;
 | 
			
		||||
		if (spi->quirks & SQ_SR2_FROM_SR1)
 | 
			
		||||
			sr1 = spiReadStatus(spi, 1);
 | 
			
		||||
 | 
			
		||||
		if (!(spi->quirks & SQ_SKIP_SR_WEL)) {
 | 
			
		||||
			spiBegin(spi);
 | 
			
		||||
			spiCommand(spi, 0x06);
 | 
			
		||||
			spiEnd(spi);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		spiBegin(spi);
 | 
			
		||||
		spiCommand(spi, 0x50);
 | 
			
		||||
		spiEnd(spi);
 | 
			
		||||
 | 
			
		||||
		spiBegin(spi);
 | 
			
		||||
		if (spi->quirks & SQ_SR2_FROM_SR1) {
 | 
			
		||||
			spiCommand(spi, 0x01);
 | 
			
		||||
			spiCommand(spi, sr1);
 | 
			
		||||
			spiCommand(spi, val);
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			spiCommand(spi, 0x31);
 | 
			
		||||
			spiCommand(spi, val);
 | 
			
		||||
		}
 | 
			
		||||
		spiEnd(spi);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	case 3:
 | 
			
		||||
		if (!(spi->quirks & SQ_SKIP_SR_WEL)) {
 | 
			
		||||
			spiBegin(spi);
 | 
			
		||||
			spiCommand(spi, 0x06);
 | 
			
		||||
			spiEnd(spi);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		spiBegin(spi);
 | 
			
		||||
		spiCommand(spi, 0x50);
 | 
			
		||||
		spiEnd(spi);
 | 
			
		||||
 | 
			
		||||
		spiBegin(spi);
 | 
			
		||||
		spiCommand(spi, 0x11);
 | 
			
		||||
		spiCommand(spi, val);
 | 
			
		||||
		spiEnd(spi);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		fprintf(stderr, "unrecognized status register: %d\n", sr);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
struct spi_id spiId(struct ff_spi *spi) {
 | 
			
		||||
	return spi->id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void spi_decode_id(struct ff_spi *spi) {
 | 
			
		||||
	spi->id.bytes = -1; // unknown
 | 
			
		||||
 | 
			
		||||
	if (spi->id.manufacturer_id == 0xef) {
 | 
			
		||||
		// spi->id.manufacturer = "Winbond";
 | 
			
		||||
		if ((spi->id.memory_type == 0x70)
 | 
			
		||||
		 && (spi->id.memory_size == 0x18)) {
 | 
			
		||||
			// spi->id.model = "W25Q128JV";
 | 
			
		||||
			// spi->id.capacity = "128 Mbit";
 | 
			
		||||
			spi->id.bytes = 16 * 1024 * 1024;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (spi->id.manufacturer_id == 0x1f) {
 | 
			
		||||
		// spi->id.manufacturer = "Adesto";
 | 
			
		||||
		 if ((spi->id.memory_type == 0x86)
 | 
			
		||||
		  && (spi->id.memory_size == 0x01)) {
 | 
			
		||||
			// spi->id.model = "AT25SF161";
 | 
			
		||||
			// spi->id.capacity = "16 Mbit";
 | 
			
		||||
			spi->id.bytes = 1 * 1024 * 1024;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
static void spi_get_id(struct ff_spi *spi) {
 | 
			
		||||
	spiBegin(spi);
 | 
			
		||||
	spiCommand(spi, 0x90);	// Read manufacturer ID
 | 
			
		||||
	spiCommand(spi, 0x00);  // Dummy byte 1
 | 
			
		||||
	spiCommand(spi, 0x00);  // Dummy byte 2
 | 
			
		||||
	spiCommand(spi, 0x00);  // Dummy byte 3
 | 
			
		||||
	spi->id.manufacturer_id = spiCommandRx(spi);
 | 
			
		||||
	spi->id.device_id = spiCommandRx(spi);
 | 
			
		||||
	spiEnd(spi);
 | 
			
		||||
	return;
 | 
			
		||||
#if 0
 | 
			
		||||
	spiBegin(spi);
 | 
			
		||||
	spiCommand(spi, 0x9f);	// Read device id
 | 
			
		||||
	spi->id._manufacturer_id = spiCommandRx(spi);
 | 
			
		||||
	spi->id.memory_type = spiCommandRx(spi);
 | 
			
		||||
	spi->id.memory_size = spiCommandRx(spi);
 | 
			
		||||
	spiEnd(spi);
 | 
			
		||||
 | 
			
		||||
	spiBegin(spi);
 | 
			
		||||
	spiCommand(spi, 0xab);	// Read electronic signature
 | 
			
		||||
	spiCommand(spi, 0x00);  // Dummy byte 1
 | 
			
		||||
	spiCommand(spi, 0x00);  // Dummy byte 2
 | 
			
		||||
	spiCommand(spi, 0x00);  // Dummy byte 3
 | 
			
		||||
	spi->id.signature = spiCommandRx(spi);
 | 
			
		||||
	spiEnd(spi);
 | 
			
		||||
 | 
			
		||||
	spiBegin(spi);
 | 
			
		||||
	spiCommand(spi, 0x4b);	// Read unique ID
 | 
			
		||||
	spiCommand(spi, 0x00);  // Dummy byte 1
 | 
			
		||||
	spiCommand(spi, 0x00);  // Dummy byte 2
 | 
			
		||||
	spiCommand(spi, 0x00);  // Dummy byte 3
 | 
			
		||||
	spiCommand(spi, 0x00);  // Dummy byte 4
 | 
			
		||||
	spi->id.serial[0] = spiCommandRx(spi);
 | 
			
		||||
	spi->id.serial[1] = spiCommandRx(spi);
 | 
			
		||||
	spi->id.serial[2] = spiCommandRx(spi);
 | 
			
		||||
	spi->id.serial[3] = spiCommandRx(spi);
 | 
			
		||||
	spiEnd(spi);
 | 
			
		||||
 | 
			
		||||
	spi_decode_id(spi);
 | 
			
		||||
	return;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
void spiOverrideSize(struct ff_spi *spi, uint32_t size) {
 | 
			
		||||
	spi->size_override = size;
 | 
			
		||||
 | 
			
		||||
	// If size is 0, re-read the capacity
 | 
			
		||||
	if (!size)
 | 
			
		||||
		spi_decode_id(spi);
 | 
			
		||||
	else
 | 
			
		||||
		spi->id.bytes = size;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
int spiSetType(struct ff_spi *spi, enum spi_type type) {
 | 
			
		||||
 | 
			
		||||
	if (spi->type == type)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
#ifndef SPI_ONLY_SINGLE
 | 
			
		||||
	switch (type) {
 | 
			
		||||
 | 
			
		||||
	case ST_SINGLE:
 | 
			
		||||
#endif
 | 
			
		||||
		if (spi->type == ST_QPI) {
 | 
			
		||||
			spiBegin(spi);
 | 
			
		||||
			spiCommand(spi, 0xff);	// Exit QPI Mode
 | 
			
		||||
			spiEnd(spi);
 | 
			
		||||
		}
 | 
			
		||||
		spi->type = type;
 | 
			
		||||
		spi_set_state(spi, SS_SINGLE);
 | 
			
		||||
#ifndef SPI_ONLY_SINGLE
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case ST_DUAL:
 | 
			
		||||
		if (spi->type == ST_QPI) {
 | 
			
		||||
			spiBegin(spi);
 | 
			
		||||
			spiCommand(spi, 0xff);	// Exit QPI Mode
 | 
			
		||||
			spiEnd(spi);
 | 
			
		||||
		}
 | 
			
		||||
		spi->type = type;
 | 
			
		||||
		spi_set_state(spi, SS_DUAL_TX);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case ST_QUAD:
 | 
			
		||||
		if (spi->type == ST_QPI) {
 | 
			
		||||
			spiBegin(spi);
 | 
			
		||||
			spiCommand(spi, 0xff);	// Exit QPI Mode
 | 
			
		||||
			spiEnd(spi);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Enable QE bit
 | 
			
		||||
		spiWriteStatus(spi, 2, spiReadStatus(spi, 2) | (1 << 1));
 | 
			
		||||
 | 
			
		||||
		spi->type = type;
 | 
			
		||||
		spi_set_state(spi, SS_QUAD_TX);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case ST_QPI:
 | 
			
		||||
		// Enable QE bit
 | 
			
		||||
		spiWriteStatus(spi, 2, spiReadStatus(spi, 2) | (1 << 1));
 | 
			
		||||
 | 
			
		||||
		spiBegin(spi);
 | 
			
		||||
		spiCommand(spi, 0x38);		// Enter QPI Mode
 | 
			
		||||
		spiEnd(spi);
 | 
			
		||||
		spi->type = type;
 | 
			
		||||
		spi_set_state(spi, SS_QUAD_TX);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		fprintf(stderr, "Unrecognized SPI type: %d\n", type);
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int spiIsBusy(struct ff_spi *spi) {
 | 
			
		||||
  	return spiReadStatus(spi, 1) & (1 << 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int spiBeginErase32(struct ff_spi *spi, uint32_t erase_addr) {
 | 
			
		||||
	// Enable Write-Enable Latch (WEL)
 | 
			
		||||
	spiBegin(spi);
 | 
			
		||||
	spiCommand(spi, 0x06);
 | 
			
		||||
	spiEnd(spi);
 | 
			
		||||
 | 
			
		||||
	spiBegin(spi);
 | 
			
		||||
	spiCommand(spi, 0x52);
 | 
			
		||||
	spiCommand(spi, erase_addr >> 16);
 | 
			
		||||
	spiCommand(spi, erase_addr >> 8);
 | 
			
		||||
	spiCommand(spi, erase_addr >> 0);
 | 
			
		||||
	spiEnd(spi);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int spiBeginErase64(struct ff_spi *spi, uint32_t erase_addr) {
 | 
			
		||||
	// Enable Write-Enable Latch (WEL)
 | 
			
		||||
	spiBegin(spi);
 | 
			
		||||
	spiCommand(spi, 0x06);
 | 
			
		||||
	spiEnd(spi);
 | 
			
		||||
 | 
			
		||||
	spiBegin(spi);
 | 
			
		||||
	spiCommand(spi, 0xD8);
 | 
			
		||||
	spiCommand(spi, erase_addr >> 16);
 | 
			
		||||
	spiCommand(spi, erase_addr >> 8);
 | 
			
		||||
	spiCommand(spi, erase_addr >> 0);
 | 
			
		||||
	spiEnd(spi);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int spiBeginWrite(struct ff_spi *spi, uint32_t addr, const void *v_data, unsigned int count) {
 | 
			
		||||
	const uint8_t write_cmd = 0x02;
 | 
			
		||||
	const uint8_t *data = v_data;
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
 | 
			
		||||
	// Enable Write-Enable Latch (WEL)
 | 
			
		||||
	spiBegin(spi);
 | 
			
		||||
	spiCommand(spi, 0x06);
 | 
			
		||||
	spiEnd(spi);
 | 
			
		||||
 | 
			
		||||
	// uint8_t sr1 = spiReadStatus(spi, 1);
 | 
			
		||||
	// if (!(sr1 & (1 << 1)))
 | 
			
		||||
	// 	fprintf(stderr, "error: write-enable latch (WEL) not set, write will probably fail\n");
 | 
			
		||||
 | 
			
		||||
	spiBegin(spi);
 | 
			
		||||
	spiCommand(spi, write_cmd);
 | 
			
		||||
	spiCommand(spi, addr >> 16);
 | 
			
		||||
	spiCommand(spi, addr >> 8);
 | 
			
		||||
	spiCommand(spi, addr >> 0);
 | 
			
		||||
	for (i = 0; (i < count) && (i < 256); i++)
 | 
			
		||||
		spiTx(spi, *data++);
 | 
			
		||||
	spiEnd(spi);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t spiReset(struct ff_spi *spi) {
 | 
			
		||||
	// XXX You should check the "Ready" bit before doing this!
 | 
			
		||||
 | 
			
		||||
	// Shift to QPI mode, then back to Single mode, to ensure
 | 
			
		||||
	// we're actually in Single mode.
 | 
			
		||||
	spiSetType(spi, ST_QPI);
 | 
			
		||||
	spiSetType(spi, ST_SINGLE);
 | 
			
		||||
 | 
			
		||||
	spiBegin(spi);
 | 
			
		||||
	spiCommand(spi, 0x66); // "Enable Reset" command
 | 
			
		||||
	spiEnd(spi);
 | 
			
		||||
 | 
			
		||||
	spiBegin(spi);
 | 
			
		||||
	spiCommand(spi, 0x99); // "Reset Device" command
 | 
			
		||||
	spiEnd(spi);
 | 
			
		||||
 | 
			
		||||
	// msleep(30);
 | 
			
		||||
 | 
			
		||||
	spiBegin(spi);
 | 
			
		||||
	spiCommand(spi, 0xab); // "Resume from Deep Power-Down" command
 | 
			
		||||
	spiEnd(spi);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int spiInit(struct ff_spi *spi) {
 | 
			
		||||
	spi->state = SS_UNCONFIGURED;
 | 
			
		||||
	spi->type = ST_UNCONFIGURED;
 | 
			
		||||
 | 
			
		||||
	// Disable memory-mapped mode and enable bit-bang mode
 | 
			
		||||
	picorvspi_cfg4_write(0);
 | 
			
		||||
 | 
			
		||||
	// Reset the SPI flash, which will return it to SPI mode even
 | 
			
		||||
	// if it's in QPI mode.
 | 
			
		||||
	spiReset(spi);
 | 
			
		||||
 | 
			
		||||
	spiSetType(spi, ST_SINGLE);
 | 
			
		||||
 | 
			
		||||
	// Have the SPI flash pay attention to us
 | 
			
		||||
	gpioWrite(spi->pins.hold, 1);
 | 
			
		||||
 | 
			
		||||
	// Disable WP
 | 
			
		||||
	gpioWrite(spi->pins.wp, 1);
 | 
			
		||||
 | 
			
		||||
	gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
 | 
			
		||||
	gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
 | 
			
		||||
	gpioSetMode(spi->pins.mosi, PI_OUTPUT); // MOSI
 | 
			
		||||
	gpioSetMode(spi->pins.miso, PI_INPUT); // MISO
 | 
			
		||||
	gpioSetMode(spi->pins.hold, PI_OUTPUT);
 | 
			
		||||
	gpioSetMode(spi->pins.wp, PI_OUTPUT);
 | 
			
		||||
 | 
			
		||||
	spi_get_id(spi);
 | 
			
		||||
 | 
			
		||||
	spi->quirks |= SQ_SR2_FROM_SR1;
 | 
			
		||||
	if (spi->id.manufacturer_id == 0xef)
 | 
			
		||||
		spi->quirks |= SQ_SKIP_SR_WEL | SQ_SECURITY_NYBBLE_SHIFT;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void spiEnableQuad(void) {
 | 
			
		||||
	struct ff_spi *spi = spiAlloc();
 | 
			
		||||
	spiInit(spi);
 | 
			
		||||
	spiWriteStatus(spi, 2, spiReadStatus(spi, 2) | (1 << 1));
 | 
			
		||||
	spiFree();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct ff_spi *spiAlloc(void) {
 | 
			
		||||
	static struct ff_spi spi;
 | 
			
		||||
	return &spi;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void spiSetPin(struct ff_spi *spi, enum spi_pin pin, int val) {
 | 
			
		||||
	switch (pin) {
 | 
			
		||||
	case SP_MOSI: spi->pins.mosi = val; break;
 | 
			
		||||
	case SP_MISO: spi->pins.miso = val; break;
 | 
			
		||||
	case SP_HOLD: spi->pins.hold = val; break;
 | 
			
		||||
	case SP_WP: spi->pins.wp = val; break;
 | 
			
		||||
	case SP_CS: spi->pins.cs = val; break;
 | 
			
		||||
	case SP_CLK: spi->pins.clk = val; break;
 | 
			
		||||
	case SP_D0: spi->pins.d0 = val; break;
 | 
			
		||||
	case SP_D1: spi->pins.d1 = val; break;
 | 
			
		||||
	case SP_D2: spi->pins.d2 = val; break;
 | 
			
		||||
	case SP_D3: spi->pins.d3 = val; break;
 | 
			
		||||
	default: fprintf(stderr, "unrecognized pin: %d\n", pin); break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void spiHold(struct ff_spi *spi) {
 | 
			
		||||
	spiBegin(spi);
 | 
			
		||||
	spiCommand(spi, 0xb9);
 | 
			
		||||
	spiEnd(spi);
 | 
			
		||||
}
 | 
			
		||||
void spiUnhold(struct ff_spi *spi) {
 | 
			
		||||
	spiBegin(spi);
 | 
			
		||||
	spiCommand(spi, 0xab);
 | 
			
		||||
	spiEnd(spi);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void spiFree(void) {
 | 
			
		||||
	// Re-enable memory-mapped mode
 | 
			
		||||
	picorvspi_cfg4_write(0x80);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								sw/src/time.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								sw/src/time.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
#include <fomu/csr.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
 | 
			
		||||
void time_init(void)
 | 
			
		||||
{
 | 
			
		||||
	int t;
 | 
			
		||||
 | 
			
		||||
	timer0_en_write(0);
 | 
			
		||||
	t = 2*SYSTEM_CLOCK_FREQUENCY;
 | 
			
		||||
	timer0_reload_write(t);
 | 
			
		||||
	timer0_load_write(t);
 | 
			
		||||
	timer0_en_write(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int elapsed(int *last_event, int period)
 | 
			
		||||
{
 | 
			
		||||
	int t, dt;
 | 
			
		||||
 | 
			
		||||
	timer0_update_value_write(1);
 | 
			
		||||
	t = timer0_reload_read() - timer0_value_read();
 | 
			
		||||
	if(period < 0) {
 | 
			
		||||
		*last_event = t;
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
	dt = t - *last_event;
 | 
			
		||||
	if(dt < 0)
 | 
			
		||||
		dt += timer0_reload_read();
 | 
			
		||||
	if((dt > period) || (dt < 0)) {
 | 
			
		||||
		*last_event = t;
 | 
			
		||||
		return 1;
 | 
			
		||||
	} else
 | 
			
		||||
		return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void msleep(int ms)
 | 
			
		||||
{
 | 
			
		||||
        timer0_en_write(0);
 | 
			
		||||
        timer0_reload_write(0);
 | 
			
		||||
        timer0_load_write(SYSTEM_CLOCK_FREQUENCY/1000*ms);
 | 
			
		||||
        timer0_en_write(1);
 | 
			
		||||
        timer0_update_value_write(1);
 | 
			
		||||
        while(timer0_value_read()) timer0_update_value_write(1);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										220
									
								
								sw/src/usb-desc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								sw/src/usb-desc.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,220 @@
 | 
			
		||||
/* Teensyduino Core Library
 | 
			
		||||
 * http://www.pjrc.com/teensy/
 | 
			
		||||
 * Copyright (c) 2013 PJRC.COM, LLC.
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining
 | 
			
		||||
 * a copy of this software and associated documentation files (the
 | 
			
		||||
 * "Software"), to deal in the Software without restriction, including
 | 
			
		||||
 * without limitation the rights to use, copy, modify, merge, publish,
 | 
			
		||||
 * distribute, sublicense, and/or sell copies of the Software, and to
 | 
			
		||||
 * permit persons to whom the Software is furnished to do so, subject to
 | 
			
		||||
 * the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * 1. The above copyright notice and this permission notice shall be 
 | 
			
		||||
 * included in all copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * 2. If the Software is incorporated into a build system that allows 
 | 
			
		||||
 * selection among a list of target devices, then similar target
 | 
			
		||||
 * devices manufactured by PJRC.COM must be included in the list of
 | 
			
		||||
 * target devices and selectable in the same manner.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | 
			
		||||
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | 
			
		||||
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | 
			
		||||
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 | 
			
		||||
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 | 
			
		||||
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 | 
			
		||||
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <usb-desc.h>
 | 
			
		||||
#include <usb-cdc.h>
 | 
			
		||||
 | 
			
		||||
// USB Descriptors are binary data which the USB host reads to
 | 
			
		||||
// automatically detect a USB device's capabilities.  The format
 | 
			
		||||
// and meaning of every field is documented in numerous USB
 | 
			
		||||
// standards.  When working with USB descriptors, despite the
 | 
			
		||||
// complexity of the standards and poor writing quality in many
 | 
			
		||||
// of those documents, remember descriptors are nothing more
 | 
			
		||||
// than constant binary data that tells the USB host what the
 | 
			
		||||
// device can do.  Computers will load drivers based on this data.
 | 
			
		||||
// Those drivers then communicate on the endpoints specified by
 | 
			
		||||
// the descriptors.
 | 
			
		||||
 | 
			
		||||
// To configure a new combination of interfaces or make minor
 | 
			
		||||
// changes to existing configuration (eg, change the name or ID
 | 
			
		||||
// numbers), usually you would edit "usb_desc.h".  This file
 | 
			
		||||
// is meant to be configured by the header, so generally it is
 | 
			
		||||
// only edited to add completely new USB interfaces or features.
 | 
			
		||||
 | 
			
		||||
// **************************************************************
 | 
			
		||||
//   USB Device
 | 
			
		||||
// **************************************************************
 | 
			
		||||
 | 
			
		||||
#define LSB(n) ((n) & 255)
 | 
			
		||||
#define MSB(n) (((n) >> 8) & 255)
 | 
			
		||||
 | 
			
		||||
// USB Device Descriptor.  The USB host reads this first, to learn
 | 
			
		||||
// what type of device is connected.
 | 
			
		||||
static const uint8_t device_descriptor[] = {
 | 
			
		||||
    18,                                     // bLength
 | 
			
		||||
    1,                                      // bDescriptorType
 | 
			
		||||
    0x01, 0x02,                             // bcdUSB
 | 
			
		||||
    USB_CLASS_CDC,                          // bDeviceClass
 | 
			
		||||
    0x00,                                   // bDeviceSubClass
 | 
			
		||||
    0x00,                                   // bDeviceProtocol
 | 
			
		||||
    EP0_SIZE,                               // bMaxPacketSize0
 | 
			
		||||
    LSB(VENDOR_ID), MSB(VENDOR_ID),         // idVendor
 | 
			
		||||
    LSB(PRODUCT_ID), MSB(PRODUCT_ID),       // idProduct
 | 
			
		||||
    LSB(DEVICE_VER), MSB(DEVICE_VER),       // bcdDevice
 | 
			
		||||
    1,                                      // iManufacturer
 | 
			
		||||
    2,                                      // iProduct
 | 
			
		||||
    0,                                      // iSerialNumber
 | 
			
		||||
    1                                       // bNumConfigurations
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// These descriptors must NOT be "const", because the USB DMA
 | 
			
		||||
// has trouble accessing flash memory with enough bandwidth
 | 
			
		||||
// while the processor is executing from flash.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// **************************************************************
 | 
			
		||||
//   USB Configuration
 | 
			
		||||
// **************************************************************
 | 
			
		||||
 | 
			
		||||
// USB Configuration Descriptor.  This huge descriptor tells all
 | 
			
		||||
// of the devices capbilities.
 | 
			
		||||
static const uint8_t config_descriptor[CONFIG_DESC_SIZE] = {
 | 
			
		||||
    // configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
 | 
			
		||||
    9,                                      // bLength;
 | 
			
		||||
    2,                                      // bDescriptorType;
 | 
			
		||||
    LSB(CONFIG_DESC_SIZE),                  // wTotalLength
 | 
			
		||||
    MSB(CONFIG_DESC_SIZE),
 | 
			
		||||
    NUM_INTERFACE,                          // bNumInterfaces
 | 
			
		||||
    1,                                      // bConfigurationValue
 | 
			
		||||
    1,                                      // iConfiguration
 | 
			
		||||
    0x80,                                   // bmAttributes
 | 
			
		||||
    50,                                     // bMaxPower
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // interface descriptor, CDC
 | 
			
		||||
    USB_DT_INTERFACE_SIZE,                  // bLength
 | 
			
		||||
    USB_DT_INTERFACE,                       // bDescriptorType
 | 
			
		||||
    0,                                      // bInterfaceNumber
 | 
			
		||||
    0,                                      // bAlternateSetting
 | 
			
		||||
    1,                                      // bNumEndpoints
 | 
			
		||||
    USB_CLASS_CDC,                          // bInterfaceClass
 | 
			
		||||
    USB_CDC_SUBCLASS_ACM,                   // bInterfaceSubClass
 | 
			
		||||
    USB_CDC_PROTOCOL_AT,                    // bInterfaceProtocol
 | 
			
		||||
    0,                                      // iInterface
 | 
			
		||||
 | 
			
		||||
    // Header Functional Descriptor
 | 
			
		||||
    0x05,                                   // bLength: Endpoint Descriptor size
 | 
			
		||||
    CS_INTERFACE,                           // bDescriptorType: CS_INTERFACE
 | 
			
		||||
    USB_CDC_TYPE_HEADER,                    // bDescriptorSubtype: Header Func Desc
 | 
			
		||||
    0x10,                                   // bcdCDC: spec release number
 | 
			
		||||
    0x01,
 | 
			
		||||
 | 
			
		||||
    // Call Managment Functional Descriptor
 | 
			
		||||
    0x05,                                   // bFunctionLength
 | 
			
		||||
    CS_INTERFACE,                           // bDescriptorType: CS_INTERFACE
 | 
			
		||||
    USB_CDC_TYPE_CALL_MANAGEMENT,           // bDescriptorSubtype: Call Management Func Desc
 | 
			
		||||
    0,                                      // bmCapabilities: D0+D1
 | 
			
		||||
    1,                                      // bDataInterface: 1
 | 
			
		||||
 | 
			
		||||
    // ACM Functional Descriptor
 | 
			
		||||
    0x04,                                   // bFunctionLength
 | 
			
		||||
    CS_INTERFACE,                           // bDescriptorType: CS_INTERFACE
 | 
			
		||||
    USB_CDC_TYPE_ACM,                       // bDescriptorSubtype: Abstract Control Management desc
 | 
			
		||||
    6,                                      // bmCapabilities
 | 
			
		||||
 | 
			
		||||
    // Union Functional Descriptor
 | 
			
		||||
    0x05,                                   // bFunctionLength
 | 
			
		||||
    CS_INTERFACE,                           // bDescriptorType: CS_INTERFACE
 | 
			
		||||
    USB_CDC_TYPE_UNION,                     // bDescriptorSubtype: Union func desc
 | 
			
		||||
    0,                                      // bMasterInterface: Communication class interface
 | 
			
		||||
    1,                                      // bSlaveInterface0: Data Class Interface
 | 
			
		||||
 | 
			
		||||
    // Endpoint descriptor
 | 
			
		||||
    USB_DT_ENDPOINT_SIZE,                   // bLength
 | 
			
		||||
    USB_DT_ENDPOINT,                        // bDescriptorType
 | 
			
		||||
    0x81,                                   // bEndpointAddress
 | 
			
		||||
    USB_ENDPOINT_ATTR_INTERRUPT,            // bmAttributes
 | 
			
		||||
    LSB(16),                                // wMaxPacketSize
 | 
			
		||||
    MSB(16),                                // wMaxPacketSize
 | 
			
		||||
    255,                                    // bInterval
 | 
			
		||||
 | 
			
		||||
    // interface descriptor, CDC
 | 
			
		||||
    USB_DT_INTERFACE_SIZE,                  // bLength
 | 
			
		||||
    USB_DT_INTERFACE,                       // bDescriptorType
 | 
			
		||||
    1,                                      // bInterfaceNumber
 | 
			
		||||
    0,                                      // bAlternateSetting
 | 
			
		||||
    2,                                      // bNumEndpoints
 | 
			
		||||
    USB_CLASS_DATA,                         // bInterfaceClass
 | 
			
		||||
    0,                                      // bInterfaceSubClass
 | 
			
		||||
    0,                                      // bInterfaceProtocol
 | 
			
		||||
    0,                                      // iInterface
 | 
			
		||||
 | 
			
		||||
    // Endpoint descriptor
 | 
			
		||||
    USB_DT_ENDPOINT_SIZE,                   // bLength
 | 
			
		||||
    USB_DT_ENDPOINT,                        // bDescriptorType
 | 
			
		||||
    0x82,                                   // bEndpointAddress
 | 
			
		||||
    USB_ENDPOINT_ATTR_BULK,                 // bmAttributes
 | 
			
		||||
    LSB(64),                                // wMaxPacketSize
 | 
			
		||||
    MSB(64),                                // wMaxPacketSize
 | 
			
		||||
    1,                                      // bInterval
 | 
			
		||||
 | 
			
		||||
    // Endpoint descriptor
 | 
			
		||||
    USB_DT_ENDPOINT_SIZE,                   // bLength
 | 
			
		||||
    USB_DT_ENDPOINT,                        // bDescriptorType
 | 
			
		||||
    0x02,                                   // bEndpointAddress
 | 
			
		||||
    USB_ENDPOINT_ATTR_BULK,                 // bmAttributes
 | 
			
		||||
    LSB(64),                                // wMaxPacketSize
 | 
			
		||||
    MSB(64),                                // wMaxPacketSize
 | 
			
		||||
    1,                                      // bInterval
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// **************************************************************
 | 
			
		||||
//   String Descriptors
 | 
			
		||||
// **************************************************************
 | 
			
		||||
 | 
			
		||||
// The descriptors above can provide human readable strings,
 | 
			
		||||
// referenced by index numbers.  These descriptors are the
 | 
			
		||||
// actual string data
 | 
			
		||||
 | 
			
		||||
static const struct usb_string_descriptor_struct string0 = {
 | 
			
		||||
    4,
 | 
			
		||||
    3,
 | 
			
		||||
    {0x0409}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
__attribute__((aligned(4)))
 | 
			
		||||
static const struct usb_string_descriptor_struct usb_string_manufacturer_name = {
 | 
			
		||||
    2 + MANUFACTURER_NAME_LEN,
 | 
			
		||||
    3,
 | 
			
		||||
    MANUFACTURER_NAME
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
__attribute__((aligned(4)))
 | 
			
		||||
static const struct usb_string_descriptor_struct usb_string_product_name = {
 | 
			
		||||
    2 + PRODUCT_NAME_LEN,
 | 
			
		||||
    3,
 | 
			
		||||
    PRODUCT_NAME
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// **************************************************************
 | 
			
		||||
//   Descriptors List
 | 
			
		||||
// **************************************************************
 | 
			
		||||
 | 
			
		||||
// This table provides access to all the descriptor data above.
 | 
			
		||||
 | 
			
		||||
const usb_descriptor_list_t usb_descriptor_list[] = {
 | 
			
		||||
    {0x0100, sizeof(device_descriptor), device_descriptor},
 | 
			
		||||
    {0x0200, sizeof(config_descriptor), config_descriptor},
 | 
			
		||||
    {0x0300, 0, (const uint8_t *)&string0},
 | 
			
		||||
    {0x0301, 0, (const uint8_t *)&usb_string_manufacturer_name},
 | 
			
		||||
    {0x0302, 0, (const uint8_t *)&usb_string_product_name},
 | 
			
		||||
    {0, 0, NULL}
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										254
									
								
								sw/src/usb-epfifo.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										254
									
								
								sw/src/usb-epfifo.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,254 @@
 | 
			
		||||
#include <irq.h>
 | 
			
		||||
#include <riscv.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <usb.h>
 | 
			
		||||
 | 
			
		||||
#ifdef CSR_USB_EP_0_OUT_EV_PENDING_ADDR
 | 
			
		||||
 | 
			
		||||
#define EP0OUT_BUFFERS 4
 | 
			
		||||
__attribute__((aligned(4)))
 | 
			
		||||
static uint8_t volatile usb_ep0out_buffer_len[EP0OUT_BUFFERS];
 | 
			
		||||
static uint8_t volatile usb_ep0out_buffer[EP0OUT_BUFFERS][256];
 | 
			
		||||
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);
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
        usb_poll();
 | 
			
		||||
    while ((usb_ep_0_in_dtb_read() & 1) == 1)
 | 
			
		||||
        usb_poll();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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();
 | 
			
		||||
        
 | 
			
		||||
        int byte_count = 0;
 | 
			
		||||
        usb_ep0out_last_tok[usb_ep0out_wr_ptr] = last_tok;
 | 
			
		||||
        volatile uint8_t * obuf = usb_ep0out_buffer[usb_ep0out_wr_ptr];
 | 
			
		||||
        if (!usb_ep_0_out_obuf_empty_read()) {
 | 
			
		||||
            while (!usb_ep_0_out_obuf_empty_read()) {
 | 
			
		||||
                obuf[byte_count++] = usb_ep_0_out_obuf_head_read();
 | 
			
		||||
                usb_ep_0_out_obuf_head_write(0);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (byte_count >= 2)
 | 
			
		||||
            usb_ep0out_buffer_len[usb_ep0out_wr_ptr] = byte_count - 2 /* Strip off CRC16 */;
 | 
			
		||||
        usb_ep0out_wr_ptr = (usb_ep0out_wr_ptr + 1) & (EP0OUT_BUFFERS-1);
 | 
			
		||||
 | 
			
		||||
        if (last_tok == USB_PID_SETUP) {
 | 
			
		||||
            usb_ep_0_in_dtb_write(1);
 | 
			
		||||
            data_offset = 0;
 | 
			
		||||
            current_length = 0;
 | 
			
		||||
            current_data = NULL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
            }
 | 
			
		||||
            usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void usb_poll(void) {
 | 
			
		||||
    // If some data was received, then process it.
 | 
			
		||||
    while (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
 | 
			
		||||
        const struct usb_setup_request *request = (const struct usb_setup_request *)(usb_ep0out_buffer[usb_ep0out_rd_ptr]);
 | 
			
		||||
        // uint8_t len = usb_ep0out_buffer_len[usb_ep0out_rd_ptr];
 | 
			
		||||
        uint8_t last_tok = usb_ep0out_last_tok[usb_ep0out_rd_ptr];
 | 
			
		||||
 | 
			
		||||
        // usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0;
 | 
			
		||||
        usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
 | 
			
		||||
 | 
			
		||||
        if (last_tok == USB_PID_SETUP) {
 | 
			
		||||
            usb_setup(request);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    process_tx();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* CSR_USB_EP_0_OUT_EV_PENDING_ADDR */
 | 
			
		||||
							
								
								
									
										114
									
								
								sw/src/usb-setup.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								sw/src/usb-setup.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,114 @@
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <usb.h>
 | 
			
		||||
 | 
			
		||||
#include <usb-desc.h>
 | 
			
		||||
 | 
			
		||||
static uint8_t reply_buffer[8];
 | 
			
		||||
static uint8_t usb_configuration = 0;
 | 
			
		||||
 | 
			
		||||
void usb_setup(const struct usb_setup_request *setup)
 | 
			
		||||
{
 | 
			
		||||
    const uint8_t *data = NULL;
 | 
			
		||||
    uint32_t datalen = 0;
 | 
			
		||||
    const usb_descriptor_list_t *list;
 | 
			
		||||
 | 
			
		||||
    switch (setup->wRequestAndType)
 | 
			
		||||
    {
 | 
			
		||||
    case 0x0500: // SET_ADDRESS
 | 
			
		||||
    case 0x0b01: // SET_INTERFACE
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case 0x0900: // SET_CONFIGURATION
 | 
			
		||||
        usb_configuration = setup->wValue;
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case 0x0880: // GET_CONFIGURATION
 | 
			
		||||
        reply_buffer[0] = usb_configuration;
 | 
			
		||||
        datalen = 1;
 | 
			
		||||
        data = reply_buffer;
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case 0x0080: // GET_STATUS (device)
 | 
			
		||||
        reply_buffer[0] = 0;
 | 
			
		||||
        reply_buffer[1] = 0;
 | 
			
		||||
        datalen = 2;
 | 
			
		||||
        data = reply_buffer;
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case 0x0082: // GET_STATUS (endpoint)
 | 
			
		||||
        if (setup->wIndex > 0)
 | 
			
		||||
        {
 | 
			
		||||
            usb_err();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        reply_buffer[0] = 0;
 | 
			
		||||
        reply_buffer[1] = 0;
 | 
			
		||||
 | 
			
		||||
        // XXX handle endpoint stall here
 | 
			
		||||
        data = reply_buffer;
 | 
			
		||||
        datalen = 2;
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case 0x0102: // CLEAR_FEATURE (endpoint)
 | 
			
		||||
        if (setup->wIndex > 0 || setup->wValue != 0)
 | 
			
		||||
        {
 | 
			
		||||
            // TODO: do we need to handle IN vs OUT here?
 | 
			
		||||
            usb_err();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case 0x0302: // SET_FEATURE (endpoint)
 | 
			
		||||
        if (setup->wIndex > 0 || setup->wValue != 0)
 | 
			
		||||
        {
 | 
			
		||||
            // TODO: do we need to handle IN vs OUT here?
 | 
			
		||||
            usb_err();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        // XXX: Should we set the stall bit?
 | 
			
		||||
        // USB->DIEP0CTL |= USB_DIEP_CTL_STALL;
 | 
			
		||||
        // TODO: do we need to clear the data toggle here?
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case 0x0680: // GET_DESCRIPTOR
 | 
			
		||||
    case 0x0681:
 | 
			
		||||
        for (list = usb_descriptor_list; 1; list++)
 | 
			
		||||
        {
 | 
			
		||||
            if (list->addr == NULL)
 | 
			
		||||
                break;
 | 
			
		||||
            if (setup->wValue == list->wValue)
 | 
			
		||||
            {
 | 
			
		||||
                data = list->addr;
 | 
			
		||||
                if ((setup->wValue >> 8) == 3)
 | 
			
		||||
                {
 | 
			
		||||
                    // for string descriptors, use the descriptor's
 | 
			
		||||
                    // length field, allowing runtime configured
 | 
			
		||||
                    // length.
 | 
			
		||||
                    datalen = *(list->addr);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    datalen = list->length;
 | 
			
		||||
                }
 | 
			
		||||
                goto send;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        usb_err();
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
        usb_err();
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
send:
 | 
			
		||||
    if (data && datalen) {
 | 
			
		||||
        if (datalen > setup->wLength)
 | 
			
		||||
            datalen = setup->wLength;
 | 
			
		||||
        usb_send(data, datalen);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        usb_ack_in();
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user