diff options
Diffstat (limited to 'firmware/src')
| -rw-r--r-- | firmware/src/dfu/dfu.c | 4 | ||||
| -rw-r--r-- | firmware/src/os/flash.c | 68 | ||||
| -rw-r--r-- | firmware/src/os/flash.h | 5 | 
3 files changed, 75 insertions, 2 deletions
| diff --git a/firmware/src/dfu/dfu.c b/firmware/src/dfu/dfu.c index 20778bd..58062a0 100644 --- a/firmware/src/dfu/dfu.c +++ b/firmware/src/dfu/dfu.c @@ -30,7 +30,7 @@  #include <dfu/dfu.h>  #include <dfu/dbgu.h> -#include <dfu/flash.h> +#include <os/flash.h>  #include <os/pcd_enumerate.h>  #include "../openpcd.h" @@ -234,7 +234,7 @@ static int __dfufunc handle_dnload(u_int16_t val, u_int16_t len)  		dfu_state = DFU_STATE_dfuMANIFEST_SYNC;  		return RET_ZLP;  	} -	if (ptr + len > (u_int8_t *) AT91C_IFLASH + AT91C_IFLASH_SIZE) { +	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; diff --git a/firmware/src/os/flash.c b/firmware/src/os/flash.c new file mode 100644 index 0000000..c729ff8 --- /dev/null +++ b/firmware/src/os/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/firmware/src/os/flash.h b/firmware/src/os/flash.h new file mode 100644 index 0000000..b812714 --- /dev/null +++ b/firmware/src/os/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 | 
