741 lines
19 KiB
C
741 lines
19 KiB
C
/**
|
||
*
|
||
* \file
|
||
*
|
||
* \brief WINC1500 SPI Flash.
|
||
*
|
||
* Copyright (c) 2017-2018 Atmel Corporation. All rights reserved.
|
||
*
|
||
* \asf_license_start
|
||
*
|
||
* \page License
|
||
*
|
||
* Redistribution and use in source and binary forms, with or without
|
||
* modification, are permitted provided that the following conditions are met:
|
||
*
|
||
* 1. Redistributions of source code must retain the above copyright notice,
|
||
* this list of conditions and the following disclaimer.
|
||
*
|
||
* 2. 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.
|
||
*
|
||
* 3. The name of Atmel may not be used to endorse or promote products derived
|
||
* from this software without specific prior written permission.
|
||
*
|
||
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
|
||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
|
||
*
|
||
* \asf_license_stop
|
||
*
|
||
*/
|
||
|
||
#ifdef PROFILING
|
||
#include "windows.h"
|
||
#endif
|
||
#include "spi_flash/include/spi_flash.h"
|
||
#define DUMMY_REGISTER (0x1084)
|
||
|
||
#define TIMEOUT (-1) /*MS*/
|
||
|
||
//#define DISABLE_UNSED_FLASH_FUNCTIONS
|
||
|
||
#define FLASH_BLOCK_SIZE (32UL * 1024)
|
||
/*!<Block Size in Flash Memory
|
||
*/
|
||
#define FLASH_SECTOR_SZ (4 * 1024UL)
|
||
/*!<Sector Size in Flash Memory
|
||
*/
|
||
#define FLASH_PAGE_SZ (256)
|
||
/*!<Page Size in Flash Memory */
|
||
|
||
#define HOST_SHARE_MEM_BASE (0xd0000UL)
|
||
#define CORTUS_SHARE_MEM_BASE (0x60000000UL)
|
||
#define NMI_SPI_FLASH_ADDR (0x111c)
|
||
/***********************************************************
|
||
SPI Flash DMA
|
||
***********************************************************/
|
||
#define GET_UINT32(X, Y) (X[0 + Y] + ((uint32)X[1 + Y] << 8) + ((uint32)X[2 + Y] << 16) + ((uint32)X[3 + Y] << 24))
|
||
#define SPI_FLASH_BASE (0x10200)
|
||
#define SPI_FLASH_MODE (SPI_FLASH_BASE + 0x00)
|
||
#define SPI_FLASH_CMD_CNT (SPI_FLASH_BASE + 0x04)
|
||
#define SPI_FLASH_DATA_CNT (SPI_FLASH_BASE + 0x08)
|
||
#define SPI_FLASH_BUF1 (SPI_FLASH_BASE + 0x0c)
|
||
#define SPI_FLASH_BUF2 (SPI_FLASH_BASE + 0x10)
|
||
#define SPI_FLASH_BUF_DIR (SPI_FLASH_BASE + 0x14)
|
||
#define SPI_FLASH_TR_DONE (SPI_FLASH_BASE + 0x18)
|
||
#define SPI_FLASH_DMA_ADDR (SPI_FLASH_BASE + 0x1c)
|
||
#define SPI_FLASH_MSB_CTL (SPI_FLASH_BASE + 0x20)
|
||
#define SPI_FLASH_TX_CTL (SPI_FLASH_BASE + 0x24)
|
||
|
||
/*********************************************/
|
||
/* STATIC FUNCTIONS */
|
||
/*********************************************/
|
||
|
||
/**
|
||
* @fn spi_flash_read_status_reg
|
||
* @brief Read status register
|
||
* @param[OUT] val
|
||
value of status reg
|
||
* @return Status of execution
|
||
* @note Compatible with MX25L6465E
|
||
* @author M. Abdelmawla
|
||
* @version 1.0
|
||
*/
|
||
static sint8 spi_flash_read_status_reg(uint8 *val)
|
||
{
|
||
sint8 ret = M2M_SUCCESS;
|
||
uint8 cmd[1];
|
||
uint32 reg;
|
||
|
||
cmd[0] = 0x05;
|
||
|
||
ret += nm_write_reg(SPI_FLASH_DATA_CNT, 4);
|
||
ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]);
|
||
ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x01);
|
||
ret += nm_write_reg(SPI_FLASH_DMA_ADDR, DUMMY_REGISTER);
|
||
ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1 << 7));
|
||
do {
|
||
ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)®);
|
||
if (M2M_SUCCESS != ret)
|
||
break;
|
||
} while (reg != 1);
|
||
|
||
reg = (M2M_SUCCESS == ret) ? (nm_read_reg(DUMMY_REGISTER)) : (0);
|
||
*val = (uint8)(reg & 0xff);
|
||
return ret;
|
||
}
|
||
|
||
#ifdef DISABLE_UNSED_FLASH_FUNCTIONS
|
||
/**
|
||
* @fn spi_flash_read_security_reg
|
||
* @brief Read security register
|
||
* @return Security register value
|
||
* @note Compatible with MX25L6465E
|
||
* @author M. Abdelmawla
|
||
* @version 1.0
|
||
*/
|
||
static uint8 spi_flash_read_security_reg(void)
|
||
{
|
||
uint8 cmd[1];
|
||
uint32 reg;
|
||
sint8 ret = M2M_SUCCESS;
|
||
|
||
cmd[0] = 0x2b;
|
||
|
||
ret += nm_write_reg(SPI_FLASH_DATA_CNT, 1);
|
||
ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]);
|
||
ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x01);
|
||
ret += nm_write_reg(SPI_FLASH_DMA_ADDR, DUMMY_REGISTER);
|
||
ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1 << 7));
|
||
do {
|
||
ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)®);
|
||
if (M2M_SUCCESS != ret)
|
||
break;
|
||
} while (reg != 1);
|
||
reg = (M2M_SUCCESS == ret) ? (nm_read_reg(DUMMY_REGISTER)) : (0);
|
||
|
||
return (sint8)reg & 0xff;
|
||
}
|
||
|
||
/**
|
||
* @fn spi_flash_gang_unblock
|
||
* @brief Unblock all flash area
|
||
* @note Compatible with MX25L6465E
|
||
* @author M. Abdelmawla
|
||
* @version 1.0
|
||
*/
|
||
static sint8 spi_flash_gang_unblock(void)
|
||
{
|
||
uint8 cmd[1];
|
||
uint32 val = 0;
|
||
sint8 ret = M2M_SUCCESS;
|
||
|
||
cmd[0] = 0x98;
|
||
|
||
ret += nm_write_reg(SPI_FLASH_DATA_CNT, 0);
|
||
ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]);
|
||
ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x01);
|
||
ret += nm_write_reg(SPI_FLASH_DMA_ADDR, 0);
|
||
ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1 << 7));
|
||
do {
|
||
ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val);
|
||
if (M2M_SUCCESS != ret)
|
||
break;
|
||
} while (val != 1);
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @fn spi_flash_clear_security_flags
|
||
* @brief Clear all security flags
|
||
* @note Compatible with MX25L6465E
|
||
* @author M. Abdelmawla
|
||
* @version 1.0
|
||
*/
|
||
static sint8 spi_flash_clear_security_flags(void)
|
||
{
|
||
uint8 cmd[1];
|
||
uint32 val = 0;
|
||
sint8 ret = M2M_SUCCESS;
|
||
|
||
cmd[0] = 0x30;
|
||
|
||
ret += nm_write_reg(SPI_FLASH_DATA_CNT, 0);
|
||
ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]);
|
||
ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x01);
|
||
ret += nm_write_reg(SPI_FLASH_DMA_ADDR, 0);
|
||
ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1 << 7));
|
||
do {
|
||
ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val);
|
||
if (M2M_SUCCESS != ret)
|
||
break;
|
||
} while (val != 1);
|
||
|
||
return ret;
|
||
}
|
||
#endif
|
||
|
||
/**
|
||
* @fn spi_flash_load_to_cortus_mem
|
||
* @brief Load data from SPI flash into cortus memory
|
||
* @param[IN] u32MemAdr
|
||
* Cortus load address. It must be set to its AHB access address
|
||
* @param[IN] u32FlashAdr
|
||
* Address to read from at the SPI flash
|
||
* @param[IN] u32Sz
|
||
* Data size
|
||
* @return Status of execution
|
||
* @note Compatible with MX25L6465E and should be working with other types
|
||
* @author M. Abdelmawla
|
||
* @version 1.0
|
||
*/
|
||
static sint8 spi_flash_load_to_cortus_mem(uint32 u32MemAdr, uint32 u32FlashAdr, uint32 u32Sz)
|
||
{
|
||
uint8 cmd[5];
|
||
uint32 val = 0;
|
||
sint8 ret = M2M_SUCCESS;
|
||
|
||
cmd[0] = 0x0b;
|
||
cmd[1] = (uint8)(u32FlashAdr >> 16);
|
||
cmd[2] = (uint8)(u32FlashAdr >> 8);
|
||
cmd[3] = (uint8)(u32FlashAdr);
|
||
cmd[4] = 0xA5;
|
||
|
||
ret += nm_write_reg(SPI_FLASH_DATA_CNT, u32Sz);
|
||
ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0] | (cmd[1] << 8) | (cmd[2] << 16) | (cmd[3] << 24));
|
||
ret += nm_write_reg(SPI_FLASH_BUF2, cmd[4]);
|
||
ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x1f);
|
||
ret += nm_write_reg(SPI_FLASH_DMA_ADDR, u32MemAdr);
|
||
ret += nm_write_reg(SPI_FLASH_CMD_CNT, 5 | (1 << 7));
|
||
do {
|
||
ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val);
|
||
if (M2M_SUCCESS != ret)
|
||
break;
|
||
} while (val != 1);
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @fn spi_flash_sector_erase
|
||
* @brief Erase sector (4KB)
|
||
* @param[IN] u32FlashAdr
|
||
* Any memory address within the sector
|
||
* @return Status of execution
|
||
* @note Compatible with MX25L6465E and should be working with other types
|
||
* @author M. Abdelmawla
|
||
* @version 1.0
|
||
*/
|
||
static sint8 spi_flash_sector_erase(uint32 u32FlashAdr)
|
||
{
|
||
uint8 cmd[4];
|
||
uint32 val = 0;
|
||
sint8 ret = M2M_SUCCESS;
|
||
|
||
cmd[0] = 0x20;
|
||
cmd[1] = (uint8)(u32FlashAdr >> 16);
|
||
cmd[2] = (uint8)(u32FlashAdr >> 8);
|
||
cmd[3] = (uint8)(u32FlashAdr);
|
||
|
||
ret += nm_write_reg(SPI_FLASH_DATA_CNT, 0);
|
||
ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0] | (cmd[1] << 8) | (cmd[2] << 16) | (cmd[3] << 24));
|
||
ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x0f);
|
||
ret += nm_write_reg(SPI_FLASH_DMA_ADDR, 0);
|
||
ret += nm_write_reg(SPI_FLASH_CMD_CNT, 4 | (1 << 7));
|
||
do {
|
||
ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val);
|
||
if (M2M_SUCCESS != ret)
|
||
break;
|
||
} while (val != 1);
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @fn spi_flash_write_enable
|
||
* @brief Send write enable command to SPI flash
|
||
* @return Status of execution
|
||
* @note Compatible with MX25L6465E and should be working with other types
|
||
* @author M. Abdelmawla
|
||
* @version 1.0
|
||
*/
|
||
static sint8 spi_flash_write_enable(void)
|
||
{
|
||
uint8 cmd[1];
|
||
uint32 val = 0;
|
||
sint8 ret = M2M_SUCCESS;
|
||
|
||
cmd[0] = 0x06;
|
||
|
||
ret += nm_write_reg(SPI_FLASH_DATA_CNT, 0);
|
||
ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]);
|
||
ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x01);
|
||
ret += nm_write_reg(SPI_FLASH_DMA_ADDR, 0);
|
||
ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1 << 7));
|
||
do {
|
||
ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val);
|
||
if (M2M_SUCCESS != ret)
|
||
break;
|
||
} while (val != 1);
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @fn spi_flash_write_disable
|
||
* @brief Send write disable command to SPI flash
|
||
* @note Compatible with MX25L6465E and should be working with other types
|
||
* @author M. Abdelmawla
|
||
* @version 1.0
|
||
*/
|
||
static sint8 spi_flash_write_disable(void)
|
||
{
|
||
uint8 cmd[1];
|
||
uint32 val = 0;
|
||
sint8 ret = M2M_SUCCESS;
|
||
cmd[0] = 0x04;
|
||
|
||
ret += nm_write_reg(SPI_FLASH_DATA_CNT, 0);
|
||
ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]);
|
||
ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x01);
|
||
ret += nm_write_reg(SPI_FLASH_DMA_ADDR, 0);
|
||
ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1 << 7));
|
||
do {
|
||
ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val);
|
||
if (M2M_SUCCESS != ret)
|
||
break;
|
||
} while (val != 1);
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @fn spi_flash_page_program
|
||
* @brief Write data (less than page size) from cortus memory to SPI flash
|
||
* @param[IN] u32MemAdr
|
||
* Cortus data address. It must be set to its AHB access address
|
||
* @param[IN] u32FlashAdr
|
||
* Address to write to at the SPI flash
|
||
* @param[IN] u32Sz
|
||
* Data size
|
||
* @note Compatible with MX25L6465E and should be working with other types
|
||
* @author M. Abdelmawla
|
||
* @version 1.0
|
||
*/
|
||
static sint8 spi_flash_page_program(uint32 u32MemAdr, uint32 u32FlashAdr, uint32 u32Sz)
|
||
{
|
||
uint8 cmd[4];
|
||
uint32 val = 0;
|
||
sint8 ret = M2M_SUCCESS;
|
||
|
||
cmd[0] = 0x02;
|
||
cmd[1] = (uint8)(u32FlashAdr >> 16);
|
||
cmd[2] = (uint8)(u32FlashAdr >> 8);
|
||
cmd[3] = (uint8)(u32FlashAdr);
|
||
|
||
ret += nm_write_reg(SPI_FLASH_DATA_CNT, 0);
|
||
ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0] | (cmd[1] << 8) | (cmd[2] << 16) | (cmd[3] << 24));
|
||
ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x0f);
|
||
ret += nm_write_reg(SPI_FLASH_DMA_ADDR, u32MemAdr);
|
||
ret += nm_write_reg(SPI_FLASH_CMD_CNT, 4 | (1 << 7) | ((u32Sz & 0xfffff) << 8));
|
||
do {
|
||
ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val);
|
||
if (M2M_SUCCESS != ret)
|
||
break;
|
||
} while (val != 1);
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @fn spi_flash_read_internal
|
||
* @brief Read from data from SPI flash
|
||
* @param[OUT] pu8Buf
|
||
* Pointer to data buffer
|
||
* @param[IN] u32Addr
|
||
* Address to read from at the SPI flash
|
||
* @param[IN] u32Sz
|
||
* Data size
|
||
* @note Data size must be < 64KB (limitation imposed by the bus wrapper)
|
||
* @author M. Abdelmawla
|
||
* @version 1.0
|
||
*/
|
||
static sint8 spi_flash_read_internal(uint8 *pu8Buf, uint32 u32Addr, uint32 u32Sz)
|
||
{
|
||
sint8 ret = M2M_SUCCESS;
|
||
/* read size must be < 64KB */
|
||
ret = spi_flash_load_to_cortus_mem(HOST_SHARE_MEM_BASE, u32Addr, u32Sz);
|
||
if (M2M_SUCCESS != ret)
|
||
goto ERR;
|
||
ret = nm_read_block(HOST_SHARE_MEM_BASE, pu8Buf, u32Sz);
|
||
ERR:
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @fn spi_flash_pp
|
||
* @brief Program data of size less than a page (256 bytes) at the SPI flash
|
||
* @param[IN] u32Offset
|
||
* Address to write to at the SPI flash
|
||
* @param[IN] pu8Buf
|
||
* Pointer to data buffer
|
||
* @param[IN] u32Sz
|
||
* Data size
|
||
* @return Status of execution
|
||
* @author M. Abdelmawla
|
||
* @version 1.0
|
||
*/
|
||
static sint8 spi_flash_pp(uint32 u32Offset, uint8 *pu8Buf, uint16 u16Sz)
|
||
{
|
||
sint8 ret = M2M_SUCCESS;
|
||
uint8 tmp;
|
||
spi_flash_write_enable();
|
||
/* use shared packet memory as temp mem */
|
||
ret += nm_write_block(HOST_SHARE_MEM_BASE, pu8Buf, u16Sz);
|
||
ret += spi_flash_page_program(HOST_SHARE_MEM_BASE, u32Offset, u16Sz);
|
||
ret += spi_flash_read_status_reg(&tmp);
|
||
do {
|
||
if (ret != M2M_SUCCESS)
|
||
goto ERR;
|
||
ret += spi_flash_read_status_reg(&tmp);
|
||
} while (tmp & 0x01);
|
||
ret += spi_flash_write_disable();
|
||
ERR:
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @fn spi_flash_rdid
|
||
* @brief Read SPI Flash ID
|
||
* @return SPI FLash ID
|
||
* @author M.S.M
|
||
* @version 1.0
|
||
*/
|
||
static uint32 spi_flash_rdid(void)
|
||
{
|
||
unsigned char cmd[1];
|
||
uint32 reg = 0;
|
||
uint32 cnt = 0;
|
||
sint8 ret = M2M_SUCCESS;
|
||
|
||
cmd[0] = 0x9f;
|
||
|
||
ret += nm_write_reg(SPI_FLASH_DATA_CNT, 4);
|
||
ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]);
|
||
ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x1);
|
||
ret += nm_write_reg(SPI_FLASH_DMA_ADDR, DUMMY_REGISTER);
|
||
ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1 << 7));
|
||
do {
|
||
ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)®);
|
||
if (M2M_SUCCESS != ret)
|
||
break;
|
||
if (++cnt > 500) {
|
||
ret = M2M_ERR_INIT;
|
||
break;
|
||
}
|
||
} while (reg != 1);
|
||
reg = (M2M_SUCCESS == ret) ? (nm_read_reg(DUMMY_REGISTER)) : (0);
|
||
M2M_PRINT("Flash ID %x \n", (unsigned int)reg);
|
||
return reg;
|
||
}
|
||
|
||
/**
|
||
* @fn spi_flash_unlock
|
||
* @brief Unlock SPI Flash
|
||
* @author M.S.M
|
||
* @version 1.0
|
||
*/
|
||
#if 0
|
||
static void spi_flash_unlock(void)
|
||
{
|
||
uint8 tmp;
|
||
tmp = spi_flash_read_security_reg();
|
||
spi_flash_clear_security_flags();
|
||
if(tmp & 0x80)
|
||
{
|
||
spi_flash_write_enable();
|
||
spi_flash_gang_unblock();
|
||
}
|
||
}
|
||
#endif
|
||
static void spi_flash_enter_low_power_mode(void)
|
||
{
|
||
volatile unsigned long tmp;
|
||
unsigned char * cmd = (unsigned char *)&tmp;
|
||
unsigned int count = 0;
|
||
|
||
cmd[0] = 0xb9;
|
||
|
||
nm_write_reg(SPI_FLASH_DATA_CNT, 0);
|
||
nm_write_reg(SPI_FLASH_BUF1, cmd[0]);
|
||
nm_write_reg(SPI_FLASH_BUF_DIR, 0x1);
|
||
nm_write_reg(SPI_FLASH_DMA_ADDR, 0);
|
||
nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1 << 7));
|
||
while (nm_read_reg(SPI_FLASH_TR_DONE) != 1) //JFM ajout<75> compteur...
|
||
{
|
||
if(count++ >= 5000)
|
||
return;
|
||
}
|
||
}
|
||
|
||
static void spi_flash_leave_low_power_mode(void)
|
||
{
|
||
volatile unsigned long tmp;
|
||
unsigned char * cmd = (unsigned char *)&tmp;
|
||
|
||
cmd[0] = 0xab;
|
||
|
||
nm_write_reg(SPI_FLASH_DATA_CNT, 0);
|
||
nm_write_reg(SPI_FLASH_BUF1, cmd[0]);
|
||
nm_write_reg(SPI_FLASH_BUF_DIR, 0x1);
|
||
nm_write_reg(SPI_FLASH_DMA_ADDR, 0);
|
||
nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1 << 7));
|
||
while (nm_read_reg(SPI_FLASH_TR_DONE) != 1)
|
||
;
|
||
}
|
||
/*********************************************/
|
||
/* GLOBAL FUNCTIONS */
|
||
/*********************************************/
|
||
/**
|
||
* @fn spi_flash_enable
|
||
* @brief Enable spi flash operations
|
||
* @author M. Abdelmawla
|
||
* @version 1.0
|
||
*/
|
||
sint8 spi_flash_enable(uint8 enable)
|
||
{
|
||
sint8 s8Ret = M2M_SUCCESS;
|
||
if (REV(nmi_get_chipid()) >= REV_3A0) {
|
||
uint32 u32Val;
|
||
|
||
/* Enable pinmux to SPI flash. */
|
||
s8Ret = nm_read_reg_with_ret(0x1410, &u32Val);
|
||
if (s8Ret != M2M_SUCCESS) {
|
||
goto ERR1;
|
||
}
|
||
/* GPIO15/16/17/18 */
|
||
u32Val &= ~((0x7777ul) << 12);
|
||
u32Val |= ((0x1111ul) << 12);
|
||
nm_write_reg(0x1410, u32Val);
|
||
if (enable) {
|
||
spi_flash_leave_low_power_mode();
|
||
} else {
|
||
spi_flash_enter_low_power_mode();
|
||
}
|
||
/* Disable pinmux to SPI flash to minimize leakage. */
|
||
u32Val &= ~((0x7777ul) << 12);
|
||
u32Val |= ((0x0010ul) << 12);
|
||
nm_write_reg(0x1410, u32Val);
|
||
}
|
||
ERR1:
|
||
return s8Ret;
|
||
}
|
||
/**
|
||
* @fn spi_flash_read
|
||
* @brief Read from data from SPI flash
|
||
* @param[OUT] pu8Buf
|
||
* Pointer to data buffer
|
||
* @param[IN] u32offset
|
||
* Address to read from at the SPI flash
|
||
* @param[IN] u32Sz
|
||
* Data size
|
||
* @return Status of execution
|
||
* @note Data size is limited by the SPI flash size only
|
||
* @author M. Abdelmawla
|
||
* @version 1.0
|
||
*/
|
||
sint8 spi_flash_read(uint8 *pu8Buf, uint32 u32offset, uint32 u32Sz)
|
||
{
|
||
sint8 ret = M2M_SUCCESS;
|
||
if (u32Sz > FLASH_BLOCK_SIZE) {
|
||
do {
|
||
ret = spi_flash_read_internal(pu8Buf, u32offset, FLASH_BLOCK_SIZE);
|
||
if (M2M_SUCCESS != ret)
|
||
goto ERR;
|
||
u32Sz -= FLASH_BLOCK_SIZE;
|
||
u32offset += FLASH_BLOCK_SIZE;
|
||
pu8Buf += FLASH_BLOCK_SIZE;
|
||
} while (u32Sz > FLASH_BLOCK_SIZE);
|
||
}
|
||
|
||
ret = spi_flash_read_internal(pu8Buf, u32offset, u32Sz);
|
||
|
||
ERR:
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @fn spi_flash_write
|
||
* @brief Proram SPI flash
|
||
* @param[IN] pu8Buf
|
||
* Pointer to data buffer
|
||
* @param[IN] u32Offset
|
||
* Address to write to at the SPI flash
|
||
* @param[IN] u32Sz
|
||
* Data size
|
||
* @return Status of execution
|
||
* @author M. Abdelmawla
|
||
* @version 1.0
|
||
*/
|
||
sint8 spi_flash_write(uint8 *pu8Buf, uint32 u32Offset, uint32 u32Sz)
|
||
{
|
||
#ifdef PROFILING
|
||
uint32 t1 = 0;
|
||
uint32 percent = 0;
|
||
uint32 tpercent = 0;
|
||
#endif
|
||
sint8 ret = M2M_SUCCESS;
|
||
uint32 u32wsz;
|
||
uint32 u32off;
|
||
uint32 u32Blksz;
|
||
u32Blksz = FLASH_PAGE_SZ;
|
||
u32off = u32Offset % u32Blksz;
|
||
#ifdef PROFILING
|
||
tpercent = (u32Sz / u32Blksz) + ((u32Sz % u32Blksz) > 0);
|
||
t1 = GetTickCount();
|
||
M2M_PRINT(">Start programming...\r\n");
|
||
#endif
|
||
if (u32Sz <= 0) {
|
||
M2M_ERR("Data size = %d", (int)u32Sz);
|
||
ret = M2M_ERR_FAIL;
|
||
goto ERR;
|
||
}
|
||
|
||
if (u32off) /*first part of data in the address page*/
|
||
{
|
||
u32wsz = u32Blksz - u32off;
|
||
if (spi_flash_pp(u32Offset, pu8Buf, (uint16)BSP_MIN(u32Sz, u32wsz)) != M2M_SUCCESS) {
|
||
ret = M2M_ERR_FAIL;
|
||
goto ERR;
|
||
}
|
||
if (u32Sz < u32wsz)
|
||
goto EXIT;
|
||
pu8Buf += u32wsz;
|
||
u32Offset += u32wsz;
|
||
u32Sz -= u32wsz;
|
||
}
|
||
while (u32Sz > 0) {
|
||
u32wsz = BSP_MIN(u32Sz, u32Blksz);
|
||
|
||
/*write complete page or the remaining data*/
|
||
if (spi_flash_pp(u32Offset, pu8Buf, (uint16)u32wsz) != M2M_SUCCESS) {
|
||
ret = M2M_ERR_FAIL;
|
||
goto ERR;
|
||
}
|
||
pu8Buf += u32wsz;
|
||
u32Offset += u32wsz;
|
||
u32Sz -= u32wsz;
|
||
#ifdef PROFILING
|
||
percent++;
|
||
printf("\r>Complete Percentage = %d%%.\r", ((percent * 100) / tpercent));
|
||
#endif
|
||
}
|
||
EXIT:
|
||
#ifdef PROFILING
|
||
M2M_PRINT("\rDone\t\t\t\t\t\t");
|
||
M2M_PRINT("\n#Programming time = %f sec\n\r", (GetTickCount() - t1) / 1000.0);
|
||
#endif
|
||
ERR:
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @fn spi_flash_erase
|
||
* @brief Erase from data from SPI flash
|
||
* @param[IN] u32Offset
|
||
* Address to write to at the SPI flash
|
||
* @param[IN] u32Sz
|
||
* Data size
|
||
* @return Status of execution
|
||
* @note Data size is limited by the SPI flash size only
|
||
* @author M. Abdelmawla
|
||
* @version 1.0
|
||
*/
|
||
sint8 spi_flash_erase(uint32 u32Offset, uint32 u32Sz)
|
||
{
|
||
uint32 i = 0;
|
||
sint8 ret = M2M_SUCCESS;
|
||
uint8 tmp = 0;
|
||
#ifdef PROFILING
|
||
uint32 t;
|
||
t = GetTickCount();
|
||
#endif
|
||
M2M_PRINT("\r\n>Start erasing...\r\n");
|
||
for (i = u32Offset; i < (u32Sz + u32Offset); i += (16 * FLASH_PAGE_SZ)) {
|
||
ret += spi_flash_write_enable();
|
||
ret += spi_flash_read_status_reg(&tmp);
|
||
ret += spi_flash_sector_erase(i + 10);
|
||
ret += spi_flash_read_status_reg(&tmp);
|
||
do {
|
||
if (ret != M2M_SUCCESS)
|
||
goto ERR;
|
||
ret += spi_flash_read_status_reg(&tmp);
|
||
} while (tmp & 0x01);
|
||
}
|
||
M2M_PRINT("Done\r\n");
|
||
#ifdef PROFILING
|
||
M2M_PRINT("#Erase time = %f sec\n", (GetTickCount() - t) / 1000.0);
|
||
#endif
|
||
ERR:
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @fn spi_flash_get_size
|
||
* @brief Get size of SPI Flash
|
||
* @return Size of Flash
|
||
* @author M.S.M
|
||
* @version 1.0
|
||
*/
|
||
uint32 spi_flash_get_size(void)
|
||
{
|
||
uint32 u32FlashId = 0, u32FlashPwr = 0;
|
||
static uint32 gu32InernalFlashSize = 0;
|
||
|
||
if (!gu32InernalFlashSize) {
|
||
u32FlashId = spi_flash_rdid(); // spi_flash_probe();
|
||
if (u32FlashId != 0xffffffff) {
|
||
/*flash size is the third byte from the FLASH RDID*/
|
||
u32FlashPwr = ((u32FlashId >> 16) & 0xff) - 0x11; /*2MBIT is the min*/
|
||
/*That number power 2 to get the flash size*/
|
||
gu32InernalFlashSize = 1 << u32FlashPwr;
|
||
M2M_INFO("Flash Size %lu Mb\n", gu32InernalFlashSize);
|
||
} else {
|
||
M2M_ERR("Cann't Detect Flash size\n");
|
||
}
|
||
}
|
||
|
||
return gu32InernalFlashSize;
|
||
}
|