diff --git a/at91_init1.c b/at91_init1.c index cf07a06..b1636ea 100644 --- a/at91_init1.c +++ b/at91_init1.c @@ -18,6 +18,7 @@ ***************************************************************************/ #include #include "AT91SAM7S256.h" +#include "board.h" static void empty_isr(void) {} @@ -36,7 +37,7 @@ void at91_init1(void) *AT91C_RSTC_RMR = (AT91C_RSTC_KEY & 0xA5 << 24) | AT91C_RSTC_URSTEN; /* Set Flash Waitstates */ - *AT91C_MC_FMR = AT91C_MC_FWS_1FWS; + *AT91C_MC_FMR = (AT91C_MC_FMCN & ((MCK / 666666) << 16)) | AT91C_MC_FWS_1FWS; /* * Enable main oscillator (MAINCK) diff --git a/include/at91_twi.h b/include/at91_twi.h index 0e23314..dc69ee2 100644 --- a/include/at91_twi.h +++ b/include/at91_twi.h @@ -1,7 +1,7 @@ #ifndef AT91TWI_H_ #define AT91TWI_H_ -#include +#include /* TWI slave addresses */ #define TWI_ADDR_BL1 0x21 @@ -10,7 +10,7 @@ #define TWI_ADDR_BL4 0x24 #define TWI_ADDR_EEPROM 0x40 -/* TWIBOOT commands */ +/* TWIBOOT commands */ #define CMD_WAIT 0x00 #define CMD_GET_INFO 0x10 #define CMD_GET_SIGNATURE 0x11 @@ -33,7 +33,7 @@ struct blmc_cmd { uint32_t cmd; /* cmd byte(s) */ uint8_t mode; /* read/write, cmdlen (1-3 bytes) */ - uint8_t size; /* data size */ + uint16_t size; /* data size */ uint8_t *data; /* read/write data */ }; diff --git a/src/at91_twi.c b/src/at91_twi.c index 3bc439e..41646de 100644 --- a/src/at91_twi.c +++ b/src/at91_twi.c @@ -210,8 +210,8 @@ void at91_twi_test(void) cmd.cmd = CMD_GET_SIGNATURE; cmd.size = 4; ret = twi_cmd(i, &cmd); - printf("sig(%ld):0x%02x%02x%02x ", ret, buf[0], buf[1], buf[2]); - + printf("sig(%ld):0x%02x%02x%02x\n\r", ret, buf[0], buf[1], buf[2]); +/* cmd.cmd = CMD_BOOT_APPLICATION; cmd.mode = BLMC_CMD_WRITE | BLMC_CMD_0_ARG; cmd.size = 0; @@ -225,6 +225,7 @@ void at91_twi_test(void) cmd.data = buf, ret = twi_cmd(i, &cmd); printf("app(%ld):'%s'\n\r", ret, buf); +*/ } } diff --git a/src/at91_udp.c b/src/at91_udp.c index c206d4d..b098b5d 100644 --- a/src/at91_udp.c +++ b/src/at91_udp.c @@ -182,13 +182,12 @@ static const struct usb_string_descriptor usb_string1 = { }; static const struct usb_string_descriptor usb_string2 = { - /* String 2 "device firmware upgrade" */ - .bLength = sizeof(struct usb_string_descriptor) + 23 * sizeof(uint16_t), + /* String 2 "sam7fc-dfu" */ + .bLength = sizeof(struct usb_string_descriptor) + 10 * sizeof(uint16_t), .bDescriptorType = USB_DT_STRING, .wData = { - 0x0064, 0x0065, 0x0076, 0x0069, 0x0063, 0x0065, 0x0020, 0x0066, - 0x0069, 0x0072, 0x006d, 0x0077, 0x0061, 0x0072, 0x0065, 0x0020, - 0x0075, 0x0070, 0x0067, 0x0072, 0x0061, 0x0064, 0x0065, + 0x0073, 0x0061, 0x006d, 0x0037, 0x0066, 0x0063, 0x002d, 0x0064, + 0x0066, 0x0075, }, }; @@ -262,7 +261,7 @@ void ep_transfer_send(uint32_t ep, char *data, uint32_t length, void (*complete_cb)(void)) { struct ep_ctx *ctx = &ep_ctx[ep]; -// printf("ep_transfer_send(%ld) size=%ld flags=0x%x\n\r", ep, length, ctx->flags); +// printf("ep_transfer_send(%ld) size=%ld(%d) flags=0x%x\n\r", ep, length, ctx->maxpktsize, ctx->flags); if (!(ctx->flags & CTX_TRANSFER) || (ctx->flags & (CTX_IN | CTX_OUT))) return; @@ -448,6 +447,10 @@ static void udp_handle_ep(uint32_t ep) if (!(*csr & AT91C_UDP_EPEDS)) return; + /* clear STALLSENT interrupt */ + if (*csr & AT91C_UDP_STALLSENT) + csr_clear_flags(*csr, (AT91C_UDP_STALLSENT | AT91C_UDP_FORCESTALL)); + /* ctrl request packet? */ if (*csr & AT91C_UDP_RXSETUP) { struct usb_ctrlrequest req; @@ -455,6 +458,10 @@ static void udp_handle_ep(uint32_t ep) for (p = (uint8_t *)&req; p < (uint8_t *)(&req +1); p++) *p = AT91C_UDP_FDR[ep]; + /* ack bank0 *now */ + if (*csr & AT91C_UDP_RX_DATA_BK0) + csr_clear_flags(*csr, AT91C_UDP_RX_DATA_BK0); + /* set data phase transfer direction */ if (req.bRequestType & USB_DIR_IN) *csr |= AT91C_UDP_DIR; @@ -500,10 +507,6 @@ static void udp_handle_ep(uint32_t ep) *csr &= ~(AT91C_UDP_TXCOMP); } - /* clear STALLSENT interrupt */ - if (*csr & AT91C_UDP_STALLSENT) - csr_clear_flags(*csr, (AT91C_UDP_STALLSENT | AT91C_UDP_FORCESTALL)); - /* data ready to read? */ if (*csr & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1)) { struct ep_ctx *ctx = &ep_ctx[ep]; @@ -517,6 +520,8 @@ static void udp_handle_ep(uint32_t ep) ctx->transfer->curpos = 0; } + void *exec_cb = NULL; + if (ctx->flags & CTX_FIFO) { fifo_rxudp(ctx->fifo, ep, len); @@ -534,8 +539,8 @@ static void udp_handle_ep(uint32_t ep) if (transfer->length == transfer->curpos) { ctx->flags &= ~CTX_OUT; - if (transfer->complete_cb) - transfer->complete_cb(); + /* exec callback after rxbank ack */ + exec_cb = transfer->complete_cb; } } @@ -553,6 +558,9 @@ static void udp_handle_ep(uint32_t ep) ctx->flags = (ctx->flags & ~CTX_RXBANK1) | CTX_RXBANK0; } + + if (exec_cb) + ctx->transfer->complete_cb(); } } diff --git a/src/dfu.c b/src/dfu.c index f208d14..e9250b4 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -20,6 +20,7 @@ #include "AT91SAM7S256.h" #include "board.h" +#include "at91_twi.h" #include "at91_udp.h" #include "usb_ch9.h" @@ -36,7 +37,7 @@ static void handle_getstatus(void) { struct dfu_status dstat; - uint32_t fmr = *AT91C_MC_FMR; + uint32_t fmr = *AT91C_MC_FSR; switch (dfu_state) { case DFU_STATE_dfuDNLOAD_SYNC: @@ -53,8 +54,7 @@ static void handle_getstatus(void) dfu_state = DFU_STATE_dfuDNLOAD_IDLE; } else { -// dfu_state = DFU_STATE_dfuDNBUSY; - dfu_state = DFU_STATE_dfuDNLOAD_IDLE; + dfu_state = DFU_STATE_dfuDNBUSY; } break; } @@ -73,36 +73,149 @@ static void handle_getstate(void) ep_transfer_send(0, (char *)&dfu_state, sizeof(dfu_state), NULL); } -static uint8_t buf[256]; +static uint16_t prog_iface; +static uint16_t prog_block; +static uint16_t prog_length; +static uint32_t prog_buf[AT91C_IFLASH_PAGE_SIZE /4]; -static void handle_dnload_cb(void) +static void handle_dnload_flash(void) { + uint32_t *ptr = (uint32_t *)((uint8_t *)0x100000 + (prog_block * 0x100)); + + uint32_t i; + prog_length += 3; + for (i = 0; i < prog_length /4; i++) + *ptr++ = prog_buf[i]; + + if (!(*AT91C_MC_FSR & AT91C_MC_FRDY)) { + printf("flash not ready!\n\r"); + return; + } + + *AT91C_MC_FCR = (AT91C_MC_KEY & (0x5A << 24)) | + (((uint32_t)ptr - 0x100004) & AT91C_MC_PAGEN) | + AT91C_MC_FCMD_START_PROG; + ep_transfer_send(0, NULL, 0, NULL); } -static uint32_t handle_dnload(uint16_t index, uint16_t value, uint16_t length) +static void handle_dnload_eeprom(void) { - printf("down:%x-%x-%x\n\r", index, value, length); + /* + * TODO: write buf to onboard eeprom @ address + * inc. address + */ + ep_transfer_send(0, NULL, 0, NULL); +} + +static void handle_dnload_blctrl(void) +{ + /* + * TODO: write buf to blctrl#iface @ address + * inc. address + */ + ep_transfer_send(0, NULL, 0, NULL); +} + +static uint32_t handle_dnload(uint16_t iface, uint16_t block, uint16_t length) +{ + printf("down:%x-%x-%x\n\r", iface, block, length); if (length == 0) { dfu_state = DFU_STATE_dfuMANIFEST_SYNC; return RET_ZLP; } - ep_transfer_receive(0, (char *)&buf, length, handle_dnload_cb); + prog_iface = iface; + prog_block = block; + prog_length = length; + + void *callback = NULL; + switch (iface) { + case 0: /* internal flash */ + if (block >= 0x3C0) { + dfu_state = DFU_STATE_dfuERROR; + dfu_status = DFU_STATUS_errADDRESS; + return RET_STALL; + } + + callback = handle_dnload_flash; + break; + + case 1: /* onboard i2c-eeprom */ + callback = handle_dnload_eeprom; + break; + + case 2: + case 3: + case 4: + case 5: /* blctrl 1-4 */ + callback = handle_dnload_blctrl; + break; + } + + ep_transfer_receive(0, (char *)&prog_buf, length, callback); return RET_NOTHING; } -static uint32_t handle_upload(uint16_t index, uint16_t value, uint16_t length) +static void handle_upload(uint16_t iface, uint16_t block, uint16_t length) { - printf("up:%x-%x-%x\n\r", index, value, length); - return 0; + printf("up:%x-%x-%x\n\r", iface, block, length); + + char *ptr = (char *)&prog_buf; + + switch (iface) { + case 0: /* internal flash */ + if (block >= 0x400) { + length = 0; + break; + } + ptr = (char *)0x100000 + (block * 0x100); + break; + + case 1: /* onboard i2c-eeprom */ + if (block >= 0x80) { + length = 0; + break; + } + + /* TODO */ + + break; + + case 2: + case 3: + case 4: + case 5: /* blctrl 1-4 */ + if (block >= 0x20) { + length = 0; + dfu_state = DFU_STATE_dfuIDLE; + break; + } + + uint32_t i2c_dev = TWI_ADDR_BL1 + (iface -2); + + struct blmc_cmd cmd = { + .cmd = (CMD_READ_FLASH << 16) | (block * 0x100), + .mode = BLMC_CMD_READ | BLMC_CMD_2_ARG, + .size = length, + .data = (uint8_t *)&prog_buf, + }; + + if (twi_cmd(i2c_dev, &cmd) != 0) { + length = 0; + dfu_state = DFU_STATE_dfuERROR; + dfu_status = DFU_STATUS_errUNKNOWN; + } + break; + } + + ep_transfer_send(0, ptr, length, NULL); } void ep0_handle_dfu(struct usb_ctrlrequest *req) { - uint32_t rc, ret = RET_NOTHING; -// printf("state:%x\n\r", dfu_state); + uint32_t ret = RET_NOTHING; switch (dfu_state) { case DFU_STATE_appIDLE: @@ -272,9 +385,7 @@ void ep0_handle_dfu(struct usb_ctrlrequest *req) switch (req->bRequest) { case USB_REQ_DFU_UPLOAD: /* state transition if less data then requested */ - rc = handle_upload(req->wIndex, req->wValue, req->wLength); - if (rc >= 0 && rc < req->wLength) - dfu_state = DFU_STATE_dfuIDLE; + handle_upload(req->wIndex, req->wValue, req->wLength); break; case USB_REQ_DFU_GETSTATUS: