blob: fac7f0a1736954223e0b32c3dcb08800b484399a [file] [log] [blame]
/******************************************************************************
**
** INTEL CONFIDENTIAL
** Copyright 2003-2004 Intel Corporation All Rights Reserved.
**
** The source code contained or described herein and all documents
** related to the source code (Material) are owned by Intel Corporation
** or its suppliers or licensors. Title to the Material remains with
** Intel Corporation or its suppliers and licensors. The Material contains
** trade secrets and proprietary and confidential information of Intel
** or its suppliers and licensors. The Material is protected by worldwide
** copyright and trade secret laws and treaty provisions. No part of the
** Material may be used, copied, reproduced, modified, published, uploaded,
** posted, transmitted, distributed, or disclosed in any way without Intel's
** prior express written permission.
**
** No license under any patent, copyright, trade secret or other intellectual
** property right is granted to or conferred upon you by disclosure or
** delivery of the Materials, either expressly, by implication, inducement,
** estoppel or otherwise. Any license under such intellectual property rights
** must be express and approved by Intel in writing.
**
** ProtocolManager.c
******************************************************************************/
/******************************************************************************
*
* (C)Copyright 2005 - 2011 Marvell. All Rights Reserved.
*
* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MARVELL.
* The copyright notice above does not evidence any actual or intended
* publication of such source code.
* This Module contains Proprietary Information of Marvell and should be
* treated as Confidential.
* The information in this file is provided for the exclusive use of the
* licensees of Marvell.
* Such users have the right to use, modify, and incorporate this code into
* products for purposes authorized by the license agreement provided they
* include this notice and the associated copyright notice with any such
* product.
* The information in this file is provided "AS IS" without warranty.
******************************************************************************/
/******************************************************************************
*
* The boot ROM protocol is documented in the boot ROM specification. This
* implements the protocol over the USB or UART port. It is expected that
* the driver for the port has a minimal set of routines to handle receiving
* and responding to commands. This file will interpret the data and prepare
* the response data for a particular command. The driver is resonsible for
* sending and receiving the data over the port.
*
* Basic process:
* - Interrupt is received from one of the ports
* - The HandleRequest routine is called to get the command from the port
* - Based on the request type either a download request or a JTAG request
* is started. At this point the other ports are disabled until the
* request is completed.
*
*
******************************************************************************/
#include "ProtocolManager.h"
#include "Errors.h"
#include "misc.h"
#include "Flash.h"
#include "FM.h"
#include "ICU.h"
#include "tim.h"
#include "PlatformConfig.h"
#include "loadoffsets.h"
#include "nand.h"
#include "downloader.h"
#include "TIMDownload.h"
#define MAX_RECV_FIFO_LEN (8192)
__attribute__((aligned(8)))UINT8 receiveBuff[MAX_RECV_FIFO_LEN];
UCHAR *pRXbuff = receiveBuff;
__attribute__((aligned(8)))UINT8 transmitBuff[MAX_RECV_FIFO_LEN];
// Here's how to interprit the version
// MAJOR
// A (stepping) = 1
// B (stepping) = 2
// C (stepping) = 3
// D (stepping) = 4
// MINOR
// This is basically the stepping number, 0=0, 1=1, 2=2 etc
// For example:
// A0 = 1000
// A1 = 1001
// B2 = 2002
// C0 = 3000
// C2 = 3002
__attribute__((aligned(4))) UINT8_T preambleString[] = { 0x00, 0xD3, 0x02, 0x2B };
UINT8_T upload_config_flash_flag = 0;
UINT8_T upload_get_times_flag = 0;
UINT8_T upload_times = 1;
UINT8_T ResetUE = 0;
UINT8_T ResetDelay = 0;
extern UINT8_T FlashInitDone;
#if NAND_CODE
extern UINT_T NandID;
#endif
#if REPORT_DDR_INFO
extern UINT_T swd_ddr_vendor_id, swd_ddr_size, swd_flash_id;
#endif
static ProtocolISR GProtocolISR;
static pProtocolCmd pGProtocolCmd;
static __attribute__((aligned(4))) ProtocolRsp GProtocolRsp;
static ProtocolMsg GProtocolMsg;
static UINT8_T sProtocolError = NoError;
//Protocol Manager helper routines - should all be 'inline' routines
pProtocolISR getProtocolISR(void) { return &GProtocolISR; }
pProtocolCmd getProtocolCmd(void) { return pGProtocolCmd; }
pProtocolCmd setProtocolCmd(void *addr) { return pGProtocolCmd = (pProtocolCmd) addr; }
pProtocolRsp getProtocolRsp(void) { return &GProtocolRsp; }
pProtocolMsg getProtocolMsg(void) { return &GProtocolMsg; }
void setProtocolError(UINT8_T Error) { sProtocolError = Error; }
UINT8_T getProtocolError(void) { return sProtocolError; }
UCHAR * getProtoBuff() { return pRXbuff; }
void setProtoBuff(UCHAR* pAddr) { pRXbuff = pAddr; }
void resetProtoBuff() { pRXbuff = receiveBuff; }
//Protocol Manager reply routines. Will call into USB API to do the actual send
UINT_T SendResponse(UINT8_T *pAckBuff, UINT_T size)
{
P_USBAPI_T pUsbApi = getProtocolISR()->plinkedUSB;
//pointer to the current USB Handle
pUsbApi->USB_Send((UINT *)pAckBuff, size, pUsbApi);
return NoError;
}
UINT_T SendAck(void)
{
UINT_T Retval = NoError;
pProtocolCmd pCmd = getProtocolCmd();
pProtocolRsp pRsp = getProtocolRsp();
pRsp->Command = pCmd->Command;
pRsp->Sequence = pCmd->Sequence;
pRsp->CID = pCmd->CID;
pRsp->Status = Ack;
pRsp->Flags = pRsp->Flags & ~(MESSAGE_FLAG);
pRsp->Flags = pRsp->Flags | getProtocolMsg()->MessageFlag;
Retval = SendResponse(&pRsp->Command, pRsp->Length + 6);
return Retval;
}
UINT_T SendError(UINT_T ErrorCode){
UINT_T Retval = NoError;
UINT_T RspSize;
//UINT_T i;
pProtocolCmd pCmd = getProtocolCmd();
pProtocolRsp pRsp = getProtocolRsp();
pRsp->Command = pCmd->Command;
pRsp->Sequence = pCmd->Sequence;
pRsp->CID = pCmd->CID;
pRsp->Status = Nack;
pRsp->Flags = getProtocolMsg()->MessageFlag;
if(ErrorCode)
{
pRsp->Length = 4;
*(UINT16_T*)&pRsp->Data[0] = ErrorCode & 0x0000FFFF;
*(UINT16_T*)&pRsp->Data[2] = (ErrorCode & 0xFFFF0000) >> 16;
}
else
pRsp->Length = 0;
RspSize = ErrorCode ? 6 + pRsp->Length : 6;
Retval = SendResponse(&pRsp->Command, RspSize);
return Retval;
}
////////////////////////////////////////////////////////////////////////
// Functions to handle specific commands
////////////////////////////////////////////////////////////////////////
UINT_T HandleGetVersionCmd()
{
UINT_T Retval= 0, i;
pProtocolRsp pRsp;
// UINT8_T *Version = (UINT8_T *)(VERSION_OFFSET + BOOTROMBASEADDR); // legacy way to get version info...
// Version used to come from BootROM's version info.
// But now the BootROM's memory space is unavailable to BootLoader.
// Furthermore, it is probably more appropriate to return the version
// info of whichever executable is running: BootROM or BootLoader.
extern UINT8_T ExecutableVersionInfo[]; // defined in [TBR|BL]_startup.s
UINT8_T *pVersion = ExecutableVersionInfo; // new way to get version info.
pRsp = getProtocolRsp();
pRsp->Length = 12;
memcpy( (void *)&(pRsp->Data[0]), pVersion, 12);
#if REPORT_DDR_INFO
pRsp->Length += 8;
for (i = 0; i < 4; i++)
pRsp->Data[12+i] = (swd_ddr_vendor_id >> (8 * i)) & 0xff;
for (i = 0; i < 4; i++)
pRsp->Data[16+i] = (swd_ddr_size >> (8 * i)) & 0xff;
pRsp->Length += 4;
for (i = 0; i < 4; i++)
pRsp->Data[20+i] = (swd_flash_id >> (8 * i)) & 0xff;
#endif
Retval = SendAck();
return Retval;
}
UINT_T HandleSelectImageCmd(UINT_T imageType)
{
UINT_T Retval;
pProtocolRsp pRsp = getProtocolRsp();
pRsp->Length = 4;
*(UINT16_T *)&pRsp->Data[0] = imageType & 0x0000FFFF;
*(UINT16_T *)&pRsp->Data[2] = (imageType & 0xFFFF0000) >> 16;
Retval = SendAck();
return Retval;
}
UINT_T HandleVerifyImageCmd()
{
UINT_T Retval= 0;
getProtocolRsp()->Length = 0;
if(getProtocolCmd()->Data[0] == Nack)
getProtocolISR()->ErrorCode = UnknownImageError;
Retval = SendAck();
return Retval;
}
UINT_T HandleDataHeaderCmd()
{
UINT_T RemainingLen = 0;
UINT_T BufferSize = 0;
UINT_T NextSize = 0;
pProtocolRsp pRsp = getProtocolRsp();
pProtocolISR pISR = getProtocolISR();
pProtocolCmd pCmd = getProtocolCmd();
pRsp->Length = 4;
RemainingLen = *(UINT32_T *)&pCmd->Data[0];
//check to make sure the data will fit
if(RemainingLen > pISR->MaxImageSize)
{
AddMessageError(REPORT_NOTIFICATION, DownloadImageTooBigError);
SendError(DownloadImageTooBigError);
pISR->ErrorCode = DownloadImageTooBigError;
return NULL;
}
pISR->DataLeft = RemainingLen; //DataLeft indicates how much of the total image remains
if (pCmd->Flags & FAST_DOWNLOAD)
{
pRsp->Flags = pRsp->Flags | FAST_DOWNLOAD;
pISR->FastDLInProgress = 1;
//setup next read for 2KB
NextSize = BufferSize = (RemainingLen > FD_BLOCK_SIZE) ? FD_BLOCK_SIZE : RemainingLen;
}
else
{
pRsp->Flags = pRsp->Flags & ~FAST_DOWNLOAD;
pISR->FastDLInProgress = 0;
//setup next read for 2KB
BufferSize = (RemainingLen > DATA_BLOCK_SIZE) ? DATA_BLOCK_SIZE : RemainingLen;
NextSize = BufferSize + COMMAND_SIZE;
}
*(UINT16_T*)&pRsp->Data[0] = BufferSize & 0x0000FFFF;
*(UINT16_T*)&pRsp->Data[2] = (BufferSize & 0xFFFF0000) >> 16;
SendAck();
return NextSize;
}
UINT_T HandleDataCmd()
{
UINT_T Retval = 0;
getProtocolCmd()->Command = DownloadDataCmd;
getProtocolRsp()->Length = 0;
SendAck();
return Retval;
}
UINT_T HandleDoneCmd()
{
UINT_T Retval= 0;
pProtocolISR pISR = getProtocolISR();
getProtocolRsp()->Length = 0;
//reset the status flags
pISR->PreambleReceived = FALSE;
SendAck();
return Retval;
}
UINT_T HandleMessageCmd(void){
UINT_T Retval= 0;
#if VERBOSE_MODE
UINT_T mIndex;
UINT_T size;
UINT_T i;
//UINT8_T Buff[LENGTHOFMESSAGES + 6];
UINT8_T *Buff = transmitBuff;
pProtocolCmd pCmd = getProtocolCmd();
pProtocolMsg pMsg = getProtocolMsg();
//tool sending extra message commands to catch messages
//if we don't have any messages, just NACK the message and continue
if(pMsg->NumMessagesQueued == 0){
SendError(0);
return NoError;
}
//must use Buff instead of GProtocolRsp
Buff[0] = pCmd->Command;
Buff[1] = pCmd->Sequence;
Buff[2] = pCmd->CID;
Buff[3] = Ack;
mIndex = pMsg->CurrentMessageIndex;
size = pMsg->Lengths[mIndex];
Buff[5] = size;
for(i = 0; i < size; i++)
Buff[6+i] = pMsg->Messages[mIndex][i];
//increment the pointer to the new current message
pMsg->CurrentMessageIndex++;
pMsg->CurrentMessageIndex %= MAXNUMOFMESSAGES;
pMsg->NumMessagesQueued--;
if(pMsg->NumMessagesQueued == 0)
pMsg->MessageFlag = 0;
else
pMsg->MessageFlag = 1;
//mark flags (message flag message type flag )
Buff[4] = (pMsg->MessageFlag | (pMsg->MessageType[mIndex] << 1));
SendResponse(&Buff[0], 6+size);
#else // end if VERBOSE_MODE
SendError(0);
#endif
return Retval;
}
UINT_T HandleDisconnect()
{
UINT start_time;
pProtocolISR pISR = getProtocolISR();
//if there is no linked USB Device, then there was never any protocol transaction
if(pISR->plinkedUSB == NULL)
return NoError;
//check to see if there are queued up messages.
if( (pISR->DisconnectReceived == TRUE) && getProtocolMsg()->MessageFlag)
{ //clear disconnect received flag as we now need to wait for a new one
pISR->DisconnectReceived = FALSE;
//reply with a NAK to allow messages to get sent
SendError(0);
}
//give the tool a short time to get all the messages and then reply with a disconnect
start_time = GetOSCR0();
while(pISR->DisconnectReceived == FALSE)
{
//if a download is waiting, terminate it and break out of loop: wtptp tool quits on a NACK
if(pISR->DLWaiting == TRUE)
{
SendError(UnknownImageError);
break;
}
if(OSCR0IntervalInSec(start_time, GetOSCR0()) > PM_DISCONNET_MS)
break;
}
//lastly, reply with an ACK
if(pISR->DisconnectReceived == TRUE)
SendAck();
//need to release PM semaphore and reset all flags!
//Semaphore_Release(PROTOCOL_semaphore);
memset(pISR, 0, sizeof(ProtocolISR));
return NoError;
}
/* InitPort()
*
* Call into the driver to setup the ports and enable interrupts
*
*/
UINT_T InitPort(UINT_T port)
{
return USBAPI_InitializeDevice(port);
}
UINT ImageDownloadWaiting(UINT_T media_num)
{
pProtocolISR pISR = getProtocolISR();
//check to see if a USB is linked and said linked USB is the matching one
// if so, return whether a GetVersion request was made (i.e. a download is waiting)
if( (pISR->plinkedUSB != NULL) &&
(pISR->plinkedUSB->bootNum == media_num) )
return pISR->DLWaiting;
else
return FALSE;
}
UINT PreambleReceived()
{
return getProtocolISR()->PreambleReceived;
}
void ClearPreambleReceived()
{
getProtocolISR()->PreambleReceived = FALSE;
}
// ShutdownPorts: shutdown all ports
void ShutdownPorts ()
{
//call into USB API to shutdown all enabled USB devices
USBAPI_ShutdownAll();
}
//Protocol Manager ISR
// There are three possible scenarios when this routine is called:
// 1. PM is already used by another USB device (unusual scenario)
// 2. PM is being used by the calling device (most likely scenario)
// 3. PM is free (starting scenario)
// The numbered comments in this routine will match up to the three mentioned scenarios
void PM_ISR(P_USBAPI_T this, UINT bytes, UINT * buffer)
{
UINT next_size, dummy = NULL;
pProtocolISR pISR = getProtocolISR();
//1. Is someone else using the protocol?
if( (pISR->plinkedUSB != this) && (pISR->plinkedUSB != NULL) )
{ //Yes. Another USB is using protocol. Transmit a NAK
this->USB_Send(&dummy, PREAMBLE_SIZE, this);
//reprime so it will try again later
this->USB_Receive(buffer, PREAMBLE_SIZE, this);
//time to leave
return;
}
//2. We're already good friends
if(pISR->plinkedUSB == this)
{
if((bytes == PREAMBLE_SIZE ) && (pISR->PreambleReceived == FALSE))
{ //check the validity of the preamble
if( PM_VerifyPreamble((UCHAR *)buffer) )
{ //good Preamble!
pISR->PreambleReceived = TRUE;
// clear out any errors, as a new Preamble mean a new Image DL
pISR->ErrorCode = 0;
//respond with the preamble
SendResponse(preambleString, PREAMBLE_SIZE);
//set the pRXBuff to protocol area
resetProtoBuff();
//Setup for a new CMD
this->USB_Receive((UINT *)getProtoBuff(), this->maxpacketsize, this);
}
else
{ //bad Preamble!
//Transmit a NAK
this->USB_Send(&dummy, PREAMBLE_SIZE, this);
//Reset USB control to download again
this->USB_Receive(buffer, PREAMBLE_SIZE, this);
}
}
else
{
//4. call into PM handler
next_size = PM_Handler(bytes);
//5. call into USBAPI to set up next RECEIVE
this->USB_Receive((UINT *)getProtoBuff(), next_size, this);
}
//all done, exit now
return;
}
//3. Newbie! Must receive a preamble or else we can't be friends.
if(pISR->plinkedUSB == NULL)
{ //check the validity of the preamble
if( (bytes == PREAMBLE_SIZE) && PM_VerifyPreamble((UCHAR *)buffer) )
{ //good Preamble!
pISR->PreambleReceived = TRUE;
// clear out any errors, as a new Preamble mean a new Image DL
pISR->ErrorCode = 0;
//Check out using semaphore and store the USB API pointer
pISR->plinkedUSB = this;
//Semaphore_Acquire(PROTOCOL_semaphore);
//respond with the preamble
SendResponse(preambleString, PREAMBLE_SIZE);
//set the pRXBuff to protocol area
resetProtoBuff();
//Setup for a new CMD
this->USB_Receive((UINT *)getProtoBuff(), this->maxpacketsize, this);
}
else
{ //Premable was not valid
//Transmit a NAK
this->USB_Send(&dummy, PREAMBLE_SIZE, this);
//Reset USB control to download again
this->USB_Receive(buffer, PREAMBLE_SIZE, this);
}
return;
}
}
// PROTOCOL HANDLER
// This routine is the singular handler for protocol commands
// - JTAG over USB (CMD 36)
// - Image Downloading
//
// Inputs:
// - pUSBhandle: pointer the calling USB handler
// - packetlength: length of the packet that triggered this call
// Outputs:
// - PrimeSize: the size to prime the next input packet for
UINT PM_Handler(UINT packetLength)
{
pProtocolCmd pCmd;
pProtocolISR pISR = getProtocolISR();
UINT next_size = pISR->plinkedUSB->maxpacketsize; //defualt is a full packet
//1st check if a fast download command is in progress
if(pISR->FastDLInProgress)
{
//Update counters
pISR->CurrentTransferAddress += packetLength;
pISR->DataLeft -= packetLength;
pISR->MaxImageSize = (packetLength > pISR->MaxImageSize) ? 0 : (pISR->MaxImageSize - packetLength);
//When DataLeft = 0, then the command is finally finished. respond back
if(pISR->DataLeft == 0)
{
pISR->FastDLInProgress = 0;
HandleDataCmd(); //send the response
resetProtoBuff(); //restore the location back to protocol area
}
else
{ // Fast Download continues... set up info for next descriprots
//security check: can only download "MaxImageSize" per image DL. If malicious software tries to download more,
//this line of code will restrict the size dTD and force USB NACKs for any additional data
next_size = (pISR->DataLeft > pISR->MaxImageSize) ? pISR->MaxImageSize : pISR->DataLeft;
next_size = (next_size < FD_BLOCK_SIZE ) ? next_size : FD_BLOCK_SIZE;
setProtoBuff((UINT8 *)pISR->CurrentTransferAddress); //set location for USB to put data
}
return next_size;
}
//normal commands
//Overlay the Command structure over the buffer
pCmd = setProtocolCmd(getProtoBuff());
//All normal commands will load the data to the protocol buffer
resetProtoBuff();
//Sanity check - make sure the size read in matches the size defined in the ProtocolCmd packet
//if ( packetLength != (8+pCmd->Length) )
//{
// pISR->ErrorCode = UnknownProtocolCmd;
// SendError(UnknownProtocolCmd);
// return next_size;
//}
// update Interrupt Status Flags
//pISR->CurrentCommand = pCmd->Command;
switch( pCmd->Command )
{
case MessageCmd:
//try and send a message
// clear the upload command flag for upload
pISR->CommandReceived = FALSE;
HandleMessageCmd();
break;
#if !BOOTROM
case ProtocolVersionCmd:
// Send the major and minor protocol version bacl
HandleProtocolVersionCmd();
break;
case GetParametersCmd:
// Send Protocol Parameters to host.
HandleGetParametersCmd();
break;
case GetImageCrcCmd:
HandleGetCrcCmd();
break;
case GetBadBlockCmd:
HandleGetBadBlock();
break;
#endif
#if JTAG_OVER_JTAG_SUPPORTED
case JtagOverMediaCmd:
//copy the JTAG data into the JTAG structure
memcpy( (void *)pJTAG_CPCData->CommandFromHost, (void*)&pCmd->Data[0], pCmd->Length);
Jtag_Media_Handler();
break;
#endif
case GetVersionCmd:
//Indicate that a download is pending, but do NOT respond yet
pISR->DLWaiting = TRUE;
pISR->CommandReceived = TRUE; // mark it as download command
break;
case UploadDataHeaderCmd:
pISR->DLWaiting = TRUE; // indicate that a upload is pending
pISR->CommandReceived = TRUE; // mark it as upload command
break;
case UploadDataCmd:
pISR->CommandReceived = TRUE; // mark it as upload command
break;
case SelectImageCmd:
HandleSelectImageCmd(pISR->CurrentImageID);
next_size = 9; //the next command will be larger than normal
break;
case VerifyImageCmd:
HandleVerifyImageCmd();
next_size = 12; //the next command will be larger than normal
break;
case DataHeaderCmd:
next_size = HandleDataHeaderCmd();
if (pISR->FastDLInProgress) //override the download address for fast download
setProtoBuff((UINT8 *)pISR->CurrentTransferAddress); //set location for USB to put data
break;
case DownloadDataCmd:
//Note: this will only be triggered for "slow" download.
//move data from the buffer to boot address
memcpy((void *)(pISR->CurrentTransferAddress), (void*)&pCmd->Data[0], pCmd->Length);
//Update counters
pISR->CurrentTransferAddress += pCmd->Length;
pISR->MaxImageSize -= (pCmd->Length > pISR->MaxImageSize) ? pISR->MaxImageSize : pCmd->Length;
HandleDataCmd();
break;
case DoneCmd:
//Indicate that a download has finished, but do NOT respond yet
pISR->DLWaiting = FALSE;
pISR->CommandReceived = TRUE; // exit for upload while loop
break;
case DisconnectCmd:
pISR->DisconnectReceived = TRUE;
break;
default:
break;
}
return next_size;
}
// PM_ReceiveImage()
//
// This is the Protocol Recieve image routine. It does the following:
// 1. Set the parameters for the download:
// -- destination address
// -- max size
// -- image ID
// 2. Check and wait for a pending image download request (GetVersion command from host)
// 3. Download will be kicked off by sending the GetVersion response.
// 4. Wait until the download has finished (DoneCommand will indicate that)
//
UINT_T PM_ReceiveImage(UINT_T dummy, UINT_T address, UINT_T size, UINT_T image_id)
{
UINT retval = NoError, start_time, wait_time = 0;
//pProtocolCmd pCmd = getProtocolCmd();
pProtocolISR pISR = getProtocolISR();
//1. set up initial DL perameters:
pISR->CurrentTransferAddress = address;
pISR->MaxImageSize = size;
pISR->CurrentImageID = image_id;
//AddMessageCompound((UINT8_T*) ("*** PM_ReceiveImage pISR->CurrentTransferAddress...\0"), pISR->CurrentTransferAddress);
do
{
//2. wait for the download request
start_time = GetOSCR0();
do
{ //Check for timeout
if( OSCR0IntervalInMilli(start_time, GetOSCR0()) > PM_DL_STARTTIME_MS )
{
retval = PM_ReceiveTimeOutError_1;
break;
}
}
while(pISR->DLWaiting == FALSE);
//check for an error
if(retval != NoError)
break;
//3. send the Get Version response to kick off the download
retval = HandleGetVersionCmd();
//check for an error
if(retval != NoError)
break;
/*
* Suppose the worst USB transfer speed is 0.5MB/s(in fact, it's about 12MB/s
* for HS mode but should also consider FS mode)
* Then, the wait time should not exceed (size / 1024 /4) milli seconds.
* The extra 2000 ms is to ensure the wait time is none-zero
*/
wait_time = (size >> 9) + 2000;
//4. Wait for the Image DL to complete or an error
start_time = GetOSCR0();
do
{ //Check for timeout
if( OSCR0IntervalInMilli(start_time, GetOSCR0()) > wait_time )
{
retval = PM_ReceiveTimeOutError_2;
break;
}
}
while( (pISR->DLWaiting == TRUE) && (pISR->ErrorCode == NoError) );
}while(FALSE);
//If there is an protocol error, override local error status
if(pISR->ErrorCode)
retval = pISR->ErrorCode;
//clear the flags to indicate an image dl is done
pISR->ErrorCode = NoError;
pISR->PreambleReceived = FALSE;
pISR->DLWaiting = FALSE;
//finish off the download by sending either the DONE cmd on success or NAK on failure
if(retval == PM_ReceiveTimeOutError_1 || retval == PM_ReceiveTimeOutError_2)
SendError(retval);
else
HandleDoneCmd();
//returns 0 if complete or an error code
return retval;
}
UINT_T GetUploadCommand(void)
{
UINT_T Retval = NoError;
UINT_T StartTime;
pProtocolISR pISR = getProtocolISR();
StartTime = GetOSCR0(); //Dummy read to flush potentially bad data
StartTime = GetOSCR0();
while(pISR->CommandReceived == FALSE)
{
Retval = CheckProtocolTimeOut(StartTime);
if(Retval != NoError)
return Retval;
}
pISR->CommandReceived = FALSE;
return Retval;
}
/*
* HandleDownloadFlow()
*
* This function will handle a upload request unitl it completes or fails
* and return the status
*/
UINT_T HandleUploadFlow(UINT_T address)
{
UINT_T Retval = NoError;
pProtocolCmd pCmd = getProtocolCmd();
pProtocolISR pISR = getProtocolISR();
pISR->CurrentTransferAddress = address;
do{
switch(pCmd->Command)
{
case UploadDataHeaderCmd:
Retval = HandleUploadDataHeaderCmd();
break;
case UploadDataCmd:
Retval = HandleUploadDataCmd();
break;
default:
if(pISR->CommandReceived == TRUE)
{
Retval = SendError(0);
Retval = UnknownProtocolCmd;
}else
Retval = NoError;
break;
}
if(Retval != NoError){
break;
}
GetUploadCommand();
}while (pCmd->Command != DoneCmd);
return Retval;
}
/**
* Debug Commands
**/
UINT_T HandleUploadDataHeaderCmd(void)
{
UINT_T Retval = NoError;
pProtocolCmd pCommand;
pProtocolISR pISR;
UploadDataParameters uploadParams, *pUploadParams;
#if NAND_CODE || QSPINAND_CODE || SPINAND_CODE
UINT_T spare_size, page_size;
UINT_T numbers, total_spare_size;
#endif
pUploadParams = &uploadParams;
pCommand = getProtocolCmd();
pISR = getProtocolISR();
memcpy((void*)pUploadParams,(void*)&pCommand->Data[0],sizeof(UploadDataParameters));
if (!upload_get_times_flag)
{
upload_times = pUploadParams->Times; // upload_times >= 1
#if USE_SERIAL_DEBUG
obm_printf("upload_times: %d\n\r", upload_times);
#endif
ResetUE = pUploadParams->ResetUE;
ResetDelay = pUploadParams->ResetTimeDelay;
obm_printf("ResetUE: %d, ResetDelay: %d\n\r", ResetUE, ResetDelay);
upload_get_times_flag = 1;
}
// Are the upload parameters ok?
Retval = VerifyUploadParameters(pUploadParams);
AddMessageError(REPORT_NOTIFICATION, PlatformBusy);
if(Retval != NoError)
{
AddMessageError(REPORT_NOTIFICATION, PlatformReady);
SendError(Retval);
return Retval;
}
else
{
getProtocolRsp()->Length = 0;
SendAck();
}
// Copy data requested into upload buffer
//AddMessageError(PlatformBusy);
//This could take a while
if(pUploadParams->Type == UPLOAD_DDR)
pISR->CurrentTransferAddress = pUploadParams->Offset;
else
Retval = CopyUploadDataIntoBuffer(pISR->CurrentTransferAddress, pUploadParams);
AddMessageError(REPORT_NOTIFICATION, PlatformReady);
// data should in buffer now
if(Retval != NoError)
{
setProtocolError(Retval);
// This was probably an error reading from source as UploadParams checked out ok.
// Set to No Error so that error can be sent to Host in HandleUploadDataCmd.
Retval = NoError;
}
else
{
#if NAND_CODE || QSPINAND_CODE || SPINAND_CODE
if (upload_nand_spare == TRUE)
{
spare_size = GetSpareAreaSize(BOOT_FLASH); // get nand spare areas size
page_size = GetPageSize(BOOT_FLASH);
numbers = pUploadParams->DataSize / page_size; // calculate spare areas number
total_spare_size = numbers * spare_size; // total spare size
pISR->DataLeft = pUploadParams->DataSize + total_spare_size; // data length + total spare length
}
else
#endif
{
pISR->DataLeft = pUploadParams->DataSize;
}
}
return Retval;
}
UINT_T HandleUploadDataCmd(void)
{
UINT_T Retval = NoError,txDataSize = 0;
pProtocolRsp pRsp = (pProtocolRsp)transmitBuff;
pProtocolCmd pCmd = getProtocolCmd();
pProtocolISR pISR = getProtocolISR();
Retval = getProtocolError();
if(Retval!= NoError)
{
// We had a problem reading data for Data Upload
SendError(Retval);
return Retval;
}
if(pISR->DataLeft <= 0)
{
Retval = SeqError;
SendError(Retval);
return Retval;
}
pRsp->Command = UploadDataCmd;
pRsp->Sequence = pCmd->Sequence;
pRsp->CID = pCmd->CID;
pRsp->Status = Ack;
// Too bad length is only a byte. Not using it.
pRsp->Length = 0;
txDataSize = pISR->DataLeft < UPLOAD_BLOCK_SIZE ? pISR->DataLeft : UPLOAD_BLOCK_SIZE;
// Not a fan but have to do this. We have 6 byte status and arbitrary data.
memcpy((void*)&pRsp->Data[0], (void*)pISR->CurrentTransferAddress, txDataSize);
// Message bit should NOT be set in flags.
// At this point getProtocolMsg()->MessageFlag will be 0.
pRsp->Flags = pRsp->Flags & ~(MESSAGE_FLAG);
pRsp->Flags = pRsp->Flags | getProtocolMsg()->MessageFlag;
Retval = SendResponse(&pRsp->Command, txDataSize + 6);
pISR->CurrentTransferAddress += txDataSize;
pISR->DataLeft -= txDataSize;
return Retval;
}
UINT_T CopyUploadDataIntoBuffer(UINT_T address, pUploadDataParameters pUploadParams)
{
UINT_T Retval = NoError;
switch(pUploadParams->Type)
{
case UPLOAD_FLASH:
// Fix me. Need code to check if sub type of flash is supported.
if (!upload_config_flash_flag && !FlashInitDone)
{
/* sub type of flash is not supported */
//Retval = PlatformInitFlash(pUploadParams->SubType & 0x1F);
Retval = Configure_Flashes(pUploadParams->SubType & 0x1F, BOOT_FLASH);
if( Retval != NoError)
FatalError(Retval, NULL, NULL);
InitializeFM(LEGACY_METHOD, BOOT_FLASH);
upload_config_flash_flag = 1; // configure flash for upload only one time
}
#if NAND_CODE || QSPINAND_CODE || SPINAND_CODE
#if NAND_CODE
if (pUploadParams->ResetUE == 1)
{
AddMessageError(REPORT_UPLOAD_NOTIFICATION, NandID);
}
#endif
upload_nand_spare = pUploadParams->IncludeOOB;
upload_disable_ecc = pUploadParams->DisableECC;
#endif
// Set the partition.
#if MMC_CODE
SetPartition(pUploadParams->Partition, BOOT_FLASH);
#endif
#if defined(NEZHA701) || defined(NEZHA702)
if ((pUploadParams->Offset <= MEP_FALSH_START &&
pUploadParams->Offset + pUploadParams->DataSize > MEP_FALSH_START) ||
(pUploadParams->Offset >= MEP_FALSH_START &&
pUploadParams->Offset < MEP_FALSH_START + MEP_FLASH_LEN))
Retval = NotSupportedError;
else
#endif
Retval = ReadFlash(pUploadParams->Offset, address, pUploadParams->DataSize, BOOT_FLASH);
break;
default:
// Not supported.
Retval = NotSupportedError;
break;
}
return Retval;
}
UINT_T VerifyUploadParameters(pUploadDataParameters pUploadParams)
{
UINT_T Retval = NoError, flashNum;
pTIM pTIM_h = GetTimPointer();
switch(pUploadParams->Type)
{
case UPLOAD_FLASH:
// Is flash subtype supported. Looking in Tim.
flashNum = pTIM_h->pConsTIM->FlashInfo.BootFlashSign & 0xFF;
if(flashNum != pUploadParams->SubType & 0xFF &&
flashNum != CI2_USB_D) //Empty board upload
Retval = UnsupportedFlashError;
if(pUploadParams->UploadBypassBBT) {
obm_printf("Upload Flash with BBT bypassed\n\r");
GetFlashProperties(BOOT_FLASH)->FlashSettings.UseBBM = 0;
}
break;
case UPLOAD_DDR:
break;
default:
// Not supported.
Retval = NotSupportedError;
break;
}
return Retval;
}
UINT_T HandleProtocolVersionCmd()
{
UINT_T Retval = 0;
pProtocolRsp pRsp;
pProtocolCmd pCmd;
pCmd = getProtocolCmd();
pRsp = getProtocolRsp();
pRsp->Command = pCmd->Command;
pRsp->Sequence = pCmd->Sequence;
pRsp->CID = pCmd->CID;
pRsp->Status = Ack;
pRsp->Length = 4;
pRsp->Data[0] = COMM_PROTOCOL_MAJOR_VERSION;
pRsp->Data[1] = COMM_PROTOCOL_MINOR_VERSION;
*(UINT16_T*)&pRsp->Data[2] = COMM_PROTOCOL_REV_VERSION;
pRsp->Flags = pRsp->Flags & ~(MESSAGE_FLAG);
pRsp->Flags = pRsp->Flags | getProtocolMsg()->MessageFlag;
SendResponse(&pRsp->Command, 6 + pRsp->Length);
return Retval;
}
UINT_T HandleGetParametersCmd()
{
UINT_T Retval = 0;
pProtocolRsp pRsp;
pProtocolCmd pCmd;
pCmd = getProtocolCmd();
pRsp = getProtocolRsp();
pRsp->Command = pCmd->Command;
pRsp->Sequence = pCmd->Sequence;
pRsp->CID = pCmd->CID;
pRsp->Status = Ack;
// Currently only sending buffer size. But we have 3 more reserved paramters.
// Note: Rsp structure only has space for 12 bytes of data ( 3 params). If we
// are going to use all 4 parameters, we need a buffer and memcpy.
pRsp->Length = 16;
*(UINT16_T *)&pRsp->Data[0] = COMM_PROTOCOL_BUFFER_SIZE & 0xffff;
*(UINT16_T *)&pRsp->Data[2] = (COMM_PROTOCOL_BUFFER_SIZE & 0xffff0000)>> 16;
pRsp->Flags = pRsp->Flags & ~(MESSAGE_FLAG);
pRsp->Flags = pRsp->Flags | getProtocolMsg()->MessageFlag;
// This should be
// SendResponse(&pRsp->Command, 6 + pRsp->Length);
// See note above
SendResponse(&pRsp->Command, 6 + pRsp->Length);
return Retval;
}
UINT_T HandleGetCrcCmd()
{
UINT_T Retval = 0;
pProtocolRsp pRsp = (pProtocolRsp)transmitBuff;
pProtocolCmd pCmd;
UINT_T BufferAddr;
INT_T BufferLen = 4; //Nack
pCmd = getProtocolCmd();
pRsp->Command = pCmd->Command;
pRsp->Sequence = pCmd->Sequence;
pRsp->CID = pCmd->CID;
Retval = GetImageReadBackCrcBuffer(&BufferAddr, &BufferLen);
pRsp->Flags = pRsp->Flags & ~(MESSAGE_FLAG);
pRsp->Flags = pRsp->Flags | getProtocolMsg()->MessageFlag;
if(Retval == NoError){
pRsp->Status = Ack;
//pRsp->Length is UINT8, BufferLen exceed 255
pRsp->Length = BufferLen;
memcpy(&pRsp->Data[0], (UINT8 *)BufferAddr, BufferLen);
}else{
pRsp->Status = Nack;
pRsp->Length = 4;
*(UINT16_T *)&pRsp->Data[0] = Retval & 0xffff;
*(UINT16_T *)&pRsp->Data[2] = (Retval & 0xffff0000)>> 16;
}
//pRsp->Length is UINT8, BufferLen exceed 255, use BufferLen instead
SendResponse(&pRsp->Command, 6 + BufferLen);
return Retval;
}
UINT_T HandleGetBadBlock()
{
UINT_T Retval = 0;
pProtocolRsp pRsp = (pProtocolRsp)transmitBuff;
pProtocolCmd pCmd;
P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH);
pBadBlockData bbData;
pCmd = getProtocolCmd();
pRsp->Command = pCmd->Command;
pRsp->Sequence = pCmd->Sequence;
pRsp->CID = pCmd->CID;
pRsp->Status = Ack;
bbData = (pBadBlockData)(&pRsp->Data[0]);
bbData->TotalBadBlocks = GetBadBlockNum();
bbData->TotalBlocks = pFlashProp->NumBlocks;
pRsp->Length = 8;
pRsp->Flags = pRsp->Flags & ~(MESSAGE_FLAG);
pRsp->Flags = pRsp->Flags | getProtocolMsg()->MessageFlag;
SendResponse(&pRsp->Command, 6 + pRsp->Length);
return Retval;
}
UINT_T AddMessageError(UINT_T ReportType, UINT_T ReportCode)
{
UINT_T Retval = 0;
#if VERBOSE_MODE
UINT_T mIndex, i;
pProtocolMsg pMsg = getProtocolMsg();
MessageReport Report;
if(pMsg->NumMessagesQueued == MAXNUMOFMESSAGES)
return MessageBufferFullError; //this is when message buffer is full
//find the next open slot in the Queue
//It will be right after the last good message
//this is a circular queue, so we use the '%' operation
mIndex = (pMsg->CurrentMessageIndex + pMsg->NumMessagesQueued) % MAXNUMOFMESSAGES;
Report.ReportType = ReportType;
Report.Reserved = 0;
for (i = 0; i < 4; i++)
{
Report.ReportCode[i] = (ReportCode >> (8 * i)) & 0xff;
}
// copy message to buffer
pMsg->Lengths[mIndex] = 6;
pMsg->Messages[mIndex][0] = Report.ReportType;
pMsg->Messages[mIndex][1] = Report.Reserved;
for (i = 0; i < 4; i++)
{
pMsg->Messages[mIndex][i + 2] = Report.ReportCode[i];
}
pMsg->MessageType[mIndex] = 1; // Message type 1 indicate report code
//set flag
pMsg->MessageFlag = MESSAGE_FLAG;
pMsg->NumMessagesQueued++;
#endif //endif VERBOSE_MODE
return NoError;
}
void InitProtocol(void)
{
pProtocolMsg pMsg = getProtocolMsg();
//pProtocolCmd pCMD = getProtocolCmd();
pProtocolRsp pRsp = getProtocolRsp();
pProtocolISR pISR = getProtocolISR();
memset(pMsg, 0, sizeof(ProtocolMsg));
//memset(pCMD, 0, sizeof(ProtocolCmd));
memset(pRsp, 0, sizeof(ProtocolRsp));
memset(pISR, 0, sizeof(ProtocolISR));
}
/*
* HandleRequest()
*
* This is the main function of the protocol manager. It is the entry point
* to start a request over a port after an interrupt is received. The process
* for handling a request is as follows:
*
* 1) Get the preamble from the port and verify it
* 2) Get the first command packet from the port
* 3) Send back and ack with proper flag settings
* 4) Based on the command jump to the download flow or the JTAG flow
* 5) Complete the download or JTAG request and when complete disconnect
* 6) return status to the caller
*
*
*/
UINT_T HandleRequest(UINT_T src_addr, UINT_T dest_addr, UINT_T max_size, UINT_T image_id)
{
UINT_T Retval = NoError;
pProtocolCmd pCmd = getProtocolCmd();
do
{
switch(pCmd->Command)
{
case GetVersionCmd:
//Retval = HandleDownloadFlow(dest_addr, image_id, max_size);
break;
#if!BOOTROM
case UploadDataHeaderCmd:
Retval = HandleUploadFlow(src_addr);
if(Retval != NoError)
return Retval;
break;
#endif
case DisconnectCmd:
//if there was an issue with a download, then tool will try to disconnect
//handle the disconnect, but return an error since we couldn't do a download
//getProtocolISR()->CommandReceived = TRUE; // This hack is needed for optimization. Handledisconnect waits for a command again
Retval = HandleDisconnect();
return Retval;
default:
//Retval.ErrorCode = SendError(0);
//Retval.ErrorCode = UnknownProtocolCmd;
break;
}
if(Retval != NoError)
break;
}while(pCmd->Command != DoneCmd);
if(pCmd->Command == DoneCmd)
HandleDoneCmd();
else
Retval = SendError(0);
return Retval;
}
//--------------------------------------------------------
// Utility routines
//--------------------------------------------------------
/*
* Verify that the Preamble matches
*/
UINT8_T PM_VerifyPreamble( UINT8_T *candidateString )
{
//Compare the candidate preamble to the defined string
if( 0 == memcmp(candidateString, preambleString, sizeof(preambleString)) )
{ //MATCH
//return that all is good
return TRUE;
}
else
{ //Bad String
return FALSE;
}
}
/*
* Check to see if routine has timed out
*/
UINT8_T CheckProtocolTimeOut(UINT_T StartTime)
{
UINT_T WaitTime = 0;
UINT_T CurrentTime;
CurrentTime = GetOSCR0();
WaitTime = OSCR0IntervalInSec(StartTime, CurrentTime); // measure wait time in sec
if (WaitTime >= PROTOCOL_WAITTIME)
return (CheckProtocolTimeOutError);
else return NoError;
}