This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

RTOS/AM5728: QSPI read issue for more than 16MB offset address(0xFFFFFF)

Part Number: AM5728

Tool/software: TI-RTOS

Hi,

I developed a flashing tool using pdk board diag qspi example.

We are able to successfully flash and boot the device, but crc validation when i am trying to read more that 16MB boundary .

I am not getting the expected data due to which CRC validation fails.

If i run CRC below 16MB boundary, i am not facing any issue.

We are flashing image on 1E0000 offset and able to read the data correctly till FFFFFF - 1E0000  i.e. E20000

Please help to resolve this issue.

I read through other forums that there is few issue with PDK driver, do we have any update for this?

I am using PDK AM57xx_1_0_0_13 version.

Thanks,

Ritesh 

  • Adding few more info and questions:

    1> I am using the MMAP mode for my usecase
    2> we are using custom board AM5728, having micron chipset MX66L51235F

    Do we have functional 4byte addressing mode in pdk driver In MMAP mode?


    Config Mode query:
    I tried using config mode too, but i am not able to write any data .

    For config mode i just change the HWattr structure in SPI_soc.c and in application passing offset as address

    Do I need to do any other modification?

    Thanks,
    Ritesh
  • 4 byte flash addressing is supported with the QSPI driver but this is implemented in the flash layer not in the driver itself. I recommend that you look at the file qspi_flash.c in the folder

    pdk_am57xx_1_0_xx\packages\ti\board\src\idkAM572x\device

    Regards,
    Rahul
  • Hi Rahul,

    For diag based example we are using this flash layer.
    After adding the 4B command support in this layer, We are able to write beyond 16 MB bar but the qspi read is not working as expected.

    I tried reading and printing the value beyond 16 MB all value comes as 0x0.

    Please help to debug this issue.

    Thanks,
    Ritesh
  • Ritesh,

    Are you able to read correctly from the first 16 MB ? The flashwriter we provide here is a good test:
    pdk_am57xx_1_0_xx\packages\ti\boot\sbl\tools\flashWriter\qspi\src

    If you erase the flash before reading, the expected value on the flash would be 0XFF. Have you tried this in config mode are you seeing the same issue with QSPI in config mode.

    Regards,
    Rahul
  • Hi Rahul,

    Yes, I am able to read the first 16 mb correctly .

    I will try flash tool with sbl.

    I tried enabling the config mode but I am not able to write data.

    For config mode:
    I changed the qspi hw attr in spi_soc.c to config mode.
    And passed the offset as address but its not working for me.

    Do I need to do anything else to get config mode working?

    Thanks,
    Ritesh
  • Do you have a scope hooked up? Can you see the data coming back from the SPI flash? Is it coming back as 0's? If so, this likely indicates you aren't erasing the SPI flash correctly and perhaps you need to focus there.
  • Hi Brad,

    No, I don't have scope hooked up.

    We had an erase issue due to which CRC was failing in uboot too, i resolved it and now data written through jtag and data read back from uboot is matching and CRC passes in uboot .

    so this validate the data written in flash is correct,


    Same CRC validation we need to do after flashing the image to flash in flash utility code loaded by jtag , here we are using pdk driver for read operation.

    I am getting CRC mismatch in this scenario, i dumped the read buffer and found the first 16 MB data matching correctly but after 16MB we are not getting correct data .
    we are getting 0x44 for every read beyond 16 MB.


    Thanks,
    Ritesh
  • Please hook up a scope. Is the flash truly returning 0x44 data or is the processor reporting garbage data for some reason? Is the SPI being read in one giant contiguous operation or is chip select being deasserted and reasserted along with resending the command and address at intervals? Are 32-bit addresses being sent?

    My guess on 0x44 is that is likely the "resting" state of the bus, i.e. pullup on D3 and pulldowns on D2/1/0. So if we're reading 0x44 that probably means that the processor is clocking in data but the QSPI doesn't realize we're still reading from it!
  • /**
     *  \file   QSPI_v1.c
     *
     *  \brief  QSPI IP Version 1 specific driver APIs implementation.
     *
     *   This file contains the driver APIs for QSPI controller.
     */
    
    /*
     * Copyright (C) 2014-2015 Texas Instruments Incorporated - http://www.ti.com/
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * Redistributions of source code must retain the above copyright
     * notice, this list of conditions and the following disclaimer.
     *
     * Redistributions in binary form must reproduce the above copyright
     * notice, this list of conditions and the following disclaimer in the
     * documentation and/or other materials provided with the
     * distribution.
     *
     * Neither the name of Texas Instruments Incorporated nor the names of
     * its contributors may be used to endorse or promote products derived
     * from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    
    #include <stdint.h>
    #include <stddef.h>
    #include <stdbool.h>
    #include <ti/drv/spi/SPI.h>
    #include <ti/drv/spi/soc/QSPI_v1.h>
    #include <ti/csl/src/ip/qspi/V1/qspi.h>
    #include <ti/csl/src/ip/qspi/V1/hw_qspi.h>
    #include <ti/drv/spi/src/SPI_osal.h>
    #include <ti/drv/uart/UART_stdio.h>
    
    /*#define WORD_INTERRUPT*/
    
    /* QSPI AM57x functions */
    static void       QSPI_close_v1(SPI_Handle handle);
    static void       QSPI_init_v1(SPI_Handle handle);
    static SPI_Handle QSPI_open_v1(SPI_Handle handle, const SPI_Params *params);
    static bool       QSPI_transfer_v1(SPI_Handle handle,
                                          SPI_Transaction *transaction);
    static void       QSPI_primeTransfer_v1(SPI_Handle handle,
                                              const SPI_Transaction *transaction);
    static void       QSPI_transferCallback_v1(SPI_Handle handle,
                                                  SPI_Transaction *msg);
    static int32_t QSPI_control_v1(SPI_Handle handle, uint32_t cmd, const void *arg);
    static void QSPI_transferCancel_v1(SPI_Handle handle);
    static void QSPI_hwiFxn_v1(uintptr_t arg);
    static void QSPI_read_v1(SPI_Handle handle, const SPI_Transaction *transaction);
    static void QSPI_write_v1(SPI_Handle handle, const SPI_Transaction *transaction);
    static void QSPI_mmap_mode_write_v1(SPI_Handle handle,
                                        const SPI_Transaction *transaction);
    static void QSPI_cmd_mode_write_v1(SPI_Handle handle,
                                       const SPI_Transaction *transaction);
    static void QSPI_cmd_mode_read_v1(SPI_Handle handle,
                                      const SPI_Transaction *transaction);
    static void QSPI_mmap_mode_read_v1(SPI_Handle handle,
                                       const SPI_Transaction *transaction);
    static void QSPIMmapCsEnable(uint32_t baseAddr, uint32_t chipSelect);
    
    typedef enum QSPI_intrPollMode_s {
        SPI_OPER_MODE_BLOCKING = 0U,  /*! Interrupt based blocking mode */
        SPI_OPER_MODE_POLLING,        /*! Non interrupt based blocking mode */
        SPI_OPER_MODE_CALLBACK        /*! Interrupt based call back mode */
    } QSPI_intrPollMode;
    
    
    
    /* SPI function table for QSPI AM57x implementation */
    const SPI_FxnTable QSPI_FxnTable_v1 = {
        &QSPI_close_v1,
        &QSPI_control_v1,
        &QSPI_init_v1,
        &QSPI_open_v1,
        &QSPI_transfer_v1,
        &QSPI_transferCancel_v1,
        NULL
    };
    
    #define   CTRL_CORE_CONTROL_IO_2       (0x4A002558U)
    #define   QSPI_MMAP_CS_SHIFT           (0x8U)
    
    /*
     *  ======== QSPI_close_v1 ========
     */
    static void QSPI_close_v1(SPI_Handle handle)
    {
        QSPI_v1_Object   *object = NULL;
        QSPI_HwAttrs const  *hwAttrs = NULL;
    
        /* Input parameter validation */
        if (handle != NULL)
        {
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)handle->object;
        hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
    
        /* Mask I2C interrupts */
        QSPIintDisable(hwAttrs->baseAddr,
            (QSPI_INTR_MASK_FRAME | QSPI_INTR_MASK_WORD));
    
        /* Destruct the Hwi */
        if(SPI_OPER_MODE_POLLING != object->intrPollMode)
        {
            SPI_osalHardwareIntDestruct(object->hwi,hwAttrs->eventId);
        }
    
        /* Destruct the instance lock */
        SPI_osalDeleteBlockingLock(object->mutex);
    
        /* Destruct the transfer completion lock */
        if(SPI_OPER_MODE_BLOCKING == object->intrPollMode)
        {
            SPI_osalDeleteBlockingLock(object->transferComplete);
        }
    
        /* Open flag is set false */
        object->isOpen = (bool)false;
        }
    
        return;
    }
    
    /*
     *  ======== QSPI_hwiFxn_v1 ========
     *  Hwi interrupt handler to service the QSPI peripheral
     *
     *  The handler is a generic handler for a QSPI object.
     */
    static void QSPI_hwiFxn_v1(uintptr_t arg)
    {
        uint32_t            intrStatus;
        QSPI_v1_Object      *object = NULL;
        QSPI_HwAttrs const  *hwAttrs = NULL;
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)(((SPI_Handle)arg)->object);
        hwAttrs = (const QSPI_HwAttrs *)(((SPI_Handle)arg)->hwAttrs);
    
        /* Read the interrupt status register */
        intrStatus = QSPIintStatus(hwAttrs->baseAddr);
    
        /* If word count interrupt */
        if(intrStatus & QSPI_INTR_MASK_WORD)
        {
            /* Clear interrupt status */
            QSPIintClear(hwAttrs->baseAddr, QSPI_INTR_MASK_WORD);
    
            /* Call the call back function */
            object->qspiParams.transferCallbackFxn((SPI_Handle)arg, NULL);
        }
    
        /* If word count interrupt */
        if(intrStatus & QSPI_INTR_MASK_FRAME)
        {
            /* Clear interrupt status */
            QSPIintClear(hwAttrs->baseAddr, QSPI_INTR_MASK_FRAME);
    
            /* Call the call back function */
            object->qspiParams.transferCallbackFxn((SPI_Handle)arg, NULL);
        }
    
        return;
    }
    
    /*
     *  ======== QSPI_init_v1 ========
     */
    static void QSPI_init_v1(SPI_Handle handle)
    {
        /* Input parameter validation */
        if (handle != NULL)
        {
            /* Mark the object as available */
            ((QSPI_v1_Object *)(handle->object))->isOpen = (bool)false;
        }
    }
    
    
    /*
     *  ======== QSPI_open_v1 ========
     */
    static SPI_Handle QSPI_open_v1(SPI_Handle handle, const SPI_Params *params)
    {
        SemaphoreP_Params     semParams;
        uint32_t       key;
        QSPI_v1_Object   *object = NULL;
        QSPI_HwAttrs const  *hwAttrs = NULL;
        OsalRegisterIntrParams_t interruptRegParams;
        uint8_t ret_flag = 0u;
    
        /* Input parameter validation */
        if (handle != NULL)
        {
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)handle->object;
        hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
    
        /* Determine if the device index was already opened */
        key = SPI_osalHardwareIntDisable();
        if(object->isOpen == (bool)true) {
            SPI_osalHardwareIntRestore(key);
            handle = NULL;
        }
        else
        {
          /* Mark the handle as being used */
          object->isOpen = (bool)true;
          SPI_osalHardwareIntRestore(key);
    
          /* Store the I2C parameters */
          if (params == NULL) {
            /* No params passed in, so use the defaults */
            SPI_Params_init(&(object->qspiParams));
          }
          else {
            /* Copy the params contents */
            object->qspiParams = *params;
          }
    
          /* Copy the controller mode from hardware attributes to object */
          object->qspiMode = hwAttrs->operMode;
          object->rxLines  = hwAttrs->rxLines;
    
          /* Extract QSPI operating mode based on hwAttrs and input parameters */
          if(SPI_MODE_BLOCKING == object->qspiParams.transferMode)
          {
            if(true == hwAttrs->intrEnable)
            {
                object->intrPollMode = SPI_OPER_MODE_BLOCKING;
            }
            else
            {
                object->intrPollMode = SPI_OPER_MODE_POLLING;
            }
          }
          else
          {
            object->intrPollMode = SPI_OPER_MODE_CALLBACK;
          }
    
    
          /* Extract the polling mode from hardware attributes. */
          if(SPI_OPER_MODE_POLLING != object->intrPollMode)
          {
    		/* register interrrupt when the 1st channel of the instance is opened */
            Osal_RegisterInterrupt_initParams(&interruptRegParams);             
    
            interruptRegParams.corepacConfig.name=NULL;
            interruptRegParams.corepacConfig.priority = 0x20;
            interruptRegParams.corepacConfig.corepacEventNum = hwAttrs->eventId;
            interruptRegParams.corepacConfig.intVecNum=hwAttrs->intrNum; /* Host Interrupt vector */
            interruptRegParams.corepacConfig.isrRoutine  = (void (*)(uintptr_t))(&QSPI_hwiFxn_v1);
            interruptRegParams.corepacConfig.arg         = (uintptr_t)handle;
    
            SPI_osalRegisterInterrupt(&interruptRegParams,&(object->hwi));
    
            if(object->hwi == NULL) {
                QSPI_close_v1(handle);
                ret_flag = 1u;
                handle = NULL;
            }
          }
    
          if(ret_flag == 0u)
          {
            /*
             * Construct thread safe handles for this QSPI peripheral
             * Semaphore to provide exclusive access to the QSPI peripheral
             */
            SPI_osalSemParamsInit(&semParams);
            semParams.mode = SemaphoreP_Mode_BINARY;
            object->mutex = SPI_osalCreateBlockingLock(1U, &semParams);
    
            /*
             * Store a callback function that posts the transfer complete
             * semaphore for synchronous mode
             */
            if (object->intrPollMode == SPI_OPER_MODE_BLOCKING) {
              /*
               * Semaphore to cause the waiting task to block for the QSPI
               * to finish
               */
              object->transferComplete = SPI_osalCreateBlockingLock(0, &semParams);
    
              /* Store internal callback function */
              object->qspiParams.transferCallbackFxn = &QSPI_transferCallback_v1;
            }
            if(object->intrPollMode == SPI_OPER_MODE_CALLBACK){
              /* Check to see if a callback function was defined for async mode */
              OSAL_Assert(object->qspiParams.transferCallbackFxn == NULL);
            }
    
            /* Setting IDLE mode for QSPI controller */
            QSPIconfigIdleMode(hwAttrs->baseAddr, QSPI_SYSCONFIG_IDLE_MODE_NO_IDLE);
    
            /* Set clock mode in mode 3 */
            QSPISetClkMode(hwAttrs->baseAddr, hwAttrs->chipSelect, hwAttrs->frmFmt);
            QSPISetCsPol(hwAttrs->baseAddr, hwAttrs->chipSelect, hwAttrs->csPol);
            QSPISetDataDelay(hwAttrs->baseAddr, hwAttrs->chipSelect,
                              hwAttrs->dataDelay);
    
            /* Enable clock and set divider value */
            QSPISetPreScaler(hwAttrs->baseAddr, 0x0U);
    
            /* Clear the interrupts and interrupt status */
            QSPIintDisable(hwAttrs->baseAddr,
                (QSPI_INTR_MASK_FRAME | QSPI_INTR_MASK_WORD)) ;
            QSPIintClear(hwAttrs->baseAddr,
                (QSPI_INTR_MASK_FRAME | QSPI_INTR_MASK_WORD));
    
            QSPISetMemMapNumAddrBytes(hwAttrs->baseAddr,
                          hwAttrs->chipSelect,
                          QSPI_MEM_MAP_NUM_ADDR_BYTES_THREE);
    
            /* Enable memory mapped port by default */
            QSPISetMemAddrSpace(hwAttrs->baseAddr,
                    hwAttrs->chipSelect,
                    QSPI_MEM_MAP_PORT_SEL_MEM_MAP_PORT);
    
    
            QSPIMmapCsEnable(hwAttrs->baseAddr, hwAttrs->chipSelect);
    
            /* Return the address of the spiObjectArray[i] configuration structure */
          }
        }
        }
        return(handle);
    }
    
    static void QSPIMmapCsEnable(uint32_t baseAddr, uint32_t chipSelect)
    {
    #if !defined(SOC_AM437x)
        uint32_t regVal;
    
        regVal = HW_RD_REG32(CTRL_CORE_CONTROL_IO_2);
        regVal |= ((chipSelect + 1U) << QSPI_MMAP_CS_SHIFT);
        HW_WR_REG32(CTRL_CORE_CONTROL_IO_2, regVal);
    #endif
    }
    
    /*
     *  ======== QSPI_primeTransfer_v1 =======
     */
    static void QSPI_primeTransfer_v1(SPI_Handle handle,
                                      const SPI_Transaction *transaction)
    {
        QSPI_v1_Object  *object = NULL;
        QSPI_HwAttrs const  *hwAttrs = NULL;
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)handle->object;
        hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
    
        /* Store the new internal counters and pointers */
        object->writeBufIdx = (uint8_t*)transaction->txBuf;
        object->writeCountIdx = transaction->count;
    
        object->readBufIdx = (uint8_t*)transaction->rxBuf;
        object->readCountIdx = transaction->count;
    
    
        /* Interrupt mode */
        if(object->intrPollMode != SPI_OPER_MODE_POLLING)
        {
    #ifdef WORD_INTERRUPT
            /* Enable the word count interrupt */
            QSPIintEnable(hwAttrs->baseAddr, QSPI_INTR_MASK_WORD);
    #else
            /* Enable the frame count interrupt */
            QSPIintEnable(hwAttrs->baseAddr, QSPI_INTR_MASK_FRAME);
    #endif
        }
    
        /* Polling Mode */
        if(object->intrPollMode == SPI_OPER_MODE_POLLING)
        {
            /* No Specific implementation is needed here. */
        }
    
        /* Identify the direction of transfer (whether read/write) */
        if(SPI_TRANSACTION_TYPE_READ == object->transactionType)
        {
            QSPI_read_v1(handle, transaction);
        }
    
        if(SPI_TRANSACTION_TYPE_WRITE == object->transactionType)
        {
            QSPI_write_v1(handle, transaction);
        }
    }
    
    static void QSPI_mmap_mode_read_v1(SPI_Handle handle,
                                       const SPI_Transaction *transaction)
    {
        QSPI_HwAttrs const  *hwAttrs = NULL;
        uint8_t *pDst = NULL;
        uint8_t *pSrc = NULL;
    
        uint32_t count;
        uint32_t mmapReadCmd = 0U;
        QSPI_v1_Object  *object;
        uint32_t offset;
        bool Flag = true;
    
        pDst = (uint8_t *)transaction->rxBuf;
        pSrc = (uint8_t *)transaction->txBuf;
        count = transaction->count;
    
        /* Get the pointer to the object and hwAttrs */
        hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
        object = (QSPI_v1_Object*)handle->object;
    
        uint32_t temp_addr = ((uint32_t)hwAttrs->memMappedBaseAddr + (uint32_t)transaction->txBuf);
        pSrc = ((uint8_t *)(temp_addr));
    
        offset = (uint32_t)transaction->txBuf;
    
        /* Extract memory map mode read command */
        mmapReadCmd = (uint32_t)object->transferCmd;
    
        /* Set the number of address bytes to three */
        QSPISetMemMapNumAddrBytes(hwAttrs->baseAddr, hwAttrs->chipSelect,
            QSPI_MEM_MAP_NUM_ADDR_BYTES_THREE);
    
    
        /* 4 byte addressing mode */
        if(offset > (uint32_t)0xFFFFFF)
        {
            /* Enable 4 byte addressing mode */
            QSPISetMemMapNumAddrBytes(hwAttrs->baseAddr, hwAttrs->chipSelect,
                QSPI_MEM_MAP_NUM_ADDR_BYTES_FOUR);
        }
    
        switch(object->rxLines)
        {
            case QSPI_RX_LINES_SINGLE:
            {
                QSPISetMemMapReadCmd(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    mmapReadCmd);
                QSPISetMemMapReadType(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    QSPI_MEM_MAP_READ_TYPE_NORMAL);
                QSPISetMemMapNumDummyBits(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    0x0U);
                break;
            }
    
            case QSPI_RX_LINES_DUAL:
            {
                QSPISetMemMapReadCmd(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    mmapReadCmd);
                QSPISetMemMapReadType(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    QSPI_MEM_MAP_READ_TYPE_DUAL);
                QSPISetMemMapNumDummyBits(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    0x8U);
                break;
            }
    
            case QSPI_RX_LINES_QUAD:
            {
                QSPISetMemMapReadCmd(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    mmapReadCmd);
                QSPISetMemMapReadType(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    QSPI_MEM_MAP_READ_TYPE_QUAD);
                QSPISetMemMapNumDummyBits(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    0x8U);
                break;
            }
    
            default:
            break;
        }
    
        while(count)
        {
    	if((offset > (uint32_t)0xFFFFFF) && (Flag == true))
    	{
    		
    		/* Enable 4 byte addressing mode */
           		 QSPISetMemMapNumAddrBytes(hwAttrs->baseAddr, hwAttrs->chipSelect,
                	  	QSPI_MEM_MAP_NUM_ADDR_BYTES_FOUR);
                   
    
    		QSPISetMemMapReadCmd(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    0x6C);
    		
    		QSPISetMemMapNumDummyBits(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    0x8U);
    		Flag =false;		
    	}
    		
    	/* Do the normal memory to memory transfer. Copy will be in bytes */
            *pDst = *pSrc;
            pDst++;
            pSrc++;
            count--;
    	offset++;
    	
         }
    
        /* 4 byte addressing mode */
        if((offset > (uint32_t)0xFFFFFF) || (Flag == false))
        {
            /*
             * After the transfer switch back to 3 byte addressing mode.
             * This is the default mode.
             */
            QSPISetMemMapNumAddrBytes(hwAttrs->baseAddr, hwAttrs->chipSelect,
                QSPI_MEM_MAP_NUM_ADDR_BYTES_THREE);
        }
    }
    
    
    static void QSPI_cmd_mode_read_v1(SPI_Handle handle,
                                      const SPI_Transaction *transaction)
    {
        QSPI_v1_Object  *object;         /* QSPI object */
        QSPI_HwAttrs const  *hwAttrs;    /* QSPI hardware attributes */
        uint32_t count = 0U;         /* transfer length in bytes */
        uint32_t wordLenBytes = 0U;  /* Word length in number of bytes */
        uint32_t cmd = 0;           /* transmit command */
        uint32_t dataVal[4] = {0U, 0U, 0U, 0U};  /* data to be written */
        uint32_t idx, idx1, idx2, idx3;  /* indexes */
        uint32_t numWords = 0U;          /* number of words */
        uint8_t *dstAddr;              /* destination address */
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)handle->object;
        hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
    
        dstAddr = object->readBufIdx;
    
        /*formulate the command */
        HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_FLEN, (object->frmLength - 1));
        HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_WLEN, (object->qspiParams.dataSize - 1));
        HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_CSNUM, hwAttrs->chipSelect);
    
        switch(object->rxLines)
        {
            case QSPI_RX_LINES_SINGLE:
            {
                HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_CMD,
                    QSPI_SPI_CMD_REG_CMD_FOUR_PIN_READ_SINGLE);
                break;
            }
            case QSPI_RX_LINES_DUAL:
            {
                HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_CMD,
                    QSPI_SPI_CMD_REG_CMD_FOUR_PIN_READ_DUAL);
                break;
            }
            case QSPI_RX_LINES_QUAD:
            {
                HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_CMD,
                    QSPI_SPI_CMD_REG_CMD_SIX_PIN_READ_QUAD);
                break;
            }
    
            default:
            break;
        }
    
        /* Enable interrupts in the polling mode */
        if(object->intrPollMode != SPI_OPER_MODE_POLLING)
        {
    #ifdef WORD_INTERRUPT
            /* Enable word count interrupt */
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_WIRQ, true);
    #else
            /* Enable frame count interrupt */
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_FIRQ, true);
    #endif
    
        }
        else
        {
            /* Disable word count interrupt */
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_WIRQ, false);
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_FIRQ, false);
        }
    
        /* Extract frame length in bytes */
        count = transaction->count;
    
        /* Extract word length in number of bytes */
        wordLenBytes = (object->qspiParams.dataSize >> 3U);
    
        /* Write the data into shift registers */
        while(count)
        {
            /* Write tx command to command register */
            QSPIsetCommandReg(hwAttrs->baseAddr, cmd);
    
    #ifdef WORD_INTERRUPT
            /* interrupt mode */
            if(SPI_OPER_MODE_BLOCKING == object->intrPollMode)
            {
                /* wait for the lock posted form the word completion interrupt */
                SPI_osalPendLock(object->transferComplete, SemaphoreP_WAIT_FOREVER);
            }
    
            if(SPI_OPER_MODE_POLLING == object->intrPollMode)
            {
                /* Wait for the QSPI busy status */
                QSPIWaitIdle(hwAttrs->baseAddr);
            }
    #else
    
                /* Wait for the QSPI busy status */
                QSPIWaitIdle(hwAttrs->baseAddr);
    #endif
    
    
            if(wordLenBytes <= 4U)
            {
                numWords = 1U;
    
                /* Read data from the data registers */
                QSPIreadData(hwAttrs->baseAddr, &dataVal[0], (int32_t)numWords);
    
                /* Write the extracted data into receive buffer */
                for(idx = 0U; idx < wordLenBytes; idx++)
                {
                    *dstAddr = (uint8_t)((dataVal[0] >> (8U - (8U * (idx + 1U)))) &
                        (0x000000FFU));
                    dstAddr++;
                }
            }
            else if((wordLenBytes > 4U) && (wordLenBytes <= 8U))
            {
                numWords = 2U;
    
                /* Read data from the data registers */
                QSPIreadData(hwAttrs->baseAddr, &dataVal[0], (int32_t)numWords);
    
                /* Formulate the 32 bit word to write to data register */
                for(idx = 0U; idx < 4U; idx++)
                {
                    *dstAddr = (uint8_t)((dataVal[0] >> (8U - (8U * (idx + 1U)))) &
                        (0x000000FFU));
                    dstAddr++;
                }
    
                for(idx1 = 4U; idx1 < wordLenBytes; idx1++)
                {
                    *dstAddr = (uint8_t)((dataVal[1] >> (8U - (8U * (idx1 + 1U)))) &
                        (0x000000FFU));
                    dstAddr++;
                }
            }
            else if((wordLenBytes > 8U) && (wordLenBytes <= 12U))
            {
                numWords = 3U;
    
                /* Read data from the data registers */
                QSPIreadData(hwAttrs->baseAddr, &dataVal[0], (int32_t)numWords);
    
                /* Formulate the 32 bit word to write to data register */
                for(idx = 0U; idx < 4U; idx++)
                {
                    *dstAddr = (uint8_t)((dataVal[0] >> (8U - (8U * (idx + 1U)))) &
                        (0x000000FFU));
                    dstAddr++;
                }
    
                for(idx1 = 4U; idx1 < 8U; idx1++)
                {
                    *dstAddr = (uint8_t)((dataVal[1] >> (8U - (8U * (idx1 + 1U)))) &
                        (0x000000FFU));
                    dstAddr++;
                }
    
                for(idx2 = 8U; idx2 < 12U; idx2++)
                {
                    *dstAddr = (uint8_t)((dataVal[2] >> (8U - (8U * (idx2 + 1U)))) &
                        (0x000000FFU));
                    dstAddr++;
                }
            }
            else if((wordLenBytes > 12U) && (wordLenBytes <= 16U))
            {
                numWords = 4U;
    
                /* Read data from the data registers */
                QSPIreadData(hwAttrs->baseAddr, &dataVal[0], (int32_t)numWords);
    
                /* Formulate the 32 bit word to write to data register */
                for(idx = 0U; idx < 4U; idx++)
                {
                    *dstAddr = (uint8_t)((dataVal[0] >> (8U - (8U * (idx + 1U)))) &
                        (0x000000FFU));
                    dstAddr++;
                }
    
                for(idx1 = 4U; idx1 < 8U; idx1++)
                {
                    *dstAddr = (uint8_t)((dataVal[1] >> (8U - (8U * (idx1 + 1U)))) &
                        (0x000000FFU));
                    dstAddr++;
                }
    
                for(idx2 = 8U; idx2 < 12U; idx2++)
                {
                    *dstAddr = (uint8_t)((dataVal[2] >> (8U - (8U * (idx2 + 1U)))) &
                        (0x000000FFU));
                    dstAddr++;
                }
    
                for(idx3 = 12U; idx3 < 16U; idx3++)
                {
                    *dstAddr = (uint8_t)((dataVal[3] >> (8U - (8U * (idx3 + 1U)))) &
                        (0x000000FFU));
                    dstAddr++;
                }
            }
            else
            {
                /* Not supported */
            }
    
            /* Update the number of bytes to be transmitted */
            count -= wordLenBytes;
        }
    
        /* Update read buffer index in the object */
        object->readBufIdx = dstAddr;
    }
    
    
    static void QSPI_read_v1(SPI_Handle handle, const SPI_Transaction *transaction)
    {
        QSPI_v1_Object  *object = NULL;
    
        object = (QSPI_v1_Object*)handle->object;
    
        if(QSPI_OPER_MODE_MMAP == object->qspiMode)
        {
            QSPI_mmap_mode_read_v1(handle, transaction);
        }
    
        if(QSPI_OPER_MODE_CFG == object->qspiMode)
        {
            QSPI_cmd_mode_read_v1(handle, transaction);
        }
    }
    
    static void QSPI_mmap_mode_write_v1(SPI_Handle handle,
                                        const SPI_Transaction *transaction)
    {
        QSPI_HwAttrs const  *hwAttrs;          /* QSPI hardware attributes */
        uint32_t mmapWriteCmd = 0U;        /* Mmap command */
        uint32_t count = 0U;               /* transaction length */
        uint8_t *pSrc;                   /* Source address */
        uint8_t *pDst;                   /* Destination address */
        QSPI_v1_Object  *object;               /* QSPI object */
        uint32_t offset;
    
        /* Copy flash transaction parameters to local variables */
        pSrc = (uint8_t*)transaction->rxBuf;
        pDst = (uint8_t*)transaction->txBuf;
        count = transaction->count;
    
        /* Get the pointer to the object and hwAttrs */
        hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
        object = (QSPI_v1_Object*)handle->object;
    
        /* Compute the flash destination address */
        uint32_t temp_addr = ((uint32_t)hwAttrs->memMappedBaseAddr + (uint32_t)transaction->txBuf);
        pDst = ((uint8_t *)(temp_addr));
    
        offset = (uint32_t)transaction->txBuf;
    
        /* Extract memory map mode command */
        mmapWriteCmd = (uint32_t)object->transferCmd;
    
        QSPISetMemMapWriteCmd(hwAttrs->baseAddr, hwAttrs->chipSelect, mmapWriteCmd);
        QSPISetMemMapNumAddrBytes(hwAttrs->baseAddr, hwAttrs->chipSelect,
            QSPI_MEM_MAP_NUM_ADDR_BYTES_THREE);
        QSPISetMemAddrSpace(hwAttrs->baseAddr, hwAttrs->chipSelect,
            QSPI_MEM_MAP_PORT_SEL_MEM_MAP_PORT);
    
        QSPIMmapCsEnable(hwAttrs->baseAddr, hwAttrs->chipSelect);
    
        /* 4 byte addressing mode. */
        if(offset > (uint32_t)0xFFFFFF)
        {
            /* Switch to four byte addressing mode */
            QSPISetMemMapNumAddrBytes(hwAttrs->baseAddr, hwAttrs->chipSelect,
                QSPI_MEM_MAP_NUM_ADDR_BYTES_FOUR);
        }
    
        while(count)
        {
            *pDst = *pSrc;
            pDst++;
            pSrc++;
            count--;
        }
    
        /* 4 byte addressing mode. */
        if(offset > (uint32_t)0xFFFFFF)
        {
            /* Switch back to three byte addressing mode. */
            QSPISetMemMapNumAddrBytes(hwAttrs->baseAddr, hwAttrs->chipSelect,
                QSPI_MEM_MAP_NUM_ADDR_BYTES_FOUR);
        }
    }
    
    
    static void QSPI_cmd_mode_write_v1(SPI_Handle handle,
                                       const SPI_Transaction *transaction)
    {
        QSPI_v1_Object  *object;         /* QSPI object */
        QSPI_HwAttrs const  *hwAttrs;    /* QSPI hardware attributes */
        uint32_t count = 0U;         /* transfer length in bytes */
        uint32_t wordLenBytes = 0U;  /* Word length in number of bytes */
        uint32_t cmd = 0;           /* transmit command */
        uint32_t dataVal[4] = {0U, 0U, 0U, 0U};  /* data to be written */
        uint32_t idx, idx1, idx2, idx3;          /* indexes */
        uint32_t numWords = 0U;                  /* number of words */
        uint8_t *srcAddr;                      /* Source address */
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)handle->object;
        hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
    
        srcAddr = object->writeBufIdx;
    
        /* formulate the command */
        HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_FLEN, (object->frmLength - 1));
        HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_WLEN, (object->qspiParams.dataSize - 1));
        HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_CSNUM, hwAttrs->chipSelect);
        HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_CMD,
            QSPI_SPI_CMD_REG_CMD_FOUR_PIN_WRITE_SINGLE);
    
    
        /* Enable interrupts in the polling mode */
        if(object->intrPollMode != SPI_OPER_MODE_POLLING)
        {
    #ifdef WORD_INTERRUPT
            /* Enable word count interrupt */
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_WIRQ, true);
    #else
            /* Enable frame count interrupt */
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_FIRQ, true);
    #endif
    
        }
        else
        {
            /* Disable word count interrupt */
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_WIRQ, false);
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_FIRQ, false);
        }
    
    
        /* Extract frame length in bytes */
        count = transaction->count;
    
        /* Extract word length in number of bytes */
        wordLenBytes = (object->qspiParams.dataSize >> 3U);
    
        /* Write the data into shift registers */
        while(count)
        {
            dataVal[0] = 0;
            dataVal[1] = 0;
            dataVal[2] = 0;
            dataVal[3] = 0;
    
            if(wordLenBytes <= 4U)
            {
                /* Formulate the 32 bit word to write to data register */
                for(idx = 0U; idx < wordLenBytes; idx++)
                {
                    dataVal[0] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                numWords = 1U;
            }
            else if((wordLenBytes > 4U) && (wordLenBytes <= 8U))
            {
                /* Formulate the 32 bit word to write to data register */
                for(idx = 0U; idx < 4U; idx++)
                {
                    dataVal[0] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                for(idx1 = 4U; idx1 < wordLenBytes; idx1++)
                {
                    dataVal[1] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                numWords = 2U;
            }
            else if((wordLenBytes > 8U) && (wordLenBytes <= 12U))
            {
                /* Formulate the 32 bit word to write to data register */
                for(idx = 0U; idx < 4U; idx++)
                {
                    dataVal[0] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                for(idx1 = 4U; idx1 < 8U; idx1++)
                {
                    dataVal[1] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                for(idx2 = 8U; idx2 < 12U; idx2++)
                {
                    dataVal[2] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                numWords = 3U;
            }
            else if((wordLenBytes > 12U) && (wordLenBytes <= 16U))
            {
                /* Formulate the 32 bit word to write to data register */
                for(idx = 0U; idx < 4U; idx++)
                {
                    dataVal[0] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                for(idx1 = 4U; idx1 < 8U; idx1++)
                {
                    dataVal[1] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                for(idx2 = 8U; idx2 < 12U; idx2++)
                {
                    dataVal[2] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                for(idx3 = 12U; idx3 < 16U; idx3++)
                {
                    dataVal[3] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                numWords = 4U;
            }
            else
            {
                /* Not supported */
            }
    
            /* Write data to data registers */
            QSPIwriteData(hwAttrs->baseAddr, &dataVal[0], (int32_t)numWords);
    
            /* Write tx command to command register */
            QSPIsetCommandReg(hwAttrs->baseAddr, cmd);
    
    #ifdef WORD_INTERRUPT
            /* interrupt mode */
            if(SPI_OPER_MODE_BLOCKING == object->intrPollMode)
            {
                /* wait for the lock posted form the word completion interrupt */
                SPI_osalPendLock(object->transferComplete, SemaphoreP_WAIT_FOREVER);
            }
    
            if(SPI_OPER_MODE_POLLING == object->intrPollMode)
            {
                /* Wait for the QSPI busy status */
                QSPIWaitIdle(hwAttrs->baseAddr);
            }
    #else
    
            /* Wait for the QSPI busy status */
            QSPIWaitIdle(hwAttrs->baseAddr);
    #endif
    
    
            /* Update the number of bytes to be transmitted */
            count -= wordLenBytes;
        }
    
        /* Update write buffer index in the object */
        object->writeBufIdx = srcAddr;
    }
    
    
    static void QSPI_write_v1(SPI_Handle handle, const SPI_Transaction *transaction)
    {
        QSPI_v1_Object  *object = NULL;         /* QSPI object */
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)handle->object;
    
        if(QSPI_OPER_MODE_MMAP == object->qspiMode)
        {
            QSPI_mmap_mode_write_v1(handle, transaction);
        }
    
        if(QSPI_OPER_MODE_CFG == object->qspiMode)
        {
            QSPI_cmd_mode_write_v1(handle, transaction);
        }
    }
    
    
    /*
     *  ======== i2c_am57x_transfer ========
     */
    static bool QSPI_transfer_v1(SPI_Handle handle, SPI_Transaction *transaction)
    {
        bool  ret = false;                /* return value */
        QSPI_v1_Object   *object;         /* QSPI object */
        QSPI_HwAttrs const  *hwAttrs;     /* QSPI hardware attributes */
    
        /* Input parameter validation */
        if ((handle != NULL) && (transaction != NULL))
        {
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)handle->object;
        hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
    
        /* Check if anything needs to be written or read */
        if (0 != transaction->count)
        {
            transaction->status=SPI_TRANSFER_STARTED;
    		/* Acquire the lock for this particular I2C handle */
            SPI_osalPendLock(object->mutex, SemaphoreP_WAIT_FOREVER);
    
            /* Book keeping of transmit and receive buffers. */
            object->writeBufIdx = (uint8_t *)transaction->txBuf;
            object->writeCountIdx = transaction->count;
            object->readBufIdx =  (uint8_t *)transaction->rxBuf;
            object->readCountIdx = transaction->count;
    
    
             /*
             * QSPI_primeTransfer_v1 is a longer process and
             * protection is needed from the QSPI interrupt
             */
            if (SPI_OPER_MODE_POLLING != object->intrPollMode)
            {
                SPI_osalHardwareIntrEnable(hwAttrs->eventId,hwAttrs->intrNum);
            }
    
            QSPI_primeTransfer_v1(handle, transaction);
    
            if (object->intrPollMode == SPI_OPER_MODE_BLOCKING) {
    #ifdef WORD_INTERRUPT
                /* transfer is completed and semaphore is posted. */
                ret = (bool)true;
    #else
                /* If the word count is zero then wait for semaphore */
                if(object->frmLength == QSPIgetStatusWordCount(hwAttrs->baseAddr))
                {
                  /* wait for the lock posted form the word completion interrupt */
                  SPI_osalPendLock(object->transferComplete, SemaphoreP_WAIT_FOREVER);
                }
    
                /* transfer is completed and semaphore is posted. */
    			transaction->status=SPI_TRANSFER_COMPLETED;
                ret = (bool)true;
    #endif
            }
            else {
                /* Always return true if in Asynchronous mode */
                ret = (bool)true;
            }
    
            /* Release the lock for this particular I2C handle */
            SPI_osalPostLock(object->mutex);
        } else {
    	   transaction->status=SPI_TRANSFER_CANCELED;
    	}
        }
    
        /* Return the number of bytes transferred by the I2C */
        return (ret);
    }
    
    /*
     *  ======== QSPI_transferCallback_v1 ========
     */
    static void QSPI_transferCallback_v1(SPI_Handle handle, SPI_Transaction *msg)
    {
        QSPI_v1_Object   *object;            /* QSPI object */
    
        /* Get the pointer to the object */
        object = (QSPI_v1_Object*)handle->object;
    
        if(msg!=NULL) {
    	   msg->status=SPI_TRANSFER_COMPLETED;
    	}
    	
    	/* Indicate transfer complete */
        SPI_osalPostLock(object->transferComplete);
    }
    
    /*
     *  ======== QSPI_control_v1 ========
     */
    static int32_t QSPI_control_v1(SPI_Handle handle, uint32_t cmd, const void *arg)
    {
        QSPI_v1_Object   *object;            /* QSPI object */
        int32_t retVal = SPI_STATUS_ERROR;
    
        /* Input parameter validation */
        if (handle != NULL)
        {
        /* Get the pointer to the object */
        object = (QSPI_v1_Object*)handle->object;
    
        switch (cmd)
        {
            case SPI_V1_CMD_SETFRAMELENGTH:
            {
                object->frmLength = *(uint32_t *)arg;
                retVal = SPI_STATUS_SUCCESS;
                break;
            }
    
            case SPI_V1_CMD_MMAP_TRANSFER_CMD:
            {
                object->transferCmd = *(uint8_t *)arg;
                retVal = SPI_STATUS_SUCCESS;
                break;
            }
    
            case SPI_V1_CMD_TRANSFERMODE_RW:
            {
                object->transactionType = *(uint32_t *)arg;
                retVal = SPI_STATUS_SUCCESS;
                break;
            }
    
            case SPI_V1_CMD_SETCONFIGMODE:
            {
                object->qspiMode = QSPI_OPER_MODE_CFG;
                retVal = SPI_STATUS_SUCCESS;
                break;
            }
    
            case SPI_V1_CMD_SETRXLINES:
            {
                object->rxLines = *(uint32_t *)arg;
                retVal = SPI_STATUS_SUCCESS;
                break;
            }
    
            case SPI_V1_CMD_SETMEMMORYMAPMODE:
            {
                object->qspiMode = QSPI_OPER_MODE_MMAP;
                retVal = SPI_STATUS_SUCCESS;
                break;
            }
    
            default:
            retVal = SPI_STATUS_UNDEFINEDCMD;
            break;
        }
        }
    
        return retVal;
    }
    
    
    /*
     *  ======== QSPI_transferCancel_v1 ========
     */
    static void QSPI_transferCancel_v1(SPI_Handle handle)
    {
        return;
    }
    
    /**
     *  \file   S25FL.c
     *
     *  \brief  Flash specific driver implementation.
     *
     */
    
    /*
     * Copyright (C) 2014-2018 Texas Instruments Incorporated - http://www.ti.com/
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * Redistributions of source code must retain the above copyright
     * notice, this list of conditions and the following disclaimer.
     *
     * Redistributions in binary form must reproduce the above copyright
     * notice, this list of conditions and the following disclaimer in the
     * documentation and/or other materials provided with the
     * distribution.
     *
     * Neither the name of Texas Instruments Incorporated nor the names of
     * its contributors may be used to endorse or promote products derived
     * from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    
    #include "qspi_flash.h"
    #include <ti/drv/spi/SPI.h>
    #include <ti/drv/spi/soc/QSPI_v1.h>
    #include <ti/drv/uart/UART_stdio.h>
    
    /*!
     *  @brief Flash object containing flash attributes.
     */
    S25FL_Object s25flObject = {NULL,
                                4,
                                S25FL_FLASH_SECTOR_SIZE,
                                S25FL_FLASH_BLOCK_SIZE,
                                S25FL_FLASH_DEVICE_SIZE,
                                S25FL_FLASH_DEVICE_ID};
    
    
    static bool SF25FL_ConfigMode_Write(uint32_t dstOffstAddr,
                                        unsigned char* srcAddr,
                                        uint32_t length,
                                        S25FL_Handle flashHandle);
    
    /*
     *  ======== SF25FL_close ========
     */
    void SF25FL_close(S25FL_Handle handle)
    {
        SPI_close(handle->spiHandle);
    }
    
    /*
     *  ======== SF25FL_open ========
     */
    S25FL_Handle SF25FL_open(unsigned int index, SPI_Params *params)
    {
        S25FL_Handle s25flHandle;
    
        s25flHandle = &s25flObject;
    
        /* Open SPI driver for SF25FL */
        s25flHandle->spiHandle = SPI_open(index, params);
    
        return s25flHandle;
    }
    
    /*
     *  ======== SF25FL_bufferWrite ========
     */
    bool SF25FL_bufferWrite(S25FL_Handle flashHandle,
                            S25FL_Transaction* flashTransaction)
    {
        bool retVal = false;                        /* return value */
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        SPI_Transaction transaction;                /* SPI transaction structure */
        unsigned int idx;                           /* index */
        uint32_t dstOffstAddr;                      /* Flash offset address */
        unsigned char *srcAddr;                     /* Address of data buffer */
        uint32_t length;                            /* data length in bytes */
        unsigned int transferType;
        unsigned char transferCmd;
        unsigned int step=0,per=0,last_per=0;
        QSPI_v1_Object  *object;
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object *)handle->object;
    
        /* Copy flash transaction parameters to local variables */
        dstOffstAddr = flashTransaction->address;
        srcAddr = flashTransaction->data;
        length = flashTransaction->dataSize;
    
        if(QSPI_OPER_MODE_CFG == object->qspiMode)
        {
            /*
             * Config mode write supports 256 bytes at a time. So if the length is
             * greater than 256, then multiple transactions have to be performed till
             * all the bytes are written.
             */
            while(length > 256)
            {
                SF25FL_ConfigMode_Write(dstOffstAddr, srcAddr, 256, flashHandle);
                dstOffstAddr = dstOffstAddr + (256 / 4);
                srcAddr += 256;
                length -= 256;
            }
            if(length > 0)
            {
                SF25FL_ConfigMode_Write(dstOffstAddr, srcAddr, length, flashHandle);
            }
        }
    
    
        if(QSPI_OPER_MODE_MMAP == object->qspiMode)
        {
    
            if(dstOffstAddr > 0xFFFFFFU)
            {
                /* Enter 32 bit addressing mode */
                S25FLFlash_Enable4ByteAddrMode(flashHandle, true);
            }
    
            for(idx = 0; idx < length; idx++)
            {
    	    step = length/100;
    	    per  =  idx/step;
                /* Write enable */
                S25FLFlash_WriteEnable(flashHandle);
    
                /* Perform the transfer */
                transaction.txBuf = (unsigned char *)dstOffstAddr;
                transaction.rxBuf = srcAddr;
                transaction.count = 1;
    
    	    if(idx <10)
    	    	UART_printf("0x%x\n", *srcAddr);
    
                transferType = SPI_TRANSACTION_TYPE_WRITE;
                if (dstOffstAddr > 0xFFFFFFU)
                {
                    transferCmd  = QSPI_LIB_CMD_PAGE_PRG_4B;
                }
                else
                {
                    transferCmd  = QSPI_LIB_CMD_PAGE_PRG;
                }
    
                SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
                SPI_control(handle, SPI_V1_CMD_MMAP_TRANSFER_CMD, (void *)&transferCmd);
                retVal = SPI_transfer(handle, &transaction);
    	    
                /* Check flash status for completion */
                while ((FlashStatus(flashHandle) & 0x1U));
    	    
                dstOffstAddr += 1;
                srcAddr += 1;
    	    if((idx % step) && (last_per != per))
                {
    
    	    	UART_printf("#");
    		last_per = per;
    	    }
    	    
            }
    
            if(dstOffstAddr > 0xFFFFFFU)
            {
                /* Exit 4 byte addressing mode */
                S25FLFlash_Enable4ByteAddrMode(flashHandle, false);
            }
        }
    
        return retVal;
    }
    
    
    
    bool SF25FL_bufferRead(S25FL_Handle flashHandle,
                           S25FL_Transaction* flashTransaction)
    {
        bool retVal = false;                        /* return value */
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        unsigned char writeVal[4];               /* data to be written */
        SPI_Transaction transaction;             /* SPI transaction structure */
        uint32_t addrLengthInBytes = 3U;         /* Flash address length in bytes */
        uint32_t readCmd;                        /* Read command */
        uint32_t numDummyBits;                   /* Number of dummy bits */
        uint32_t frameLength;                    /* Frame length */
        uint32_t dstOffstAddr;                   /* Flash offset address */
        unsigned char *srcAddr;                  /* Address of data buffer */
        uint32_t length;                         /* data length in bytes */
        unsigned int *tempPtr = (unsigned int *)&writeVal[0];  /* temp pointer */
        unsigned int frmLength;
        unsigned int transferType;
        unsigned char transferCmd;
        QSPI_v1_Object  *object;
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object *)handle->object;
    
        /* Copy flash transaction parameters to local variables */
        dstOffstAddr = (uint32_t)flashTransaction->data;
        srcAddr = (unsigned char *)flashTransaction->address;
        length = flashTransaction->dataSize;
    
        /* Initialize variables */
        frameLength = 0;
        readCmd = 0;
        numDummyBits = 0;
    
        if(QSPI_OPER_MODE_CFG == object->qspiMode)
        {
            //addrLengthInBytes = 3U;
            if(flashTransaction->address > 0xFFFFFF)
            {
                /* Enter 32 bit addressing mode */
                S25FLFlash_Enable4ByteAddrMode(flashHandle, true);
                addrLengthInBytes = 4;
            }
    
            switch(object->rxLines)
            {
                case QSPI_RX_LINES_SINGLE:
                {
                    if(flashTransaction->address > 0xFFFFFF)
                    {
                        readCmd = QSPI_LIB_CMD_READ_SINGLE_4B;
                    }
                    else
                    {
                        readCmd = QSPI_LIB_CMD_READ_SINGLE;
                    }
                    numDummyBits = 0U;
    
                    /* total transaction frame length in number of words (bytes)*/
                    frameLength = length + 1 + addrLengthInBytes;
                    break;
                }
    
                case QSPI_RX_LINES_DUAL:
                {
                    if(flashTransaction->address > 0xFFFFFF)
                    {
                        readCmd = QSPI_LIB_CMD_READ_DUAL_4B;
                    }
                    else
                    {
                        readCmd = QSPI_LIB_CMD_READ_DUAL;
                    }
                    numDummyBits = 8U;
    
                    /* total transaction frame length in number of words (bytes)*/
                    frameLength = length + 1 + 1 + addrLengthInBytes;
                    break;
                }
    
                case QSPI_RX_LINES_QUAD:
                {
                    if(flashTransaction->address > 0xFFFFFF)
                    {
                        readCmd = QSPI_LIB_CMD_READ_QUAD_4B;
                    }
                    else
                    {
                        readCmd = QSPI_LIB_CMD_READ_QUAD;
                    }
                    numDummyBits = 8U;
    
                    /* total transaction frame length in number of words (bytes)*/
                    frameLength = length + 1 + 1 + addrLengthInBytes;
                    break;
                }
    
                default:
                break;
            }
    
            /* total transaction frame length */
            frmLength = frameLength;
            SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
            /* Write read command */
            writeVal[0] = readCmd;
            transaction.txBuf = (unsigned char *)&writeVal[0];
            transaction.rxBuf = NULL;
            transaction.count = 1;
    
            transferType = SPI_TRANSACTION_TYPE_WRITE;
            SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
            retVal = SPI_transfer(handle, &transaction);
    
            /* Write dummy bits for fast read if required */
            if(0 != numDummyBits)
            {
                writeVal[0] = 0U;
                transaction.txBuf = (unsigned char *)&writeVal[0];
                transaction.rxBuf = NULL;
                transaction.count = (numDummyBits >> 3);      /* In bytes */
    
            transferType = SPI_TRANSACTION_TYPE_WRITE;
            SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
                retVal = SPI_transfer(handle, &transaction);
            }
    
            /* Write Address Bytes */
            *tempPtr = (unsigned int)srcAddr;
            transaction.txBuf = (unsigned char *)tempPtr;
            transaction.rxBuf = NULL;
            transaction.count = addrLengthInBytes;
    
            transferType = SPI_TRANSACTION_TYPE_WRITE;
            SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
            retVal = SPI_transfer(handle, &transaction);
    
            /* Read the actual flash data */
            transaction.txBuf = NULL;
            transaction.rxBuf = (unsigned char *)dstOffstAddr;
            transaction.count = length;
    
            transferType = SPI_TRANSACTION_TYPE_READ;
            SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
            retVal = SPI_transfer(handle, &transaction);
    
            if(flashTransaction->address > 0xFFFFFF)
            {
                /* Exit 32 bit addressing mode */
                S25FLFlash_Enable4ByteAddrMode(flashHandle, false);
                addrLengthInBytes = 3;
            }
        }
    
        if(QSPI_OPER_MODE_MMAP == object->qspiMode)
        {
            if(flashTransaction->address > 0xFFFFFF)
            {
                /* Enter 32 bit addressing mode */
                S25FLFlash_Enable4ByteAddrMode(flashHandle, true);
            }
    
            switch(object->rxLines)
            {
                case QSPI_RX_LINES_SINGLE:
                {
                    if(flashTransaction->address > 0xFFFFFF)
                    {
                        readCmd = QSPI_LIB_CMD_READ_SINGLE_4B;
                    }
                    else
                    {
                        readCmd = QSPI_LIB_CMD_READ_SINGLE;
                    }
                    break;
                }
    
                case QSPI_RX_LINES_DUAL:
                {
                    if(flashTransaction->address > 0xFFFFFF)
                    {
                        readCmd = QSPI_LIB_CMD_READ_DUAL_4B;
                    }
                    else
                    {
                        readCmd = QSPI_LIB_CMD_READ_DUAL;
                    }
                    break;
                }
    
                case QSPI_RX_LINES_QUAD:
                {
                    if(flashTransaction->address > 0xFFFFFF)
                    {
                        readCmd = QSPI_LIB_CMD_READ_QUAD_4B;
                    }
                    else
                    {
                        readCmd = QSPI_LIB_CMD_READ_QUAD;
                    }
                    break;
                }
    
                default:
                break;
            }
            /* Perform the transfer */
            transaction.txBuf = srcAddr;
            transaction.rxBuf = (uint8_t *)dstOffstAddr;
            transaction.count = length;
    
            transferType = SPI_TRANSACTION_TYPE_READ;
            transferCmd  = (unsigned char)readCmd;
            SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
            SPI_control(handle, SPI_V1_CMD_MMAP_TRANSFER_CMD, (void *)&transferCmd);
            retVal = SPI_transfer(handle, &transaction);
    
            if(flashTransaction->address > 0xFFFFFF)
            {
                /* Exit 32 bit addressing mode */
                S25FLFlash_Enable4ByteAddrMode(flashHandle, false);
            }
        }
    
        return retVal;
    }
    
    
    bool S25FLFlash_WriteEnable(S25FL_Handle flashHandle)
    {
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        bool retVal = false;                /* return value */
        unsigned char writeVal;             /* data to be written */
        SPI_Transaction transaction;        /* SPI transaction structure */
        unsigned int operMode;              /* temp variable to hold mode */
        unsigned int rxLines;               /* temp variable to hold rx lines */
        unsigned int frmLength;
        unsigned int transferType;
        QSPI_v1_Object  *object;
        unsigned int rxLinesArg;
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object *)handle->object;
    
        /* These operations require the qspi to be configured in the following mode
           only: tx/rx single line and config mode. */
    
        /* Save the current mode and rxLine configurations */
        operMode = object->qspiMode;
        rxLines  = object->rxLines;
    
        /* Update the mode and rxLines with the required values */
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, NULL);
    
        rxLinesArg = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLinesArg);
    
        /* transaction frame length in words (bytes) */
        frmLength = 1;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
        /* Write enable command */
        writeVal = QSPI_LIB_CMD_WRITE_ENABLE;
    
        /* Update transaction parameters */
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count  = 1;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Restore operating mode and rx Lines */
        object->qspiMode = operMode;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        return retVal;
    }
    
    
    bool S25FLFlash_Enable4ByteAddrMode(S25FL_Handle flashHandle,
                                        bool enable4ByteMode)
    {
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        bool retVal = false;             /* return value */
        unsigned char writeVal;          /* data to be written */
        SPI_Transaction transaction;     /* SPI transaction structure */
        unsigned int operMode;           /* temp variable to hold mode */
        unsigned int rxLines;            /* temp variable to hold rx lines */
        unsigned int transferType;
        QSPI_v1_Object  *object;
        unsigned int rxLinesArg;
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object *)handle->object;
    
        /* These operations require the qspi to be configured in the following mode
           only: tx/rx single line and config mode. */
    
        /* Save the current mode and rxLine configurations */
        operMode = object->qspiMode;
        rxLines  = object->rxLines;
    
    
        /* Update the mode and rxLines with the required values */
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, NULL);
        rxLinesArg = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLinesArg);
    
        /* Command to control the 4 byte mode */
        if (true == enable4ByteMode)
        {
            writeVal = QSPI_LIB_CMD_ENTER_4_BYTE_ADDR;
        }
        else
        {
            writeVal = QSPI_LIB_CMD_EXIT_4_BYTE_ADDR;
        }
    
        /* Write 4 byte enable/disable command to flash */
        transaction.count = 1U;                    /* Frame length in bytes */
        transaction.txBuf = (unsigned char *)&writeVal;  /* Value to be written */
        transaction.rxBuf = NULL;                  /* Nothing to read */
        transaction.arg   = NULL;                  /* Not applicable */
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Restore operating mode and rx Lines */
        object->qspiMode = operMode;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        return retVal;
    }
    
    
    uint32_t FlashStatus(S25FL_Handle flashHandle)
    {
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        bool retVal = false;             /* return value */
        unsigned char writeVal;          /* data to be written */
        SPI_Transaction transaction;     /* SPI transaction structure */
        uint32_t rxData = 0U;            /* received data */
        unsigned int operMode;           /* temp variable to hold mode */
        unsigned int rxLines;            /* temp variable to hold rx lines */
        unsigned int frmLength;
        unsigned int transferType;
        QSPI_v1_Object  *object;
        unsigned int rxLinesArg;
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object *)handle->object;
    
        /* These operations require the qspi to be configured in the following mode
           only: tx/rx single line and config mode. */
    
        /* Save the current mode and rxLine configurations */
        operMode = object->qspiMode;
        rxLines  = object->rxLines;
    
        /* Update the mode and rxLines with the required values */
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, NULL);
    
        rxLinesArg = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLinesArg);
    
        /* Total transaction frame length in words (bytes) */
        frmLength = 1 + 1;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
        /* Write Address Bytes */
        writeVal = QSPI_LIB_CMD_READ_STATUS_REG;
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = 1U;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        if(retVal == false)
        {
            /* Error */
        }
    
        /* Read the status register */
        transaction.txBuf = NULL;
        transaction.rxBuf = (unsigned char *)&rxData;
        transaction.count = 1U;
    
        transferType = SPI_TRANSACTION_TYPE_READ;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        if(retVal == false)
        {
            /* Error */
        }
    
        /* Restore operating mode and rx Lines */
        object->qspiMode = operMode;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        return (rxData & 0xFF);
    }
    
    bool S25FLFlash_QuadModeEnable(S25FL_Handle flashHandle)
    {
        SPI_Transaction transaction;                /* SPI transaction structure */
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        unsigned char writeVal = 0U;    /* data to be written */
        uint32_t norStatus;             /* flash status value */
        uint32_t configReg;             /* configuration register value */
        uint32_t data;                  /* data to be written */
        bool retVal = false;            /* return value */
        unsigned int operMode;          /* temp variable to hold mode */
        unsigned int rxLines;           /* temp variable to hold rx lines */
        unsigned int frmLength;
        unsigned int transferType;
        QSPI_v1_Object  *object;
        unsigned int rxLinesArg;
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object *)handle->object;
    
        /* These operations require the qspi to be configured in the following mode
           only: tx/rx single line and config mode. */
    
        /* Save the current mode and rxLine configurations */
        operMode = object->qspiMode;
        rxLines  = object->rxLines;
    
        /* Update the mode and rxLines with the required values */
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, NULL);
    
        rxLinesArg = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLinesArg);
    
        /* Set transfer length in bytes: Reading status register */
        frmLength = 1 + 1;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
        /* Read Status register */
        writeVal = QSPI_LIB_CMD_READ_STATUS_REG;
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        transaction.txBuf = NULL;
        transaction.rxBuf = (unsigned char *)&norStatus;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_READ;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Set transfer length in bytes: Reading status register */
        frmLength = 1 + 1;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
        /* Read command register */
        writeVal = QSPI_LIB_CMD_QUAD_RD_CMD_REG;
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        transaction.txBuf = NULL;
        transaction.rxBuf = (unsigned char *)&configReg;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_READ;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Set 2nd bit of configuration register to 1 to enable quad mode */
        configReg |= (QSPI_FLASH_QUAD_ENABLE_VALUE << QSPI_FLASH_QUAD_ENABLE_BIT);
        data = (QSPI_LIB_CMD_WRITE_STATUS_REG << 16) | (norStatus << 8) | configReg;
    
        /* Set transfer length in bytes */
        frmLength = 1;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
    
        transaction.txBuf = (unsigned char *)&data;
        transaction.rxBuf = NULL;
        transaction.count = 3;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Wait till the status register is being written */
        while (1U == (FlashStatus(flashHandle) & 0x1U));
    
        /* Restore operating mode and rx Lines */
        object->qspiMode = operMode;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        return retVal;
    }
    
    bool S25FLFlash_BlockErase(S25FL_Handle flashHandle, unsigned int blockNumber)
    {
        uint32_t eraseAddr;    /* Flash erase address */
        uint32_t writeVal;     /* data to be written */
        SPI_Handle handle = flashHandle->spiHandle;  /* SPI handle */
        SPI_Transaction transaction;         /* SPI transaction structure */
        unsigned int addrLenInBytes = 3;     /* address length in bytes */
        bool retVal = false;                 /* return value */
        unsigned int operMode;               /* temp variable to hold mode */
        unsigned int rxLines;                /* temp variable to hold rx lines */
        unsigned int frmLength;
        unsigned int transferType;
        QSPI_v1_Object  *object;
        unsigned int rxLinesArg;
        uint32_t tempAddr;
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object *)handle->object;
    
        /* Compute flash erase address based on the block size */
        eraseAddr = blockNumber * flashHandle->blockSize;
        /* These operations require the qspi to be configured in the following mode
           only: tx/rx single line and config mode. */
    
        /* Save the current mode and rxLine configurations */
        operMode = object->qspiMode;
        rxLines  = object->rxLines;
    
        /* Update the mode and rxLines with the required values */
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, NULL);
    
        rxLinesArg = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLinesArg);
    
        if(eraseAddr > 0xFFFFFF)
        {
            /* Enter 4 byte addressing mode */
            S25FLFlash_Enable4ByteAddrMode(flashHandle, true);
            addrLenInBytes = 4;
        }
    #if 0
        tempAddr = ((eraseAddr & 0xFF000000) >> 24) |
                   ((eraseAddr & 0x00FF0000) >> 8)  |
                   ((eraseAddr & 0x0000FF00) << 8)  |
                   ((eraseAddr & 0x000000FF) << 24);
    
        if(addrLenInBytes == 3)
        {
            tempAddr = (tempAddr >> 8) & 0x00FFFFFF;
        }
    #endif
        tempAddr = blockNumber;
        UART_printf("temp addr:0x%x\n", tempAddr);
        /* Flash write enable */
        S25FLFlash_WriteEnable(flashHandle);
    
    
        /*total transaction frame length */
        frmLength = 1 + addrLenInBytes;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, ((void *)&frmLength));
        if(eraseAddr > 0xFFFFFF)
        {
        	writeVal = QSPI_LIB_CMD_BLOCK_ERASE_4B;
        }
        else
        {
        	/* Block erase command */
       	writeVal = QSPI_LIB_CMD_BLOCK_ERASE;
        }
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
    
        retVal = SPI_transfer(handle, &transaction);
        /* Send erase address */
        writeVal = tempAddr;
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = addrLenInBytes;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Check flash status for write completion */
        while (1U == (FlashStatus(flashHandle) & 0x1U));
    
        if(eraseAddr > 0xFFFFFF)
        {
            /* Exit 4 byte addressing mode */
            S25FLFlash_Enable4ByteAddrMode(flashHandle, false);
            addrLenInBytes = 3;
        }
    
        /* Restore operating mode and rx Lines */
        object->qspiMode = operMode;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        return retVal;
    }
    
    bool S25FLFlash_ChipErase(S25FL_Handle flashHandle)
    {
        uint32_t writeVal;     /* data to be written */
        SPI_Handle handle = flashHandle->spiHandle;  /* SPI handle */
        SPI_Transaction transaction;         /* SPI transaction structure */
        bool retVal = false;                 /* return value */
        unsigned int operMode;               /* temp variable to hold mode */
        unsigned int rxLines;                /* temp variable to hold rx lines */
        unsigned int frmLength;
        unsigned int transferType;
        QSPI_v1_Object  *object;
        unsigned int rxLinesArg;
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object *)handle->object;
    
        /* These operations require the qspi to be configured in the following mode
           only: tx/rx single line and config mode. */
    
        /* Save the current mode and rxLine configurations */
        operMode = object->qspiMode;
        rxLines  = object->rxLines;
    
        /* Update the mode and rxLines with the required values */
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, NULL);
    
        rxLinesArg = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLinesArg);
    
        /* Flash write enable */
        S25FLFlash_WriteEnable(flashHandle);
    
    
        /*total transaction frame length */
        frmLength = 1;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, ((void *)&frmLength));
        /* Block erase command */
        writeVal = 0x60;
    
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
    
        retVal = SPI_transfer(handle, &transaction);
        
    
        /* Check flash status for write completion */
        while (1U == (FlashStatus(flashHandle) & 0x1U));
    
        /* Restore operating mode and rx Lines */
        object->qspiMode = operMode;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        return retVal;
    }
    
    
    void FlashPrintId(S25FL_Handle flashHandle)
    {
        uint32_t writeVal;               /* data to be written */
        SPI_Handle handle = flashHandle->spiHandle;  /* SPI handle */
        SPI_Transaction transaction;     /* SPI transaction structure */
        bool retVal = false;             /* return value */
        unsigned char mfgId = 0;         /* manufacture ID value */
        unsigned char deviceId = 0;      /* device ID value */
        unsigned int operMode;           /* temp variable to hold mode */
        unsigned int rxLines;            /* temp variable to hold rx lines */
        unsigned int frmLength;
        unsigned int transferType;
        QSPI_v1_Object  *object;
        unsigned int rxLinesArg;
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object *)handle->object;
    
        /* These operations require the qspi to be configured in the following mode
           only: tx/rx single line and config mode. */
    
        /* Save the current mode and rxLine configurations */
        operMode = object->qspiMode;
        rxLines  = object->rxLines;
    
        /* Update the mode and rxLines with the required values */
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, NULL);
    
        rxLinesArg = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLinesArg);
    
        /* Total transaction frame length in bytes */
        frmLength = 1 + 3 + 2;   /* cmd + address + read data */
        /* Total transaction frame length in bytes */
        frmLength = 1 + 3 + 2;   /* cmd + address + read data */
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
        /* Write Command */
        writeVal = QSPI_LIB_CMD_READ_MFG_ID;
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        if(retVal == false)
        {
            /* Error */
        }
    
        /* Write Address Bytes */
        writeVal = 0x0U;
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = 3;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
    
        retVal = SPI_transfer(handle, &transaction);
    
    
        /* Read Manufacturer ID
         * The manufacturer ID is of 1 byte(8 bits)
         */
        transaction.txBuf = NULL;
        transaction.rxBuf = &mfgId;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_READ;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Read Device ID */
        transaction.txBuf = NULL;
        transaction.rxBuf = &deviceId;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_READ;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Note - This ID is the device ID of the flash device.
         * This ID is read from the flash
         */
    
        /* Restore operating mode and rx Lines */
        object->qspiMode = operMode;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    }
    
    static bool SF25FL_ConfigMode_Write(uint32_t dstOffstAddr,
                                        unsigned char* srcAddr,
                                        uint32_t length,
                                        S25FL_Handle flashHandle)
    {
        bool retVal = false;                        /* return value */
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        uint32_t addrLengthInBytes = 3U;            /* Flash addr length in bytes */
        unsigned int frmLength;
        unsigned char writeVal[4];                  /* data to be written to QSPI */
        SPI_Transaction transaction;                /* SPI transaction structure */
        unsigned int transferType;
    
    
        addrLengthInBytes = 3U;        /* Flash address length in bytes */
    
        /* Extract address word length from the flash's destination offst addr*/
        if(dstOffstAddr > 0xFFFFFF)
        {
            /* Enter 32 bit addressing mode */
            S25FLFlash_Enable4ByteAddrMode(flashHandle, true);
            addrLengthInBytes = 4;
        }
    
        /* Write Enable */
        S25FLFlash_WriteEnable(flashHandle);
    
        /* total transaction frame length in number of words (bytes)*/
        frmLength = 1 + addrLengthInBytes + length;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, ((void *)&frmLength));
        if(dstOffstAddr > 0xFFFFFF)
        {
       	 /* Send Flash write command */
       	 writeVal[0] = QSPI_LIB_CMD_PAGE_PRG_4B;   /* Flash write command */
        }
        else
        {
    	/* Send Flash write command */
             writeVal[0] = QSPI_LIB_CMD_PAGE_PRG;   /* Flash write command */
        }
        transaction.txBuf = (unsigned char *)&writeVal[0];
        transaction.rxBuf = NULL;
        transaction.count = 1U;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
        retVal = SPI_transfer(handle, &transaction);
    
        /* Send flash address offset to which data has to be written */
        transaction.txBuf = (unsigned char *)dstOffstAddr;
        transaction.rxBuf = NULL;
        transaction.count = addrLengthInBytes;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
        retVal = SPI_transfer(handle, &transaction);
    
        /* Write buffer data to flash */
        transaction.txBuf = (unsigned char *)srcAddr;
        transaction.rxBuf = NULL;
        transaction.count = length;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
        retVal = SPI_transfer(handle, &transaction);
    
        /* Check flash status for write completion */
        while ((FlashStatus(flashHandle) & 0x1U));
    
        if(dstOffstAddr > 0xFFFFFF)
        {
            /* Exit 32 bit addressing mode */
            S25FLFlash_Enable4ByteAddrMode(flashHandle, false);
            addrLengthInBytes = 3;
        }
    
        return retVal;
    }
    
    Hi Brad,

    I am able to resolve the issue.

    Our image starts from 3 byte address offset:0x1E0000 and goes till 0x1137EC8 offset(4 byte address)

    In The flash layer pdk_am57xx_1_0_xx\packages\ti\board\src\idkAM572x\device\qspi_flash.c file

    to switch to 4 byte address mode it only check starting address and then pass to qspi core driver:ti/drv/spi/src/v1/QSPI_v1.c for copy the data from src to destination mapped address.

    so during my read operation which starts from 0x1E0000 when i try to read beyond 0xFFFFFF offset it doesn't switch to 4 byte address mode due to which i am not getting  data or getting dummy data 0x44.

    I added a condition in  QSPI_v1.c  to check for offset and once it crossed the 0xFFFFFF offset i set the AddrBytes, read cmd and dummy bit for 4byte address mode.

    I am able to pass the crc now after above changes.

    Attaching changed file for reference.

    Thanks,

    Ritesh

  • That's good news. Thanks for the update.