/* * Copyright (c) LOTUS. All rights reserved. */ #include #include #include #include #include #include #include #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); }