fixes from bootloader branch
This commit is contained in:
parent
773cc44a09
commit
7f54c86b7c
@ -1,7 +1,7 @@
|
|||||||
#ifndef AT91TWI_H_
|
#ifndef AT91TWI_H_
|
||||||
#define AT91TWI_H_
|
#define AT91TWI_H_
|
||||||
|
|
||||||
#include <list.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/* TWI slave addresses */
|
/* TWI slave addresses */
|
||||||
#define TWI_ADDR_BL1 0x21
|
#define TWI_ADDR_BL1 0x21
|
||||||
@ -10,7 +10,7 @@
|
|||||||
#define TWI_ADDR_BL4 0x24
|
#define TWI_ADDR_BL4 0x24
|
||||||
#define TWI_ADDR_EEPROM 0x40
|
#define TWI_ADDR_EEPROM 0x40
|
||||||
|
|
||||||
/* TWIBOOT commands */
|
/* TWIBOOT commands */
|
||||||
#define CMD_WAIT 0x00
|
#define CMD_WAIT 0x00
|
||||||
#define CMD_GET_INFO 0x10
|
#define CMD_GET_INFO 0x10
|
||||||
#define CMD_GET_SIGNATURE 0x11
|
#define CMD_GET_SIGNATURE 0x11
|
||||||
@ -33,7 +33,7 @@
|
|||||||
struct blmc_cmd {
|
struct blmc_cmd {
|
||||||
uint32_t cmd; /* cmd byte(s) */
|
uint32_t cmd; /* cmd byte(s) */
|
||||||
uint8_t mode; /* read/write, cmdlen (1-3 bytes) */
|
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 */
|
uint8_t *data; /* read/write data */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
104
src/at91_udp.c
104
src/at91_udp.c
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "usb_ch9.h"
|
#include "usb_ch9.h"
|
||||||
#include "usb_cdc.h"
|
#include "usb_cdc.h"
|
||||||
|
#include "usb_dfu.h"
|
||||||
|
|
||||||
#define csr_clear_flags(csr, flags) \
|
#define csr_clear_flags(csr, flags) \
|
||||||
while ((csr) & (flags)) \
|
while ((csr) & (flags)) \
|
||||||
@ -73,6 +74,7 @@ static const struct usb_device_descriptor dev_descriptor = {
|
|||||||
.idVendor = USB_VENDOR_ID,
|
.idVendor = USB_VENDOR_ID,
|
||||||
.idProduct = USB_PRODUCT_ID +1,
|
.idProduct = USB_PRODUCT_ID +1,
|
||||||
.bcdDevice = 0x0001,
|
.bcdDevice = 0x0001,
|
||||||
|
.iProduct = 0x01,
|
||||||
.bNumConfigurations = 1,
|
.bNumConfigurations = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -87,6 +89,8 @@ struct my_config {
|
|||||||
struct usb_interface_descriptor data_iface;
|
struct usb_interface_descriptor data_iface;
|
||||||
struct usb_endpoint_descriptor dataout_ep;
|
struct usb_endpoint_descriptor dataout_ep;
|
||||||
struct usb_endpoint_descriptor datain_ep;
|
struct usb_endpoint_descriptor datain_ep;
|
||||||
|
struct usb_interface_descriptor dfu_iface;
|
||||||
|
struct usb_dfu_descriptor dfu;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
static const struct my_config cfg_descriptor = {
|
static const struct my_config cfg_descriptor = {
|
||||||
@ -94,7 +98,7 @@ static const struct my_config cfg_descriptor = {
|
|||||||
.bLength = sizeof(struct usb_config_descriptor),
|
.bLength = sizeof(struct usb_config_descriptor),
|
||||||
.bDescriptorType = USB_DT_CONFIG,
|
.bDescriptorType = USB_DT_CONFIG,
|
||||||
.wTotalLength = sizeof(struct my_config),
|
.wTotalLength = sizeof(struct my_config),
|
||||||
.bNumInterfaces = 2,
|
.bNumInterfaces = 3,
|
||||||
.bConfigurationValue = 1,
|
.bConfigurationValue = 1,
|
||||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER | USB_CONFIG_ATT_WAKEUP,
|
.bmAttributes = USB_CONFIG_ATT_SELFPOWER | USB_CONFIG_ATT_WAKEUP,
|
||||||
.bMaxPower = 50,
|
.bMaxPower = 50,
|
||||||
@ -163,9 +167,50 @@ static const struct my_config cfg_descriptor = {
|
|||||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||||
.wMaxPacketSize = 64,
|
.wMaxPacketSize = 64,
|
||||||
},
|
},
|
||||||
|
.dfu_iface = {
|
||||||
|
.bLength = sizeof(struct usb_interface_descriptor),
|
||||||
|
.bDescriptorType = USB_DT_INTERFACE,
|
||||||
|
.bInterfaceNumber = 2,
|
||||||
|
.bInterfaceClass = USB_CLASS_APP_SPEC,
|
||||||
|
.bInterfaceSubClass = 0x01, /* DFU */
|
||||||
|
.bInterfaceProtocol = 0x01,
|
||||||
|
},
|
||||||
|
.dfu = {
|
||||||
|
.bLength = sizeof(struct usb_dfu_descriptor),
|
||||||
|
.bDescriptorType = USB_TYPE_DFU,
|
||||||
|
.bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_CAN_UPLOAD | USB_DFU_MANIFEST_TOL | USB_DFU_WILL_DETACH,
|
||||||
|
.wDetachTimeOut = 0xff00,
|
||||||
|
.wTransferSize = AT91C_IFLASH_PAGE_SIZE,
|
||||||
|
.bcdDFUVersion = 0x0101,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ep_transfer_send(uint32_t ep, char *data, uint32_t length,
|
static const struct dfu_status dfu_status = {
|
||||||
|
.bStatus = DFU_STATUS_OK,
|
||||||
|
.bState = DFU_STATE_appIDLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct usb_string_descriptor usb_string0 = {
|
||||||
|
/* String 0 - Language */
|
||||||
|
.bLength = sizeof(struct usb_string_descriptor) + 1 * sizeof(uint16_t),
|
||||||
|
.bDescriptorType = USB_DT_STRING,
|
||||||
|
.wData = { 0x0409 /* English */ },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct usb_string_descriptor usb_string1 = {
|
||||||
|
/* String 1 "sam7fc" */
|
||||||
|
.bLength = sizeof(struct usb_string_descriptor) + 6 * sizeof(uint16_t),
|
||||||
|
.bDescriptorType = USB_DT_STRING,
|
||||||
|
.wData = {
|
||||||
|
0x0073, 0x0061, 0x006d, 0x0037, 0x0066, 0x0063,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct usb_string_descriptor *usb_strings[] = {
|
||||||
|
&usb_string0, &usb_string1,
|
||||||
|
};
|
||||||
|
|
||||||
|
void ep_transfer_send(uint32_t ep, char *data, uint32_t length,
|
||||||
void (*complete_cb)(void))
|
void (*complete_cb)(void))
|
||||||
{
|
{
|
||||||
struct ep_ctx *ctx = &ep_ctx[ep];
|
struct ep_ctx *ctx = &ep_ctx[ep];
|
||||||
@ -192,7 +237,7 @@ static void ep_transfer_send(uint32_t ep, char *data, uint32_t length,
|
|||||||
AT91C_UDP_CSR[ep] |= AT91C_UDP_TXPKTRDY;
|
AT91C_UDP_CSR[ep] |= AT91C_UDP_TXPKTRDY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ep_transfer_receive(uint32_t ep, char *data, uint32_t length,
|
void ep_transfer_receive(uint32_t ep, char *data, uint32_t length,
|
||||||
void (*complete_cb)(void))
|
void (*complete_cb)(void))
|
||||||
{
|
{
|
||||||
struct ep_ctx *ctx = &ep_ctx[ep];
|
struct ep_ctx *ctx = &ep_ctx[ep];
|
||||||
@ -292,6 +337,24 @@ static void ep_handle_ctrlrequest(struct usb_ctrlrequest *req)
|
|||||||
NULL);
|
NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case USB_DT_STRING: /* 0x03 */
|
||||||
|
;
|
||||||
|
uint8_t index = req->wValue & 0xFF;
|
||||||
|
if (index < ARRAY_SIZE(usb_strings)) {
|
||||||
|
ep_transfer_send(0, (char *)usb_strings[index],
|
||||||
|
MIN(usb_strings[index]->bLength, req->wLength),
|
||||||
|
NULL);
|
||||||
|
} else {
|
||||||
|
ep_send_stall(0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_DT_CS_DEVICE: /* 0x21 */
|
||||||
|
ep_transfer_send(0, (char *)&cfg_descriptor.dfu,
|
||||||
|
MIN(sizeof(cfg_descriptor.dfu), req->wLength),
|
||||||
|
NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ep_send_stall(0);
|
ep_send_stall(0);
|
||||||
break;
|
break;
|
||||||
@ -310,7 +373,6 @@ static void ep_handle_ctrlrequest(struct usb_ctrlrequest *req)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case (USB_TYPE_STANDARD | USB_RECIP_INTERFACE): /* 0x01/0x81 */
|
case (USB_TYPE_STANDARD | USB_RECIP_INTERFACE): /* 0x01/0x81 */
|
||||||
// TODO: follow current_interface
|
|
||||||
switch (req->bRequest) {
|
switch (req->bRequest) {
|
||||||
case USB_REQ_SET_INTERFACE: /* 0x0b */
|
case USB_REQ_SET_INTERFACE: /* 0x0b */
|
||||||
current_interface = req->wValue;
|
current_interface = req->wValue;
|
||||||
@ -326,8 +388,16 @@ static void ep_handle_ctrlrequest(struct usb_ctrlrequest *req)
|
|||||||
case (USB_TYPE_CLASS | USB_RECIP_INTERFACE): /* 0x21/0xA1 */
|
case (USB_TYPE_CLASS | USB_RECIP_INTERFACE): /* 0x21/0xA1 */
|
||||||
// TODO: follow current_interface
|
// TODO: follow current_interface
|
||||||
switch (req->bRequest) {
|
switch (req->bRequest) {
|
||||||
|
case USB_REQ_DFU_DETACH: /* 0x00 */
|
||||||
|
ep_transfer_send(0, NULL, 0, NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_REQ_DFU_GETSTATUS: /* 0x03 */
|
||||||
|
ep_transfer_send(0, (char *)&dfu_status, sizeof(dfu_status), NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
case USB_CDC_REQ_SET_LINE_CODING: /* 0x20 */
|
case USB_CDC_REQ_SET_LINE_CODING: /* 0x20 */
|
||||||
/* read 7 bytes */
|
/* TODO: read 7 bytes to dummy buffer */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case USB_CDC_REQ_SET_CONTROL_LINE_STATE: /* 0x22 */
|
case USB_CDC_REQ_SET_CONTROL_LINE_STATE: /* 0x22 */
|
||||||
@ -353,6 +423,10 @@ static void udp_handle_ep(uint32_t ep)
|
|||||||
if (!(*csr & AT91C_UDP_EPEDS))
|
if (!(*csr & AT91C_UDP_EPEDS))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* clear STALLSENT interrupt */
|
||||||
|
if (*csr & AT91C_UDP_STALLSENT)
|
||||||
|
csr_clear_flags(*csr, (AT91C_UDP_STALLSENT | AT91C_UDP_FORCESTALL));
|
||||||
|
|
||||||
/* ctrl request packet? */
|
/* ctrl request packet? */
|
||||||
if (*csr & AT91C_UDP_RXSETUP) {
|
if (*csr & AT91C_UDP_RXSETUP) {
|
||||||
struct usb_ctrlrequest req;
|
struct usb_ctrlrequest req;
|
||||||
@ -360,6 +434,10 @@ static void udp_handle_ep(uint32_t ep)
|
|||||||
for (p = (uint8_t *)&req; p < (uint8_t *)(&req +1); p++)
|
for (p = (uint8_t *)&req; p < (uint8_t *)(&req +1); p++)
|
||||||
*p = AT91C_UDP_FDR[ep];
|
*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 */
|
/* set data phase transfer direction */
|
||||||
if (req.bRequestType & USB_DIR_IN)
|
if (req.bRequestType & USB_DIR_IN)
|
||||||
*csr |= AT91C_UDP_DIR;
|
*csr |= AT91C_UDP_DIR;
|
||||||
@ -370,6 +448,8 @@ static void udp_handle_ep(uint32_t ep)
|
|||||||
ep_handle_ctrlrequest(&req);
|
ep_handle_ctrlrequest(&req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void (* transfer_cb)(void) = NULL;
|
||||||
|
|
||||||
/* transmit complete? */
|
/* transmit complete? */
|
||||||
if (*csr & AT91C_UDP_TXCOMP) {
|
if (*csr & AT91C_UDP_TXCOMP) {
|
||||||
struct ep_ctx *ctx = &ep_ctx[ep];
|
struct ep_ctx *ctx = &ep_ctx[ep];
|
||||||
@ -395,9 +475,7 @@ static void udp_handle_ep(uint32_t ep)
|
|||||||
/* transfer complete, execute callback */
|
/* transfer complete, execute callback */
|
||||||
} else {
|
} else {
|
||||||
ctx->flags &= ~CTX_IN;
|
ctx->flags &= ~CTX_IN;
|
||||||
|
transfer_cb = transfer->complete_cb;
|
||||||
if (transfer->complete_cb)
|
|
||||||
transfer->complete_cb();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,14 +483,9 @@ static void udp_handle_ep(uint32_t ep)
|
|||||||
*csr &= ~(AT91C_UDP_TXCOMP);
|
*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? */
|
/* data ready to read? */
|
||||||
if (*csr & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1)) {
|
if (*csr & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1)) {
|
||||||
struct ep_ctx *ctx = &ep_ctx[ep];
|
struct ep_ctx *ctx = &ep_ctx[ep];
|
||||||
|
|
||||||
uint16_t len = (*csr & AT91C_UDP_RXBYTECNT) >> 16;
|
uint16_t len = (*csr & AT91C_UDP_RXBYTECNT) >> 16;
|
||||||
|
|
||||||
// TODO: only ep0 status OUT?
|
// TODO: only ep0 status OUT?
|
||||||
@ -459,6 +532,9 @@ static void udp_handle_ep(uint32_t ep)
|
|||||||
ctx->flags = (ctx->flags & ~CTX_RXBANK1) | CTX_RXBANK0;
|
ctx->flags = (ctx->flags & ~CTX_RXBANK1) | CTX_RXBANK0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (transfer_cb)
|
||||||
|
transfer_cb();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void udp_isr(void)
|
static void udp_isr(void)
|
||||||
@ -509,8 +585,6 @@ void at91_udp_init(void)
|
|||||||
pio->PIO_CODR = UDP_PULLUP;
|
pio->PIO_CODR = UDP_PULLUP;
|
||||||
pio->PIO_PER = UDP_PULLUP;
|
pio->PIO_PER = UDP_PULLUP;
|
||||||
pio->PIO_OER = UDP_PULLUP;
|
pio->PIO_OER = UDP_PULLUP;
|
||||||
// TODO: needed?
|
|
||||||
pio->PIO_PPUDR = UDP_VBUS_MON;
|
|
||||||
|
|
||||||
/* UDPCK (48MHz) = PLLCK / 2 */
|
/* UDPCK (48MHz) = PLLCK / 2 */
|
||||||
*AT91C_CKGR_PLLR |= AT91C_CKGR_USBDIV_1;
|
*AT91C_CKGR_PLLR |= AT91C_CKGR_USBDIV_1;
|
||||||
|
Loading…
Reference in New Issue
Block a user