diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2010-10-28 09:44:56 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-10-28 09:44:56 -0700 |
commit | e4c5bf8e3dca827a1b3a6fac494eae8c74b7e1e7 (patch) | |
tree | ea51b391f7d74ca695dcb9f5e46eb02688a92ed9 /drivers/staging/ft1000/ft1000-usb/ft1000_download.c | |
parent | 81280572ca6f54009edfa4deee563e8678784218 (diff) | |
parent | a4ac0d847af9dd34d5953a5e264400326144b6b2 (diff) | |
download | op-kernel-dev-e4c5bf8e3dca827a1b3a6fac494eae8c74b7e1e7.zip op-kernel-dev-e4c5bf8e3dca827a1b3a6fac494eae8c74b7e1e7.tar.gz |
Merge 'staging-next' to Linus's tree
This merges the staging-next tree to Linus's tree and resolves
some conflicts that were present due to changes in other trees that were
affected by files here.
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/ft1000/ft1000-usb/ft1000_download.c')
-rw-r--r-- | drivers/staging/ft1000/ft1000-usb/ft1000_download.c | 1248 |
1 files changed, 1248 insertions, 0 deletions
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c new file mode 100644 index 0000000..4dd456f --- /dev/null +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c @@ -0,0 +1,1248 @@ +//===================================================== +// CopyRight (C) 2007 Qualcomm Inc. All Rights Reserved. +// +// +// This file is part of Express Card USB Driver +// +// $Id: +//==================================================== +// 20090926; aelias; removed compiler warnings; ubuntu 9.04; 2.6.28-15-generic + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/usb.h> +#include <linux/vmalloc.h> +#include "ft1000_usb.h" + + +#define DWNLD_HANDSHAKE_LOC 0x02 +#define DWNLD_TYPE_LOC 0x04 +#define DWNLD_SIZE_MSW_LOC 0x06 +#define DWNLD_SIZE_LSW_LOC 0x08 +#define DWNLD_PS_HDR_LOC 0x0A + +#define MAX_DSP_WAIT_LOOPS 40 +#define DSP_WAIT_SLEEP_TIME 1000 /* 1 millisecond */ +#define DSP_WAIT_DISPATCH_LVL 50 /* 50 usec */ + +#define HANDSHAKE_TIMEOUT_VALUE 0xF1F1 +#define HANDSHAKE_RESET_VALUE 0xFEFE /* When DSP requests startover */ +#define HANDSHAKE_RESET_VALUE_USB 0xFE7E /* When DSP requests startover */ +#define HANDSHAKE_DSP_BL_READY 0xFEFE /* At start DSP writes this when bootloader ready */ +#define HANDSHAKE_DSP_BL_READY_USB 0xFE7E /* At start DSP writes this when bootloader ready */ +#define HANDSHAKE_DRIVER_READY 0xFFFF /* Driver writes after receiving 0xFEFE */ +#define HANDSHAKE_SEND_DATA 0x0000 /* DSP writes this when ready for more data */ + +#define HANDSHAKE_REQUEST 0x0001 /* Request from DSP */ +#define HANDSHAKE_RESPONSE 0x0000 /* Satisfied DSP request */ + +#define REQUEST_CODE_LENGTH 0x0000 +#define REQUEST_RUN_ADDRESS 0x0001 +#define REQUEST_CODE_SEGMENT 0x0002 /* In WORD count */ +#define REQUEST_DONE_BL 0x0003 +#define REQUEST_DONE_CL 0x0004 +#define REQUEST_VERSION_INFO 0x0005 +#define REQUEST_CODE_BY_VERSION 0x0006 +#define REQUEST_MAILBOX_DATA 0x0007 +#define REQUEST_FILE_CHECKSUM 0x0008 + +#define STATE_START_DWNLD 0x01 +#define STATE_BOOT_DWNLD 0x02 +#define STATE_CODE_DWNLD 0x03 +#define STATE_DONE_DWNLD 0x04 +#define STATE_SECTION_PROV 0x05 +#define STATE_DONE_PROV 0x06 +#define STATE_DONE_FILE 0x07 + +#define MAX_LENGTH 0x7f0 + +// Temporary download mechanism for Magnemite +#define DWNLD_MAG_TYPE_LOC 0x00 +#define DWNLD_MAG_LEN_LOC 0x01 +#define DWNLD_MAG_ADDR_LOC 0x02 +#define DWNLD_MAG_CHKSUM_LOC 0x03 +#define DWNLD_MAG_VAL_LOC 0x04 + +#define HANDSHAKE_MAG_DSP_BL_READY 0xFEFE0000 /* At start DSP writes this when bootloader ready */ +#define HANDSHAKE_MAG_DSP_ENTRY 0x01000000 /* Dsp writes this to request for entry address */ +#define HANDSHAKE_MAG_DSP_DATA 0x02000000 /* Dsp writes this to request for data block */ +#define HANDSHAKE_MAG_DSP_DONE 0x03000000 /* Dsp writes this to indicate download done */ + +#define HANDSHAKE_MAG_DRV_READY 0xFFFF0000 /* Driver writes this to indicate ready to download */ +#define HANDSHAKE_MAG_DRV_DATA 0x02FECDAB /* Driver writes this to indicate data available to DSP */ +#define HANDSHAKE_MAG_DRV_ENTRY 0x01FECDAB /* Driver writes this to indicate entry point to DSP */ + +#define HANDSHAKE_MAG_TIMEOUT_VALUE 0xF1F1 + + +// New Magnemite downloader +#define DWNLD_MAG1_HANDSHAKE_LOC 0x00 +#define DWNLD_MAG1_TYPE_LOC 0x01 +#define DWNLD_MAG1_SIZE_LOC 0x02 +#define DWNLD_MAG1_PS_HDR_LOC 0x03 + +struct dsp_file_hdr { + long version_id; // Version ID of this image format. + long package_id; // Package ID of code release. + long build_date; // Date/time stamp when file was built. + long commands_offset; // Offset to attached commands in Pseudo Hdr format. + long loader_offset; // Offset to bootloader code. + long loader_code_address; // Start address of bootloader. + long loader_code_end; // Where bootloader code ends. + long loader_code_size; + long version_data_offset; // Offset were scrambled version data begins. + long version_data_size; // Size, in words, of scrambled version data. + long nDspImages; // Number of DSP images in file. +}; + +#pragma pack(1) +struct dsp_image_info { + long coff_date; // Date/time when DSP Coff image was built. + long begin_offset; // Offset in file where image begins. + long end_offset; // Offset in file where image begins. + long run_address; // On chip Start address of DSP code. + long image_size; // Size of image. + long version; // Embedded version # of DSP code. + unsigned short checksum; // DSP File checksum + unsigned short pad1; +}; + + +//--------------------------------------------------------------------------- +// Function: check_usb_db +// +// Parameters: struct ft1000_device - device structure +// +// Returns: 0 - success +// +// Description: This function checks if the doorbell register is cleared +// +// Notes: +// +//--------------------------------------------------------------------------- +static ULONG check_usb_db (struct ft1000_device *ft1000dev) +{ + int loopcnt; + USHORT temp; + ULONG status; + + loopcnt = 0; + while (loopcnt < 10) + { + + status = ft1000_read_register (ft1000dev, &temp, FT1000_REG_DOORBELL); + DEBUG("check_usb_db: read FT1000_REG_DOORBELL value is %x\n", temp); + if (temp & 0x0080) + { + DEBUG("FT1000:Got checkusb doorbell\n"); + status = ft1000_write_register (ft1000dev, 0x0080, FT1000_REG_DOORBELL); + status = ft1000_write_register (ft1000dev, 0x0100, FT1000_REG_DOORBELL); + status = ft1000_write_register (ft1000dev, 0x8000, FT1000_REG_DOORBELL); + break; + } + else + { + loopcnt++; + msleep (10); + } + + } //end of while + + + loopcnt = 0; + while (loopcnt < 20) + { + + status = ft1000_read_register (ft1000dev, &temp, FT1000_REG_DOORBELL); + DEBUG("FT1000:check_usb_db:Doorbell = 0x%x\n", temp); + if (temp & 0x8000) + { + loopcnt++; + msleep (10); + } + else + { + DEBUG("check_usb_db: door bell is cleared, return 0\n"); + return 0; + } +#if 0 + // Check if Card is present + status = ft1000_read_register (ft1000dev, &temp, FT1000_REG_SUP_IMASK); + if (temp == 0x0000) { + break; + } + + status = ft1000_read_register (ft1000dev, &temp, FT1000_REG_ASIC_ID); + if (temp == 0xffff) { + break; + } +#endif + } + + return HANDSHAKE_MAG_TIMEOUT_VALUE; + +} + +//--------------------------------------------------------------------------- +// Function: get_handshake +// +// Parameters: struct ft1000_device - device structure +// USHORT expected_value - the handshake value expected +// +// Returns: handshakevalue - success +// HANDSHAKE_TIMEOUT_VALUE - failure +// +// Description: This function gets the handshake and compare with the expected value +// +// Notes: +// +//--------------------------------------------------------------------------- +static USHORT get_handshake(struct ft1000_device *ft1000dev, USHORT expected_value) +{ + USHORT handshake; + int loopcnt; + ULONG status=0; + struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); + + loopcnt = 0; + while (loopcnt < 100) + { + + // Need to clear downloader doorbell if Hartley ASIC + status = ft1000_write_register (ft1000dev, FT1000_DB_DNLD_RX, FT1000_REG_DOORBELL); + //DEBUG("FT1000:get_handshake:doorbell = 0x%x\n", temp); + if (pft1000info->fcodeldr) + { + DEBUG(" get_handshake: fcodeldr is %d\n", pft1000info->fcodeldr); + pft1000info->fcodeldr = 0; + status = check_usb_db(ft1000dev); + if (status != STATUS_SUCCESS) + { + DEBUG("get_handshake: check_usb_db failed\n"); + status = STATUS_FAILURE; + break; + } + status = ft1000_write_register (ft1000dev, FT1000_DB_DNLD_RX, FT1000_REG_DOORBELL); + } + + status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (PUCHAR)&handshake, 1); + //DEBUG("get_handshake: handshake is %x\n", tempx); + handshake = ntohs(handshake); + //DEBUG("get_handshake: after swap, handshake is %x\n", handshake); + + if (status) + return HANDSHAKE_TIMEOUT_VALUE; + + //DEBUG("get_handshake: handshake= %x\n", handshake); + if ((handshake == expected_value) || (handshake == HANDSHAKE_RESET_VALUE_USB)) + { + //DEBUG("get_handshake: return handshake %x\n", handshake); + return handshake; + } + else + { + loopcnt++; + msleep (10); + } + //DEBUG("HANDSHKE LOOP: %d\n", loopcnt); + + } + + //DEBUG("get_handshake: return handshake time out\n"); + return HANDSHAKE_TIMEOUT_VALUE; +} + +//--------------------------------------------------------------------------- +// Function: put_handshake +// +// Parameters: struct ft1000_device - device structure +// USHORT handshake_value - handshake to be written +// +// Returns: none +// +// Description: This function write the handshake value to the handshake location +// in DPRAM +// +// Notes: +// +//--------------------------------------------------------------------------- +static void put_handshake(struct ft1000_device *ft1000dev,USHORT handshake_value) +{ + ULONG tempx; + USHORT tempword; + ULONG status; + + + + tempx = (ULONG)handshake_value; + tempx = ntohl(tempx); + + tempword = (USHORT)(tempx & 0xffff); + status = ft1000_write_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, tempword, 0); + tempword = (USHORT)(tempx >> 16); + status = ft1000_write_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, tempword, 1); + status = ft1000_write_register(ft1000dev, FT1000_DB_DNLD_TX, FT1000_REG_DOORBELL); +} + +static USHORT get_handshake_usb(struct ft1000_device *ft1000dev, USHORT expected_value) +{ + USHORT handshake; + int loopcnt; + USHORT temp; + ULONG status=0; + + struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); + loopcnt = 0; + handshake = 0; + while (loopcnt < 100) + { + if (pft1000info->usbboot == 2) { + status = ft1000_read_dpram32 (ft1000dev, 0, (PUCHAR)&(pft1000info->tempbuf[0]), 64); + for (temp=0; temp<16; temp++) + DEBUG("tempbuf %d = 0x%x\n", temp, pft1000info->tempbuf[temp]); + status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (PUCHAR)&handshake, 1); + DEBUG("handshake from read_dpram16 = 0x%x\n", handshake); + if (pft1000info->dspalive == pft1000info->tempbuf[6]) + handshake = 0; + else { + handshake = pft1000info->tempbuf[1]; + pft1000info->dspalive = pft1000info->tempbuf[6]; + } + } + else { + status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (PUCHAR)&handshake, 1); + } + loopcnt++; + msleep(10); + handshake = ntohs(handshake); + if ((handshake == expected_value) || (handshake == HANDSHAKE_RESET_VALUE_USB)) + { + return handshake; + } + } + + return HANDSHAKE_TIMEOUT_VALUE; +} + +static void put_handshake_usb(struct ft1000_device *ft1000dev,USHORT handshake_value) +{ + int i; + + for (i=0; i<1000; i++); +} + +//--------------------------------------------------------------------------- +// Function: get_request_type +// +// Parameters: struct ft1000_device - device structure +// +// Returns: request type - success +// +// Description: This function returns the request type +// +// Notes: +// +//--------------------------------------------------------------------------- +static USHORT get_request_type(struct ft1000_device *ft1000dev) +{ + USHORT request_type; + ULONG status; + USHORT tempword; + ULONG tempx; + struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); + + if ( pft1000info->bootmode == 1) + { + status = fix_ft1000_read_dpram32 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (PUCHAR)&tempx); + tempx = ntohl(tempx); + } + else + { + tempx = 0; + + status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (PUCHAR)&tempword, 1); + tempx |= (tempword << 16); + tempx = ntohl(tempx); + } + request_type = (USHORT)tempx; + + //DEBUG("get_request_type: request_type is %x\n", request_type); + return request_type; + +} + +static USHORT get_request_type_usb(struct ft1000_device *ft1000dev) +{ + USHORT request_type; + ULONG status; + USHORT tempword; + ULONG tempx; + struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); + if ( pft1000info->bootmode == 1) + { + status = fix_ft1000_read_dpram32 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (PUCHAR)&tempx); + tempx = ntohl(tempx); + } + else + { + if (pft1000info->usbboot == 2) { + tempx = pft1000info->tempbuf[2]; + tempword = pft1000info->tempbuf[3]; + } + else { + tempx = 0; + status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (PUCHAR)&tempword, 1); + } + tempx |= (tempword << 16); + tempx = ntohl(tempx); + } + request_type = (USHORT)tempx; + + //DEBUG("get_request_type: request_type is %x\n", request_type); + return request_type; + +} + +//--------------------------------------------------------------------------- +// Function: get_request_value +// +// Parameters: struct ft1000_device - device structure +// +// Returns: request value - success +// +// Description: This function returns the request value +// +// Notes: +// +//--------------------------------------------------------------------------- +static long get_request_value(struct ft1000_device *ft1000dev) +{ + ULONG value; + USHORT tempword; + ULONG status; + struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); + + + if ( pft1000info->bootmode == 1) + { + status = fix_ft1000_read_dpram32(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&value); + value = ntohl(value); + } + else + { + status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&tempword, 0); + value = tempword; + status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&tempword, 1); + value |= (tempword << 16); + value = ntohl(value); + } + + + //DEBUG("get_request_value: value is %x\n", value); + return value; + +} + +#if 0 +static long get_request_value_usb(struct ft1000_device *ft1000dev) +{ + ULONG value; + USHORT tempword; + ULONG status; + struct ft1000_info * pft1000info = netdev_priv(ft1000dev->net); + + if (pft1000info->usbboot == 2) { + value = pft1000info->tempbuf[4]; + tempword = pft1000info->tempbuf[5]; + } + else { + value = 0; + status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&tempword, 1); + } + + value |= (tempword << 16); + value = ntohl(value); + + if (pft1000info->usbboot == 1) + pft1000info->usbboot = 2; + + //DEBUG("get_request_value_usb: value is %x\n", value); + return value; + +} +#endif + +//--------------------------------------------------------------------------- +// Function: put_request_value +// +// Parameters: struct ft1000_device - device structure +// long lvalue - value to be put into DPRAM location DWNLD_MAG1_SIZE_LOC +// +// Returns: none +// +// Description: This function writes a value to DWNLD_MAG1_SIZE_LOC +// +// Notes: +// +//--------------------------------------------------------------------------- +static void put_request_value(struct ft1000_device *ft1000dev, long lvalue) +{ + ULONG tempx; + ULONG status; + + tempx = ntohl(lvalue); + status = fix_ft1000_write_dpram32(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&tempx); + + + + //DEBUG("put_request_value: value is %x\n", lvalue); + +} + + + +//--------------------------------------------------------------------------- +// Function: hdr_checksum +// +// Parameters: struct pseudo_hdr *pHdr - Pseudo header pointer +// +// Returns: checksum - success +// +// Description: This function returns the checksum of the pseudo header +// +// Notes: +// +//--------------------------------------------------------------------------- +static USHORT hdr_checksum(struct pseudo_hdr *pHdr) +{ + USHORT *usPtr = (USHORT *)pHdr; + USHORT chksum; + + + chksum = ((((((usPtr[0] ^ usPtr[1]) ^ usPtr[2]) ^ usPtr[3]) ^ + usPtr[4]) ^ usPtr[5]) ^ usPtr[6]); + + return chksum; +} + + +//--------------------------------------------------------------------------- +// Function: write_blk +// +// Parameters: struct ft1000_device - device structure +// USHORT **pUsFile - DSP image file pointer in USHORT +// UCHAR **pUcFile - DSP image file pointer in UCHAR +// long word_length - lenght of the buffer to be written +// to DPRAM +// +// Returns: STATUS_SUCCESS - success +// STATUS_FAILURE - failure +// +// Description: This function writes a block of DSP image to DPRAM +// +// Notes: +// +//--------------------------------------------------------------------------- +static ULONG write_blk (struct ft1000_device *ft1000dev, USHORT **pUsFile, UCHAR **pUcFile, long word_length) +{ + ULONG Status = STATUS_SUCCESS; + USHORT dpram; + long temp_word_length; + int loopcnt, i, j; + USHORT *pTempFile; + USHORT tempword; + USHORT tempbuffer[64]; + USHORT resultbuffer[64]; + struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); + + //DEBUG("FT1000:download:start word_length = %d\n",(int)word_length); + dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC; + tempword = *(*pUsFile); + (*pUsFile)++; + Status = ft1000_write_dpram16(ft1000dev, dpram, tempword, 0); + tempword = *(*pUsFile); + (*pUsFile)++; + Status = ft1000_write_dpram16(ft1000dev, dpram++, tempword, 1); + + *pUcFile = *pUcFile + 4; + word_length--; + tempword = (USHORT)word_length; + word_length = (word_length / 16) + 1; + pTempFile = *pUsFile; + temp_word_length = word_length; + for (; word_length > 0; word_length--) /* In words */ + { + loopcnt = 0; + + for (i=0; i<32; i++) + { + if (tempword != 0) + { + tempbuffer[i++] = *(*pUsFile); + (*pUsFile)++; + tempbuffer[i] = *(*pUsFile); + (*pUsFile)++; + *pUcFile = *pUcFile + 4; + loopcnt++; + tempword--; + } + else + { + tempbuffer[i++] = 0; + tempbuffer[i] = 0; + } + } + + //DEBUG("write_blk: loopcnt is %d\n", loopcnt); + //DEBUG("write_blk: bootmode = %d\n", bootmode); + //DEBUG("write_blk: dpram = %x\n", dpram); + if (pft1000info->bootmode == 0) + { + if (dpram >= 0x3F4) + Status = ft1000_write_dpram32 (ft1000dev, dpram, (PUCHAR)&tempbuffer[0], 8); + else + Status = ft1000_write_dpram32 (ft1000dev, dpram, (PUCHAR)&tempbuffer[0], 64); + } + else + { + for (j=0; j<10; j++) + { + Status = ft1000_write_dpram32 (ft1000dev, dpram, (PUCHAR)&tempbuffer[0], 64); + if (Status == STATUS_SUCCESS) + { + // Work around for ASIC bit stuffing problem. + if ( (tempbuffer[31] & 0xfe00) == 0xfe00) + { + Status = ft1000_write_dpram32(ft1000dev, dpram+12, (PUCHAR)&tempbuffer[24], 64); + } + // Let's check the data written + Status = ft1000_read_dpram32 (ft1000dev, dpram, (PUCHAR)&resultbuffer[0], 64); + if ( (tempbuffer[31] & 0xfe00) == 0xfe00) + { + for (i=0; i<28; i++) + { + if (resultbuffer[i] != tempbuffer[i]) + { + //NdisMSleep (100); + DEBUG("FT1000:download:DPRAM write failed 1 during bootloading\n"); + msleep(10); + Status = STATUS_FAILURE; + break; + } + } + Status = ft1000_read_dpram32 (ft1000dev, dpram+12, (PUCHAR)&resultbuffer[0], 64); + for (i=0; i<16; i++) + { + if (resultbuffer[i] != tempbuffer[i+24]) + { + //NdisMSleep (100); + DEBUG("FT1000:download:DPRAM write failed 2 during bootloading\n"); + msleep(10); + Status = STATUS_FAILURE; + break; + } + } + } + else + { + for (i=0; i<32; i++) + { + if (resultbuffer[i] != tempbuffer[i]) + { + //NdisMSleep (100); + DEBUG("FT1000:download:DPRAM write failed 3 during bootloading\n"); + msleep(10); + Status = STATUS_FAILURE; + break; + } + } + } + + if (Status == STATUS_SUCCESS) + break; + + } + } + + if (Status != STATUS_SUCCESS) + { + DEBUG("FT1000:download:Write failed tempbuffer[31] = 0x%x\n", tempbuffer[31]); + break; + } + + } + dpram = dpram + loopcnt; + } + + return Status; +} + +static void usb_dnld_complete (struct urb *urb) +{ + //DEBUG("****** usb_dnld_complete\n"); +} + +//--------------------------------------------------------------------------- +// Function: write_blk_fifo +// +// Parameters: struct ft1000_device - device structure +// USHORT **pUsFile - DSP image file pointer in USHORT +// UCHAR **pUcFile - DSP image file pointer in UCHAR +// long word_length - lenght of the buffer to be written +// to DPRAM +// +// Returns: STATUS_SUCCESS - success +// STATUS_FAILURE - failure +// +// Description: This function writes a block of DSP image to DPRAM +// +// Notes: +// +//--------------------------------------------------------------------------- +static ULONG write_blk_fifo (struct ft1000_device *ft1000dev, USHORT **pUsFile, UCHAR **pUcFile, long word_length) +{ + ULONG Status = STATUS_SUCCESS; + int byte_length; + long aligncnt; + + byte_length = word_length * 4; + + if (byte_length % 4) + aligncnt = 4 - (byte_length % 4); + else + aligncnt = 0; + byte_length += aligncnt; + + if (byte_length && ((byte_length % 64) == 0)) { + byte_length += 4; + } + + if (byte_length < 64) + byte_length = 68; + +#if 0 + pblk = kzalloc(byte_length, GFP_KERNEL); + memcpy (pblk, *pUcFile, byte_length); + + pipe = usb_sndbulkpipe (ft1000dev->dev, ft1000dev->bulk_out_endpointAddr); + + Status = usb_bulk_msg (ft1000dev->dev, + pipe, + pblk, + byte_length, + &cnt, + 10); + DEBUG("write_blk_fifo Status = 0x%8x Bytes Transfer = %d Data = 0x%x\n", Status, cnt, *pblk); + + kfree(pblk); +#else + usb_init_urb(ft1000dev->tx_urb); + memcpy (ft1000dev->tx_buf, *pUcFile, byte_length); + usb_fill_bulk_urb(ft1000dev->tx_urb, + ft1000dev->dev, + usb_sndbulkpipe(ft1000dev->dev, ft1000dev->bulk_out_endpointAddr), + ft1000dev->tx_buf, + byte_length, + usb_dnld_complete, + (void*)ft1000dev); + + usb_submit_urb(ft1000dev->tx_urb, GFP_ATOMIC); +#endif + + *pUsFile = *pUsFile + (word_length << 1); + *pUcFile = *pUcFile + (word_length << 2); + + return Status; +} + +//--------------------------------------------------------------------------- +// +// Function: scram_dnldr +// +// Synopsis: Scramble downloader for Harley based ASIC via USB interface +// +// Arguments: pFileStart - pointer to start of file +// FileLength - file length +// +// Returns: status - return code +//--------------------------------------------------------------------------- + +u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLength) +{ + u16 Status = STATUS_SUCCESS; + UINT uiState; + USHORT handshake; + struct pseudo_hdr *pHdr; + USHORT usHdrLength; + long word_length; + USHORT request; + USHORT temp; + USHORT tempword; + + struct dsp_file_hdr *pFileHdr5; + struct dsp_image_info *pDspImageInfoV6 = NULL; + long requested_version; + BOOLEAN bGoodVersion; + struct drv_msg *pMailBoxData; + USHORT *pUsData = NULL; + USHORT *pUsFile = NULL; + UCHAR *pUcFile = NULL; + UCHAR *pBootEnd = NULL, *pCodeEnd= NULL; + int imageN; + long loader_code_address, loader_code_size = 0; + long run_address = 0, run_size = 0; + + ULONG templong; + ULONG image_chksum = 0; + + USHORT dpram = 0; + PUCHAR pbuffer; + struct prov_record *pprov_record; + struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); + + DEBUG("Entered scram_dnldr...\n"); + + pft1000info->fcodeldr = 0; + pft1000info->usbboot = 0; + pft1000info->dspalive = 0xffff; + + + // + // Get version id of file, at first 4 bytes of file, for newer files. + // + + uiState = STATE_START_DWNLD; + + pFileHdr5 = (struct dsp_file_hdr *)pFileStart; + + ft1000_write_register (ft1000dev, 0x800, FT1000_REG_MAG_WATERMARK); + + pUsFile = (USHORT *)(pFileStart + pFileHdr5->loader_offset); + pUcFile = (UCHAR *)(pFileStart + pFileHdr5->loader_offset); + + pBootEnd = (UCHAR *)(pFileStart + pFileHdr5->loader_code_end); + + loader_code_address = pFileHdr5->loader_code_address; + loader_code_size = pFileHdr5->loader_code_size; + bGoodVersion = FALSE; + + while ((Status == STATUS_SUCCESS) && (uiState != STATE_DONE_FILE)) + { + switch (uiState) + { + case STATE_START_DWNLD: + DEBUG("FT1000:STATE_START_DWNLD\n"); + if (pft1000info->usbboot) + handshake = get_handshake_usb(ft1000dev, HANDSHAKE_DSP_BL_READY); + else + handshake = get_handshake(ft1000dev, HANDSHAKE_DSP_BL_READY); + + if (handshake == HANDSHAKE_DSP_BL_READY) + { + DEBUG("scram_dnldr: handshake is HANDSHAKE_DSP_BL_READY, call put_handshake(HANDSHAKE_DRIVER_READY)\n"); + put_handshake(ft1000dev, HANDSHAKE_DRIVER_READY); + } + else + { + DEBUG("FT1000:download:Download error: Handshake failed\n"); + Status = STATUS_FAILURE; + } + + uiState = STATE_BOOT_DWNLD; + + break; + + case STATE_BOOT_DWNLD: + DEBUG("FT1000:STATE_BOOT_DWNLD\n"); + pft1000info->bootmode = 1; + handshake = get_handshake(ft1000dev, HANDSHAKE_REQUEST); + if (handshake == HANDSHAKE_REQUEST) + { + /* + * Get type associated with the request. + */ + request = get_request_type(ft1000dev); + switch (request) + { + case REQUEST_RUN_ADDRESS: + DEBUG("FT1000:REQUEST_RUN_ADDRESS\n"); + put_request_value(ft1000dev, loader_code_address); + break; + case REQUEST_CODE_LENGTH: + DEBUG("FT1000:REQUEST_CODE_LENGTH\n"); + put_request_value(ft1000dev, loader_code_size); + break; + case REQUEST_DONE_BL: + DEBUG("FT1000:REQUEST_DONE_BL\n"); + /* Reposition ptrs to beginning of code section */ + pUsFile = (USHORT *)(pBootEnd); + pUcFile = (UCHAR *)(pBootEnd); + //DEBUG("FT1000:download:pUsFile = 0x%8x\n", (int)pUsFile); + //DEBUG("FT1000:download:pUcFile = 0x%8x\n", (int)pUcFile); + uiState = STATE_CODE_DWNLD; + pft1000info->fcodeldr = 1; + break; + case REQUEST_CODE_SEGMENT: + //DEBUG("FT1000:REQUEST_CODE_SEGMENT\n"); + word_length = get_request_value(ft1000dev); + //DEBUG("FT1000:word_length = 0x%x\n", (int)word_length); + //NdisMSleep (100); + if (word_length > MAX_LENGTH) + { + DEBUG("FT1000:download:Download error: Max length exceeded\n"); + Status = STATUS_FAILURE; + break; + } + if ( (word_length*2 + pUcFile) > pBootEnd) + { + /* + * Error, beyond boot code range. + */ + DEBUG("FT1000:download:Download error: Requested len=%d exceeds BOOT code boundry.\n", + (int)word_length); + Status = STATUS_FAILURE; + break; + } + /* + * Position ASIC DPRAM auto-increment pointer. + */ + dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC; + if (word_length & 0x1) + word_length++; + word_length = word_length / 2; + + Status = write_blk(ft1000dev, &pUsFile, &pUcFile, word_length); + //DEBUG("write_blk returned %d\n", Status); + break; + default: + DEBUG("FT1000:download:Download error: Bad request type=%d in BOOT download state.\n",request); + Status = STATUS_FAILURE; + break; + } + if (pft1000info->usbboot) + put_handshake_usb(ft1000dev, HANDSHAKE_RESPONSE); + else + put_handshake(ft1000dev, HANDSHAKE_RESPONSE); + } + else + { + DEBUG("FT1000:download:Download error: Handshake failed\n"); + Status = STATUS_FAILURE; + } + + break; + + case STATE_CODE_DWNLD: + //DEBUG("FT1000:STATE_CODE_DWNLD\n"); + pft1000info->bootmode = 0; + if (pft1000info->usbboot) + handshake = get_handshake_usb(ft1000dev, HANDSHAKE_REQUEST); + else + handshake = get_handshake(ft1000dev, HANDSHAKE_REQUEST); + if (handshake == HANDSHAKE_REQUEST) + { + /* + * Get type associated with the request. + */ + if (pft1000info->usbboot) + request = get_request_type_usb(ft1000dev); + else + request = get_request_type(ft1000dev); + switch (request) + { + case REQUEST_FILE_CHECKSUM: + DEBUG("FT1000:download:image_chksum = 0x%8x\n", image_chksum); + put_request_value(ft1000dev, image_chksum); + break; + case REQUEST_RUN_ADDRESS: + DEBUG("FT1000:download: REQUEST_RUN_ADDRESS\n"); + if (bGoodVersion) + { + DEBUG("FT1000:download:run_address = 0x%8x\n", (int)run_address); + put_request_value(ft1000dev, run_address); + } + else + { + DEBUG("FT1000:download:Download error: Got Run address request before image offset request.\n"); + Status = STATUS_FAILURE; + break; + } + break; + case REQUEST_CODE_LENGTH: + DEBUG("FT1000:download:REQUEST_CODE_LENGTH\n"); + if (bGoodVersion) + { + DEBUG("FT1000:download:run_size = 0x%8x\n", (int)run_size); + put_request_value(ft1000dev, run_size); + } + else + { + DEBUG("FT1000:download:Download error: Got Size request before image offset request.\n"); + Status = STATUS_FAILURE; + break; + } + break; + case REQUEST_DONE_CL: + pft1000info->usbboot = 3; + /* Reposition ptrs to beginning of provisioning section */ + pUsFile = (USHORT *)(pFileStart + pFileHdr5->commands_offset); + pUcFile = (UCHAR *)(pFileStart + pFileHdr5->commands_offset); + uiState = STATE_DONE_DWNLD; + break; + case REQUEST_CODE_SEGMENT: + //DEBUG("FT1000:download: REQUEST_CODE_SEGMENT - CODELOADER\n"); + if (!bGoodVersion) + { + DEBUG("FT1000:download:Download error: Got Code Segment request before image offset request.\n"); + Status = STATUS_FAILURE; + break; + } +#if 0 + word_length = get_request_value_usb(ft1000dev); + //DEBUG("FT1000:download:word_length = %d\n", (int)word_length); + if (word_length > MAX_LENGTH/2) +#else + word_length = get_request_value(ft1000dev); + //DEBUG("FT1000:download:word_length = %d\n", (int)word_length); + if (word_length > MAX_LENGTH) +#endif + { + DEBUG("FT1000:download:Download error: Max length exceeded\n"); + Status = STATUS_FAILURE; + break; + } + if ( (word_length*2 + pUcFile) > pCodeEnd) + { + /* + * Error, beyond boot code range. + */ + DEBUG("FT1000:download:Download error: Requested len=%d exceeds DSP code boundry.\n", + (int)word_length); + Status = STATUS_FAILURE; + break; + } + /* + * Position ASIC DPRAM auto-increment pointer. + */ + dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC; + if (word_length & 0x1) + word_length++; + word_length = word_length / 2; + + write_blk_fifo (ft1000dev, &pUsFile, &pUcFile, word_length); + if (pft1000info->usbboot == 0) + pft1000info->usbboot++; + if (pft1000info->usbboot == 1) { + tempword = 0; + ft1000_write_dpram16 (ft1000dev, DWNLD_MAG1_PS_HDR_LOC, tempword, 0); + } + + break; + + case REQUEST_MAILBOX_DATA: + DEBUG("FT1000:download: REQUEST_MAILBOX_DATA\n"); + // Convert length from byte count to word count. Make sure we round up. + word_length = (long)(pft1000info->DSPInfoBlklen + 1)/2; + put_request_value(ft1000dev, word_length); + pMailBoxData = (struct drv_msg *)&(pft1000info->DSPInfoBlk[0]); + /* + * Position ASIC DPRAM auto-increment pointer. + */ + + + pUsData = (USHORT *)&pMailBoxData->data[0]; + dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC; + if (word_length & 0x1) + word_length++; + + word_length = (word_length / 2); + + + for (; word_length > 0; word_length--) /* In words */ + { + + templong = *pUsData++; + templong |= (*pUsData++ << 16); + Status = fix_ft1000_write_dpram32 (ft1000dev, dpram++, (PUCHAR)&templong); + + } + break; + + case REQUEST_VERSION_INFO: + DEBUG("FT1000:download:REQUEST_VERSION_INFO\n"); + word_length = pFileHdr5->version_data_size; + put_request_value(ft1000dev, word_length); + /* + * Position ASIC DPRAM auto-increment pointer. + */ + + pUsFile = (USHORT *)(pFileStart + pFileHdr5->version_data_offset); + + + dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC; + if (word_length & 0x1) + word_length++; + + word_length = (word_length / 2); + + + for (; word_length > 0; word_length--) /* In words */ + { + + templong = ntohs(*pUsFile++); + temp = ntohs(*pUsFile++); + templong |= (temp << 16); + Status = fix_ft1000_write_dpram32 (ft1000dev, dpram++, (PUCHAR)&templong); + + } + break; + + case REQUEST_CODE_BY_VERSION: + DEBUG("FT1000:download:REQUEST_CODE_BY_VERSION\n"); + bGoodVersion = FALSE; + requested_version = get_request_value(ft1000dev); + + pDspImageInfoV6 = (struct dsp_image_info *)(pFileStart + sizeof(struct dsp_file_hdr )); + + for (imageN = 0; imageN < pFileHdr5->nDspImages; imageN++) + { + + temp = (USHORT)(pDspImageInfoV6->version); + templong = temp; + temp = (USHORT)(pDspImageInfoV6->version >> 16); + templong |= (temp << 16); + if (templong == (ULONG)requested_version) + { + bGoodVersion = TRUE; + DEBUG("FT1000:download: bGoodVersion is TRUE\n"); + pUsFile = (USHORT *)(pFileStart + pDspImageInfoV6->begin_offset); + pUcFile = (UCHAR *)(pFileStart + pDspImageInfoV6->begin_offset); + pCodeEnd = (UCHAR *)(pFileStart + pDspImageInfoV6->end_offset); + run_address = pDspImageInfoV6->run_address; + run_size = pDspImageInfoV6->image_size; + image_chksum = (ULONG)pDspImageInfoV6->checksum; + break; + } + pDspImageInfoV6++; + + + } //end of for + + if (!bGoodVersion) + { + /* + * Error, beyond boot code range. + */ + DEBUG("FT1000:download:Download error: Bad Version Request = 0x%x.\n",(int)requested_version); + Status = STATUS_FAILURE; + break; + } + break; + + default: + DEBUG("FT1000:download:Download error: Bad request type=%d in CODE download state.\n",request); + Status = STATUS_FAILURE; + break; + } + if (pft1000info->usbboot) + put_handshake_usb(ft1000dev, HANDSHAKE_RESPONSE); + else + put_handshake(ft1000dev, HANDSHAKE_RESPONSE); + } + else + { + DEBUG("FT1000:download:Download error: Handshake failed\n"); + Status = STATUS_FAILURE; + } + + break; + + case STATE_DONE_DWNLD: + DEBUG("FT1000:download:Code loader is done...\n"); + uiState = STATE_SECTION_PROV; + break; + + case STATE_SECTION_PROV: + DEBUG("FT1000:download:STATE_SECTION_PROV\n"); + pHdr = (struct pseudo_hdr *)pUcFile; + + if (pHdr->checksum == hdr_checksum(pHdr)) + { + if (pHdr->portdest != 0x80 /* Dsp OAM */) + { + uiState = STATE_DONE_PROV; + break; + } + usHdrLength = ntohs(pHdr->length); /* Byte length for PROV records */ + + // Get buffer for provisioning data + pbuffer = kmalloc((usHdrLength + sizeof(struct pseudo_hdr)), GFP_ATOMIC); + if (pbuffer) { + memcpy(pbuffer, (void *)pUcFile, (UINT)(usHdrLength + sizeof(struct pseudo_hdr))); + // link provisioning data + pprov_record = kmalloc(sizeof(struct prov_record), GFP_ATOMIC); + if (pprov_record) { + pprov_record->pprov_data = pbuffer; + list_add_tail (&pprov_record->list, &pft1000info->prov_list); + // Move to next entry if available + pUcFile = (UCHAR *)((unsigned long)pUcFile + (UINT)((usHdrLength + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr)); + if ( (unsigned long)(pUcFile) - (unsigned long)(pFileStart) >= (unsigned long)FileLength) { + uiState = STATE_DONE_FILE; + } + } + else { + kfree(pbuffer); + Status = STATUS_FAILURE; + } + } + else { + Status = STATUS_FAILURE; + } + } + else + { + /* Checksum did not compute */ + Status = STATUS_FAILURE; + } + DEBUG("ft1000:download: after STATE_SECTION_PROV, uiState = %d, Status= %d\n", uiState, Status); + break; + + case STATE_DONE_PROV: + DEBUG("FT1000:download:STATE_DONE_PROV\n"); + uiState = STATE_DONE_FILE; + break; + + + default: + Status = STATUS_FAILURE; + break; + } /* End Switch */ + + if (Status != STATUS_SUCCESS) { + break; + } + +/**** + // Check if Card is present + Status = Harley_Read_Register(&temp, FT1000_REG_SUP_IMASK); + if ( (Status != NDIS_STATUS_SUCCESS) || (temp == 0x0000) ) { + break; + } + + Status = Harley_Read_Register(&temp, FT1000_REG_ASIC_ID); + if ( (Status != NDIS_STATUS_SUCCESS) || (temp == 0xffff) ) { + break; + } +****/ + + } /* End while */ + + DEBUG("Download exiting with status = 0x%8x\n", Status); + ft1000_write_register(ft1000dev, FT1000_DB_DNLD_TX, FT1000_REG_DOORBELL); + + return Status; +} + |