diff options
author | henryk <henryk@6dc7ffe9-61d6-0310-9af1-9938baff3ed1> | 2007-11-07 16:28:57 +0000 |
---|---|---|
committer | henryk <henryk@6dc7ffe9-61d6-0310-9af1-9938baff3ed1> | 2007-11-07 16:28:57 +0000 |
commit | 39cb47ed0951074afb24687fcb6e66947b4f8ef8 (patch) | |
tree | 53c25e96487b86ac64113180d3731e73d75c13c5 /openpicc | |
parent | 2306bcac783751b073babef1bf60dd196cfef73d (diff) |
Start working at dfu by copying from main openpcd repository (with modifications), doesn't boot application yet
git-svn-id: https://svn.openpcd.org:2342/trunk@315 6dc7ffe9-61d6-0310-9af1-9938baff3ed1
Diffstat (limited to 'openpicc')
-rw-r--r-- | openpicc/Makefile.dfu | 566 | ||||
-rw-r--r-- | openpicc/application/flash.c | 68 | ||||
-rw-r--r-- | openpicc/application/flash.h | 5 | ||||
-rw-r--r-- | openpicc/config/board.h | 19 | ||||
-rw-r--r-- | openpicc/dfu/dbgu.c | 140 | ||||
-rw-r--r-- | openpicc/dfu/dbgu.h | 25 | ||||
-rw-r--r-- | openpicc/dfu/dfu.c | 938 | ||||
-rw-r--r-- | openpicc/dfu/dfu.h | 143 | ||||
-rw-r--r-- | openpicc/dfu/usb_strings_dfu.h | 120 | ||||
-rw-r--r-- | openpicc/dfu/usb_strings_dfu.txt | 5 | ||||
-rw-r--r-- | openpicc/include/compile.h | 9 | ||||
-rw-r--r-- | openpicc/include/usb_ch9.h | 550 | ||||
-rw-r--r-- | openpicc/include/usb_dfu.h | 81 | ||||
-rw-r--r-- | openpicc/os/boot/Cstartup.S | 450 | ||||
-rw-r--r-- | openpicc/os/boot/Cstartup_SAM7.c | 101 | ||||
-rw-r--r-- | openpicc/os/boot/Cstartup_app.S | 194 |
16 files changed, 3375 insertions, 39 deletions
diff --git a/openpicc/Makefile.dfu b/openpicc/Makefile.dfu new file mode 100644 index 0000000..9a6f5fd --- /dev/null +++ b/openpicc/Makefile.dfu @@ -0,0 +1,566 @@ +# Hey Emacs, this is a -*- makefile -*- +# +# WinARM makefile for the FreeRTOS-demo on LPC2138 +# based in information from the FreeRTOS LPC2106 example +# +# by Martin Thomas, Kaiserslautern, Germany +# <eversmith@heizung-thomas.de> +# +# based on the WinAVR makefile written by Eric B. Weddington, Jörg Wunsch, et al. +# Released to the Public Domain +# Please read the make user manual! +# +# +# On command line: +# +# make all = Make software. +# +# make clean = Clean out built project files. +# +# make program = Download the hex file to the device +# +# (TODO: make filename.s = Just compile filename.c into the assembler code only) +# +# To rebuild project do "make clean" then "make all". +# +# Changelog: +# - 17. Feb. 2005 - added thumb-interwork support (mth) +# - 28. Apr. 2005 - added C++ support (mth) +# - 29. Arp. 2005 - changed handling for lst-Filename (mth) +# - 1. Nov. 2005 - exception-vector placement options (mth) +# - 15. Nov. 2005 - added library-search-path (EXTRA_LIB...) (mth) +# - 2. Dec. 2005 - fixed ihex and binary file extensions (mth) +# - 22. Feb. 2006 - added AT91LIBNOWARN setting (mth) +# - 19. Apr. 2006 - option FLASH_TOOL (default lpc21isp); variable IMGEXT (mth) +# - 19. Mai. 2006 - USE_THUMB_MODE switch, ROM_RUN->RUN_FROM_ROM RAM_RUN->RUN_FROM_RAM + + +FLASH_TOOL = AT91FLASH +#FLASH_TOOL = UVISION +#FLASH_TOOL = OPENOCD + +# MCU name and submodel +MCU = arm7tdmi +#SUBMDL = AT91SAM7S64 +SUBMDL = AT91SAM7S256 + +USE_THUMB_MODE = NO +#USE_THUMB_MODE = YES + +## Create ROM-Image (final) +RUN_MODE=RUN_FROM_ROM +## Create RAM-Image (debugging) - not used in this example +#RUN_MODE=RUN_FROM_RAM + +## We want to produce a full-flash image, but including DFU +IMGTYPE=-sam7dfu-dfu + +# with / at end +PATH_TO_LINKSCRIPTS=link/ + +#### not used in this example: +## Exception-Vector placement only supported for "ROM_RUN" +## (placement settings ignored when using "RAM_RUN") +## - Exception vectors in ROM: +#VECTOR_LOCATION=VECTORS_IN_ROM +## - Exception vectors in RAM: +#VECTOR_LOCATION=VECTORS_IN_RAM + +# Target file name (without extension). +TARGET:=dfu + +USBSTRINGS=dfu/usb_strings_dfu.h + +# List C source files here. (C dependencies are automatically generated.) +# use file-extension c for "c-only"-files +SRC = + +# List C source files here which must be compiled in ARM-Mode. +# use file-extension c for "c-only"-files + +SRCARM = os/boot/Cstartup_SAM7.c os/core/ARM7_AT91SAM7S/lib_AT91SAM7.c \ + dfu/dfu.c dfu/dbgu.c application/flash.c + +# List C++ source files here. +# use file-extension cpp for C++-files (use extension .cpp) +CPPSRC = + +# List C++ source files here which must be compiled in ARM-Mode. +# use file-extension cpp for C++-files (use extension .cpp) +#CPPSRCARM = $(TARGET).cpp +CPPSRCARM = + +# List Assembler source files here. +# Make them always end in a capital .S. Files ending in a lowercase .s +# will not be considered source files but generated files (assembler +# output from the compiler), and will be deleted upon "make clean"! +# Even though the DOS/Win* filesystem matches both .s and .S the same, +# it will preserve the spelling of the filenames, and gcc itself does +# care about how the name is spelled on its command-line. +ASRC = + +# List Assembler source files here which must be assembled in ARM-Mode.. +ASRCARM = os/boot/Cstartup.S + +ifeq ($(DEBUG),1) +SRCARM += lib/vsprintf.c lib/ctype.c lib/string.c +ASRCARM += lib/div64.S +endif + +## Output format. (can be ihex or binary) +## (binary i.e. for openocd and SAM-BA, hex i.e. for lpc21isp and uVision) +#FORMAT = ihex +FORMAT = binary + +# Optimization level, can be [0, 1, 2, 3, s]. +# 0 = turn off optimization. s = optimize for size. +# (Note: 3 is not always the best optimization level. See avr-libc FAQ.) +OPT = s +#OPT = 0 + +# Debugging format. +# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. +# AVR (extended) COFF requires stabs, plus an avr-objcopy run. +#DEBUGF = stabs +DEBUGF = dwarf-2 + +# List any extra directories to look for include files here. +# Each directory must be seperated by a space. +#### FreeRTOS +EXTRAINCDIRS = os/core/ARM7_AT91SAM7S config + +# List any extra directories to look for library files here. +# Each directory must be seperated by a space. +#EXTRA_LIBDIRS = ../arm7_efsl_0_2_4 +EXTRA_LIBDIRS = + +## Using the Atmel AT91_lib produces warning with +## the default warning-levels. +## yes - disable these warnings; no - keep default settings +AT91LIBNOWARN = yes +#AT91LIBNOWARN = no + +# Compiler flag to set the C Standard level. +# c89 - "ANSI" C +# gnu89 - c89 plus GCC extensions +# c99 - ISO C99 standard (not yet fully implemented) +# gnu99 - c99 plus GCC extensions +CSTANDARD = -std=gnu99 + +# Place -D or -U options for C here +CDEFS = -D$(RUN_MODE) -D__MS_types__ -D__LIBRFID__ -DCONFIG_USB_STRING + +ifdef DEBUG +CDEFS += -DDEBUG +ADEFS += -DDEBUG +endif + +ifeq ($(BOARD),OLIMEX) +CDEFS += -DOLIMEX +ADEFS += -DOLIMEX +endif + +ifeq ($(BOARD),PICC) +CDEFS += -DPICC +ADEFS += -DPICC +CINCS = -Isrc/picc +endif + +ifeq ($(BOARD),PCD) +SUBMDL = AT91SAM7S128 +CDEFS += -DPCD +ADEFS += -DPCD +CINCS = -Isrc/pcd +endif + +# Place -I options here +CINCS += -Iinclude -Isrc + +# Place -D or -U options for ASM here +ADEFS += -D$(RUN_MODE) + +ifdef VECTOR_LOCATION +CDEFS += -D$(VECTOR_LOCATION) +ADEFS += -D$(VECTOR_LOCATION) +endif + +CDEFS += -D__$(SUBMDL)__ +ADEFS += -D__$(SUBMDL)__ + + +# Compiler flags. +# -g*: generate debugging information +# -O*: optimization level +# -f...: tuning, see GCC manual and avr-libc documentation +# -Wall...: warning level +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns...: create assembler listing +# +# Flags for C and C++ (arm-elf-gcc/arm-elf-g++) +CFLAGS += -g$(DEBUGF) -DBOARD=$(BOARD) +CFLAGS += $(CDEFS) $(CINCS) +CFLAGS += -O$(OPT) +CFLAGS += -Wall -Wextra -Wcast-align -Wimplicit -Wunused +CFLAGS += -Wpointer-arith -Wswitch +CFLAGS += -Wredundant-decls -Wreturn-type -Wshadow +CFLAGS += -Wbad-function-cast -Wsign-compare -Waggregate-return +CFLAGS += -Wa,-adhlns=$(subst $(suffix $<),.lst,$<) +CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) +#CFLAGS += -ffunction-sections -fdata-sections + +# flags only for C +CONLYFLAGS += -Wnested-externs +CONLYFLAGS += $(CSTANDARD) + +ifneq ($(AT91LIBNOWARN),yes) +#AT91-lib warnings with: +CFLAGS += -Wcast-qual +CONLYFLAGS += -Wmissing-prototypes +CONLYFLAGS += -Wstrict-prototypes +CONLYFLAGS += -Wmissing-declarations +endif + +# flags only for C++ (arm-elf-g++) +# CPPFLAGS = -fno-rtti -fno-exceptions +CPPFLAGS = + +# Assembler flags. +# -Wa,...: tell GCC to pass this to the assembler. +# -ahlns: create listing +# -g$(DEBUGF): have the assembler create line number information +ASFLAGS = $(ADEFS) -Wa,-adhlns=$(<:.S=.lst),--g$(DEBUGF) -Iinclude/ -D__ASSEMBLY__ + + +#Additional libraries. + +# Extra libraries +# Each library-name must be seperated by a space. +# To add libxyz.a, libabc.a and libefsl.a: +# EXTRA_LIBS = xyz abc efsl +#EXTRA_LIBS = efsl +EXTRA_LIBS = + +#Support for newlibc-lpc (file: libnewlibc-lpc.a) +#NEWLIBLPC = -lnewlib-lpc + +MATH_LIB = #-lm + +# CPLUSPLUS_LIB = -lstdc++ + + +# Linker flags. +# -Wl,...: tell GCC to pass this to linker. +# -Map: create map file +# --cref: add cross reference to map file +LDFLAGS = -nostartfiles -Wl,-Map=$(TARGET).map,--cref +LDFLAGS += $(NEWLIBLPC) $(MATH_LIB) +LDFLAGS += -lc -lgcc +LDFLAGS += $(CPLUSPLUS_LIB) +LDFLAGS += $(patsubst %,-L%,$(EXTRA_LIBDIRS)) +LDFLAGS += $(patsubst %,-l%,$(EXTRA_LIBS)) +#LDFLAGS += --gc-sections + +# Set Linker-Script Depending On Selected Memory and Controller +ifeq ($(RUN_MODE),RUN_FROM_RAM) +LDFLAGS +=-T$(PATH_TO_LINKSCRIPTS)$(SUBMDL)-RAM.ld +else +LDFLAGS +=-T$(PATH_TO_LINKSCRIPTS)$(SUBMDL)-ROM$(IMGTYPE).ld +endif + + +# --------------------------------------------------------------------------- +# Flash-Programming support using lpc21isp by Martin Maurer +# only for Philips LPC and Analog ADuC ARMs +# +# Settings and variables: +#LPC21ISP = lpc21isp +LPC21ISP = lpc21isp +LPC21ISP_PORT = com1 +LPC21ISP_BAUD = 38400 +LPC21ISP_XTAL = 12000 +LPC21ISP_FLASHFILE = $(TARGET).hex +# verbose output: +#LPC21ISP_DEBUG = -debug +# enter bootloader via RS232 DTR/RTS (only if hardware supports this +# feature - see Philips AppNote): +LPC21ISP_CONTROL = -control +# --------------------------------------------------------------------------- + + +# Define directories, if needed. +## DIRARM = c:/WinARM/ +## DIRARMBIN = $(DIRAVR)/bin/ +## DIRAVRUTILS = $(DIRAVR)/utils/bin/ + +# Define programs and commands. +SHELL = sh +CC = arm-elf-gcc +CPP = arm-elf-g++ +OBJCOPY = arm-elf-objcopy +OBJDUMP = arm-elf-objdump +SIZE = arm-elf-size +NM = arm-elf-nm +REMOVE = rm -f +COPY = cp + +# Define Messages +# English +MSG_ERRORS_NONE = Errors: none +MSG_BEGIN = "-------- begin (mode: $(RUN_MODE)) --------" +MSG_END = -------- end -------- +MSG_SIZE_BEFORE = Size before: +MSG_SIZE_AFTER = Size after: +MSG_FLASH = Creating load file for Flash: +MSG_EXTENDED_LISTING = Creating Extended Listing: +MSG_SYMBOL_TABLE = Creating Symbol Table: +MSG_LINKING = Linking: +MSG_COMPILING = Compiling C: +MSG_COMPILING_ARM = "Compiling C (ARM-only):" +MSG_COMPILINGCPP = Compiling C++: +MSG_COMPILINGCPP_ARM = "Compiling C++ (ARM-only):" +MSG_ASSEMBLING = Assembling: +MSG_ASSEMBLING_ARM = "Assembling (ARM-only):" +MSG_CLEANING = Cleaning project: +MSG_FORMATERROR = Can not handle output-format +MSG_LPC21_RESETREMINDER = You may have to bring the target in bootloader-mode now. + +# Define all object files. +COBJ = $(SRC:.c=.o) +AOBJ = $(ASRC:.S=.o) +COBJARM = $(SRCARM:.c=.o) +AOBJARM = $(ASRCARM:.S=.o) +CPPOBJ = $(CPPSRC:.cpp=.o) +CPPOBJARM = $(CPPSRCARM:.cpp=.o) + +# Define all listing files. +LST = $(ASRC:.S=.lst) $(ASRCARM:.S=.lst) $(SRC:.c=.lst) $(SRCARM:.c=.lst) +LST += $(CPPSRC:.cpp=.lst) $(CPPSRCARM:.cpp=.lst) + +# Compiler flags to generate dependency files. +### GENDEPFLAGS = -Wp,-M,-MP,-MT,$(*F).o,-MF,.dep/$(@F).d +GENDEPFLAGS = -MD -MP -MF .dep/$(@F).d + +# Combine all necessary flags and optional flags. +# Add target processor to flags. +ALL_CFLAGS = -mcpu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS) +ALL_ASFLAGS = -mcpu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) + + +# Default target. +all: begin gccversion sizebefore build sizeafter finished end + +ifeq ($(FORMAT),ihex) +build: elf hex lss sym +hex: $(TARGET).hex +IMGEXT=hex +else +ifeq ($(FORMAT),binary) +build: elf bin lss sym +bin: $(TARGET).bin +IMGEXT=bin +else +$(error "$(MSG_FORMATERROR) $(FORMAT)") +endif +endif + +elf: $(TARGET).elf +lss: $(TARGET).lss +sym: $(TARGET).sym + +# Eye candy. +begin: + @echo + @echo $(MSG_BEGIN) + +finished: + @echo $(MSG_ERRORS_NONE) + +end: + @echo $(MSG_END) + @echo + + +# Display size of file. +HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex +ELFSIZE = $(SIZE) -A $(TARGET).elf +sizebefore: + @if [ -f $(TARGET).elf ]; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); echo; fi + +sizeafter: + @if [ -f $(TARGET).elf ]; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); echo; fi + + +# Display compiler version information. +gccversion : + @$(CC) --version + + +# Program the device. +# Program the device by using our relais card robot over USB +ifeq ($(FLASH_TOOL),AT91FLASH) +program: $(TARGET).$(IMGEXT) + ls -l $(TARGET).$(IMGEXT) + at91flash $(TARGET).$(IMGEXT) +else +ifeq ($(FLASH_TOOL),UVISION) +# Program the device with Keil's uVision (needs configured uVision-Workspace). +program: $(TARGET).$(IMGEXT) + @echo + @echo "Programming with uVision" + C:\Keil\uv3\Uv3.exe -f uvisionflash.Uv2 -ouvisionflash.txt +else +ifeq ($(FLASH_TOOL),OPENOCD) +# Program the device with Dominic Rath's OPENOCD in "batch-mode", needs cfg and "reset-script". +program: $(TARGET).$(IMGEXT) + @echo + @echo "Programming with OPENOCD" + C:\WinARM\utils\openocd\openocd_svn59\openocd.exe -f oocd_sam7_flash.cfg +else +# Program the device. - lpc21isp will not work for SAM7 +program: $(TARGET).$(IMGEXT) + @echo + @echo $(MSG_LPC21_RESETREMINDER) + $(LPC21ISP) $(LPC21ISP_OPTIONS) $(LPC21ISP_DEBUG) $(LPC21ISP_FLASHFILE) $(LPC21ISP_PORT) $(LPC21ISP_BAUD) $(LPC21ISP_XTAL) +endif +endif +endif + + +# Create final output file (.hex) from ELF output file. +%.hex: %.elf + @echo + @echo $(MSG_FLASH) $@ + $(OBJCOPY) -O $(FORMAT) $< $@ + +# Create final output file (.bin) from ELF output file. +%.bin: %.elf + @echo + @echo $(MSG_FLASH) $@ + $(OBJCOPY) -O $(FORMAT) $< $@ + + +# Create extended listing file from ELF output file. +# testing: option -C +%.lss: %.elf + @echo + @echo $(MSG_EXTENDED_LISTING) $@ + $(OBJDUMP) -h -S -C $< > $@ + + +# Create a symbol table from ELF output file. +%.sym: %.elf + @echo + @echo $(MSG_SYMBOL_TABLE) $@ + $(NM) -n $< > $@ + + +# Link: create ELF output file from object files. +.SECONDARY : $(TARGET).elf +.PRECIOUS : $(AOBJARM) $(AOBJ) $(COBJARM) $(COBJ) $(CPPOBJ) $(CPPOBJARM) +%.elf: $(AOBJARM) $(AOBJ) $(COBJARM) $(COBJ) $(CPPOBJ) $(CPPOBJARM) + @echo + @echo $(MSG_LINKING) $@ + $(CC) $(ALL_CFLAGS) $(AOBJARM) $(AOBJ) $(COBJARM) $(COBJ) $(CPPOBJ) $(CPPOBJARM) --output $@ $(LDFLAGS) + +# Compile: create object files from C source files. ARM/Thumb +$(COBJ) : %.o : %.c + @echo + @echo $(MSG_COMPILING) $< + $(CC) -c $(ALL_CFLAGS) $(CONLYFLAGS) $< -o $@ + +# Compile: create object files from C source files. ARM-only +$(COBJARM) : %.o : %.c include/compile.h $(USBSTRINGS) + @echo + @echo $(MSG_COMPILING_ARM) $< + $(CC) -c $(ALL_CFLAGS) $(CONLYFLAGS) $< -o $@ + +# Compile: create object files from C++ source files. ARM/Thumb +$(CPPOBJ) : %.o : %.cpp + @echo + @echo $(MSG_COMPILINGCPP) $< + $(CPP) -c $(ALL_CFLAGS) $(CPPFLAGS) $< -o $@ + +# Compile: create object files from C++ source files. ARM-only +$(CPPOBJARM) : %.o : %.cpp + @echo + @echo $(MSG_COMPILINGCPP_ARM) $< + $(CPP) -c $(ALL_CFLAGS) $(CPPFLAGS) $< -o $@ + + +# Compile: create assembler files from C source files. ARM/Thumb +## does not work - TODO - hints welcome +##$(COBJ) : %.s : %.c +## $(CC) $(THUMB) -S $(ALL_CFLAGS) $< -o $@ + + +# Assemble: create object files from assembler source files. ARM/Thumb +$(AOBJ) : %.o : %.S + @echo + @echo $(MSG_ASSEMBLING) $< + $(CC) -c $(ALL_ASFLAGS) $< -o $@ + + +# Assemble: create object files from assembler source files. ARM-only +$(AOBJARM) : %.o : %.S + @echo + @echo $(MSG_ASSEMBLING_ARM) $< + $(CC) -c $(ALL_ASFLAGS) $< -o $@ + + +# Target: clean project. +clean: begin clean_list finished end + + +clean_list : + @echo + @echo $(MSG_CLEANING) + $(REMOVE) $(TARGET).hex + $(REMOVE) $(TARGET).bin + $(REMOVE) $(TARGET).obj + $(REMOVE) $(TARGET).elf + $(REMOVE) $(TARGET).map + $(REMOVE) $(TARGET).obj + $(REMOVE) $(TARGET).a90 + $(REMOVE) $(TARGET).sym + $(REMOVE) $(TARGET).lnk + $(REMOVE) $(TARGET).lss + $(REMOVE) $(COBJ) + $(REMOVE) $(CPPOBJ) + $(REMOVE) $(AOBJ) + $(REMOVE) $(COBJARM) + $(REMOVE) $(CPPOBJARM) + $(REMOVE) $(AOBJARM) + $(REMOVE) $(LST) + $(REMOVE) $(SRC:.c=.s) + $(REMOVE) $(SRC:.c=.d) + $(REMOVE) $(SRCARM:.c=.s) + $(REMOVE) $(SRCARM:.c=.d) + $(REMOVE) $(CPPSRC:.cpp=.s) + $(REMOVE) $(CPPSRC:.cpp=.d) + $(REMOVE) $(CPPSRCARM:.cpp=.s) + $(REMOVE) $(CPPSRCARM:.cpp=.d) + $(REMOVE) .dep/* + $(REMOVE) src/picc/usb_strings_dfu.h + $(REMOVE) src/dfu/usb_strings_dfu.h + $(REMOVE) scripts/usbstring + +.PHONY: include/compile.h +include/compile.h: + scripts/mkcompile_h > $@ + +.PHONY: +$(USBSTRINGS): %.h : %.txt ./scripts/usbstring + cat $< | ./scripts/usbstring > $@ + +scripts/usbstring: scripts/usbstring.c + gcc $^ -o $@ + + +# Include the dependency files. +-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) + + +# Listing of phony targets. +.PHONY : all begin finish end sizebefore sizeafter gccversion \ +build elf hex bin lss sym clean clean_list program + diff --git a/openpicc/application/flash.c b/openpicc/application/flash.c new file mode 100644 index 0000000..c729ff8 --- /dev/null +++ b/openpicc/application/flash.c @@ -0,0 +1,68 @@ +#include <sys/types.h> +#include <lib_AT91SAM7.h> +#include <AT91SAM7.h> +#include <dfu/dbgu.h> +#include <board.h> + +#define EFCS_CMD_WRITE_PAGE 0x1 +#define EFCS_CMD_SET_LOCK_BIT 0x2 +#define EFCS_CMD_WRITE_PAGE_LOCK 0x3 +#define EFCS_CMD_CLEAR_LOCK 0x4 +#define EFCS_CMD_ERASE_ALL 0x8 +#define EFCS_CMD_SET_NVM_BIT 0xb +#define EFCS_CMD_CLEAR_NVM_BIT 0xd +#define EFCS_CMD_SET_SECURITY_BIT 0xf + +static u_int16_t page_from_ramaddr(const void *addr) +{ + u_int32_t ramaddr = (u_int32_t) addr; + ramaddr -= (u_int32_t) AT91C_IFLASH; + return ((ramaddr >> AT91C_IFLASH_PAGE_SHIFT)); +} +#define PAGES_PER_LOCKREGION (AT91C_IFLASH_LOCK_REGION_SIZE>>AT91C_IFLASH_PAGE_SHIFT) +#define IS_FIRST_PAGE_OF_LOCKREGION(x) ((x % PAGES_PER_LOCKREGION) == 0) +#define LOCKREGION_FROM_PAGE(x) (x / PAGES_PER_LOCKREGION) + +static int is_page_locked(u_int16_t page) +{ + u_int16_t lockregion = LOCKREGION_FROM_PAGE(page); + + return (AT91C_BASE_MC->MC_FSR & (lockregion << 16)); +} + +static void unlock_page(u_int16_t page) +{ + page &= 0x3ff; + AT91F_MC_EFC_PerformCmd(AT91C_BASE_MC, AT91C_MC_FCMD_UNLOCK | + AT91C_MC_CORRECT_KEY | (page << 8)); +} + +void flash_page(u_int8_t *addr) +{ + u_int16_t page = page_from_ramaddr(addr) & 0x3ff; + u_int32_t fsr = AT91F_MC_EFC_GetStatus(AT91C_BASE_MC); + DEBUGP("flash_page(0x%x=%u) ", addr, page); + + if (is_page_locked(page)) { + DEBUGP("unlocking "); + unlock_page(page); + } + + if (!(fsr & AT91C_MC_FRDY)) { + DEBUGP("NOT_FLASHING "); + return; + } + + DEBUGP("performing start_prog "); + + AT91F_MC_EFC_PerformCmd(AT91C_BASE_MC, AT91C_MC_FCMD_START_PROG | + AT91C_MC_CORRECT_KEY | (page << 8)); +} + +void flash_init(void) +{ + unsigned int fmcn = AT91F_MC_EFC_ComputeFMCN(MCK); + + AT91F_MC_EFC_CfgModeReg(AT91C_BASE_MC, (fmcn&0xff) << 16 | + AT91C_MC_FWS_3FWS); +} diff --git a/openpicc/application/flash.h b/openpicc/application/flash.h new file mode 100644 index 0000000..b812714 --- /dev/null +++ b/openpicc/application/flash.h @@ -0,0 +1,5 @@ +#ifndef _FLASH_H +#define _FLASH_H +extern void flash_page(u_int8_t *addr); +extern void flash_init(void); +#endif diff --git a/openpicc/config/board.h b/openpicc/config/board.h index 065c26d..c052d1e 100644 --- a/openpicc/config/board.h +++ b/openpicc/config/board.h @@ -61,6 +61,25 @@ #define OPENPICC_PIO_PLL_INHIBIT AT91C_PIO_PA24 #define OPENPICC_PIO_PLL_LOCK AT91C_PIO_PA4 +#define OPENPCD_PIO_UDP_CNX NO_UDP_CNX +#define OPENPCD_PIO_UDP_PUPv4 AT91C_PIO_PA16 +#define OPENPCD_PIO_LED1 AT91C_PIO_PA25 +#define OPENPCD_PIO_LED2 AT91C_PIO_PA12 +#define PIO_BOOTLDR AT91C_PIO_PA6 + +#define OPENPCD_VENDOR_ID 0x16c0 +#define OPENPCD_PRODUCT_ID 0x076b +#define OPENPICC_PRODUCT_ID 0x076c + +#define USB_PRODUCT_ID OPENPICC_PRODUCT_ID +#define USB_VENDOR_ID OPENPCD_VENDOR_ID + +/*----------------------*/ +/* interrupt priorities */ +/*----------------------*/ + +#define OPENPCD_IRQ_PRIO_UDP (AT91C_AIC_PRIOR_LOWEST+2) + /*-----------------*/ /* task priorities */ /*-----------------*/ diff --git a/openpicc/dfu/dbgu.c b/openpicc/dfu/dbgu.c new file mode 100644 index 0000000..ded704b --- /dev/null +++ b/openpicc/dfu/dbgu.c @@ -0,0 +1,140 @@ +/* AT91SAM7 debug function implementation for OpenPCD + * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <lib_AT91SAM7.h> +#include <board.h> +#include <dfu/dbgu.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#define USART_SYS_LEVEL 4 +void AT91F_DBGU_Ready(void) +{ + while (!(AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_TXEMPTY)) ; +} + +static void DBGU_irq_handler(void) +{ + static char value; + + AT91F_DBGU_Get(&value); + switch (value) { + case '9': + AT91F_DBGU_Printk("Resetting SAM7\n\r"); + AT91F_RSTSoftReset(AT91C_BASE_RSTC, AT91C_RSTC_PROCRST| + AT91C_RSTC_PERRST|AT91C_RSTC_EXTRST); + break; + default: + AT91F_DBGU_Printk("\n\r"); + } +} + +void AT91F_DBGU_Init(void) +{ + /* Open PIO for DBGU */ + AT91F_DBGU_CfgPIO(); + /* Enable Transmitter & receivier */ + ((AT91PS_USART) AT91C_BASE_DBGU)->US_CR = + AT91C_US_RSTTX | AT91C_US_RSTRX; + + /* Configure DBGU */ + AT91F_US_Configure(AT91C_BASE_DBGU, + MCK, AT91C_US_ASYNC_MODE, + AT91C_DBGU_BAUD, 0); + + /* Enable Transmitter & receivier */ + ((AT91PS_USART) AT91C_BASE_DBGU)->US_CR = + AT91C_US_RXEN | AT91C_US_TXEN; + + /* Enable USART IT error and AT91C_US_ENDRX */ + AT91F_US_EnableIt((AT91PS_USART) AT91C_BASE_DBGU, AT91C_US_RXRDY); + + /* open interrupt */ + + AT91F_AIC_ConfigureIt(AT91C_ID_SYS, USART_SYS_LEVEL, + AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, + DBGU_irq_handler); + AT91F_AIC_EnableIt(AT91C_ID_SYS); + +} + +void AT91F_DBGU_Printk(char *buffer) +{ + while (*buffer != '\0') { + while (!AT91F_US_TxReady((AT91PS_USART) AT91C_BASE_DBGU)) ; + AT91F_US_PutChar((AT91PS_USART) AT91C_BASE_DBGU, *buffer++); + } +} + +int AT91F_DBGU_Get(char *val) +{ + if ((AT91F_US_RxReady((AT91PS_USART) AT91C_BASE_DBGU)) == 0) + return (0); + else { + *val = AT91F_US_GetChar((AT91PS_USART) AT91C_BASE_DBGU); + return (-1); + } +} + +#ifdef DEBUG + +void AT91F_DBGU_Frame(char *buffer) +{ + unsigned char len; + + for (len = 0; buffer[len] != '\0'; len++) { } + + AT91F_US_SendFrame((AT91PS_USART) AT91C_BASE_DBGU, + (unsigned char *)buffer, len, 0, 0); +} + + +const char * +hexdump(const void *data, unsigned int len) +{ + static char string[256]; + unsigned char *d = (unsigned char *) data; + unsigned int i, left; + + string[0] = '\0'; + left = sizeof(string); + for (i = 0; len--; i += 3) { + if (i >= sizeof(string) -4) + break; + snprintf(string+i, 4, " %02x", *d++); + } + return string; +} + +static char dbg_buf[2048]; +void debugp(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vsnprintf(dbg_buf, sizeof(dbg_buf)-1, format, ap); + va_end(ap); + + dbg_buf[sizeof(dbg_buf)-1] = '\0'; + //AT91F_DBGU_Frame(dbg_buf); + AT91F_DBGU_Printk(dbg_buf); +} + +#endif diff --git a/openpicc/dfu/dbgu.h b/openpicc/dfu/dbgu.h new file mode 100644 index 0000000..5ec8a49 --- /dev/null +++ b/openpicc/dfu/dbgu.h @@ -0,0 +1,25 @@ +#ifndef dbgu_h +#define dbgu_h + +#define AT91C_DBGU_BAUD 115200 + +#define DEBUGP(x, args ...) debugp(x, ## args) +#define DEBUGPCR(x, args ...) DEBUGP(x "\r\n", ## args) +#define DEBUGPCRF(x, args ...) DEBUGPCR("%s(%d): " x, __FUNCTION__, __LINE__, ## args) + +extern void AT91F_DBGU_Init(void); +extern void AT91F_DBGU_Printk(char *buffer); +extern int AT91F_DBGU_Get(char *val); +extern void AT91F_DBGU_Ready(void); + +#ifdef DEBUG +extern void debugp(const char *format, ...); +extern const char *hexdump(const void *data, unsigned int len); +extern void AT91F_DBGU_Frame(char *buffer); +#else +#define debugp(x, args ...) +#define hexdump(x, args ...) +#define AT91F_DBGU_Frame(x) +#endif + +#endif /* dbgu_h */ diff --git a/openpicc/dfu/dfu.c b/openpicc/dfu/dfu.c new file mode 100644 index 0000000..af09a62 --- /dev/null +++ b/openpicc/dfu/dfu.c @@ -0,0 +1,938 @@ +/* USB Device Firmware Update Implementation for OpenPCD + * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de> + * + * This ought to be compliant to the USB DFU Spec 1.0 as available from + * http://www.usb.org/developers/devclass_docs/usbdfu10.pdf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <errno.h> +#include <usb_ch9.h> +#include <usb_dfu.h> +#include <board.h> +#include <lib_AT91SAM7.h> + +#include "usb_strings_dfu.h" + +#include <dfu/dfu.h> +#include <dfu/dbgu.h> +#include <application/flash.h> +//#include <os/pcd_enumerate.h> +//#include "../openpcd.h" + +#include <compile.h> + +#define SAM7DFU_SIZE 0x4000 + +/* If debug is enabled, we need to access debug functions from flash + * and therefore have to omit flashing */ +#define DEBUG_DFU_NOFLASH + +#ifdef DEBUG +#define DEBUG_DFU_EP0 +//#define DEBUG_DFU_RECV +#endif + +#ifdef DEBUG_DFU_EP0 +#define DEBUGE DEBUGP +#else +#define DEBUGE(x, args ...) +#endif + +#ifdef DEBUG_DFU_RECV +#define DEBUGR DEBUGP +#else +#define DEBUGR(x, args ...) +#endif + +#define RET_NOTHING 0 +#define RET_ZLP 1 +#define RET_STALL 2 + +#define led1on() AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED1) +#define led1off() AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED1) + +#define led2on() AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED2) +#define led2off() AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED2) + +static void __dfufunc udp_init(void) +{ + /* Set the PLL USB Divider */ + AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1; + + /* Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock */ + AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP; + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP); + + /* Enable UDP PullUp (USB_DP_PUP) : enable & Clear of the + * corresponding PIO Set in PIO mode and Configure in Output */ +#if defined(PCD) + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP); +#endif + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUPv4); +} + +/* Send Data through the control endpoint */ +static void __dfufunc udp_ep0_send_data(const char *pData, u_int32_t length) +{ + AT91PS_UDP pUdp = AT91C_BASE_UDP; + u_int32_t cpt = 0; + AT91_REG csr; + + DEBUGE("send_data: %u bytes ", length); + + do { + cpt = MIN(length, 8); + length -= cpt; + + while (cpt--) + pUdp->UDP_FDR[0] = *pData++; + + if (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) { + pUdp->UDP_CSR[0] &= ~(AT91C_UDP_TXCOMP); + while (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) ; + } + + pUdp->UDP_CSR[0] |= AT91C_UDP_TXPKTRDY; + do { + csr = pUdp->UDP_CSR[0]; + + /* Data IN stage has been stopped by a status OUT */ + if (csr & AT91C_UDP_RX_DATA_BK0) { + pUdp->UDP_CSR[0] &= ~(AT91C_UDP_RX_DATA_BK0); + DEBUGE("stopped by status out "); + return; + } + } while (!(csr & AT91C_UDP_TXCOMP)); + + } while (length); + + if (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) { + pUdp->UDP_CSR[0] &= ~(AT91C_UDP_TXCOMP); + while (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) ; + } +} + +static void udp_ep0_recv_clean(void) +{ + unsigned int i; + u_int8_t dummy; + const AT91PS_UDP pUdp = AT91C_BASE_UDP; + + while (!(pUdp->UDP_CSR[0] & AT91C_UDP_RX_DATA_BK0)) ; + + for (i = 0; i < (pUdp->UDP_CSR[0] >> 16); i++) + dummy = pUdp->UDP_FDR[0]; + + pUdp->UDP_CSR[0] &= ~(AT91C_UDP_RX_DATA_BK0); +} + +/* receive data from EP0 */ +static int __dfufunc udp_ep0_recv_data(u_int8_t *data, u_int16_t len) +{ + AT91PS_UDP pUdp = AT91C_BASE_UDP; + AT91_REG csr; + u_int16_t i, num_rcv; + u_int32_t num_rcv_total = 0; + + do { + /* FIXME: do we need to check whether we've been interrupted + * by a RX SETUP stage? */ + do { + csr = pUdp->UDP_CSR[0]; + DEBUGR("CSR=%08x ", csr); + } while (!(csr & AT91C_UDP_RX_DATA_BK0)) ; + + num_rcv = pUdp->UDP_CSR[0] >> 16; + + /* make sure we don't read more than requested */ + if (num_rcv_total + num_rcv > len) + num_rcv = num_rcv_total - len; + + DEBUGR("num_rcv = %u ", num_rcv); + for (i = 0; i < num_rcv; i++) + *data++ = pUdp->UDP_FDR[0]; + pUdp->UDP_CSR[0] &= ~(AT91C_UDP_RX_DATA_BK0); + + num_rcv_total += num_rcv; + + /* we need to continue to pull data until we either receive + * a packet < endpoint size or == 0 */ + } while (num_rcv == 8 && num_rcv_total < len); + + DEBUGE("ep0_rcv_returning(%u total) ", num_rcv_total); + + return num_rcv_total; +} + +/* Send zero length packet through the control endpoint */ +static void __dfufunc udp_ep0_send_zlp(void) +{ + AT91PS_UDP pUdp = AT91C_BASE_UDP; + pUdp->UDP_CSR[0] |= AT91C_UDP_TXPKTRDY; + while (!(pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP)) ; + pUdp->UDP_CSR[0] &= ~(AT91C_UDP_TXCOMP); + while (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) ; +} + +/* Stall the control endpoint */ +static void __dfufunc udp_ep0_send_stall(void) +{ + AT91PS_UDP pUdp = AT91C_BASE_UDP; + pUdp->UDP_CSR[0] |= AT91C_UDP_FORCESTALL; + while (!(pUdp->UDP_CSR[0] & AT91C_UDP_ISOERROR)) ; + pUdp->UDP_CSR[0] &= ~(AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR); + while (pUdp->UDP_CSR[0] & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR)) ; +} + + +static u_int8_t *ptr = (u_int8_t *) AT91C_IFLASH + SAM7DFU_SIZE; +static __dfudata u_int8_t dfu_status; +__dfudata u_int32_t dfu_state = DFU_STATE_appIDLE; +static u_int32_t pagebuf32[AT91C_IFLASH_PAGE_SIZE/4]; + +static int __dfufunc handle_dnload(u_int16_t val, u_int16_t len) +{ + volatile u_int32_t *p = (volatile u_int32_t *)ptr; + u_int8_t *pagebuf = (u_int8_t *) pagebuf32; + int i; + + DEBUGE("download "); + + if (len > AT91C_IFLASH_PAGE_SIZE) { + /* Too big. Not that we'd really care, but it's a + * DFU protocol violation */ + DEBUGP("length exceeds flash page size "); + dfu_state = DFU_STATE_dfuERROR; + dfu_status = DFU_STATUS_errADDRESS; + return RET_STALL; + } + if (len & 0x3) { + /* reject non-four-byte-aligned writes */ + DEBUGP("not four-byte-aligned length "); + dfu_state = DFU_STATE_dfuERROR; + dfu_status = DFU_STATUS_errADDRESS; + return RET_STALL; + } + if (len == 0) { + DEBUGP("zero-size write -> MANIFEST_SYNC "); + flash_page(p); + dfu_state = DFU_STATE_dfuMANIFEST_SYNC; + return RET_ZLP; + } + if (ptr + len >= (u_int8_t *) AT91C_IFLASH + AT91C_IFLASH_SIZE - ENVIRONMENT_SIZE ) { + DEBUGP("end of write exceeds flash end "); + dfu_state = DFU_STATE_dfuERROR; + dfu_status = DFU_STATUS_errADDRESS; + return RET_STALL; + } + + DEBUGP("try_to_recv=%u ", len); + udp_ep0_recv_data(pagebuf, len); + + DEBUGR(hexdump(pagebuf, len)); + + /* we can only access the write buffer with correctly aligned + * 32bit writes ! */ +#ifndef DEBUG_DFU_NOFLASH + DEBUGP("copying "); + for (i = 0; i < len/4; i++) { + *p++ = pagebuf32[i]; + /* If we have filled a page buffer, flash it */ + if (((unsigned long)p % AT91C_IFLASH_PAGE_SIZE) == 0) { + DEBUGP("page_full "); + flash_page(p-1); + } + } + ptr = (u_int8_t *) p; +#endif + + return RET_ZLP; +} + +#define AT91C_IFLASH_END ((u_int8_t *)AT91C_IFLASH + AT91C_IFLASH_SIZE) +static __dfufunc int handle_upload(u_int16_t val, u_int16_t len) +{ + DEBUGE("upload "); + if (len > AT91C_IFLASH_PAGE_SIZE) { + /* Too big */ + dfu_state = DFU_STATE_dfuERROR; + dfu_status = DFU_STATUS_errADDRESS; + udp_ep0_send_stall(); + return -EINVAL; + } + + if (ptr + len > AT91C_IFLASH_END) + len = AT91C_IFLASH_END - (u_int8_t *)ptr; + + udp_ep0_send_data((char *)ptr, len); + ptr+= len; + + return len; +} + +static __dfufunc void handle_getstatus(void) +{ + struct dfu_status dstat; + u_int32_t fsr = AT91F_MC_EFC_GetStatus(AT91C_BASE_MC); + + DEBUGE("getstatus(fsr=0x%08x) ", fsr); + + switch (dfu_state) { + case DFU_STATE_dfuDNLOAD_SYNC: + case DFU_STATE_dfuDNBUSY: + if (fsr & AT91C_MC_PROGE) { + DEBUGE("errPROG "); + dfu_status = DFU_STATUS_errPROG; + dfu_state = DFU_STATE_dfuERROR; + } else if (fsr & AT91C_MC_LOCKE) { + DEBUGE("errWRITE "); + dfu_status = DFU_STATUS_errWRITE; + dfu_state = DFU_STATE_dfuERROR; + } else if (fsr & AT91C_MC_FRDY) { + DEBUGE("DNLOAD_IDLE "); + dfu_state = DFU_STATE_dfuDNLOAD_IDLE; + } else { + DEBUGE("DNBUSY "); + dfu_state = DFU_STATE_dfuDNBUSY; + } + break; + case DFU_STATE_dfuMANIFEST_SYNC: + dfu_state = DFU_STATE_dfuMANIFEST; + break; + } + + /* send status response */ + dstat.bStatus = dfu_status; + dstat.bState = dfu_state; + dstat.iString = 0; + /* FIXME: set dstat.bwPollTimeout */ + + udp_ep0_send_data((char *)&dstat, sizeof(dstat)); +} + +static void __dfufunc handle_getstate(void) +{ + u_int8_t u8 = dfu_state; + DEBUGE("getstate "); + + udp_ep0_send_data((char *)&u8, sizeof(u8)); +} + +/* callback function for DFU requests */ +int __dfufunc dfu_ep0_handler(u_int8_t req_type, u_int8_t req, + u_int16_t val, u_int16_t len) +{ + int rc, ret = RET_NOTHING; + + DEBUGE("old_state = %u ", dfu_state); + + switch (dfu_state) { + case DFU_STATE_appIDLE: + switch (req) { + case USB_REQ_DFU_GETSTATUS: + handle_getstatus(); + break; + case USB_REQ_DFU_GETSTATE: + handle_getstate(); + break; + case USB_REQ_DFU_DETACH: + dfu_state = DFU_STATE_appDETACH; + ret = RET_ZLP; + goto out; + break; + default: + ret = RET_STALL; + } + break; + case DFU_STATE_appDETACH: + switch (req) { + case USB_REQ_DFU_GETSTATUS: + handle_getstatus(); + break; + case USB_REQ_DFU_GETSTATE: + handle_getstate(); + break; + default: + dfu_state = DFU_STATE_appIDLE; + ret = RET_STALL; + goto out; + break; + } + /* FIXME: implement timer to return to appIDLE */ + break; + case DFU_STATE_dfuIDLE: + switch (req) { + case USB_REQ_DFU_DNLOAD: + if (len == 0) { + dfu_state = DFU_STATE_dfuERROR; + ret = RET_STALL; + goto out; + } + dfu_state = DFU_STATE_dfuDNLOAD_SYNC; + ptr = (u_int8_t *) AT91C_IFLASH + SAM7DFU_SIZE; + ret = handle_dnload(val, len); + break; + case USB_REQ_DFU_UPLOAD: + ptr = (u_int8_t *) AT91C_IFLASH + SAM7DFU_SIZE; + dfu_state = DFU_STATE_dfuUPLOAD_IDLE; + handle_upload(val, len); + break; + case USB_REQ_DFU_ABORT: + /* no zlp? */ + ret = RET_ZLP; + break; + case USB_REQ_DFU_GETSTATUS: + handle_getstatus(); + break; + case USB_REQ_DFU_GETSTATE: + handle_getstate(); + break; + default: + dfu_state = DFU_STATE_dfuERROR; + ret = RET_STALL; + goto out; + break; + } + break; + case DFU_STATE_dfuDNLOAD_SYNC: + switch (req) { + case USB_REQ_DFU_GETSTATUS: + handle_getstatus(); + /* FIXME: state transition depending on block completeness */ + break; + case USB_REQ_DFU_GETSTATE: + handle_getstate(); + break; + default: + dfu_state = DFU_STATE_dfuERROR; + ret = RET_STALL; + goto out; + } + break; + case DFU_STATE_dfuDNBUSY: + switch (req) { + case USB_REQ_DFU_GETSTATUS: + /* FIXME: only accept getstatus if bwPollTimeout + * has elapsed */ + handle_getstatus(); + break; + default: + dfu_state = DFU_STATE_dfuERROR; + ret = RET_STALL; + goto out; + } + break; + case DFU_STATE_dfuDNLOAD_IDLE: + switch (req) { + case USB_REQ_DFU_DNLOAD: + dfu_state = DFU_STATE_dfuDNLOAD_SYNC; + ret = handle_dnload(val, len); + break; + case USB_REQ_DFU_ABORT: + dfu_state = DFU_STATE_dfuIDLE; + ret = RET_ZLP; + break; + case USB_REQ_DFU_GETSTATUS: + handle_getstatus(); + break; + case USB_REQ_DFU_GETSTATE: + handle_getstate(); + break; + default: + dfu_state = DFU_STATE_dfuERROR; + ret = RET_STALL; + break; + } + break; + case DFU_STATE_dfuMANIFEST_SYNC: + switch (req) { + case USB_REQ_DFU_GETSTATUS: + handle_getstatus(); + break; + case USB_REQ_DFU_GETSTATE: + handle_getstate(); + break; + default: + dfu_state = DFU_STATE_dfuERROR; + ret = RET_STALL; + break; + } + break; + case DFU_STATE_dfuMANIFEST: + dfu_state = DFU_STATE_dfuERROR; + ret = RET_STALL; + break; + case DFU_STATE_dfuMANIFEST_WAIT_RST: + /* we should never go here */ + break; + case DFU_STATE_dfuUPLOAD_IDLE: + switch (req) { + case USB_REQ_DFU_UPLOAD: + /* state transition if less data then requested */ + rc = handle_upload(val, len); + if (rc >= 0 && rc < len) + dfu_state = DFU_STATE_dfuIDLE; + break; + case USB_REQ_DFU_ABORT: + dfu_state = DFU_STATE_dfuIDLE; + /* no zlp? */ + ret = RET_ZLP; + break; + case USB_REQ_DFU_GETSTATUS: + handle_getstatus(); + break; + case USB_REQ_DFU_GETSTATE: + handle_getstate(); + break; + default: + dfu_state = DFU_STATE_dfuERROR; + ret = RET_STALL; + break; + } + break; + case DFU_STATE_dfuERROR: + switch (req) { + case USB_REQ_DFU_GETSTATUS: + handle_getstatus(); + break; + case USB_REQ_DFU_GETSTATE: + handle_getstate(); + break; + case USB_REQ_DFU_CLRSTATUS: + dfu_state = DFU_STATE_dfuIDLE; + dfu_status = DFU_STATUS_OK; + /* no zlp? */ + ret = RET_ZLP; + break; + default: + dfu_state = DFU_STATE_dfuERROR; + ret = RET_STALL; + break; + } + break; + } + +out: + DEBUGE("new_state = %u\r\n", dfu_state); + + switch (ret) { + case RET_NOTHING: + break; + case RET_ZLP: + udp_ep0_send_zlp(); + break; + case RET_STALL: + udp_ep0_send_stall(); + break; + } + return 0; +} + +static u_int8_t cur_config; + +/* USB DFU Device descriptor in DFU mode */ +__dfustruct const struct usb_device_descriptor dfu_dev_descriptor = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0100, + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize0 = 8, + .idVendor = USB_VENDOR_ID, + .idProduct = USB_PRODUCT_ID, + .bcdDevice = 0x0000, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 0x00, + .bNumConfigurations = 0x01, +}; + +/* USB DFU Config descriptor in DFU mode */ +__dfustruct const struct _dfu_desc dfu_cfg_descriptor = { + .ucfg = { + .bLength = USB_DT_CONFIG_SIZE, + .bDescriptorType = USB_DT_CONFIG, + .wTotalLength = USB_DT_CONFIG_SIZE + + 2* USB_DT_INTERFACE_SIZE + + USB_DT_DFU_SIZE, + .bNumInterfaces = 1, + .bConfigurationValue = 1, +#ifdef CONFIG_USB_STRING + .iConfiguration = 3, +#else + .iConfiguration = 0, +#endif + .bmAttributes = USB_CONFIG_ATT_ONE, + .bMaxPower = 100, + }, + .uif[0] = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0x00, + .bAlternateSetting = 0x00, + .bNumEndpoints = 0x00, + .bInterfaceClass = 0xfe, + .bInterfaceSubClass = 0x01, + .bInterfaceProtocol = 0x02, +#ifdef CONFIG_USB_STRING + .iInterface = 4, +#else + .iInterface = 0, +#endif + }, + .uif[1] = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0x00, + .bAlternateSetting = 0x01, + .bNumEndpoints = 0x00, + .bInterfaceClass = 0xfe, + .bInterfaceSubClass = 0x01, + .bInterfaceProtocol = 0x02, +#ifdef CONFIG_USB_STRING + .iInterface = 5, +#else + .iInterface = 0, +#endif + }, + + .func_dfu = DFU_FUNC_DESC, +}; + + +/* minimal USB EP0 handler in DFU mode */ +static __dfufunc void dfu_udp_ep0_handler(void) +{ + AT91PS_UDP pUDP = AT91C_BASE_UDP; + u_int8_t bmRequestType, bRequest; + u_int16_t wValue, wIndex, wLength, wStatus; + u_int32_t csr = pUDP->UDP_CSR[0]; + + DEBUGE("CSR=0x%04x ", csr); + + if (csr & AT91C_UDP_STALLSENT) { + DEBUGE("ACK_STALLSENT "); + pUDP->UDP_CSR[0] = ~AT91C_UDP_STALLSENT; + } + + if (csr & AT91C_UDP_RX_DATA_BK0) { + DEBUGE("ACK_BANK0 "); + pUDP->UDP_CSR[0] &= ~AT91C_UDP_RX_DATA_BK0; + } + + if (!(csr & AT91C_UDP_RXSETUP)) { + DEBUGE("no setup packet\r\n"); + return; + } + + DEBUGE("len=%d ", csr >> 16); + if (csr >> 16 == 0) { + DEBUGE("empty packet\r\n"); + return; + } + + bmRequestType = pUDP->UDP_FDR[0]; + bRequest = pUDP->UDP_FDR[0]; + wValue = (pUDP->UDP_FDR[0] & 0xFF); + wValue |= (pUDP->UDP_FDR[0] << 8); + wIndex = (pUDP->UDP_FDR[0] & 0xFF); + wIndex |= (pUDP->UDP_FDR[0] << 8); + wLength = (pUDP->UDP_FDR[0] & 0xFF); + wLength |= (pUDP->UDP_FDR[0] << 8); + + DEBUGE("bmRequestType=0x%2x ", bmRequestType); + + if (bmRequestType & 0x80) { + DEBUGE("DATA_IN=1 "); + pUDP->UDP_CSR[0] |= AT91C_UDP_DIR; + while (!(pUDP->UDP_CSR[0] & AT91C_UDP_DIR)) ; + } + pUDP->UDP_CSR[0] &= ~AT91C_UDP_RXSETUP; + while ((pUDP->UDP_CSR[0] & AT91C_UDP_RXSETUP)) ; + + /* Handle supported standard device request Cf Table 9-3 in USB + * speciication Rev 1.1 */ + switch ((bRequest << 8) | bmRequestType) { + u_int8_t desc_type, desc_index; + case STD_GET_DESCRIPTOR: + DEBUGE("GET_DESCRIPTOR "); + desc_type = wValue >> 8; + desc_index = wValue & 0xff; + switch (desc_type) { + case USB_DT_DEVICE: + /* Return Device Descriptor */ + udp_ep0_send_data((const char *) + &dfu_dev_descriptor, + MIN(sizeof(dfu_dev_descriptor), + wLength)); + break; + case USB_DT_CONFIG: + /* Return Configuration Descriptor */ + udp_ep0_send_data((const char *) + &dfu_cfg_descriptor, + MIN(sizeof(dfu_cfg_descriptor), + wLength)); + break; + case USB_DT_STRING: + /* Return String Descriptor */ + if (desc_index > ARRAY_SIZE(usb_strings)) { + udp_ep0_send_stall(); + break; + } + DEBUGE("bLength=%u, wLength=%u ", + usb_strings[desc_index]->bLength, wLength); + udp_ep0_send_data((const char *) usb_strings[desc_index], + MIN(usb_strings[desc_index]->bLength, + wLength)); + break; + case USB_DT_CS_DEVICE: + /* Return Function descriptor */ + udp_ep0_send_data((const char *) &dfu_cfg_descriptor.func_dfu, + MIN(sizeof(dfu_cfg_descriptor.func_dfu), + wLength)); + break; + default: + udp_ep0_send_stall(); + break; + } + break; + case STD_SET_ADDRESS: + DEBUGE("SET_ADDRESS "); + udp_ep0_send_zlp(); + pUDP->UDP_FADDR = (AT91C_UDP_FEN | wValue); + pUDP->UDP_GLBSTATE = (wValue) ? AT91C_UDP_FADDEN : 0; + break; + case STD_SET_CONFIGURATION: + DEBUGE("SET_CONFIG "); + if (wValue) + DEBUGE("VALUE!=0 "); + cur_config = wValue; + udp_ep0_send_zlp(); + pUDP->UDP_GLBSTATE = + (wValue) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN; + pUDP->UDP_CSR[1] = + (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) : + 0; + pUDP->UDP_CSR[2] = + (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) : 0; + pUDP->UDP_CSR[3] = + (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) : 0; + pUDP->UDP_IER = (AT91C_UDP_EPINT0|AT91C_UDP_EPINT1| + AT91C_UDP_EPINT2|AT91C_UDP_EPINT3); + break; + case STD_GET_CONFIGURATION: + DEBUGE("GET_CONFIG "); + udp_ep0_send_data((char *)&(cur_config), + sizeof(cur_config)); + break; + case STD_GET_STATUS_ZERO: + DEBUGE("GET_STATUS_ZERO "); + wStatus = 0; + udp_ep0_send_data((char *)&wStatus, sizeof(wStatus)); + break; + case STD_GET_STATUS_INTERFACE: + DEBUGE("GET_STATUS_INTERFACE "); + wStatus = 0; + udp_ep0_send_data((char *)&wStatus, sizeof(wStatus)); + break; + case STD_GET_STATUS_ENDPOINT: + DEBUGE("GET_STATUS_ENDPOINT(EPidx=%u) ", wIndex&0x0f); + wStatus = 0; + wIndex &= 0x0F; + if ((pUDP->UDP_GLBSTATE & AT91C_UDP_CONFG) && (wIndex == 0)) { + wStatus = + (pUDP->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1; + udp_ep0_send_data((char *)&wStatus, + sizeof(wStatus)); + } else if ((pUDP->UDP_GLBSTATE & AT91C_UDP_FADDEN) + && (wIndex == 0)) { + wStatus = + (pUDP->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1; + udp_ep0_send_data((char *)&wStatus, + sizeof(wStatus)); + } else + udp_ep0_send_stall(); + break; + case STD_SET_FEATURE_ZERO: + DEBUGE("SET_FEATURE_ZERO "); + udp_ep0_send_stall(); + break; + case STD_SET_FEATURE_INTERFACE: + DEBUGE("SET_FEATURE_INTERFACE "); + udp_ep0_send_zlp(); + break; + case STD_SET_FEATURE_ENDPOINT: + DEBUGE("SET_FEATURE_ENDPOINT "); + udp_ep0_send_stall(); + break; + case STD_CLEAR_FEATURE_ZERO: + DEBUGE("CLEAR_FEATURE_ZERO "); + udp_ep0_send_stall(); + break; + case STD_CLEAR_FEATURE_INTERFACE: + DEBUGE("CLEAR_FEATURE_INTERFACE "); + udp_ep0_send_zlp(); + break; + case STD_CLEAR_FEATURE_ENDPOINT: + DEBUGE("CLEAR_FEATURE_ENDPOINT(EPidx=%u) ", wIndex & 0x0f); + udp_ep0_send_stall(); + break; + case STD_SET_INTERFACE: + DEBUGE("SET INTERFACE "); + /* FIXME: store the interface number somewhere, once + * we need to support DFU flashing DFU */ + udp_ep0_send_zlp(); + break; + default: + DEBUGE("DEFAULT(req=0x%02x, type=0x%02x) ", + bRequest, bmRequestType); + if ((bmRequestType & 0x3f) == USB_TYPE_DFU) { + dfu_ep0_handler(bmRequestType, bRequest, + wValue, wLength); + } else + udp_ep0_send_stall(); + break; + } + DEBUGE("\r\n"); +} + +/* minimal USB IRQ handler in DFU mode */ +static __dfufunc void dfu_udp_irq(void) +{ + AT91PS_UDP pUDP = AT91C_BASE_UDP; + AT91_REG isr = pUDP->UDP_ISR; + led1on(); + + if (isr & AT91C_UDP_ENDBUSRES) { + led2on(); + pUDP->UDP_IER = AT91C_UDP_EPINT0; + /* reset all endpoints */ + pUDP->UDP_RSTEP = (unsigned int)-1; + pUDP->UDP_RSTEP = 0; + /* Enable the function */ + pUDP->UDP_FADDR = AT91C_UDP_FEN; + /* Configure endpoint 0 */ + pUDP->UDP_CSR[0] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL); + cur_config = 0; + + if (dfu_state == DFU_STATE_dfuMANIFEST_WAIT_RST || + dfu_state == DFU_STATE_dfuMANIFEST) { + AT91F_RSTSoftReset(AT91C_BASE_RSTC, AT91C_RSTC_PROCRST| + AT91C_RSTC_PERRST| + AT91C_RSTC_EXTRST); + } + + } + + if (isr & AT91C_UDP_EPINT0) + dfu_udp_ep0_handler(); + + /* clear all interrupts */ + pUDP->UDP_ICR = isr; + + AT91F_AIC_ClearIt(AT91C_ID_UDP); + + led1off(); +} + +/* this is only called once before DFU mode, no __dfufunc required */ +static void dfu_switch(void) +{ + AT91PS_AIC pAic = AT91C_BASE_AIC; + + DEBUGE("\r\nsam7dfu: switching to DFU mode\r\n"); + + dfu_state = DFU_STATE_appDETACH; + AT91F_RSTSoftReset(AT91C_BASE_RSTC, AT91C_RSTC_PROCRST| + AT91C_RSTC_PERRST|AT91C_RSTC_EXTRST); + + /* We should never reach here, but anyway avoid returning to the + * caller since he doesn't expect us to do so */ + while (1) ; +} + +void __dfufunc dfu_main(void) +{ + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED1); + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED2); + led1off(); + led2off(); + + AT91F_DBGU_Init(); + AT91F_DBGU_Printk("\n\r\n\rsam7dfu - AT91SAM7 USB DFU bootloader\n\r" + "(C) 2006 by Harald Welte <hwelte@hmw-consulting.de>\n\r" + "This software is FREE SOFTWARE licensed under GNU GPL\n\r"); + AT91F_DBGU_Printk("Version " COMPILE_SVNREV + " compiled " COMPILE_DATE + " by " COMPILE_BY "\n\r\n\r"); + + udp_init(); + + dfu_state = DFU_STATE_dfuIDLE; + + /* This implements + AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_UDP, + OPENPCD_IRQ_PRIO_UDP, + AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, dfu_udp_irq); + */ + AT91PS_AIC pAic = AT91C_BASE_AIC; + pAic->AIC_IDCR = 1 << AT91C_ID_UDP; + pAic->AIC_SVR[AT91C_ID_UDP] = (unsigned int) &dfu_udp_irq; + pAic->AIC_SMR[AT91C_ID_UDP] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | + OPENPCD_IRQ_PRIO_UDP; + pAic->AIC_ICCR = 1 << AT91C_ID_UDP; + + AT91F_AIC_EnableIt(AT91C_ID_UDP); + + /* End-of-Bus-Reset is always enabled */ + + /* Clear for set the Pull up resistor */ +#if defined(PCD) + AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP); +#endif + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUPv4); + + flash_init(); + + AT91F_DBGU_Printk("You may now start the DFU up/download process\r\n"); + /* do nothing, since all of DFU is interrupt driven */ + int i = 0; + while (1) { + /* Occasionally reset watchdog */ + i = (i+1) % 10000; + if( i== 0) { + AT91F_WDTRestart(AT91C_BASE_WDTC); + } + } +} + +const struct dfuapi __dfufunctab dfu_api = { + .udp_init = &udp_init, + .ep0_send_data = &udp_ep0_send_data, + .ep0_send_zlp = &udp_ep0_send_zlp, + .ep0_send_stall = &udp_ep0_send_stall, + .dfu_ep0_handler = &dfu_ep0_handler, + .dfu_switch = &dfu_switch, + .dfu_state = &dfu_state, + .dfu_dev_descriptor = &dfu_dev_descriptor, + .dfu_cfg_descriptor = &dfu_cfg_descriptor, +}; + +/* just for testing */ +int foo = 12345; diff --git a/openpicc/dfu/dfu.h b/openpicc/dfu/dfu.h new file mode 100644 index 0000000..77f80a1 --- /dev/null +++ b/openpicc/dfu/dfu.h @@ -0,0 +1,143 @@ +#ifndef _DFU_H +#define _DFU_H + +/* USB Device Firmware Update Implementation for OpenPCD + * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de> + * + * This ought to be compliant to the USB DFU Spec 1.0 as available from + * http://www.usb.org/developers/devclass_docs/usbdfu10.pdf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + */ + +#include <sys/types.h> +#include <usb_ch9.h> +#include <usb_dfu.h> + +/* USB DFU functional descriptor */ +#define DFU_FUNC_DESC { \ + .bLength = USB_DT_DFU_SIZE, \ + .bDescriptorType = USB_DT_DFU, \ + .bmAttributes = USB_DFU_CAN_UPLOAD | USB_DFU_CAN_DOWNLOAD, \ + .wDetachTimeOut = 0xff00, \ + .wTransferSize = AT91C_IFLASH_PAGE_SIZE, \ + .bcdDFUVersion = 0x0100, \ +} + +/* USB Interface descriptor in Runtime mode */ +#ifdef CONFIG_USB_STRING +#define DFU_RT_IF_DESC { \ + { \ + .bLength = USB_DT_INTERFACE_SIZE, \ + .bDescriptorType = USB_DT_INTERFACE, \ + .bInterfaceNumber = 0x01, \ + .bAlternateSetting = 0x00, \ + .bNumEndpoints = 0x00, \ + .bInterfaceClass = 0xfe, \ + .bInterfaceSubClass = 0x01, \ + .bInterfaceProtocol = 0x01, \ + .iInterface = 1, \ + }, { \ + .bLength = USB_DT_INTERFACE_SIZE, \ + .bDescriptorType = USB_DT_INTERFACE, \ + .bInterfaceNumber = 0x02, \ + .bAlternateSetting = 0x00, \ + .bNumEndpoints = 0x00, \ + .bInterfaceClass = 0xfe, \ + .bInterfaceSubClass = 0x01, \ + .bInterfaceProtocol = 0x01, \ + .iInterface = 2, \ + }, \ +} +#else +#define DFU_RT_IF_DESC { \ + { \ + .bLength = USB_DT_INTERFACE_SIZE, \ + .bDescriptorType = USB_DT_INTERFACE, \ + .bInterfaceNumber = 0x01, \ + .bAlternateSetting = 0x00, \ + .bNumEndpoints = 0x00, \ + .bInterfaceClass = 0xfe, \ + .bInterfaceSubClass = 0x01, \ + .bInterfaceProtocol = 0x01, \ + .iInterface = 0, \ + }, { \ + .bLength = USB_DT_INTERFACE_SIZE, \ + .bDescriptorType = USB_DT_INTERFACE, \ + .bInterfaceNumber = 0x02, \ + .bAlternateSetting = 0x00, \ + .bNumEndpoints = 0x00, \ + .bInterfaceClass = 0xfe, \ + .bInterfaceSubClass = 0x01, \ + .bInterfaceProtocol = 0x01, \ + .iInterface = 0, \ + }, \ +} +#endif + +#define __dfufunctab __attribute__ ((section (".dfu.functab"))) +#define __dfudata __attribute__ ((section (".data.shared"))) +#define __dfufunc +#define __dfustruct const + +#define DFU_API_LOCATION ((const struct dfuapi *) 0x00103fd0) + +struct _dfu_desc { + struct usb_config_descriptor ucfg; + struct usb_interface_descriptor uif[2]; + struct usb_dfu_func_descriptor func_dfu; +}; + +struct dfuapi { + void (*udp_init)(void); + void (*ep0_send_data)(const char *data, u_int32_t len); + void (*ep0_send_zlp)(void); + void (*ep0_send_stall)(void); + int (*dfu_ep0_handler)(u_int8_t req_type, u_int8_t req, + u_int16_t val, u_int16_t len); + void (*dfu_switch)(void); + u_int32_t *dfu_state; + const struct usb_device_descriptor *dfu_dev_descriptor; + const struct _dfu_desc *dfu_cfg_descriptor; +}; + +/* From openpcd/firmware/src/os/pcd_enumerate.h */ +/* USB standard request code */ + +#define STD_GET_STATUS_ZERO 0x0080 +#define STD_GET_STATUS_INTERFACE 0x0081 +#define STD_GET_STATUS_ENDPOINT 0x0082 + +#define STD_CLEAR_FEATURE_ZERO 0x0100 +#define STD_CLEAR_FEATURE_INTERFACE 0x0101 +#define STD_CLEAR_FEATURE_ENDPOINT 0x0102 + +#define STD_SET_FEATURE_ZERO 0x0300 +#define STD_SET_FEATURE_INTERFACE 0x0301 +#define STD_SET_FEATURE_ENDPOINT 0x0302 + +#define STD_SET_ADDRESS 0x0500 +#define STD_GET_DESCRIPTOR 0x0680 +#define STD_SET_DESCRIPTOR 0x0700 +#define STD_GET_CONFIGURATION 0x0880 +#define STD_SET_CONFIGURATION 0x0900 +#define STD_GET_INTERFACE 0x0A81 +#define STD_SET_INTERFACE 0x0B01 +#define STD_SYNCH_FRAME 0x0C82 + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +#endif /* _DFU_H */ diff --git a/openpicc/dfu/usb_strings_dfu.h b/openpicc/dfu/usb_strings_dfu.h new file mode 100644 index 0000000..24fde2f --- /dev/null +++ b/openpicc/dfu/usb_strings_dfu.h @@ -0,0 +1,120 @@ +#ifndef _USB_STRINGS_H +#define _USB_STRINGS_H + +/* THIS FILE IS AUTOGENERATED, DO NOT MODIFY MANUALLY */ + +#include <usb_ch9.h> +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +static const struct { + struct usb_descriptor_header hdr; + u_int16_t wData[]; +} __attribute__((packed)) string0 = { + .hdr = { + .bLength = sizeof(struct usb_descriptor_header) + 1 * sizeof(u_int16_t), + .bDescriptorType = USB_DT_STRING, + }, + .wData = {0x0409 /* English */ }, +}; + +/* String 1 "bitmanufaktur.de IT Solutions and hmw-consulting.de" */ +static const struct { + struct usb_descriptor_header hdr; + u_int16_t wData[]; +} __attribute__((packed)) string1 = { + .hdr = { + .bLength = sizeof(struct usb_descriptor_header) + 51 * sizeof(u_int16_t), + .bDescriptorType = USB_DT_STRING, + }, + .wData = { 0x0062, 0x0069, 0x0074, 0x006d, 0x0061, 0x006e, + 0x0075, 0x0066, 0x0061, 0x006b, 0x0074, 0x0075, + 0x0072, 0x002e, 0x0064, 0x0065, 0x0020, 0x0049, + 0x0054, 0x0020, 0x0053, 0x006f, 0x006c, 0x0075, + 0x0074, 0x0069, 0x006f, 0x006e, 0x0073, 0x0020, + 0x0061, 0x006e, 0x0064, 0x0020, 0x0068, 0x006d, + 0x0077, 0x002d, 0x0063, 0x006f, 0x006e, 0x0073, + 0x0075, 0x006c, 0x0074, 0x0069, 0x006e, 0x0067, + 0x002e, 0x0064, 0x0065, }, +}; + +/* String 2 "OpenPICC RFID Simulator - DFU Mode" */ +static const struct { + struct usb_descriptor_header hdr; + u_int16_t wData[]; +} __attribute__((packed)) string2 = { + .hdr = { + .bLength = sizeof(struct usb_descriptor_header) + 34 * sizeof(u_int16_t), + .bDescriptorType = USB_DT_STRING, + }, + .wData = { 0x004f, 0x0070, 0x0065, 0x006e, 0x0050, 0x0049, + 0x0043, 0x0043, 0x0020, 0x0052, 0x0046, 0x0049, + 0x0044, 0x0020, 0x0053, 0x0069, 0x006d, 0x0075, + 0x006c, 0x0061, 0x0074, 0x006f, 0x0072, 0x0020, + 0x002d, 0x0020, 0x0044, 0x0046, 0x0055, 0x0020, + 0x004d, 0x006f, 0x0064, 0x0065, }, +}; + +/* String 3 "OpenPIIC DFU Configuration" */ +static const struct { + struct usb_descriptor_header hdr; + u_int16_t wData[]; +} __attribute__((packed)) string3 = { + .hdr = { + .bLength = sizeof(struct usb_descriptor_header) + 26 * sizeof(u_int16_t), + .bDescriptorType = USB_DT_STRING, + }, + .wData = { 0x004f, 0x0070, 0x0065, 0x006e, 0x0050, 0x0049, + 0x0049, 0x0043, 0x0020, 0x0044, 0x0046, 0x0055, + 0x0020, 0x0043, 0x006f, 0x006e, 0x0066, 0x0069, + 0x0067, 0x0075, 0x0072, 0x0061, 0x0074, 0x0069, + 0x006f, 0x006e, }, +}; + +/* String 4 "OpenPICC DFU Interface - Application Partition" */ +static const struct { + struct usb_descriptor_header hdr; + u_int16_t wData[]; +} __attribute__((packed)) string4 = { + .hdr = { + .bLength = sizeof(struct usb_descriptor_header) + 46 * sizeof(u_int16_t), + .bDescriptorType = USB_DT_STRING, + }, + .wData = { 0x004f, 0x0070, 0x0065, 0x006e, 0x0050, 0x0049, + 0x0043, 0x0043, 0x0020, 0x0044, 0x0046, 0x0055, + 0x0020, 0x0049, 0x006e, 0x0074, 0x0065, 0x0072, + 0x0066, 0x0061, 0x0063, 0x0065, 0x0020, 0x002d, + 0x0020, 0x0041, 0x0070, 0x0070, 0x006c, 0x0069, + 0x0063, 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, + 0x0020, 0x0050, 0x0061, 0x0072, 0x0074, 0x0069, + 0x0074, 0x0069, 0x006f, 0x006e, }, +}; + +/* String 5 "OpenPICC DFU Interface - Bootloader Partition" */ +static const struct { + struct usb_descriptor_header hdr; + u_int16_t wData[]; +} __attribute__((packed)) string5 = { + .hdr = { + .bLength = sizeof(struct usb_descriptor_header) + 45 * sizeof(u_int16_t), + .bDescriptorType = USB_DT_STRING, + }, + .wData = { 0x004f, 0x0070, 0x0065, 0x006e, 0x0050, 0x0049, + 0x0043, 0x0043, 0x0020, 0x0044, 0x0046, 0x0055, + 0x0020, 0x0049, 0x006e, 0x0074, 0x0065, 0x0072, + 0x0066, 0x0061, 0x0063, 0x0065, 0x0020, 0x002d, + 0x0020, 0x0042, 0x006f, 0x006f, 0x0074, 0x006c, + 0x006f, 0x0061, 0x0064, 0x0065, 0x0072, 0x0020, + 0x0050, 0x0061, 0x0072, 0x0074, 0x0069, 0x0074, + 0x0069, 0x006f, 0x006e, }, +}; + +static const struct usb_descriptor_header *usb_strings[] = { + (struct usb_descriptor_header *) &string0, + (struct usb_descriptor_header *) &string1, + (struct usb_descriptor_header *) &string2, + (struct usb_descriptor_header *) &string3, + (struct usb_descriptor_header *) &string4, + (struct usb_descriptor_header *) &string5, +}; + +#endif /* _USB_STRINGS_H */ diff --git a/openpicc/dfu/usb_strings_dfu.txt b/openpicc/dfu/usb_strings_dfu.txt new file mode 100644 index 0000000..681c30a --- /dev/null +++ b/openpicc/dfu/usb_strings_dfu.txt @@ -0,0 +1,5 @@ +bitmanufaktur.de IT Solutions and hmw-consulting.de +OpenPICC RFID Simulator - DFU Mode +OpenPIIC DFU Configuration +OpenPICC DFU Interface - Application Partition +OpenPICC DFU Interface - Bootloader Partition diff --git a/openpicc/include/compile.h b/openpicc/include/compile.h new file mode 100644 index 0000000..14ec5dd --- /dev/null +++ b/openpicc/include/compile.h @@ -0,0 +1,9 @@ +#ifndef _COMPILE_H +#define _COMPILE_H + +/* This file is auto generated */ +#define COMPILE_DATE "20071107-171917" +#define COMPILE_BY "henryk@dawn.ploetzli.ch" +#define COMPILE_SVNREV "313-unclean" + +#endif /* _COMPILE_H */ diff --git a/openpicc/include/usb_ch9.h b/openpicc/include/usb_ch9.h new file mode 100644 index 0000000..46066f2 --- /dev/null +++ b/openpicc/include/usb_ch9.h @@ -0,0 +1,550 @@ +/* + * This file holds USB constants and structures that are needed for USB + * device APIs. These are used by the USB device model, which is defined + * in chapter 9 of the USB 2.0 specification. Linux has several APIs in C + * that need these: + * + * - the master/host side Linux-USB kernel driver API; + * - the "usbfs" user space API; and + * - the Linux "gadget" slave/device/peripheral side driver API. + * + * USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems + * act either as a USB master/host or as a USB slave/device. That means + * the master and slave side APIs benefit from working well together. + * + * There's also "Wireless USB", using low power short range radios for + * peripheral interconnection but otherwise building on the USB framework. + */ + +#ifndef __LINUX_USB_CH9_H +#define __LINUX_USB_CH9_H + +#include <sys/types.h> + +/*-------------------------------------------------------------------------*/ + +/* CONTROL REQUEST SUPPORT */ + +/* + * USB directions + * + * This bit flag is used in endpoint descriptors' bEndpointAddress field. + * It's also one of three fields in control requests bRequestType. + */ +#define USB_DIR_OUT 0 /* to device */ +#define USB_DIR_IN 0x80 /* to host */ + +/* + * USB types, the second of three bRequestType fields + */ +#define USB_TYPE_MASK (0x03 << 5) +#define USB_TYPE_STANDARD (0x00 << 5) +#define USB_TYPE_CLASS (0x01 << 5) +#define USB_TYPE_VENDOR (0x02 << 5) +#define USB_TYPE_RESERVED (0x03 << 5) + +/* + * USB recipients, the third of three bRequestType fields + */ +#define USB_RECIP_MASK 0x1f +#define USB_RECIP_DEVICE 0x00 +#define USB_RECIP_INTERFACE 0x01 +#define USB_RECIP_ENDPOINT 0x02 +#define USB_RECIP_OTHER 0x03 + +/* + * Standard requests, for the bRequest field of a SETUP packet. + * + * These are qualified by the bRequestType field, so that for example + * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved + * by a GET_STATUS request. + */ +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +#define USB_REQ_SET_FEATURE 0x03 +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C + +#define USB_REQ_SET_ENCRYPTION 0x0D /* Wireless USB */ +#define USB_REQ_GET_ENCRYPTION 0x0E +#define USB_REQ_SET_HANDSHAKE 0x0F +#define USB_REQ_GET_HANDSHAKE 0x10 +#define USB_REQ_SET_CONNECTION 0x11 +#define USB_REQ_SET_SECURITY_DATA 0x12 +#define USB_REQ_GET_SECURITY_DATA 0x13 +#define USB_REQ_SET_WUSB_DATA 0x14 +#define USB_REQ_LOOPBACK_DATA_WRITE 0x15 +#define USB_REQ_LOOPBACK_DATA_READ 0x16 +#define USB_REQ_SET_INTERFACE_DS 0x17 + +/* + * USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and + * are read as a bit array returned by USB_REQ_GET_STATUS. (So there + * are at most sixteen features of each type.) + */ +#define USB_DEVICE_SELF_POWERED 0 /* (read only) */ +#define USB_DEVICE_REMOTE_WAKEUP 1 /* dev may initiate wakeup */ +#define USB_DEVICE_TEST_MODE 2 /* (wired high speed only) */ +#define USB_DEVICE_BATTERY 2 /* (wireless) */ +#define USB_DEVICE_B_HNP_ENABLE 3 /* (otg) dev may initiate HNP */ +#define USB_DEVICE_WUSB_DEVICE 3 /* (wireless)*/ +#define USB_DEVICE_A_HNP_SUPPORT 4 /* (otg) RH port supports HNP */ +#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* (otg) other RH port does */ +#define USB_DEVICE_DEBUG_MODE 6 /* (special devices only) */ + +#define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */ + + +/** + * struct usb_ctrlrequest - SETUP data for a USB device control request + * @bRequestType: matches the USB bmRequestType field + * @bRequest: matches the USB bRequest field + * @wValue: matches the USB wValue field (le16 byte order) + * @wIndex: matches the USB wIndex field (le16 byte order) + * @wLength: matches the USB wLength field (le16 byte order) + * + * This structure is used to send control requests to a USB device. It matches + * the different fields of the USB 2.0 Spec section 9.3, table 9-2. See the + * USB spec for a fuller description of the different fields, and what they are + * used for. + * + * Note that the driver for any interface can issue control requests. + * For most devices, interfaces don't coordinate with each other, so + * such requests may be made at any time. + */ +struct usb_ctrlrequest { + u_int8_t bRequestType; + u_int8_t bRequest; + u_int16_t wValue; + u_int16_t wIndex; + u_int16_t wLength; +} __attribute__ ((packed)); + +/*-------------------------------------------------------------------------*/ + +/* + * STANDARD DESCRIPTORS ... as returned by GET_DESCRIPTOR, or + * (rarely) accepted by SET_DESCRIPTOR. + * + * Note that all multi-byte values here are encoded in little endian + * byte order "on the wire". But when exposed through Linux-USB APIs, + * they've been converted to cpu byte order. + */ + +/* + * Descriptor types ... USB 2.0 spec table 9.5 + */ +#define USB_DT_DEVICE 0x01 +#define USB_DT_CONFIG 0x02 +#define USB_DT_STRING 0x03 +#define USB_DT_INTERFACE 0x04 +#define USB_DT_ENDPOINT 0x05 +#define USB_DT_DEVICE_QUALIFIER 0x06 +#define USB_DT_OTHER_SPEED_CONFIG 0x07 +#define USB_DT_INTERFACE_POWER 0x08 +/* these are from a minor usb 2.0 revision (ECN) */ +#define USB_DT_OTG 0x09 +#define USB_DT_DEBUG 0x0a +#define USB_DT_INTERFACE_ASSOCIATION 0x0b +/* these are from the Wireless USB spec */ +#define USB_DT_SECURITY 0x0c +#define USB_DT_KEY 0x0d +#define USB_DT_ENCRYPTION_TYPE 0x0e +#define USB_DT_BOS 0x0f +#define USB_DT_DEVICE_CAPABILITY 0x10 +#define USB_DT_WIRELESS_ENDPOINT_COMP 0x11 + +/* conventional codes for class-specific descriptors */ +#define USB_DT_CS_DEVICE 0x21 +#define USB_DT_CS_CONFIG 0x22 +#define USB_DT_CS_STRING 0x23 +#define USB_DT_CS_INTERFACE 0x24 +#define USB_DT_CS_ENDPOINT 0x25 + +/* All standard descriptors have these 2 fields at the beginning */ +struct usb_descriptor_header { + u_int8_t bLength; + u_int8_t bDescriptorType; +} __attribute__ ((packed)); + + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_DEVICE: Device descriptor */ +struct usb_device_descriptor { + u_int8_t bLength; + u_int8_t bDescriptorType; + + u_int16_t bcdUSB; + u_int8_t bDeviceClass; + u_int8_t bDeviceSubClass; + u_int8_t bDeviceProtocol; + u_int8_t bMaxPacketSize0; + u_int16_t idVendor; + u_int16_t idProduct; + u_int16_t bcdDevice; + u_int8_t iManufacturer; + u_int8_t iProduct; + u_int8_t iSerialNumber; + u_int8_t bNumConfigurations; +} __attribute__ ((packed)); + +#define USB_DT_DEVICE_SIZE 18 + + +/* + * Device and/or Interface Class codes + * as found in bDeviceClass or bInterfaceClass + * and defined by www.usb.org documents + */ +#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */ +#define USB_CLASS_AUDIO 1 +#define USB_CLASS_COMM 2 +#define USB_CLASS_HID 3 +#define USB_CLASS_PHYSICAL 5 +#define USB_CLASS_STILL_IMAGE 6 +#define USB_CLASS_PRINTER 7 +#define USB_CLASS_MASS_STORAGE 8 +#define USB_CLASS_HUB 9 +#define USB_CLASS_CDC_DATA 0x0a +#define USB_CLASS_CSCID 0x0b /* chip+ smart card */ +#define USB_CLASS_CONTENT_SEC 0x0d /* content security */ +#define USB_CLASS_VIDEO 0x0e +#define USB_CLASS_WIRELESS_CONTROLLER 0xe0 +#define USB_CLASS_APP_SPEC 0xfe +#define USB_CLASS_VENDOR_SPEC 0xff + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_CONFIG: Configuration descriptor information. + * + * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the + * descriptor type is different. Highspeed-capable devices can look + * different depending on what speed they're currently running. Only + * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG + * descriptors. + */ +struct usb_config_descriptor { + u_int8_t bLength; + u_int8_t bDescriptorType; + + u_int16_t wTotalLength; + u_int8_t bNumInterfaces; + u_int8_t bConfigurationValue; + u_int8_t iConfiguration; + u_int8_t bmAttributes; + u_int8_t bMaxPower; +} __attribute__ ((packed)); + +#define USB_DT_CONFIG_SIZE 9 + +/* from config descriptor bmAttributes */ +#define USB_CONFIG_ATT_ONE (1 << 7) /* must be set */ +#define USB_CONFIG_ATT_SELFPOWER (1 << 6) /* self powered */ +#define USB_CONFIG_ATT_WAKEUP (1 << 5) /* can wakeup */ +#define USB_CONFIG_ATT_BATTERY (1 << 4) /* battery powered */ + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_STRING: String descriptor */ +struct usb_string_descriptor { + u_int8_t bLength; + u_int8_t bDescriptorType; + + u_int16_t wData[0]; /* UTF-16LE encoded */ +} __attribute__ ((packed)); + +/* note that "string" zero is special, it holds language codes that + * the device supports, not Unicode characters. + */ + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_INTERFACE: Interface descriptor */ +struct usb_interface_descriptor { + u_int8_t bLength; + u_int8_t bDescriptorType; + + u_int8_t bInterfaceNumber; + u_int8_t bAlternateSetting; + u_int8_t bNumEndpoints; + u_int8_t bInterfaceClass; + u_int8_t bInterfaceSubClass; + u_int8_t bInterfaceProtocol; + u_int8_t iInterface; +} __attribute__ ((packed)); + +#define USB_DT_INTERFACE_SIZE 9 + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_ENDPOINT: Endpoint descriptor */ +struct usb_endpoint_descriptor { + u_int8_t bLength; + u_int8_t bDescriptorType; + + u_int8_t bEndpointAddress; + u_int8_t bmAttributes; + u_int16_t wMaxPacketSize; + u_int8_t bInterval; +} __attribute__ ((packed)); + +#define USB_DT_ENDPOINT_SIZE 7 +#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ + + +/* + * Endpoints + */ +#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */ +#define USB_ENDPOINT_DIR_MASK 0x80 + +#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */ +#define USB_ENDPOINT_XFER_CONTROL 0 +#define USB_ENDPOINT_XFER_ISOC 1 +#define USB_ENDPOINT_XFER_BULK 2 +#define USB_ENDPOINT_XFER_INT 3 +#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80 + + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */ +struct usb_qualifier_descriptor { + u_int8_t bLength; + u_int8_t bDescriptorType; + + u_int16_t bcdUSB; + u_int8_t bDeviceClass; + u_int8_t bDeviceSubClass; + u_int8_t bDeviceProtocol; + u_int8_t bMaxPacketSize0; + u_int8_t bNumConfigurations; + u_int8_t bRESERVED; +} __attribute__ ((packed)); + + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_OTG (from OTG 1.0a supplement) */ +struct usb_otg_descriptor { + u_int8_t bLength; + u_int8_t bDescriptorType; + + u_int8_t bmAttributes; /* support for HNP, SRP, etc */ +} __attribute__ ((packed)); + +/* from usb_otg_descriptor.bmAttributes */ +#define USB_OTG_SRP (1 << 0) +#define USB_OTG_HNP (1 << 1) /* swap host/device roles */ + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_DEBUG: for special highspeed devices, replacing serial console */ +struct usb_debug_descriptor { + u_int8_t bLength; + u_int8_t bDescriptorType; + + /* bulk endpoints with 8 byte maxpacket */ + u_int8_t bDebugInEndpoint; + u_int8_t bDebugOutEndpoint; +}; + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_INTERFACE_ASSOCIATION: groups interfaces */ +struct usb_interface_assoc_descriptor { + u_int8_t bLength; + u_int8_t bDescriptorType; + + u_int8_t bFirstInterface; + u_int8_t bInterfaceCount; + u_int8_t bFunctionClass; + u_int8_t bFunctionSubClass; + u_int8_t bFunctionProtocol; + u_int8_t iFunction; +} __attribute__ ((packed)); + + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_SECURITY: group of wireless security descriptors, including + * encryption types available for setting up a CC/association. + */ +struct usb_security_descriptor { + u_int8_t bLength; + u_int8_t bDescriptorType; + + u_int16_t wTotalLength; + u_int8_t bNumEncryptionTypes; +}; + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_KEY: used with {GET,SET}_SECURITY_DATA; only public keys + * may be retrieved. + */ +struct usb_key_descriptor { + u_int8_t bLength; + u_int8_t bDescriptorType; + + u_int8_t tTKID[3]; + u_int8_t bReserved; + u_int8_t bKeyData[0]; +}; + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_ENCRYPTION_TYPE: bundled in DT_SECURITY groups */ +struct usb_encryption_descriptor { + u_int8_t bLength; + u_int8_t bDescriptorType; + + u_int8_t bEncryptionType; +#define USB_ENC_TYPE_UNSECURE 0 +#define USB_ENC_TYPE_WIRED 1 /* non-wireless mode */ +#define USB_ENC_TYPE_CCM_1 2 /* aes128/cbc session */ +#define USB_ENC_TYPE_RSA_1 3 /* rsa3072/sha1 auth */ + u_int8_t bEncryptionValue; /* use in SET_ENCRYPTION */ + u_int8_t bAuthKeyIndex; +}; + + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_BOS: group of wireless capabilities */ +struct usb_bos_descriptor { + u_int8_t bLength; + u_int8_t bDescriptorType; + + u_int16_t wTotalLength; + u_int8_t bNumDeviceCaps; +}; + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_DEVICE_CAPABILITY: grouped with BOS */ +struct usb_dev_cap_header { + u_int8_t bLength; + u_int8_t bDescriptorType; + u_int8_t bDevCapabilityType; +}; + +#define USB_CAP_TYPE_WIRELESS_USB 1 + +struct usb_wireless_cap_descriptor { /* Ultra Wide Band */ + u_int8_t bLength; + u_int8_t bDescriptorType; + u_int8_t bDevCapabilityType; + + u_int8_t bmAttributes; +#define USB_WIRELESS_P2P_DRD (1 << 1) +#define USB_WIRELESS_BEACON_MASK (3 << 2) +#define USB_WIRELESS_BEACON_SELF (1 << 2) +#define USB_WIRELESS_BEACON_DIRECTED (2 << 2) +#define USB_WIRELESS_BEACON_NONE (3 << 2) + u_int16_t wPHYRates; /* bit rates, Mbps */ +#define USB_WIRELESS_PHY_53 (1 << 0) /* always set */ +#define USB_WIRELESS_PHY_80 (1 << 1) +#define USB_WIRELESS_PHY_107 (1 << 2) /* always set */ +#define USB_WIRELESS_PHY_160 (1 << 3) +#define USB_WIRELESS_PHY_200 (1 << 4) /* always set */ +#define USB_WIRELESS_PHY_320 (1 << 5) +#define USB_WIRELESS_PHY_400 (1 << 6) +#define USB_WIRELESS_PHY_480 (1 << 7) + u_int8_t bmTFITXPowerInfo; /* TFI power levels */ + u_int8_t bmFFITXPowerInfo; /* FFI power levels */ + u_int16_t bmBandGroup; + u_int8_t bReserved; +}; + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_WIRELESS_ENDPOINT_COMP: companion descriptor associated with + * each endpoint descriptor for a wireless device + */ +struct usb_wireless_ep_comp_descriptor { + u_int8_t bLength; + u_int8_t bDescriptorType; + + u_int8_t bMaxBurst; + u_int8_t bMaxSequence; + u_int16_t wMaxStreamDelay; + u_int16_t wOverTheAirPacketSize; + u_int8_t bOverTheAirInterval; + u_int8_t bmCompAttributes; +#define USB_ENDPOINT_SWITCH_MASK 0x03 /* in bmCompAttributes */ +#define USB_ENDPOINT_SWITCH_NO 0 +#define USB_ENDPOINT_SWITCH_SWITCH 1 +#define USB_ENDPOINT_SWITCH_SCALE 2 +}; + +/*-------------------------------------------------------------------------*/ + +/* USB_REQ_SET_HANDSHAKE is a four-way handshake used between a wireless + * host and a device for connection set up, mutual authentication, and + * exchanging short lived session keys. The handshake depends on a CC. + */ +struct usb_handshake { + u_int8_t bMessageNumber; + u_int8_t bStatus; + u_int8_t tTKID[3]; + u_int8_t bReserved; + u_int8_t CDID[16]; + u_int8_t nonce[16]; + u_int8_t MIC[8]; +}; + +/*-------------------------------------------------------------------------*/ + +/* USB_REQ_SET_CONNECTION modifies or revokes a connection context (CC). + * A CC may also be set up using non-wireless secure channels (including + * wired USB!), and some devices may support CCs with multiple hosts. + */ +struct usb_connection_context { + u_int8_t CHID[16]; /* persistent host id */ + u_int8_t CDID[16]; /* device id (unique w/in host context) */ + u_int8_t CK[16]; /* connection key */ +}; + +/*-------------------------------------------------------------------------*/ + +/* USB 2.0 defines three speeds, here's how Linux identifies them */ + +enum usb_device_speed { + USB_SPEED_UNKNOWN = 0, /* enumerating */ + USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */ + USB_SPEED_HIGH, /* usb 2.0 */ + USB_SPEED_VARIABLE, /* wireless (usb 2.5) */ +}; + +enum usb_device_state { + /* NOTATTACHED isn't in the USB spec, and this state acts + * the same as ATTACHED ... but it's clearer this way. + */ + USB_STATE_NOTATTACHED = 0, + + /* chapter 9 and authentication (wireless) device states */ + USB_STATE_ATTACHED, + USB_STATE_POWERED, /* wired */ + USB_STATE_UNAUTHENTICATED, /* auth */ + USB_STATE_RECONNECTING, /* auth */ + USB_STATE_DEFAULT, /* limited function */ + USB_STATE_ADDRESS, + USB_STATE_CONFIGURED, /* most functions */ + + USB_STATE_SUSPENDED + + /* NOTE: there are actually four different SUSPENDED + * states, returning to POWERED, DEFAULT, ADDRESS, or + * CONFIGURED respectively when SOF tokens flow again. + */ +}; + +#endif /* __LINUX_USB_CH9_H */ diff --git a/openpicc/include/usb_dfu.h b/openpicc/include/usb_dfu.h new file mode 100644 index 0000000..5000edc --- /dev/null +++ b/openpicc/include/usb_dfu.h @@ -0,0 +1,81 @@ +#ifndef _USB_DFU_H +#define _USB_DFU_H +/* USB Device Firmware Update Implementation for OpenPCD + * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de> + * + * Protocol definitions for USB DFU + * + * This ought to be compliant to the USB DFU Spec 1.0 as available from + * http://www.usb.org/developers/devclass_docs/usbdfu10.pdf + * + */ + +#include <sys/types.h> + +#define USB_DT_DFU 0x21 + +struct usb_dfu_func_descriptor { + u_int8_t bLength; + u_int8_t bDescriptorType; + u_int8_t bmAttributes; +#define USB_DFU_CAN_DOWNLOAD (1 << 0) +#define USB_DFU_CAN_UPLOAD (1 << 1) +#define USB_DFU_MANIFEST_TOL (1 << 2) +#define USB_DFU_WILL_DETACH (1 << 3) + u_int16_t wDetachTimeOut; + u_int16_t wTransferSize; + u_int16_t bcdDFUVersion; +} __attribute__ ((packed)); + +#define USB_DT_DFU_SIZE 9 + +#define USB_TYPE_DFU (USB_TYPE_CLASS|USB_RECIP_INTERFACE) + +/* DFU class-specific requests (Section 3, DFU Rev 1.1) */ +#define USB_REQ_DFU_DETACH 0x00 +#define USB_REQ_DFU_DNLOAD 0x01 +#define USB_REQ_DFU_UPLOAD 0x02 +#define USB_REQ_DFU_GETSTATUS 0x03 +#define USB_REQ_DFU_CLRSTATUS 0x04 +#define USB_REQ_DFU_GETSTATE 0x05 +#define USB_REQ_DFU_ABORT 0x06 + +struct dfu_status { + u_int8_t bStatus; + u_int8_t bwPollTimeout[3]; + u_int8_t bState; + u_int8_t iString; +} __attribute__((packed)); + +#define DFU_STATUS_OK 0x00 +#define DFU_STATUS_errTARGET 0x01 +#define DFU_STATUS_errFILE 0x02 +#define DFU_STATUS_errWRITE 0x03 +#define DFU_STATUS_errERASE 0x04 +#define DFU_STATUS_errCHECK_ERASED 0x05 +#define DFU_STATUS_errPROG 0x06 +#define DFU_STATUS_errVERIFY 0x07 +#define DFU_STATUS_errADDRESS 0x08 +#define DFU_STATUS_errNOTDONE 0x09 +#define DFU_STATUS_errFIRMWARE 0x0a +#define DFU_STATUS_errVENDOR 0x0b +#define DFU_STATUS_errUSBR 0x0c +#define DFU_STATUS_errPOR 0x0d +#define DFU_STATUS_errUNKNOWN 0x0e +#define DFU_STATUS_errSTALLEDPKT 0x0f + +enum dfu_state { + DFU_STATE_appIDLE = 0, + DFU_STATE_appDETACH = 1, + DFU_STATE_dfuIDLE = 2, + DFU_STATE_dfuDNLOAD_SYNC = 3, + DFU_STATE_dfuDNBUSY = 4, + DFU_STATE_dfuDNLOAD_IDLE = 5, + DFU_STATE_dfuMANIFEST_SYNC = 6, + DFU_STATE_dfuMANIFEST = 7, + DFU_STATE_dfuMANIFEST_WAIT_RST = 8, + DFU_STATE_dfuUPLOAD_IDLE = 9, + DFU_STATE_dfuERROR = 10, +}; + +#endif /* _USB_DFU_H */ diff --git a/openpicc/os/boot/Cstartup.S b/openpicc/os/boot/Cstartup.S new file mode 100644 index 0000000..83e7696 --- /dev/null +++ b/openpicc/os/boot/Cstartup.S @@ -0,0 +1,450 @@ +/* AT91SAM7 low-level startup outines for OpenPCD / OpenPICC DFU loader + * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/*------------------------------------------------------------------------------ +//*- ATMEL Microcontroller Software Support - ROUSSET - +//*------------------------------------------------------------------------------ +//* The software is delivered "AS IS" without warranty or condition of any +//* kind, either express, implied or statutory. This includes without +//* limitation any warranty or condition with respect to merchantability or +//* fitness for any particular purpose, or against the infringements of +//* intellectual property rights of others. +//*----------------------------------------------------------------------------- +//*- File source : Cstartup.s +//*- Object : Generic CStartup for KEIL and GCC No Use REMAP +//*- Compilation flag : None +//*- +//*- 1.0 18/Oct/04 JPP : Creation +//*- 1.1 21/Feb/05 JPP : Set Interrupt +//*- 1.1 01/Apr/05 JPP : save SPSR +//*-----------------------------------------------------------------------------*/ + +/* Enable DFU by press of hardware POI_BOOTLDR switch */ +#define CONFIG_DFU_SWITCH + +/* Enable DFU by magic value in RAM and software reset */ +#define CONFIG_DFU_MAGIC + +//#define DEBUG_LL + +#define PIOA_PER 0xFFFFF400 +#define PIOA_OER 0xFFFFF410 +#define PIOA_SODR 0xFFFFF430 +#define PIOA_CODR 0xFFFFF434 +#define LED1 25 /* this only works on OpenPICC, not Olimex */ + +#ifdef DEBUG_LL +/* Debugging macros for switching on/off LED1 (green) */ + .macro led1on + ldr r2, =PIOA_CODR + mov r1, #(1 << LED1) + str r1, [r2] + .endm + .macro led1off + ldr r2, =PIOA_SODR + mov r1, #(1 << LED1) + str r1, [r2] + .endm + .macro ledinit + ldr r2, =PIOA_PER + mov r1, #(1 << LED1) + str r1, [r2] + ldr r2, =PIOA_OER + str r1, [r2] + led1off + .endm +#else + .macro ledinit + .endm + .macro led1on + .endm + .macro led1off + .endm +#endif + + .equ IRQ_Stack_Size, 0x00000400 + .equ FIQ_Stack_Size, 0x00000400 + + .equ AIC_IVR, (256) + .equ AIC_FVR, (260) + .equ AIC_EOICR, (304) + .equ AIC_MCR_RCR, (0xf00) + .equ AT91C_BASE_AIC, (0xFFFFF000) + .equ AT91C_PMC_PCER, (0xFFFFFC10) + .equ AT91C_BASE_PIOA, (0xFFFFF400) + .equ AT91C_ID_PIOA, (2) + .equ PIOA_PDSR, (0x3c) +#if defined(PCD) + .equ PIO_BOOTLDR, (1 << 27) +#elif defined(PICC) + .equ PIO_BOOTLDR, (1 << 6) +#elif defined(OLIMEX) + .equ PIO_BOOTLDR, (1 << 19) +#else +#error please define PIO_BOOTLDR +#endif + + +/* #include "AT91SAM7S64_inc.h" */ + +/* Exception Vectors in RAM */ + + .text + .arm + .section .vectram, "ax" + + .global _remap_call_dfu + .func _remap_call_dfu +_remap_call_dfu: + led1on + /* Remap RAM to 0x00000000 for DFU */ + ldr r1, =AT91C_BASE_AIC + mov r2, #0x01 + str r2, [r1, #AIC_MCR_RCR] + + ldr r4, =dfu_main + bx r4 + + .size _remap_call_dfu, . - _remap_call_dfu + .endfunc + + +#;------------------------------------------------------------------------------ +#;- Section Definition +#;----------------- +#;- Section +#;- .internal_ram_top Top_Stack: used by the cstartup for vector initalisation +#;- management defined by ld and affect from ldscript +#;------------------------------------------------------------------------------ + .section .internal_ram_top + .code 32 + .align 0 + .global Top_Stack +Top_Stack: + +/*------------------------------------------------------------------------------ +*- Area Definition +*------------------------------------------------------------------------------ +* .text is used instead of .section .text so it works with arm-aout too. */ + .section .reset + .text +reset: +/*------------------------------------------------------------------------------ +//*- Exception vectors +//*-------------------- +//*- These vectors can be read at address 0 or at RAM address +//*- They ABSOLUTELY requires to be in relative addresssing mode in order to +//*- guarantee a valid jump. For the moment, all are just looping. +//*- If an exception occurs before remap, this would result in an infinite loop. +//*- To ensure if a exeption occurs before start application to infinite loop. +//*------------------------------------------------------------------------------*/ + + B InitReset /* 0x00 Reset handler */ +undefvec: + B undefvec /* 0x04 Undefined Instruction */ +swivec: + B swivec /* 0x08 Software Interrupt */ +pabtvec: + B pabtvec /* 0x0C Prefetch Abort */ +dabtvec: + b dabtvec /* 0x10 Data Abort */ +rsvdvec: + b rsvdvec /* 0x14 reserved */ +irqvec: + b IRQ_Handler_Entry /* 0x18 IRQ */ +fiqvec: + ldr pc, [pc, #-0xF20] /* 0x1c FIQ */ + +dfu_state_dummy: + .word 0 + + .global IRQ_Handler_Entry + .func IRQ_Handler_Entry + +FIQ_Handler_Entry: + +/*- Switch in SVC/User Mode to allow User Stack access for C code */ +/* because the FIQ is not yet acknowledged*/ + +/*- Save and r0 in FIQ_Register */ + mov r9, r0 + ldr r0, [r8, #AIC_FVR] + msr CPSR_c, #I_BIT | F_BIT | ARM_MODE_SVC + + /*- Save scratch/used registers and LR in User Stack */ + stmfd sp!, { r1-r3, r12, lr} + + /*- Branch to the routine pointed by the AIC_FVR */ + mov r14, pc + bx r0 + + /*- Restore scratch/used registers and LR from User Stack */ + ldmia sp!, { r1-r3, r12, lr} + + /*- Leave Interrupts disabled and switch back in FIQ mode */ + msr CPSR_c, #I_BIT | F_BIT | ARM_MODE_FIQ + + /*- Restore the R0 ARM_MODE_SVC register */ + mov r0,r9 + + /*- Restore the Program Counter using the LR_fiq directly in the PC */ + subs pc, lr, #4 + +IRQ_Handler_Entry: + + /*- Manage Exception Entry */ + /*- Adjust and save LR_irq in IRQ stack */ + sub lr, lr, #4 + stmfd sp!, {lr} + + /*- Save SPSR need to be saved for nested interrupt */ + mrs r14, SPSR + stmfd sp!, {r14} + + /*- Save and r0 in IRQ stack */ + stmfd sp!, {r0} + + /*- Write in the IVR to support Protect Mode */ + /*- No effect in Normal Mode */ + /*- De-assert the NIRQ and clear the source in Protect Mode */ + ldr r14, =AT91C_BASE_AIC + ldr r0 , [r14, #AIC_IVR] + str r14, [r14, #AIC_IVR] + + /*- Enable Interrupt and Switch in Supervisor Mode */ + msr CPSR_c, #ARM_MODE_SVC + + /*- Save scratch/used registers and LR in User Stack */ + stmfd sp!, { r1-r3, r12, r14} + + /*- Branch to the routine pointed by the AIC_IVR */ + mov r14, pc + bx r0 + + /*- Restore scratch/used registers and LR from User Stack*/ + ldmia sp!, { r1-r3, r12, r14} + + /*- Disable Interrupt and switch back in IRQ mode */ + msr CPSR_c, #I_BIT | ARM_MODE_IRQ + + /*- Mark the End of Interrupt on the AIC */ + ldr r14, =AT91C_BASE_AIC + str r14, [r14, #AIC_EOICR] + + /*- Restore SPSR_irq and r0 from IRQ stack */ + ldmia sp!, {r0} + + /*- Restore SPSR_irq and r0 from IRQ stack */ + ldmia sp!, {r14} + msr SPSR_cxsf, r14 + + /*- Restore adjusted LR_irq from IRQ stack directly in the PC */ + ldmia sp!, {pc}^ + + .size IRQ_Handler_Entry, . - IRQ_Handler_Entry + .endfunc + .align 0 +.RAM_TOP: + .word Top_Stack + + .global _startup + .func _startup +InitReset: +/*------------------------------------------------------------------------------ +/*- Low level Init (PMC, AIC, ? ....) by C function AT91F_LowLevelInit +/*------------------------------------------------------------------------------*/ + .extern AT91F_LowLevelInit +/*- minumum C initialization */ +/*- call AT91F_LowLevelInit( void) */ + + ldr r13,.RAM_TOP /* temporary stack in internal RAM */ +/*--Call Low level init function in ABSOLUTE through the Interworking */ + ldr r0,=AT91F_LowLevelInit + mov lr, pc + bx r0 + ledinit + +/*------------------------------------------------------------------------------ +//*- Top of Stack Definition +//*------------------------- +//*- Interrupt and Supervisor Stack are located at the top of internal memory in +//*- order to speed the exception handling context saving and restoring. +//*- ARM_MODE_SVC (Application, C) Stack is located at the top of the external memory. +//*------------------------------------------------------------------------------*/ + + .EQU ARM_MODE_FIQ, 0x11 + .EQU ARM_MODE_IRQ, 0x12 + .EQU ARM_MODE_SVC, 0x13 + + .EQU I_BIT, 0x80 + .EQU F_BIT, 0x40 + + +#define AT91C_RSTC_RSR 0xFFFFFD04 +#define AT91C_RSTC_RSTTYP_SOFTWARE (0x03 << 8) +#define DFU_STATE_appDETACH 1 + + +/*------------------------------------------------------------------------------ +//*- Setup the stack for each mode +//*-------------------------------*/ + mov r0,r13 + +/*- Set up Fast Interrupt Mode and set FIQ Mode Stack*/ + msr CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT + mov r13, r0 + sub r0, r0, #FIQ_Stack_Size + +/*- Init the FIQ register*/ + ldr r8, =AT91C_BASE_AIC + +/*- Set up Interrupt Mode and set IRQ Mode Stack*/ + msr CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT + mov r13, r0 /* Init stack IRQ */ + sub r0, r0, #IRQ_Stack_Size + +/*- Set up Supervisor Mode and set Supervisor Mode Stack*/ + msr CPSR_c, #ARM_MODE_SVC | I_BIT | F_BIT + mov r13, r0 /* Init stack Sup */ + +/* - Enable Interrupts and FIQ */ + msr CPSR_c, #ARM_MODE_SVC + +#ifdef CONFIG_DFU_MAGIC + ldr r1, =AT91C_RSTC_RSR + ldr r2, [r1] + #and r2, r2, AT91C_RSTC_RSTTYP + tst r2, #AT91C_RSTC_RSTTYP_SOFTWARE + beq dfu_magic_end + + ldr r1, =dfu_state + ldr r2, [r1] + cmp r2, #DFU_STATE_appDETACH + beq _reloc_dfu +dfu_magic_end: +#endif + +# Relocate DFU .data.shared section (Copy from ROM to RAM) + LDR R1, =_etext + LDR R2, =_data_shared + LDR R3, =_edata_shared +LoopRelDS: CMP R2, R3 + LDRLO R0, [R1], #4 + STRLO R0, [R2], #4 + BLO LoopRelDS + +/* +# Clear DFU .bss section (Zero init) + MOV R0, #0 + LDR R1, =__bss_start__ + LDR R2, =__bss_end__ +LoopZI: CMP R1, R2 + STRLO R0, [R1], #4 + BLO LoopZI +*/ + + /* prepare c function call to main */ + mov r0, #0 /* argc = 0 */ + ldr lr, =exit + ldr r10, =0x00104000 + +#ifdef CONFIG_DFU_SWITCH + /* check whether bootloader button is pressed */ + ldr r1, =AT91C_PMC_PCER + mov r2, #(1 << AT91C_ID_PIOA) + str r2, [r1] + + ldr r1, =AT91C_BASE_PIOA + ldr r2, [r1, #PIOA_PDSR] + tst r2, #PIO_BOOTLDR + bne _reloc_dfu +#endif + + bx r10 + +_reloc_dfu: + /* Relocate DFU .data section (Copy from ROM to RAM) */ + LDR R1, =_data_flash + LDR R2, =_data + LDR R3, =_edata +LoopRel: CMP R2, R3 + LDRLO R0, [R1], #4 + STRLO R0, [R2], #4 + BLO LoopRel + + /* Clear DFU .bss section (Zero init) */ + MOV R0, #0 + LDR R1, =__bss_start__ + LDR R2, =__bss_end__ +LoopZI: CMP R1, R2 + STRLO R0, [R1], #4 + BLO LoopZI + + /* relocate DFU .text into RAM */ + ldr r1, =0x00100000 + ldr r2, =0x00200000 + ldr r3, =_etext + add r3, r3, r2 +loop_rel_t: cmp r2, r3 + ldrlo r4, [r1], #4 + strlo r4, [r2], #4 + blo loop_rel_t + ldr r4, =_remap_call_dfu + bx r4 + + .size _startup, . - _startup + .endfunc + +/* "exit" dummy to avoid sbrk write read etc. needed by the newlib default "exit" */ + .global exit + .func exit +exit: + b . + .size exit, . - exit + .endfunc + +/*--------------------------------------------------------------- +//* ?EXEPTION_VECTOR +//* This module is only linked if needed for closing files. +//*---------------------------------------------------------------*/ + .global AT91F_Default_FIQ_handler + .func AT91F_Default_FIQ_handler +AT91F_Default_FIQ_handler: + b AT91F_Default_FIQ_handler + .size AT91F_Default_FIQ_handler, . - AT91F_Default_FIQ_handler + .endfunc + + .global AT91F_Default_IRQ_handler + .func AT91F_Default_IRQ_handler +AT91F_Default_IRQ_handler: + b AT91F_Default_IRQ_handler + .size AT91F_Default_IRQ_handler, . - AT91F_Default_IRQ_handler + .endfunc + + .global AT91F_Spurious_handler + .func AT91F_Spurious_handler +AT91F_Spurious_handler: + b AT91F_Spurious_handler + .size AT91F_Spurious_handler, . - AT91F_Spurious_handler + .endfunc + + + + .end + diff --git a/openpicc/os/boot/Cstartup_SAM7.c b/openpicc/os/boot/Cstartup_SAM7.c index 450a95e..4ab263f 100644 --- a/openpicc/os/boot/Cstartup_SAM7.c +++ b/openpicc/os/boot/Cstartup_SAM7.c @@ -8,60 +8,83 @@ //* intellectual property rights of others. //*---------------------------------------------------------------------------- //* File Name : Cstartup_SAM7.c -//* Object : Low level initializations written in C for IAR -//* tools -//* 1.0 08/Sep/04 JPP : Creation -//* 1.10 10/Sep/04 JPP : Update AT91C_CKGR_PLLCOUNT filed +//* Object : Low level initializations written in C for GCC Tools +//* Creation : 12/Jun/04 +//* 1.2 28/Feb/05 JPP : LIB change AT91C_WDTC_WDDIS & PLL +//* 1.3 21/Mar/05 JPP : Change PLL Wait time //*---------------------------------------------------------------------------- - // Include the board file description #include <board.h> +// The following functions must be write in ARM mode this function called directly +// by exception vector +extern void AT91F_Spurious_handler (void); +extern void AT91F_Default_IRQ_handler (void); +extern void AT91F_Default_FIQ_handler (void); + //*---------------------------------------------------------------------------- //* \fn AT91F_LowLevelInit //* \brief This function performs very low level HW initialization //* this function can be use a Stack, depending the compilation //* optimization mode //*---------------------------------------------------------------------------- -void AT91F_LowLevelInit (void) +void +AT91F_LowLevelInit (void) { - AT91PS_PMC pPMC = AT91C_BASE_PMC; - - //* Set flash wait state - // Single Cycle Access at Up to 30 MHz, or 40 - // if MCK = 47923200 I have 50 Cycle for 1 useconde ( flied MC_FMR->FMCN - AT91C_BASE_MC->MC_FMR = ((AT91C_MC_FMCN) & (75 << 16)) | AT91C_MC_FWS_1FWS; + volatile int i; + + //* Debounce power supply + for(i=0;i<1024;i++); + + AT91PS_PMC pPMC = AT91C_BASE_PMC; + //* Set Flash Waite sate + // Single Cycle Access at Up to 30 MHz, or 40 + // if MCK = 47923200 I have 50 Cycle for 1 usecond ( flied MC_FMR->FMCN + AT91C_BASE_MC->MC_FMR = ((AT91C_MC_FMCN) & (48 << 16)) | AT91C_MC_FWS_1FWS; - //* Watchdog Enable - AT91C_BASE_WDTC->WDTC_WDMR = (0x80 << 16) | AT91C_WDTC_WDRSTEN | 0x80; + //* Set MCK at 47 923 200 + // 1 Enabling the Main Oscillator: + // SCK = 1/32768 = 30.51 uSecond + // Start up time = 8 * 6 / SCK = 56 * 30.51 = 1,46484375 ms + pPMC->PMC_MOR = ((AT91C_CKGR_OSCOUNT) & (0x06 << 8)) | AT91C_CKGR_MOSCEN; + // Wait the startup time + while (!(pPMC->PMC_SR & AT91C_PMC_MOSCS)); + // 2 Checking the Main Oscillator Frequency (Optional) + // 3 Setting PLL and divider: + // - div by 24 Fin = 0,7680 =(18,432 / 24) + // - Mul 125: Fout = 96,0000 =(0,7680 *125) + // for 96 MHz the erroe is 0.16% + // Field out NOT USED = 0 + // PLLCOUNT pll startup time estimate at : 0.844 ms + // PLLCOUNT 28 = 0.000844 /(1/32768) +#if 0 + pPMC->PMC_PLLR = ((AT91C_CKGR_DIV & 0x05) | + (AT91C_CKGR_PLLCOUNT & (28 << 8)) | + (AT91C_CKGR_MUL & (25 << 16))); +#else + pPMC->PMC_PLLR = ((AT91C_CKGR_DIV & 24) | + (AT91C_CKGR_PLLCOUNT & (28 << 8)) | + (AT91C_CKGR_MUL & (125 << 16))); +#endif - //* Set MCK at 47 923 200 - // 1 Enabling the Main Oscillator: - // SCK = 1/32768 = 30.51 uSeconde - // Start up time = 8 * 6 / SCK = 56 * 30.51 = 1,46484375 ms - pPMC->PMC_MOR = (((AT91C_CKGR_OSCOUNT & (0x06 << 8)) | AT91C_CKGR_MOSCEN)); - // Wait the startup time + // Wait the startup time + while (!(pPMC->PMC_SR & AT91C_PMC_LOCK)); + while (!(pPMC->PMC_SR & AT91C_PMC_MCKRDY)); + // 4. Selection of Master Clock and Processor Clock + // select the PLL clock divided by 2 + pPMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2; + while (!(pPMC->PMC_SR & AT91C_PMC_MCKRDY)); - while (!(pPMC->PMC_SR & AT91C_PMC_MOSCS)); - // 2 Checking the Main Oscillator Frequency (Optional) - // 3 Setting PLL and divider: - // - div by 5 Fin = 3,6864 =(18,432 / 5) - // - Mul 25+1: Fout = 95,8464 =(3,6864 *26) - // for 96 MHz the erroe is 0.16% - //eld out NOT USED = 0 Fi - pPMC->PMC_PLLR = ((AT91C_CKGR_DIV & 5) | - (AT91C_CKGR_PLLCOUNT & (28 << 8)) | - (AT91C_CKGR_MUL & (25 << 16))); + pPMC->PMC_MCKR |= AT91C_PMC_CSS_PLL_CLK; + while (!(pPMC->PMC_SR & AT91C_PMC_MCKRDY)); - // Wait the startup time - while (!(pPMC->PMC_SR & AT91C_PMC_LOCK)); - - // 4. Selection of Master Clock and Processor Clock - // select the PLL clock divided by 2 - pPMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2; - while (!(pPMC->PMC_SR & AT91C_PMC_MCKRDY)); + // Set up the default interrupts handler vectors + AT91C_BASE_AIC->AIC_SVR[0] = (int) AT91F_Default_FIQ_handler; + for (i = 1; i < 31; i++) + { + AT91C_BASE_AIC->AIC_SVR[i] = (int) AT91F_Default_IRQ_handler; + } + AT91C_BASE_AIC->AIC_SPU = (int) AT91F_Spurious_handler; - pPMC->PMC_MCKR |= AT91C_PMC_CSS_PLL_CLK; - while (!(pPMC->PMC_SR & AT91C_PMC_MCKRDY)); } diff --git a/openpicc/os/boot/Cstartup_app.S b/openpicc/os/boot/Cstartup_app.S new file mode 100644 index 0000000..448cc93 --- /dev/null +++ b/openpicc/os/boot/Cstartup_app.S @@ -0,0 +1,194 @@ +/* Cstartup header for the application to be started by at91dfu + * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + +//#define DEBUG_LL + + .equ AIC_FVR, (260) + .equ AIC_EOICR, (304) + .equ AT91C_BASE_AIC, (0xFFFFF000) + .equ ARM_MODE_FIQ, 0x11 + .equ ARM_MODE_IRQ, 0x12 + .equ ARM_MODE_SVC, 0x13 + + .equ I_BIT, 0x80 + .equ F_BIT, 0x40 + + +#define AT91C_BASE_PIOA 0xFFFFF400 +#define AT91C_BASE_TC0 0xFFFA0000 +#define AT91C_TC_SWTRG (1 << 2) +#define PIOA_SODR 0x30 +#define PIOA_CODR 0x34 +#define PIOA_PDSR 0x3c +#define PIOA_ISR 0x4c +#define PIOA_IDR 0x44 +#define PIO_DATA (1 << 27) +#define TC_CCR 0x00 + + +#define PIO_LED1 (1 << 25) /* this only works on OpenPICC, not Olimex */ + +#ifdef DEBUG_LL +/* Debugging macros for switching on/off LED1 (green) */ +#define PIOA_PER 0xFFFFF400 +#define PIOA_OER 0xFFFFF410 + .macro led1on + ldr r2, =AT91C_BASE_PIOA + mov r1, #PIO_LED1 + str r1, [r2, #PIOA_CODR] + .endm + .macro led1off + ldr r2, =AT91C_BASE_PIOA + mov r1, #PIO_LED1 + str r1, [r2, #PIOA_SODR] + .endm + .macro ledinit + ldr r2, =PIOA_PER + mov r1, #PIO_LED1 + str r1, [r2] + ldr r2, =PIOA_OER + str r1, [r2] + led1off + .endm +#else + .macro ledinit + .endm + .macro led1on + .endm + .macro led1off + .endm +#endif + + .global _startup + .func _startup +_startup: + /* Relocate .data section (copy from Flash to RAM) */ + ldr r1, =_etext + ldr r2, =_data + ldr r3, =_edata +loop_r: cmp r2, r3 + ldrlo r0, [r1], #4 + strlo r0, [r2], #4 + blo loop_r + + /* Clear .bss section (Zero init) */ + mov r0, #0 + ldr r1, =__bss_start__ + ldr r2, =__bss_end__ +loop_z: cmp r1, r2 + strlo r0, [r1], #4 + blo loop_z + + /* initialize FIQ mode registers */ + msr CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT + ldr r10, =AT91C_BASE_PIOA + ldr r12, =AT91C_BASE_TC0 + mov r9, #AT91C_TC_SWTRG + msr CPSR_c, #ARM_MODE_SVC + + led1on + + /* prepare C function call to main */ + mov r0, #0 /* argc = 0 */ + ldr lr, =exit + ldr r10, =main + + bx r10 + + .size _startup, . - _startup + .endfunc + +/* "exit" dummy to avoid sbrk write read etc. needed by the newlib default "exit" */ + .global exit + .func exit +exit: + b . + .size exit, . - exit + .endfunc + + +#define LED_TRIGGER +#define CALL_PIO_IRQ_DEMUX + + .text + .arm + .section .fastrun, "ax" + + .global fiq_handler + .func fiq_handler +fiq_handler: + /* code that uses pre-initialized FIQ reg */ + /* r8 AT91C_BASE_AIC (dfu init) + r9 AT91C_TC_SWTRG + r10 AT91C_BASE_PIOA + r11 tmp + r12 AT91C_BASE_TC0 + r13 stack + r14 lr + */ + + ldr r8, [r10, #PIOA_ISR] + tst r8, #PIO_DATA /* check for PIO_DATA change */ + ldrne r11, [r10, #PIOA_PDSR] + tstne r11, #PIO_DATA /* check for PIO_DATA == 1 */ + strne r9, [r12, #TC_CCR] /* software trigger */ +#ifdef LED_TRIGGER + movne r11, #PIO_LED1 + strne r11, [r10, #PIOA_CODR] /* enable LED */ +#endif + +#if 1 + movne r11, #PIO_DATA + strne r11, [r10, #PIOA_IDR] /* disable further PIO_DATA FIQ */ +#endif + + /*- Mark the End of Interrupt on the AIC */ + ldr r11, =AT91C_BASE_AIC + str r11, [r11, #AIC_EOICR] + +#ifdef LED_TRIGGER + mov r11, #PIO_LED1 + str r11, [r10, #PIOA_SODR] /* disable LED */ +#endif + +#ifdef CALL_PIO_IRQ_DEMUX + /* push r0, r1-r3, r12, r14 onto FIQ stack */ + stmfd sp!, { r0-r3, r12, lr} + mov r0, r8 + + /* enable interrupts while handling demux */ + /* msr CPSR_c, #F_BIT | ARM_MODE_SVC */ + + /* Call C function, give PIOA_ISR as argument */ + ldr r11, =__pio_irq_demux + mov r14, pc + bx r11 + + /* msr CPSR_c, #I_BIT | F_BIT | ARM_MODE_FIQ */ + ldmia sp!, { r0-r3, r12, lr } +#endif + + /*- Restore the Program Counter using the LR_fiq directly in the PC */ + subs pc, lr, #4 + + .size fiq_handler, . - fiq_handler + .endfunc + .end + |