xfel/fel.c
2023-05-19 13:42:37 +08:00

433 lines
10 KiB
C

#include <fel.h>
extern struct chip_t a10;
extern struct chip_t a13_a10s_r8;
extern struct chip_t a20;
extern struct chip_t a23;
extern struct chip_t a31;
extern struct chip_t a33_r16;
extern struct chip_t a40i_r40;
extern struct chip_t a50;
extern struct chip_t a64;
extern struct chip_t a80;
extern struct chip_t a83t;
extern struct chip_t d1_f133;
extern struct chip_t f1c100s_f1c200s_f1c500s;
extern struct chip_t h2_h3;
extern struct chip_t h5;
extern struct chip_t h6;
extern struct chip_t h616;
extern struct chip_t r128;
extern struct chip_t r328;
extern struct chip_t r329;
extern struct chip_t r528_t113;
extern struct chip_t t507;
extern struct chip_t v3s_s3;
extern struct chip_t v536;
extern struct chip_t v831;
extern struct chip_t v851_v853;
static struct chip_t * chips[] = {
&a10,
&a13_a10s_r8,
&a20,
&a23,
&a31,
&a33_r16,
&a40i_r40,
&a50,
&a64,
&a80,
&a83t,
&d1_f133,
&f1c100s_f1c200s_f1c500s,
&h2_h3,
&h5,
&h6,
&h616,
&r128,
&r328,
&r329,
&r528_t113,
&t507,
&v3s_s3,
&v536,
&v831,
&v851_v853,
};
struct usb_request_t {
char magic[8];
uint32_t length;
uint32_t unknown1;
uint16_t request;
uint32_t length2;
char pad[10];
} __attribute__((packed));
struct fel_request_t {
uint32_t request;
uint32_t address;
uint32_t length;
uint32_t pad;
} __attribute__((packed));
static inline void usb_bulk_send(libusb_device_handle * hdl, int ep, const char * buf, size_t len)
{
size_t max_chunk = 128 * 1024;
size_t chunk;
int r, bytes;
while(len > 0)
{
chunk = len < max_chunk ? len : max_chunk;
r = libusb_bulk_transfer(hdl, ep, (void *)buf, chunk, &bytes, 10000);
if(r != 0)
{
printf("usb bulk send error\r\n");
exit(-1);
}
len -= bytes;
buf += bytes;
}
}
static inline void usb_bulk_recv(libusb_device_handle * hdl, int ep, char * buf, size_t len)
{
int r, bytes;
while(len > 0)
{
r = libusb_bulk_transfer(hdl, ep, (void *)buf, len, &bytes, 10000);
if(r != 0)
{
printf("usb bulk recv error\r\n");
exit(-1);
}
len -= bytes;
buf += bytes;
}
}
static inline void send_usb_request(struct xfel_ctx_t * ctx, int type, size_t length)
{
struct usb_request_t req = {
.magic = "AWUC",
.request = cpu_to_le16(type),
.length = cpu_to_le32(length),
.unknown1 = cpu_to_le32(0x0c000000)
};
req.length2 = req.length;
usb_bulk_send(ctx->hdl, ctx->epout, (const char *)&req, sizeof(struct usb_request_t));
}
static inline void read_usb_response(struct xfel_ctx_t * ctx)
{
char buf[13];
usb_bulk_recv(ctx->hdl, ctx->epin, (char *)buf, sizeof(buf));
assert(strcmp(buf, "AWUS") == 0);
}
static inline void usb_write(struct xfel_ctx_t * ctx, const void * buf, size_t len)
{
send_usb_request(ctx, 0x12, len);
usb_bulk_send(ctx->hdl, ctx->epout, (const char *)buf, len);
read_usb_response(ctx);
}
static inline void usb_read(struct xfel_ctx_t * ctx, const void * data, size_t len)
{
send_usb_request(ctx, 0x11, len);
usb_bulk_send(ctx->hdl, ctx->epin, (const char *)data, len);
read_usb_response(ctx);
}
static inline void send_fel_request(struct xfel_ctx_t * ctx, int type, uint32_t addr, uint32_t length)
{
struct fel_request_t req = {
.request = cpu_to_le32(type),
.address = cpu_to_le32(addr),
.length = cpu_to_le32(length)
};
usb_write(ctx, &req, sizeof(struct fel_request_t));
}
static inline void read_fel_status(struct xfel_ctx_t * ctx)
{
char buf[8];
usb_read(ctx, buf, sizeof(buf));
}
static inline int fel_version(struct xfel_ctx_t * ctx)
{
int i;
send_fel_request(ctx, 0x001, 0, 0);
usb_read(ctx, &ctx->version, sizeof(ctx->version));
read_fel_status(ctx);
ctx->version.id = le32_to_cpu(ctx->version.id);
ctx->version.firmware = le32_to_cpu(ctx->version.firmware);
ctx->version.protocol = le16_to_cpu(ctx->version.protocol);
ctx->version.scratchpad = le32_to_cpu(ctx->version.scratchpad);
for(i = 0; i < ARRAY_SIZE(chips); i++)
{
ctx->chip = chips[i];
if(fel_chip_detect(ctx, ctx->version.id))
return 1;
}
printf("WARNING: Not yet support this device ID 0x%08x\r\n", ctx->version.id);
return 0;
}
int fel_init(struct xfel_ctx_t * ctx)
{
if(ctx && ctx->hdl)
{
struct libusb_config_descriptor * config;
int if_idx, set_idx, ep_idx;
const struct libusb_interface * iface;
const struct libusb_interface_descriptor * setting;
const struct libusb_endpoint_descriptor * ep;
if(libusb_kernel_driver_active(ctx->hdl, 0))
libusb_detach_kernel_driver(ctx->hdl, 0);
if(libusb_claim_interface(ctx->hdl, 0) == 0)
{
if(libusb_get_active_config_descriptor(libusb_get_device(ctx->hdl), &config) == 0)
{
for(if_idx = 0; if_idx < config->bNumInterfaces; if_idx++)
{
iface = config->interface + if_idx;
for(set_idx = 0; set_idx < iface->num_altsetting; set_idx++)
{
setting = iface->altsetting + set_idx;
for(ep_idx = 0; ep_idx < setting->bNumEndpoints; ep_idx++)
{
ep = setting->endpoint + ep_idx;
if((ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) != LIBUSB_TRANSFER_TYPE_BULK)
continue;
if((ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN)
ctx->epin = ep->bEndpointAddress;
else
ctx->epout = ep->bEndpointAddress;
}
}
}
libusb_free_config_descriptor(config);
return fel_version(ctx);
}
}
}
return 0;
}
void fel_exec(struct xfel_ctx_t * ctx, uint32_t addr)
{
send_fel_request(ctx, 0x102, addr, 0);
read_fel_status(ctx);
}
static inline void fel_read_raw(struct xfel_ctx_t * ctx, uint32_t addr, void * buf, size_t len)
{
send_fel_request(ctx, 0x103, addr, len);
usb_read(ctx, buf, len);
read_fel_status(ctx);
}
static inline void fel_write_raw(struct xfel_ctx_t * ctx, uint32_t addr, void * buf, size_t len)
{
send_fel_request(ctx, 0x101, addr, len);
usb_write(ctx, buf, len);
read_fel_status(ctx);
}
uint32_t fel_read32(struct xfel_ctx_t * ctx, uint32_t addr)
{
uint32_t val;
fel_read_raw(ctx, addr, &val, sizeof(uint32_t));
return val;
}
void fel_write32(struct xfel_ctx_t * ctx, uint32_t addr, uint32_t val)
{
fel_write_raw(ctx, addr, &val, sizeof(uint32_t));
}
void fel_read(struct xfel_ctx_t * ctx, uint32_t addr, void * buf, size_t len)
{
size_t n;
while(len > 0)
{
n = len > 65536 ? 65536 : len;
fel_read_raw(ctx, addr, buf, n);
addr += n;
buf += n;
len -= n;
}
}
void fel_write(struct xfel_ctx_t * ctx, uint32_t addr, void * buf, size_t len)
{
size_t n;
while(len > 0)
{
n = len > 65536 ? 65536 : len;
fel_write_raw(ctx, addr, buf, n);
addr += n;
buf += n;
len -= n;
}
}
void fel_read_progress(struct xfel_ctx_t * ctx, uint32_t addr, void * buf, size_t len)
{
struct progress_t p;
size_t n;
progress_start(&p, len);
while(len > 0)
{
n = len > 65536 ? 65536 : len;
fel_read_raw(ctx, addr, buf, n);
addr += n;
buf += n;
len -= n;
progress_update(&p, n);
}
progress_stop(&p);
}
void fel_write_progress(struct xfel_ctx_t * ctx, uint32_t addr, void * buf, size_t len)
{
struct progress_t p;
size_t n;
progress_start(&p, len);
while(len > 0)
{
n = len > 65536 ? 65536 : len;
fel_write_raw(ctx, addr, buf, n);
addr += n;
buf += n;
len -= n;
progress_update(&p, n);
}
progress_stop(&p);
}
int fel_spi_init(struct xfel_ctx_t * ctx, uint32_t * swapbuf, uint32_t * swaplen, uint32_t * cmdlen)
{
uint8_t cbuf[2];
if(!fel_chip_spi_init(ctx, swapbuf, swaplen, cmdlen))
return 0;
cbuf[0] = SPI_CMD_INIT;
cbuf[1] = SPI_CMD_END;
if(!fel_chip_spi_run(ctx, cbuf, sizeof(cbuf)))
return 0;
return 1;
}
int fel_spi_xfer(struct xfel_ctx_t * ctx, uint32_t swapbuf, uint32_t swaplen, uint32_t cmdlen, void * txbuf, uint32_t txlen, void * rxbuf, uint32_t rxlen)
{
uint8_t cbuf[256];
uint32_t clen;
uint32_t n;
if((txlen <= swaplen) && (rxlen <= swaplen))
{
clen = 0;
cbuf[clen++] = SPI_CMD_SELECT;
if(txlen > 0)
{
cbuf[clen++] = SPI_CMD_TXBUF;
cbuf[clen++] = (swapbuf >> 0) & 0xff;
cbuf[clen++] = (swapbuf >> 8) & 0xff;
cbuf[clen++] = (swapbuf >> 16) & 0xff;
cbuf[clen++] = (swapbuf >> 24) & 0xff;
cbuf[clen++] = (txlen >> 0) & 0xff;
cbuf[clen++] = (txlen >> 8) & 0xff;
cbuf[clen++] = (txlen >> 16) & 0xff;
cbuf[clen++] = (txlen >> 24) & 0xff;
}
if(rxlen > 0)
{
cbuf[clen++] = SPI_CMD_RXBUF;
cbuf[clen++] = (swapbuf >> 0) & 0xff;
cbuf[clen++] = (swapbuf >> 8) & 0xff;
cbuf[clen++] = (swapbuf >> 16) & 0xff;
cbuf[clen++] = (swapbuf >> 24) & 0xff;
cbuf[clen++] = (rxlen >> 0) & 0xff;
cbuf[clen++] = (rxlen >> 8) & 0xff;
cbuf[clen++] = (rxlen >> 16) & 0xff;
cbuf[clen++] = (rxlen >> 24) & 0xff;
}
cbuf[clen++] = SPI_CMD_DESELECT;
cbuf[clen++] = SPI_CMD_END;
if(txlen > 0)
fel_write(ctx, swapbuf, txbuf, txlen);
if((clen > cmdlen) || !fel_chip_spi_run(ctx, cbuf, clen))
return 0;
if(rxlen > 0)
fel_read(ctx, swapbuf, rxbuf, rxlen);
}
else
{
clen = 0;
cbuf[clen++] = SPI_CMD_SELECT;
cbuf[clen++] = SPI_CMD_END;
if(!fel_chip_spi_run(ctx, cbuf, clen))
return 0;
while(txlen > 0)
{
n = txlen > swaplen ? swaplen : txlen;
clen = 0;
cbuf[clen++] = SPI_CMD_TXBUF;
cbuf[clen++] = (swapbuf >> 0) & 0xff;
cbuf[clen++] = (swapbuf >> 8) & 0xff;
cbuf[clen++] = (swapbuf >> 16) & 0xff;
cbuf[clen++] = (swapbuf >> 24) & 0xff;
cbuf[clen++] = (n >> 0) & 0xff;
cbuf[clen++] = (n >> 8) & 0xff;
cbuf[clen++] = (n >> 16) & 0xff;
cbuf[clen++] = (n >> 24) & 0xff;
cbuf[clen++] = SPI_CMD_END;
fel_write(ctx, swapbuf, txbuf, n);
if(!fel_chip_spi_run(ctx, cbuf, clen))
return 0;
txbuf += n;
txlen -= n;
}
while(rxlen > 0)
{
n = rxlen > swaplen ? swaplen : rxlen;
clen = 0;
cbuf[clen++] = SPI_CMD_RXBUF;
cbuf[clen++] = (swapbuf >> 0) & 0xff;
cbuf[clen++] = (swapbuf >> 8) & 0xff;
cbuf[clen++] = (swapbuf >> 16) & 0xff;
cbuf[clen++] = (swapbuf >> 24) & 0xff;
cbuf[clen++] = (n >> 0) & 0xff;
cbuf[clen++] = (n >> 8) & 0xff;
cbuf[clen++] = (n >> 16) & 0xff;
cbuf[clen++] = (n >> 24) & 0xff;
cbuf[clen++] = SPI_CMD_END;
if(!fel_chip_spi_run(ctx, cbuf, clen))
return 0;
fel_read(ctx, swapbuf, rxbuf, n);
rxbuf += n;
rxlen -= n;
}
clen = 0;
cbuf[clen++] = SPI_CMD_DESELECT;
cbuf[clen++] = SPI_CMD_END;
if((clen > cmdlen) || !fel_chip_spi_run(ctx, cbuf, clen))
return 0;
}
return 1;
}