diff options
Diffstat (limited to 'drivers/net/wireless/eswin/usb/fw.c')
-rw-r--r-- | drivers/net/wireless/eswin/usb/fw.c | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/drivers/net/wireless/eswin/usb/fw.c b/drivers/net/wireless/eswin/usb/fw.c new file mode 100644 index 000000000000..66254d8f6a64 --- /dev/null +++ b/drivers/net/wireless/eswin/usb/fw.c @@ -0,0 +1,266 @@ +/** +****************************************************************************** +* +* @file fw.c +* +* @brief ecrnx usb firmware download functions +* +* Copyright (C) ESWIN 2015-2020 +* +****************************************************************************** +*/ + +#include <linux/firmware.h> +#include "core.h" +#include "usb.h" +#include "fw_head_check.h" + +extern char *fw_name; + +#define MAX_PACKET_SIZE 512 +#define DATA_ADDR_O 0x20000 + +#define DATA_ADDR_O_1 0x10000 + +struct cfg_sync +{ + char magic; + char type; + short length; + char crc8; +}; + +struct cfg_msg +{ + char magic; + char type; + short length; + unsigned int data_addr; + unsigned int data_len; + char crc8; +}; + +typedef struct _ack_msg +{ + unsigned char magic; + unsigned char type; + unsigned short length; + char data[0]; +} ack_msg; + +typedef enum +{ + STATU_SUCCESS = 0, + STATU_ERR +} ACK_STATUS; + +unsigned char eswin_crc8(unsigned char * buf, unsigned short length) +{ + unsigned char crc = 0, i = 0; + while(length--) + { + crc ^= *buf++; + for(i = 8; i > 0; i--) + { + if(crc & 0x80) + { + crc = (crc << 1) ^ 0x31; + } + else + { + crc <<= 1; + } + } + } + return crc; +} + +char eswin_fw_ack_check(u8 * buff) +{ + ack_msg* msg = (ack_msg*)buff; + if(msg->magic != 0x5a) + { + ECRNX_PRINT("dl-fw ack fail, magic: %d\n", msg->magic); + return -1; + } + if(msg->data[0] != STATU_SUCCESS) + { + ECRNX_PRINT("dl-fw ack fail, status: %d\n", msg->data[0]); + return -1; + } + return 0; +} + +char eswin_fw_file_download(struct eswin *tr) +{ + int ret,i; + unsigned int lengthLeft, lengthSend, offset = HEAD_SIZE, total_send_len = 0; + unsigned char length_str[9]={0}; + const u8 * dataAddr; + u8 * buff; + struct sk_buff *skb; + //char str_msg[16]; + char str_sync[4] = {0x63,0x6e,0x79,0x73}; + unsigned int file_load_addr[3] = {0x20000U, 0x40000U, 0x50000U}; // ilm addr(start addr); dlm addr; iram0 addr + + struct cfg_msg * p_msg; + struct cfg_sync * p_sync; + u8 prev_dl_pst = 0; + + skb = dev_alloc_skb(MAX_PACKET_SIZE + 16); + buff = (u8 *)skb->data; + + p_msg = (struct cfg_msg *)buff; + p_sync = (struct cfg_sync *)buff; + + lengthLeft = tr->fw->size; + dataAddr = tr->fw->data; + + /* 0 download sync*/ + memcpy(buff,str_sync,4); + tr->ops->write(tr,buff,4); + ret = tr->ops->wait_ack(tr,buff,1); + ECRNX_PRINT("dl-fw >> sync, ret: %d\n", ret); + if((buff[0] != '3')||(ret < 0)) + { + ECRNX_PRINT("dl-fw >> download sync fail, ack: %d\n", buff[0]); + dev_kfree_skb(skb); + return -1; + } + /* 1 usb sync */ + p_sync->magic = 0xA5; + p_sync->type = 0x00; + p_sync->length = 0x00; + p_sync->crc8 = eswin_crc8(buff,sizeof(struct cfg_msg)-1); + + tr->ops->write(tr, buff, sizeof(struct cfg_sync)); + ret = tr->ops->wait_ack(tr, buff, 6); + ECRNX_PRINT("dl-fw >> sync, ret: %d\n", ret); + if((eswin_fw_ack_check(buff) < 0)||(ret < 0)) + { + dev_kfree_skb(skb); + ECRNX_PRINT("fimeware download fail! \n"); + return -1; + } + + for(i=0;i<3;i++) + { + memcpy(length_str, dataAddr + offset, 8); + ret = kstrtoint(length_str, 10, (int*)&lengthLeft); + offset+=8; + /* 2 cfg */ + p_msg->magic = 0xA5; + p_msg->type = 0x01; + p_msg->length = 0x08; + p_msg->data_addr = file_load_addr[i]; + p_msg->data_len = lengthLeft; + p_msg->crc8 = 0x00; + + tr->ops->write(tr, buff, sizeof(struct cfg_msg)); + ret = tr->ops->wait_ack(tr, buff, 6); + if((eswin_fw_ack_check(buff) < 0)||(ret < 0)) + { + dev_kfree_skb(skb); + ECRNX_PRINT("fimeware download fail! \n"); + return -1; + } + + buff[0] = 0xA5; + buff[1] = 0x01; + + /* 3 load fw */ + do { + lengthSend = (lengthLeft >= MAX_PACKET_SIZE) ? MAX_PACKET_SIZE : lengthLeft; + total_send_len += lengthSend; + + buff[0] = 0xA5; + buff[1] = 0x01; + buff[2] = lengthSend & 0xFF; + buff[3] = (lengthSend>>8) & 0xFF; + + memcpy(&buff[4], dataAddr + offset, lengthSend); + tr->ops->write(tr, buff, lengthSend + 5); + + if(lengthSend >= MAX_PACKET_SIZE) + { + if(prev_dl_pst < total_send_len/(tr->fw->size/100)) + { + prev_dl_pst = total_send_len/(tr->fw->size/100); + ECRNX_PRINT("firmware downloading %d%% \n", prev_dl_pst); + } + } + else if(i == 2) + { + ECRNX_PRINT("firmware downloading 100%% \n"); + } + + ret = tr->ops->wait_ack(tr, buff, 6); + if((eswin_fw_ack_check(buff) < 0)||(ret < 0)) + { + dev_kfree_skb(skb); + ECRNX_PRINT("fimeware download fail! \n"); + return -1; + } + offset += lengthSend; + lengthLeft -= lengthSend; + } while(lengthLeft); + } + + /* 4 start up */ + buff[0] = 0xA5; + buff[1] = 0x06; + buff[2] = 0x02; + buff[3] = 0x00; + + buff[4] = (char)((file_load_addr[0]) & 0xFF); + buff[5] = (char)(((file_load_addr[0])>>8) & 0xFF); + buff[6] = (char)(((file_load_addr[0])>>16) & 0xFF); + buff[7] = (char)(((file_load_addr[0])>>24) & 0xFF); + + tr->ops->write(tr, skb->data, 9); + tr->ops->wait_ack(tr, buff, 6); + if((eswin_fw_ack_check(buff) < 0)||(ret < 0)) + { + dev_kfree_skb(skb); + ECRNX_PRINT("fimeware download fail! \n"); + return -1; + } + + ECRNX_PRINT("fimeware download successfully! \n"); + + dev_kfree_skb(skb); + return 0; +} + +bool eswin_fw_file_chech(struct eswin *tr) +{ + int status; + + if (fw_name == NULL) + goto err_fw; + + + //if (tr->fw) + // return true; + + ECRNX_PRINT("%s, Checking firmware... (%s)\n", __func__, fw_name); + + status = request_firmware((const struct firmware **)&tr->fw, fw_name, tr->dev); + if (status != 0) { + ECRNX_PRINT("%s, error status = %d\n", __func__, status); + goto err_fw; + } + + ECRNX_PRINT("%s, request fw OK and size is %d\n", __func__, tr->fw->size); + + if(fw_check_head(tr) == false) + { + goto err_fw; + } + return true; + +err_fw: + tr->fw = NULL; + return false; +} + |