aboutsummaryrefslogtreecommitdiffstats
path: root/firmware
diff options
context:
space:
mode:
authorlaforge <laforge@6dc7ffe9-61d6-0310-9af1-9938baff3ed1>2006-09-20 12:08:36 +0000
committerlaforge <laforge@6dc7ffe9-61d6-0310-9af1-9938baff3ed1>2006-09-20 12:08:36 +0000
commit26bc6a68838f33a5436bf305c352c3b1c4ad893c (patch)
tree2fbc01ef66f1702deade5cd95611134f705d6962 /firmware
parenteecad3322a0f5822378d7d9644879c9fe41f35d9 (diff)
- add support for flashing to DFU
git-svn-id: https://svn.openpcd.org:2342/trunk@210 6dc7ffe9-61d6-0310-9af1-9938baff3ed1
Diffstat (limited to 'firmware')
-rw-r--r--firmware/Makefile.dfu3
-rw-r--r--firmware/src/dfu/dfu.c66
-rw-r--r--firmware/src/dfu/dfu.h2
-rw-r--r--firmware/src/dfu/flash.c42
4 files changed, 59 insertions, 54 deletions
diff --git a/firmware/Makefile.dfu b/firmware/Makefile.dfu
index e5daeac..10c3616 100644
--- a/firmware/Makefile.dfu
+++ b/firmware/Makefile.dfu
@@ -76,7 +76,8 @@ 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 src/dfu/dbgu.c
+SRCARM = src/start/Cstartup_SAM7.c \
+ src/dfu/dfu.c src/dfu/dbgu.c src/dfu/flash.c
# List C++ source files here.
# use file-extension cpp for C++-files (use extension .cpp)
diff --git a/firmware/src/dfu/dfu.c b/firmware/src/dfu/dfu.c
index c5f706e..4e39f59 100644
--- a/firmware/src/dfu/dfu.c
+++ b/firmware/src/dfu/dfu.c
@@ -28,6 +28,7 @@
#include <dfu/dfu.h>
#include <dfu/dbgu.h>
+#include <dfu/flash.h>
#include <os/pcd_enumerate.h>
#include "../openpcd.h"
@@ -108,15 +109,25 @@ static void __dfufunc udp_ep0_send_data(const char *pData, u_int32_t length)
static int __dfufunc udp_ep0_recv_data(char *data, u_int32_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? */
- while (!(pUdp->UDP_CSR[0] & AT91C_UDP_RX_DATA_BK0)) ;
+ do {
+ csr = pUdp->UDP_CSR[0];
+ DEBUGE("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;
+
+ DEBUGE("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);
@@ -125,7 +136,9 @@ static int __dfufunc udp_ep0_recv_data(char *data, u_int32_t len)
/* we need to continue to pull data until we either receive
* a packet < endpoint size or == 0 */
- } while (num_rcv == 8);
+ } while (num_rcv == 8 && num_rcv_total < len);
+
+ DEBUGE("ep0_rcv_returning(%u total) ", num_rcv_total);
return num_rcv_total;
}
@@ -152,31 +165,13 @@ static void __dfufunc udp_ep0_send_stall(void)
static u_int8_t status;
-static u_int8_t *ptr = AT91C_IFLASH + SAM7DFU_SIZE;
+static u_int8_t *ptr = (u_int8_t *) AT91C_IFLASH + SAM7DFU_SIZE;
static __dfudata u_int32_t dfu_state = DFU_STATE_appIDLE;
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 ");
@@ -199,7 +194,7 @@ static int __dfufunc handle_dnload(u_int16_t val, u_int16_t len)
dfu_state = DFU_STATE_dfuMANIFEST_SYNC;
return 0;
}
- if (ptr + len > AT91C_IFLASH + AT91C_IFLASH_SIZE) {
+ if (ptr + len > (u_int8_t *) AT91C_IFLASH + AT91C_IFLASH_SIZE) {
dfu_state = DFU_STATE_dfuERROR;
status = DFU_STATUS_errADDRESS;
udp_ep0_send_stall();
@@ -212,20 +207,14 @@ static int __dfufunc handle_dnload(u_int16_t val, u_int16_t 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
-
-
- /* 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);
+ for (i = 0; i < len/4; i++) {
+ *p++ = (u_int32_t *) (pagebuf[i*4]);
+ /* If we have filled a page buffer, flash it */
+ if ((p % AT91C_FLASH_PAGE_SIZE) == 0)
+ flash_page(p-4);
+ }
+ ptr = p;
#endif
return 0;
@@ -235,7 +224,7 @@ static __dfufunc int handle_upload(u_int16_t val, u_int16_t len)
{
DEBUGE("upload ");
if (len > AT91C_IFLASH_PAGE_SIZE
- || ptr > AT91C_IFLASH_SIZE - 0x1000) {
+ || ptr > (u_int8_t *) AT91C_IFLASH + AT91C_IFLASH_SIZE - SAM7DFU_SIZE) {
/* Too big */
dfu_state = DFU_STATE_dfuERROR;
status = DFU_STATUS_errADDRESS;
@@ -332,12 +321,12 @@ int __dfufunc dfu_ep0_handler(u_int8_t req_type, u_int8_t req,
dfu_state = DFU_STATE_dfuERROR;
goto send_stall;
}
- ptr = AT91C_IFLASH + SAM7DFU_SIZE;
+ ptr = (u_int8_t *) AT91C_IFLASH + SAM7DFU_SIZE;
handle_dnload(val, len);
dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
break;
case USB_REQ_DFU_UPLOAD:
- ptr = AT91C_IFLASH + SAM7DFU_SIZE;
+ ptr = (u_int8_t *) AT91C_IFLASH + SAM7DFU_SIZE;
dfu_state = DFU_STATE_dfuUPLOAD_IDLE;
handle_upload(val, len);
break;
@@ -452,6 +441,7 @@ int __dfufunc dfu_ep0_handler(u_int8_t req_type, u_int8_t req,
break;
case USB_REQ_DFU_CLRSTATUS:
dfu_state = DFU_STATE_dfuIDLE;
+ status = DFU_STATUS_OK;
/* no zlp? */
goto send_zlp;
break;
diff --git a/firmware/src/dfu/dfu.h b/firmware/src/dfu/dfu.h
index e587fe4..b8d48ec 100644
--- a/firmware/src/dfu/dfu.h
+++ b/firmware/src/dfu/dfu.h
@@ -71,7 +71,7 @@ struct dfuapi {
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_int8_t *dfu_state;
+ u_int32_t *dfu_state;
const struct usb_device_descriptor *dfu_dev_descriptor;
const struct _dfu_desc *dfu_cfg_descriptor;
};
diff --git a/firmware/src/dfu/flash.c b/firmware/src/dfu/flash.c
index 675552d..8806bae 100644
--- a/firmware/src/dfu/flash.c
+++ b/firmware/src/dfu/flash.c
@@ -1,4 +1,6 @@
-
+#include <sys/types.h>
+#include <lib_AT91SAM7.h>
+#include <AT91SAM7.h>
#define EFCS_CMD_WRITE_PAGE 0x01
#define EFCS_CMD_SET_LOCK_BIT 0x02
@@ -10,26 +12,38 @@
#define EFCS_CMD_SET_SECURITY_BIT 0x0f
-int unlock_page(u_int16_t page)
+static u_int16_t page_from_ramaddr(const void *addr)
{
- AT91C_MC_FCMD_UNLOCK | AT91C_MC_CORRECT_KEY |
-
+ 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)
-int flash_sector(unsigned int sector, const u_int8_t *data, unsigned int len)
+static int is_page_locked(u_int16_t page)
{
- volatile u_int32_t *p = (volatile u_int32_t *)0;
- u_int32_t *src32 = (u_int32_t *)data;
- int i;
+ u_int16_t lockregion = LOCKREGION_FROM_PAGE(page);
- /* hand-code memcpy because we need to make sure only 32bit accesses
- * are used */
- for (i = 0; i < len/4; i++)
- p[i] = src32[i];
+ return (AT91C_BASE_MC->MC_FSR & (lockregion << 16));
+}
- AT91F_MC_EFC_PerformCmd(pmc , AT91C_MC_FCMD_START_PROG|
- AT91C_MC_CORRECT_KEY | );
+static void unlock_page(u_int16_t page)
+{
+ AT91F_MC_EFC_PerformCmd(AT91C_BASE_MC, AT91C_MC_FCMD_UNLOCK |
+ AT91C_MC_CORRECT_KEY | page);
}
+void flash_page(u_int8_t *addr)
+{
+ u_int16_t page = page_from_ramaddr(addr);
+
+ if (is_page_locked(page))
+ unlock_page(page);
+
+ AT91F_MC_EFC_PerformCmd(AT91C_BASE_MC, AT91C_MC_FCMD_START_PROG |
+ AT91C_MC_CORRECT_KEY | page);
+}