From 26bc6a68838f33a5436bf305c352c3b1c4ad893c Mon Sep 17 00:00:00 2001
From: laforge <laforge@6dc7ffe9-61d6-0310-9af1-9938baff3ed1>
Date: Wed, 20 Sep 2006 12:08:36 +0000
Subject: - add support for flashing to DFU

git-svn-id: https://svn.openpcd.org:2342/trunk@210 6dc7ffe9-61d6-0310-9af1-9938baff3ed1
---
 firmware/Makefile.dfu    |  3 ++-
 firmware/src/dfu/dfu.c   | 66 ++++++++++++++++++++----------------------------
 firmware/src/dfu/dfu.h   |  2 +-
 firmware/src/dfu/flash.c | 42 ++++++++++++++++++++----------
 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);
+}
 
 
-- 
cgit v1.2.3