summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/Makefile3
-rw-r--r--firmware/Makefile.dfu10
-rwxr-xr-xfirmware/scripts/mkcompile_h24
-rw-r--r--firmware/src/dfu/dfu.c118
-rw-r--r--firmware/src/dfu/dfu.h15
-rw-r--r--firmware/src/dfu/flash.c10
6 files changed, 145 insertions, 35 deletions
diff --git a/firmware/Makefile b/firmware/Makefile
index a916ae6..b5044e4 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -563,6 +563,9 @@ clean_list :
$(REMOVE) $(CPPSRCARM:.cpp=.d)
$(REMOVE) .dep/*
+.PHONY: include/compile.h
+include/compile.h:
+ scripts/mkcompile_h > $@
# Include the dependency files.
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
diff --git a/firmware/Makefile.dfu b/firmware/Makefile.dfu
index 5fcb4d3..c8e9781 100644
--- a/firmware/Makefile.dfu
+++ b/firmware/Makefile.dfu
@@ -76,7 +76,7 @@ SRC =
# List C source files here which must be compiled in ARM-Mode.
# use file-extension c for "c-only"-files
-SRCARM = src/start/Cstartup_SAM7.c src/dfu/dfu.c
+SRCARM = src/start/Cstartup_SAM7.c src/dfu/dfu.c src/dfu/dbgu.c
# List C++ source files here.
# use file-extension cpp for C++-files (use extension .cpp)
@@ -99,6 +99,11 @@ ASRC =
# List Assembler source files here which must be assembled in ARM-Mode..
ASRCARM = src/start/Cstartup.S
+ifeq ($(DEBUG),1)
+SRCARM += lib/lib_AT91SAM7.c 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
@@ -526,6 +531,9 @@ clean_list :
$(REMOVE) $(CPPSRCARM:.cpp=.d)
$(REMOVE) .dep/*
+.PHONY: include/compile.h
+include/compile.h:
+ scripts/mkcompile_h > $@
# Include the dependency files.
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
diff --git a/firmware/scripts/mkcompile_h b/firmware/scripts/mkcompile_h
new file mode 100755
index 0000000..22ac262
--- /dev/null
+++ b/firmware/scripts/mkcompile_h
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+MAX_LEN=32
+TRUNCATE="sed -e s/\(.\{1,$MAX_LEN\}\).*/\1/"
+
+DATE=`LC_ALL=C LANG=C date +%Y%m%d-%H%M%S`
+BY=`whoami`
+HOST=`hostname | $TRUNCATE`
+BYHOST=`echo ${BY}@${HOST} | $TRUNCATE`
+SVNREV=`svn info | grep \^Revision: | cut -c 11-`
+
+svn st | grep \^M >/dev/null
+
+[ "$?" -eq "0" ] && SVNREV=${SVNREV}-unclean
+
+echo "#ifndef _COMPILE_H"
+echo "#define _COMPILE_H"
+echo
+echo /\* This file is auto generated \*/
+echo \#define COMPILE_DATE \"${DATE}\"
+echo \#define COMPILE_BY \"${BYHOST}\"
+echo \#define COMPILE_SVNREV \"${SVNREV}\"
+echo
+echo "#endif /* _COMPILE_H */"
diff --git a/firmware/src/dfu/dfu.c b/firmware/src/dfu/dfu.c
index 763aa04..09c8784 100644
--- a/firmware/src/dfu/dfu.c
+++ b/firmware/src/dfu/dfu.c
@@ -23,24 +23,29 @@
#include <errno.h>
#include <usb_ch9.h>
#include <usb_dfu.h>
+#include <board.h>
#include <lib_AT91SAM7.h>
#include <dfu/dfu.h>
+#include <dfu/dbgu.h>
#include <os/pcd_enumerate.h>
#include "../openpcd.h"
/* If debug is enabled, we need to access debug functions from flash
* and therefore have to omit flashing */
-//#define DEBUG_DFU
+#define DEBUG_DFU
-#ifdef DEBUG_DFU
#define DEBUGE DEBUGP
-#define DEBUGI DEBUGP
-#else
-#define DEBUGE(x, args ...) do { } while (0)
-#define DEBUGI(x, args ...) do { } while (0)
-#endif
+static void flash_init(void)
+{
+ unsigned int fmcn = AT91F_MC_EFC_ComputeFMCN(MCK);
+
+ AT91F_MC_EFC_CfgModeReg(AT91C_BASE_MC, fmcn << 16 | AT91C_MC_FWS_3FWS |
+ AT91C_MC_FRDY | AT91C_MC_LOCKE |
+ AT91C_MC_PROGE);
+
+}
static void __dfufunc udp_init(void)
{
@@ -97,6 +102,32 @@ static void __dfufunc udp_ep0_send_data(const char *pData, u_int32_t length)
}
}
+/* receive data from EP0 */
+static int __dfufunc udp_ep0_recv_data(char *data, u_int32_t len)
+{
+ AT91PS_UDP pUdp = AT91C_BASE_UDP;
+ 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? */
+ while (!(pUdp->UDP_CSR[0] & AT91C_UDP_RX_DATA_BK0)) ;
+
+ num_rcv = pUdp->UDP_CSR[0] >> 16;
+ 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);
+
+ return num_rcv_total;
+}
+
/* Send zero length packet through the control endpoint */
static void __dfufunc udp_ep0_send_zlp(void)
{
@@ -119,12 +150,31 @@ static void __dfufunc udp_ep0_send_stall(void)
static u_int8_t status;
-static u_int8_t *ptr;
+static u_int8_t *ptr = (u_int8_t *)0x00101000;
static __dfudata u_int32_t dfu_state;
+static u_int8_t pagebuf[AT91C_IFLASH_PAGE_SIZE];
+
+static u_int16_t page_from_ramaddr(const void *addr)
+{
+ u_int32_t ramaddr = (u_int32_t) ptr;
+ 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 int __dfufunc handle_dnload(u_int16_t val, u_int16_t len)
{
volatile u_int32_t *p = (volatile u_int32_t *)ptr;
+ u_int16_t page = page_from_ramaddr(ptr);
DEBUGE("download ");
@@ -136,6 +186,7 @@ static int __dfufunc handle_dnload(u_int16_t val, u_int16_t len)
return -EINVAL;
}
if (len & 0x3) {
+ /* reject non-four-byte-aligned writes */
dfu_state = DFU_STATE_dfuERROR;
status = DFU_STATUS_errADDRESS;
udp_ep0_send_stall();
@@ -145,14 +196,27 @@ static int __dfufunc handle_dnload(u_int16_t val, u_int16_t len)
dfu_state = DFU_STATE_dfuMANIFEST_SYNC;
return 0;
}
+
+ udp_ep0_recv_data(pagebuf, sizeof(pagebuf));
+
+ DEBUGP(hexdump(pagebuf, len));
+
+ /* we can only access the write buffer with correctly aligned
+ * 32bit writes ! */
#if 0
for (i = 0; i < len/4; i++)
p[i] =
#endif
- /* FIXME: get data packet from FIFO, (erase+)write flash */
+
+ /* unlock, (erase+)write flash */
#ifndef DEBUG_DFU
+ if (is_page_locked(page))
+ AT91F_MC_EFC_PerformCmd(AT91C_BASE_MC, AT91C_MC_FCMD_UNLOCK |
+ AT91C_MC_CORRECT_KEY | page);
+ AT91F_MC_EFC_PerformCmd(AT91C_BASE_MC, AT91C_MC_FCMD_START_PROG |
+ AT91C_MC_CORRECT_KEY | page);
#endif
return 0;
@@ -182,13 +246,34 @@ static __dfufunc int handle_upload(u_int16_t val, u_int16_t len)
static __dfufunc void handle_getstatus(void)
{
struct dfu_status dstat;
+ u_int32_t fsr = AT91F_MC_EFC_GetStatus(AT91C_BASE_MC);
DEBUGE("getstatus ");
+ switch (dfu_state) {
+ case DFU_STATE_dfuDNLOAD_SYNC:
+ case DFU_STATE_dfuDNBUSY:
+ if (fsr & AT91C_MC_PROGE) {
+ status = DFU_STATUS_errPROG;
+ dfu_state = DFU_STATE_dfuERROR;
+ } else if (fsr & AT91C_MC_LOCKE) {
+ status = DFU_STATUS_errWRITE;
+ dfu_state = DFU_STATE_dfuERROR;
+ } else if (fsr & AT91C_MC_FRDY)
+ dfu_state = DFU_STATE_dfuDNLOAD_IDLE;
+ else
+ dfu_state = DFU_STATE_dfuDNBUSY;
+ break;
+ case DFU_STATE_dfuMANIFEST_SYNC:
+ dfu_state = DFU_STATE_dfuMANIFEST;
+ break;
+ }
+
/* send status response */
dstat.bStatus = status;
dstat.bState = dfu_state;
dstat.iString = 0;
+
udp_ep0_send_data((char *)&dstat, sizeof(dstat));
}
@@ -196,6 +281,7 @@ static void __dfufunc handle_getstate(void)
{
u_int8_t u8 = dfu_state;
DEBUGE("getstate ");
+
udp_ep0_send_data((char *)&u8, sizeof(u8));
}
@@ -237,6 +323,7 @@ int __dfufunc dfu_ep0_handler(u_int8_t req_type, u_int8_t req,
goto send_stall;
}
handle_dnload(val, len);
+ dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
break;
case USB_REQ_DFU_UPLOAD:
ptr = 0x00101000; /* Flash base address for app */
@@ -280,8 +367,7 @@ int __dfufunc dfu_ep0_handler(u_int8_t req_type, u_int8_t req,
case DFU_STATE_dfuDNLOAD_IDLE:
switch (req) {
case USB_REQ_DFU_DNLOAD:
- if (handle_dnload(val, len))
- /* FIXME: state transition */
+ handle_dnload(val, len);
break;
case USB_REQ_DFU_ABORT:
dfu_state = DFU_STATE_dfuIDLE;
@@ -302,6 +388,7 @@ int __dfufunc dfu_ep0_handler(u_int8_t req_type, u_int8_t req,
case DFU_STATE_dfuMANIFEST_SYNC:
switch (req) {
case USB_REQ_DFU_GETSTATUS:
+ handle_getstatus();
break;
case USB_REQ_DFU_GETSTATE:
handle_getstate();
@@ -516,6 +603,11 @@ static __dfufunc void dfu_udp_ep0_handler(void)
MIN(sizeof(dfu_if_descriptor),
wLength));
#endif
+ } else if (wValue == 0x2100) {
+ /* Return Function descriptor */
+ udp_ep0_send_data((const char *) &dfu_cfg_descriptor.func_dfu,
+ MIN(sizeof(dfu_cfg_descriptor.func_dfu),
+ wLength));
} else
udp_ep0_send_stall();
break;
@@ -654,6 +746,8 @@ static void dfu_switch(void)
void __dfufunc dfu_main(void)
{
+ AT91F_DBGU_Init();
+
udp_init();
/* This implements
@@ -675,6 +769,8 @@ void __dfufunc dfu_main(void)
/* Clear for set the Pull up resistor */
AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP);
+ flash_init();
+
/* do nothing, since all of DFU is interrupt driven */
while (1) ;
}
diff --git a/firmware/src/dfu/dfu.h b/firmware/src/dfu/dfu.h
index 4b7508f..e587fe4 100644
--- a/firmware/src/dfu/dfu.h
+++ b/firmware/src/dfu/dfu.h
@@ -54,19 +54,8 @@
#define __dfudata __attribute__ ((section (".data.shared")))
#define __dfufunc
#define __dfustruct const
-
-#if 0
-extern void __dfufunc udp_ep0_send_data(const char *data, u_int32_t length);
-extern void __dfufunc udp_ep0_send_zlp(void);
-extern void __dfufunc udp_ep0_send_stall(void);
-extern __dfustruct struct usb_device_descriptor dfu_dev_descriptor;
-extern __dfustruct struct _dfu_desc dfu_cfg_descriptor;
-extern void dfu_switch(void);
-extern int __dfufunc dfu_ep0_handler(u_int8_t req_type, u_int8_t req,
- u_int16_t val, u_int16_t len);
-extern static u_int8_t dfu_state;
-struct udp_pcd;
-#endif
+
+#define DFU_API_LOCATION ((const struct dfuapi *) 0x00100fd0)
struct _dfu_desc {
struct usb_config_descriptor ucfg;
diff --git a/firmware/src/dfu/flash.c b/firmware/src/dfu/flash.c
index 2aaf760..675552d 100644
--- a/firmware/src/dfu/flash.c
+++ b/firmware/src/dfu/flash.c
@@ -32,14 +32,4 @@ int flash_sector(unsigned int sector, const u_int8_t *data, unsigned int len)
}
-void flash_init(void)
-{
- unsigned int fmcn = AT91F_MC_EFC_ComputerFMCN(48000000);
-
- AT91F_MC_EFC_CfgModeReg(ff, fmcn << 16 | AT91C_MC_FWS_3FWS |
- AT91C_MC_FRDY | AT91C_MC_LOCKE |
- AT91C_MC_PROGE);
- AT91F_AIC_EnableIt();
-
-}
personal git repositories of Harald Welte. Your mileage may vary