diff options
Diffstat (limited to 'firmware/src/dfu')
-rw-r--r-- | firmware/src/dfu/dfu.c | 66 | ||||
-rw-r--r-- | firmware/src/dfu/dfu.h | 2 | ||||
-rw-r--r-- | firmware/src/dfu/flash.c | 42 |
3 files changed, 57 insertions, 53 deletions
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); +} |