241 lines
4.6 KiB
C
Executable File
241 lines
4.6 KiB
C
Executable File
/*
|
|
* Copyright (c) LOTUS. All rights reserved.
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <watchdog.h>
|
|
#include <command.h>
|
|
#include <serial.h>
|
|
#include <usb.h>
|
|
#include <crc16.h>
|
|
#include <linux/lotus/usb.h>
|
|
|
|
#define XHEAD 0xAB
|
|
#define XCMD 0xCD
|
|
#define ACK 0xAA /* ACK VALUE */
|
|
#define NAK 0x55 /* NAK VALUE */
|
|
|
|
#define START_FRAME_LEN 5
|
|
#define MAX_BUFF_SIZE 1024
|
|
#define MAX_SEND_SIZE 20
|
|
|
|
static char recv_buf[MAX_BUFF_SIZE];
|
|
|
|
#undef DUMP_SWITCH
|
|
#ifdef DUMP_SWITCH
|
|
static void dump_buf(char *buf, int len)
|
|
{
|
|
int i;
|
|
char *p = buf;
|
|
printf("%s->%d, buf=0x%.8x, len=%d\n",
|
|
__FUNCTION__, __LINE__,
|
|
(int)(buf), (int)(len));
|
|
for (i = 0; i < (len); i++) {
|
|
printf("0x%.2x ", *(p + i));
|
|
if (!((i + 1) & 0x07))
|
|
printf("\n");
|
|
}
|
|
printf("\n");
|
|
}
|
|
#endif
|
|
|
|
static unsigned short calc_crc16(const unsigned char *packet, unsigned long length)
|
|
{
|
|
unsigned short crc16 = 0;
|
|
unsigned long i;
|
|
|
|
const unsigned short *crc16_table = get_crc16_table();
|
|
if (crc16_table == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i < length; i++)
|
|
crc16 = ((crc16 << 8) | /* fetches High or low 8 bit */
|
|
packet[i]) ^ crc16_table[(crc16 >> 8) & 0xFF];
|
|
|
|
for (i = 0; i < 2; i++) /* 2: Cycle and fetches High or low 8 bit */
|
|
crc16 = ((crc16 << 8) | 0) ^ crc16_table[(crc16 >> 8) & 0xFF];
|
|
|
|
return crc16;
|
|
}
|
|
|
|
static int recv_byte(void)
|
|
{
|
|
if (serial_tstc())
|
|
return serial_getc();
|
|
|
|
return -1;
|
|
}
|
|
|
|
static char recv_data(void)
|
|
{
|
|
int ret = -1;
|
|
|
|
while (ret == -1)
|
|
ret = recv_byte();
|
|
|
|
return (char)ret;
|
|
}
|
|
|
|
void download_process(void)
|
|
{
|
|
int i = 0, cr = 0, ret = -1;
|
|
unsigned int head_frame_len = 0;
|
|
unsigned int cmd_len = 0;
|
|
unsigned char send_buf[MAX_SEND_SIZE] = {0};
|
|
unsigned short cksum;
|
|
|
|
do {
|
|
do {
|
|
do {
|
|
cr = recv_byte();
|
|
} while (cr != XHEAD);
|
|
|
|
head_frame_len = START_FRAME_LEN;
|
|
recv_buf[0] = (char)cr;
|
|
|
|
/* RECV: head frame */
|
|
for (i = 0; i < (head_frame_len - 1) && i < (sizeof(recv_buf) - 1); i++) {
|
|
recv_buf[i + 1] = recv_data();
|
|
}
|
|
|
|
/* crc check */
|
|
cksum = calc_crc16((unsigned char*)recv_buf,3);
|
|
if (cksum == (((unsigned char)recv_buf[3] << 8) | (unsigned char)recv_buf[4])) {
|
|
/* init */
|
|
cmd_len = (unsigned short)(((unsigned char)recv_buf[1] << 8) | (unsigned char)recv_buf[2]) + 3;
|
|
if (cmd_len >= sizeof(recv_buf))
|
|
goto head_fail;
|
|
|
|
/* SEND: ack */
|
|
send_buf[0] = ACK;
|
|
serial_putc(send_buf[0]);
|
|
break;
|
|
}
|
|
|
|
head_fail:
|
|
/* init */
|
|
cmd_len = 0;
|
|
memset(recv_buf, 0, sizeof(recv_buf));
|
|
|
|
/* SEND: nak */
|
|
send_buf[0] = NAK;
|
|
serial_putc(send_buf[0]);
|
|
|
|
} while (1);
|
|
|
|
do {
|
|
do {
|
|
cr = recv_byte();
|
|
} while (cr != XCMD);
|
|
|
|
recv_buf[0] = (char)cr;
|
|
|
|
/* RECV: cmd data, cmd_len check in head flow */
|
|
for (i = 0;i < (cmd_len - 1); i++) {
|
|
recv_buf[i + 1] = recv_data();
|
|
}
|
|
|
|
/* crc check */
|
|
cksum = calc_crc16((unsigned char*)recv_buf, cmd_len - 2);
|
|
if (cksum == (((unsigned char)recv_buf[cmd_len - 2] << 8) | (unsigned char)recv_buf[cmd_len - 1])) {
|
|
/* SEND: ack wait result */
|
|
send_buf[0] = ACK;
|
|
serial_putc(send_buf[0]);
|
|
break;
|
|
}
|
|
|
|
memset(recv_buf, 0, sizeof(recv_buf));
|
|
/* SEND: nak */
|
|
send_buf[0] = NAK;
|
|
serial_putc(send_buf[0]);
|
|
#ifdef DUMP_SWITCH
|
|
dump_buf(recv_buf, cmd_len);
|
|
#endif
|
|
} while (1);
|
|
|
|
/* clean crc */
|
|
recv_buf[cmd_len - 1] = 0;
|
|
recv_buf[cmd_len - 2] = 0;
|
|
|
|
/* cmd process */
|
|
ret = run_command((recv_buf + 1), 0);
|
|
if (ret != 0) {
|
|
/* SEND: end flag */
|
|
serial_puts("[EOT](ERROR)\n");
|
|
} else{
|
|
/* SEND: end flag */
|
|
serial_puts("[EOT](OK)\n");
|
|
}
|
|
|
|
} while (1);
|
|
}
|
|
|
|
void set_update_mode_flag(int flag)
|
|
{
|
|
#ifdef REG_UPDATE_MODE_FLAG
|
|
writel(flag, REG_UPDATE_MODE_FLAG);
|
|
#endif
|
|
}
|
|
|
|
int is_bootstrap(void)
|
|
{
|
|
if (readl(REG_START_FLAG) == START_MAGIC)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
void set_bootstrap_flag(u32 flag)
|
|
{
|
|
writel(flag, REG_START_FLAG);
|
|
writel(flag, SYS_CTRL_REG_BASE + REG_SC_DDRT14);
|
|
}
|
|
|
|
void usb_eth_init(void)
|
|
{
|
|
/* Support usb eth */
|
|
run_command("usb start", 0);
|
|
}
|
|
|
|
int is_usb_device_bootstrap(void)
|
|
{
|
|
if (readl(SYS_CTRL_REG_BASE + REG_SC_SYSBOOT9) == SELF_BOOT_TYPE_USBDEV)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
void download_boot(void)
|
|
{
|
|
if (!is_bootstrap())
|
|
return;
|
|
|
|
/* Enable uart output for download */
|
|
serial_enable_output(true);
|
|
|
|
/* Clear flag */
|
|
set_bootstrap_flag(0);
|
|
|
|
if (!is_usb_device_bootstrap())
|
|
usb_eth_init();
|
|
|
|
serial_puts("start download process.\n");
|
|
|
|
/* Wait cmd from tool */
|
|
for (;;) {
|
|
if (is_usb_device_bootstrap()) {
|
|
/* Clear updata mode flag */
|
|
set_update_mode_flag(1);
|
|
#ifdef CONFIG_USB_GADGET
|
|
udc_connect();
|
|
#else
|
|
printf("[ERROR]: Downloading boot from usb NOT supported.\n");
|
|
#endif
|
|
} else
|
|
download_process();
|
|
}
|
|
|
|
serial_enable_output(false);
|
|
}
|