diff options
author | laforge <laforge@6dc7ffe9-61d6-0310-9af1-9938baff3ed1> | 2006-09-22 21:29:57 +0000 |
---|---|---|
committer | laforge <laforge@6dc7ffe9-61d6-0310-9af1-9938baff3ed1> | 2006-09-22 21:29:57 +0000 |
commit | 1c2b1d22016957bebe0a49c9069b85815f7cf936 (patch) | |
tree | 77046d2750dcb60ce46976f94027e65df67c502e /firmware/src/dfu | |
parent | 238c6c3c0ac40dcdef82c430fae52cad34ed5a10 (diff) |
- we increase the DFU size from 4k to 16k size. This is mainly due to the
SAM7S128 and SAM7S256 being restricted to 16k lock region size. If we want
to lock the bootloader, it has to be 16k aligned. This wastes a lot of
memory, since a non-debug DFU implementation fits currently into less than
4k. But anyway, we have lots of flexibility for the future given that amount
of space.
- The DFU size change introduces also a change in dfu_api location to 0x103fd0
- Allow GETSTATE and GETSTATUS from runtime mode (optional in DFU spec)
- Make dfu_status a .data.shared variable, since it is used from GETSTATUS
which we already support in runtime mode
- do some led switching while flashing via DFU
- disable all non-usb/dbgu interrupts when switching to DFU mode
- fix interrupt-storm problem when dbgu is used in DFU loader
- add missing linker script for SAM7S128
git-svn-id: https://svn.openpcd.org:2342/trunk@218 6dc7ffe9-61d6-0310-9af1-9938baff3ed1
Diffstat (limited to 'firmware/src/dfu')
-rw-r--r-- | firmware/src/dfu/dbgu.c | 5 | ||||
-rw-r--r-- | firmware/src/dfu/dfu.c | 70 | ||||
-rw-r--r-- | firmware/src/dfu/dfu.h | 2 | ||||
-rw-r--r-- | firmware/src/dfu/flash.c | 5 |
4 files changed, 59 insertions, 23 deletions
diff --git a/firmware/src/dfu/dbgu.c b/firmware/src/dfu/dbgu.c index 4a8d68f..367a399 100644 --- a/firmware/src/dfu/dbgu.c +++ b/firmware/src/dfu/dbgu.c @@ -65,11 +65,8 @@ void AT91F_DBGU_Init(void) /* open interrupt */ - /* FIXME: This should be HIGH_LEVEL, but somehow this triggers an - * interrupt storm. no idea why it's working in 'os' but not in 'dfu' - * */ AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SYS, USART_SYS_LEVEL, - AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE, + AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, DBGU_irq_handler); AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SYS); diff --git a/firmware/src/dfu/dfu.c b/firmware/src/dfu/dfu.c index bb8d057..693f2eb 100644 --- a/firmware/src/dfu/dfu.c +++ b/firmware/src/dfu/dfu.c @@ -32,7 +32,9 @@ #include <os/pcd_enumerate.h> #include "../openpcd.h" -#define SAM7DFU_SIZE 0x1000 +#include <compile.h> + +#define SAM7DFU_SIZE 0x4000 /* If debug is enabled, we need to access debug functions from flash * and therefore have to omit flashing */ @@ -57,6 +59,12 @@ #define RET_ZLP 1 #define RET_STALL 2 +#define led1on() AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED1) +#define led1off() AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED1) + +#define led2on() AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED2) +#define led2off() AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED2) + static void __dfufunc udp_init(void) { /* Set the PLL USB Divider */ @@ -185,8 +193,8 @@ static void __dfufunc udp_ep0_send_stall(void) } -static u_int8_t status; static u_int8_t *ptr = (u_int8_t *) AT91C_IFLASH + SAM7DFU_SIZE; +static __dfudata u_int8_t dfu_status; static __dfudata u_int32_t dfu_state = DFU_STATE_appIDLE; static u_int32_t pagebuf32[AT91C_IFLASH_PAGE_SIZE/4]; @@ -203,14 +211,14 @@ static int __dfufunc handle_dnload(u_int16_t val, u_int16_t len) * DFU protocol violation */ DEBUGP("length exceeds flash page size "); dfu_state = DFU_STATE_dfuERROR; - status = DFU_STATUS_errADDRESS; + dfu_status = DFU_STATUS_errADDRESS; return RET_STALL; } if (len & 0x3) { /* reject non-four-byte-aligned writes */ DEBUGP("not four-byte-aligned length "); dfu_state = DFU_STATE_dfuERROR; - status = DFU_STATUS_errADDRESS; + dfu_status = DFU_STATUS_errADDRESS; return RET_STALL; } if (len == 0) { @@ -222,7 +230,7 @@ static int __dfufunc handle_dnload(u_int16_t val, u_int16_t len) if (ptr + len > (u_int8_t *) AT91C_IFLASH + AT91C_IFLASH_SIZE) { DEBUGP("end of write exceeds flash end "); dfu_state = DFU_STATE_dfuERROR; - status = DFU_STATUS_errADDRESS; + dfu_status = DFU_STATUS_errADDRESS; return RET_STALL; } @@ -256,7 +264,7 @@ static __dfufunc int handle_upload(u_int16_t val, u_int16_t len) if (len > AT91C_IFLASH_PAGE_SIZE) { /* Too big */ dfu_state = DFU_STATE_dfuERROR; - status = DFU_STATUS_errADDRESS; + dfu_status = DFU_STATUS_errADDRESS; udp_ep0_send_stall(); return -EINVAL; } @@ -282,11 +290,11 @@ static __dfufunc void handle_getstatus(void) case DFU_STATE_dfuDNBUSY: if (fsr & AT91C_MC_PROGE) { DEBUGE("errPROG "); - status = DFU_STATUS_errPROG; + dfu_status = DFU_STATUS_errPROG; dfu_state = DFU_STATE_dfuERROR; } else if (fsr & AT91C_MC_LOCKE) { DEBUGE("errWRITE "); - status = DFU_STATUS_errWRITE; + dfu_status = DFU_STATUS_errWRITE; dfu_state = DFU_STATE_dfuERROR; } else if (fsr & AT91C_MC_FRDY) { DEBUGE("DNLOAD_IDLE "); @@ -302,7 +310,7 @@ static __dfufunc void handle_getstatus(void) } /* send status response */ - dstat.bStatus = status; + dstat.bStatus = dfu_status; dstat.bState = dfu_state; dstat.iString = 0; /* FIXME: set dstat.bwPollTimeout */ @@ -328,12 +336,21 @@ int __dfufunc dfu_ep0_handler(u_int8_t req_type, u_int8_t req, switch (dfu_state) { case DFU_STATE_appIDLE: - if (req != USB_REQ_DFU_DETACH) { - ret = RET_STALL; + switch (req) { + case USB_REQ_DFU_GETSTATUS: + handle_getstatus(); + break; + case USB_REQ_DFU_GETSTATE: + handle_getstate(); + break; + case USB_REQ_DFU_DETACH: + dfu_state = DFU_STATE_appDETACH; + ret = RET_ZLP; goto out; + break; + default: + ret = RET_STALL; } - dfu_state = DFU_STATE_appDETACH; - ret = RET_ZLP; break; case DFU_STATE_appDETACH: switch (req) { @@ -491,7 +508,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; + dfu_status = DFU_STATUS_OK; /* no zlp? */ ret = RET_ZLP; break; @@ -768,8 +785,10 @@ static __dfufunc void dfu_udp_irq(void) { AT91PS_UDP pUDP = AT91C_BASE_UDP; AT91_REG isr = pUDP->UDP_ISR; + led1on(); if (isr & AT91C_UDP_ENDBUSRES) { + led2on(); pUDP->UDP_IER = AT91C_UDP_EPINT0; /* reset all endpoints */ pUDP->UDP_RSTEP = (unsigned int)-1; @@ -788,6 +807,9 @@ static __dfufunc void dfu_udp_irq(void) pUDP->UDP_ICR = isr; AT91F_AIC_ClearIt(AT91C_BASE_AIC, AT91C_ID_UDP); + + { volatile int i; for (i=0; i< 0x3ff; i++) ; } + led1off(); } /* this is only called once before DFU mode, no __dfufunc required */ @@ -795,17 +817,35 @@ static void dfu_switch(void) { AT91PS_AIC pAic = AT91C_BASE_AIC; - DEBUGE("Switching to DFU mode "); + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED1); + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED2); + led1off(); + led2off(); + + flash_init(); + + /* disable all non-usb (and non-dbgu) interrupts */ + pAic->AIC_IDCR = ~((1 << AT91C_ID_UDP)|(1 << AT91C_ID_SYS)); pAic->AIC_SVR[AT91C_ID_UDP] = (unsigned int) &dfu_udp_irq; dfu_state = DFU_STATE_dfuIDLE; + dfu_status = DFU_STATUS_OK; } void __dfufunc dfu_main(void) { + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED1); + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED2); + led1off(); + led2off(); + AT91F_DBGU_Init(); DEBUGE("sam7dfu startup\r\n"); + AT91F_DBGU_Printk("\n\r"); + AT91F_DBGU_Printk(COMPILE_DATE " " COMPILE_BY " " COMPILE_SVNREV); + AT91F_DBGU_Printk("\n\r"); + udp_init(); dfu_state = DFU_STATE_dfuIDLE; diff --git a/firmware/src/dfu/dfu.h b/firmware/src/dfu/dfu.h index b8d48ec..4d53ce7 100644 --- a/firmware/src/dfu/dfu.h +++ b/firmware/src/dfu/dfu.h @@ -55,7 +55,7 @@ #define __dfufunc #define __dfustruct const -#define DFU_API_LOCATION ((const struct dfuapi *) 0x00100fd0) +#define DFU_API_LOCATION ((const struct dfuapi *) 0x00103fd0) struct _dfu_desc { struct usb_config_descriptor ucfg; diff --git a/firmware/src/dfu/flash.c b/firmware/src/dfu/flash.c index 4d0c9d9..0411f73 100644 --- a/firmware/src/dfu/flash.c +++ b/firmware/src/dfu/flash.c @@ -65,7 +65,6 @@ 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); + AT91F_MC_EFC_CfgModeReg(AT91C_BASE_MC, (fmcn&0xff) << 16 | + AT91C_MC_FWS_3FWS); } |