You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2990 lines
86 KiB
2990 lines
86 KiB
/* vxbSp25SpiFlash.c - Spansion S25XX(and similar) serials SPI Flash Driver */
|
|
|
|
/*
|
|
* Copyright (c) 2012-2014 Wind River Systems, Inc.
|
|
*
|
|
* The right to copy, distribute, modify or otherwise make use
|
|
* of this software may be licensed only pursuant to the terms
|
|
* of an applicable Wind River license agreement.
|
|
*/
|
|
|
|
/*
|
|
modification history
|
|
--------------------
|
|
03jun14,wyt Update manuId, devId and extId in spS25JedecProbe.
|
|
01h,04nov13,e_d Fix prevent issue. (WIND00440963)
|
|
01g,14Oct13,d_l Change function's argument to FLASH macro. (WIND00438547)
|
|
eliminate warnings.
|
|
01f,11oct13,sye Updated n25q128a with JEDECID_NO_EXT. (WIND00438393)
|
|
01e,15aug13,sye Added support for n25q128a device.
|
|
01d,01feb13,ylu Fix Null pointer in pDrvCtrl.
|
|
01c,24jan13,y_y Added support for some SST chips.
|
|
01b,14jan13,y_y fix pWrBuf allocate error in spS25SpiFlashInstInit2().
|
|
01a,14sep12,y_y created.
|
|
*/
|
|
|
|
/*
|
|
DESCRIPTION
|
|
|
|
This module implements a vxBus driver for most SPI verdor serial Flash chips.
|
|
Series supported include Atmel AT25, Spansion S25, SST 25xx, ST M25P, EON EN25
|
|
and Winbond W25X, etc. See the device list described by spiFlashList[] for
|
|
all the supported chips.
|
|
|
|
SUPPORT
|
|
|
|
This driver can support the SPI Flash device which have the following
|
|
instruction sets:
|
|
|
|
\cs
|
|
SPI_RDID_9F_CMD (0x9F) /@ Read Identification @/
|
|
SPI_READ_CMD (0x03) /@ Read Data Bytes @/
|
|
SPI_FAST_READ_CMD (0x0B) /@ Read Data Bytes at Higher Speed @/
|
|
SPI_PP_CMD (0x02) /@ Page Program @/
|
|
SPI_BE_CMD (0xC7) /@ Chip Erase @/
|
|
SPI_SE_CMD (0xD8) /@ Sector(block) Erase @/
|
|
\ce
|
|
|
|
Note:
|
|
1. If one SPI Flash device has the same command set above, but has not been
|
|
listed in spiFlashList[], user can just add it with the required information to
|
|
the array, and then the driver can be used for the device.
|
|
2. Not all of the devices listed in spiFlashList[] have been verified.
|
|
|
|
This module could be divided into three parts:
|
|
|
|
a) SPI flash auto probe.
|
|
|
|
This driver can automatically identify the SPI NOR Flash chip by CFI method,
|
|
JEDEC method, device name method and dynamic probe method.
|
|
|
|
CFI(Common Flash memory Interface) is supported by some SPI NOR Flash devices,
|
|
and can be used to obtain device information and topology, such as
|
|
flash pagesize, sectorsize, chipsize, erase block region information,
|
|
operation voltage and timing, interface type, etc.
|
|
|
|
JEDEC method is supported by most SPI NOR Flash chips, and can be used to
|
|
obtain Manufacturer, Device and Extend ID, then search one pre-defined table
|
|
(spiFlashList[]) to retrieve the flash information if has match one.
|
|
|
|
Device name match method is used for the SPI Flash devices which don't support
|
|
the 2 methods above, and can only make used of the device name to identify the
|
|
Flash devices.
|
|
|
|
Dynamic probe retrieves key parameters from hwconf.c, user needs to supply the
|
|
right pagesize, chipsize, sectorsize based on the device datasheet to driver
|
|
used. However, the weakness of dynamic probe, is ignore the ID information.
|
|
|
|
The below block diagram desribes the process of automatical probe.
|
|
|
|
\cs
|
|
+---------------+
|
|
| Name Match? |----> No (Probe failed)
|
|
+---------------+
|
|
WITH JEDEC ID | YES NO JEDEC ID
|
|
<----------------------------------------->
|
|
| |
|
|
+------------+ |
|
|
| CFI Probe |---YES(Probe OK) |
|
|
+------------+ |
|
|
| No |
|
|
| |
|
|
+------------+ |
|
|
|JEDEC Probe |---YES(Probe OK) +----------------+
|
|
+------------+ | NO JEDEC Probe |---YES(Probe OK)
|
|
| No +----------------+
|
|
|------------------------------------------| No
|
|
|
|
|
+---------------+
|
|
| Dynamic Probe |---YES(Probe OK)
|
|
+---------------+
|
|
|--No
|
|
+---------------+
|
|
| Probe Failed |
|
|
+---------------+
|
|
\ce
|
|
|
|
b) SPI Flash operation implementation
|
|
|
|
This driver implementations SPI Flash standard operation:
|
|
|
|
spS25spiFlashRead(), spS25spiFlashProgram() and spS25spiFlashSectorErase(),
|
|
if the totol erase size is equals to chipsize, spS25spiFlashChipErase() will
|
|
be instead.
|
|
|
|
c) Fill the mtd struct for filesystem use
|
|
|
|
The Flash information and operation routines are composed into one Flash chip
|
|
information structure, and can be obtained the method - vxbFlashChipInfoGet(),
|
|
which will be used by MTD layer.
|
|
|
|
EXTERNAL INTERFACE
|
|
|
|
The driver provides the standard vxbus external interface
|
|
vxbSpS25SpiFlashRegister(). This function registers the driver with the
|
|
vxbus subsystem, and instances will be created as needed. The driver also
|
|
provides vxbSpiFlashRead(), vxbSpiFlashWrite(), and vxbSpiFlashErase routine
|
|
for convenience to access the flash.
|
|
|
|
To add the driver to your vxWorks image, add the following component to the
|
|
kernel configuration, or define the following macro in config.h.
|
|
|
|
\cs
|
|
vxprj component add DRV_SPIFLASH_SP25
|
|
\ce
|
|
|
|
\cs
|
|
#define DRV_SPIFLASH_SP25
|
|
\ce
|
|
|
|
Then add device to the hwconf.c SPI device table with the name in spiFlashList.
|
|
For example:
|
|
|
|
\cs
|
|
struct vxbSpiDevInfo spiDevTbl[] = {
|
|
|
|
/@ Name chipSelect bitWidth, Freq, mode @/
|
|
|
|
{ "spiFlash_sp25probe", 0, 8, FREQ_50_MHZ, SPI_MODE_0},
|
|
{ "spiFlash_m25p40-nonjedec", 1, 8, FREQ_50_MHZ, SPI_MODE_0},
|
|
};
|
|
\ce
|
|
|
|
The driver recommends that use "sp25probe" as the device name if you want to use
|
|
CFI/JEDEC/DYNAMIC method.
|
|
|
|
SEE ALSO: vxBus, vxbSpiLib.c, sysTffs.c
|
|
*/
|
|
|
|
/* includes */
|
|
|
|
#include <vxWorks.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <logLib.h>
|
|
#include <vxBusLib.h>
|
|
#include <semLib.h>
|
|
#include <taskLib.h>
|
|
#include <sysLib.h>
|
|
#include <tickLib.h>
|
|
#include <hwif/vxbus/vxBus.h>
|
|
#include <hwif/vxbus/hwConf.h>
|
|
#include <hwif/vxbus/vxbPlbLib.h>
|
|
#include <hwif/util/hwMemLib.h>
|
|
#include <hwif/util/vxbParamSys.h>
|
|
|
|
#include <hwif/vxbus/vxbSpiLib.h>
|
|
#include "vxbSp25SpiFlash.h"
|
|
#include <usrLib.h>
|
|
|
|
/* defines */
|
|
|
|
#undef SPI_FLASH_DBG
|
|
#ifdef SPI_FLASH_DBG
|
|
|
|
#ifdef LOCAL
|
|
#undef LOCAL
|
|
#define LOCAL
|
|
#endif
|
|
|
|
IMPORT FUNCPTR _func_logMsg;
|
|
LOCAL int debugLevel = 100;
|
|
|
|
# define PRINTF_DEBUG
|
|
# ifdef PRINTF_DEBUG
|
|
# define SPI_FLASH_LOG(lvl,fmt, X1, X2, X3, X4, X5, X6) \
|
|
if (debugLevel >= lvl) \
|
|
printf(fmt, X1, X2, X3, X4, X5, X6)
|
|
# else /* PRINTF_DEBUG */
|
|
# define SPI_FLASH_LOG(lvl, fmt, X1, X2, X3, X4, X5, X6) \
|
|
if (debugLevel >= lvl) \
|
|
{ \
|
|
if (_func_logMsg != NULL) \
|
|
_func_logMsg (fmt, (int)X1, (int)X2, (int)X3,\
|
|
(int)X4, (int)X5, (int)X6); \
|
|
}
|
|
# endif /* PRINTF_DEBUG */
|
|
#else /* SPI_FLASH_DBG */
|
|
# undef SPI_FLASH_LOG
|
|
# define SPI_FLASH_LOG(lvl,fmt,a,b,c,d,e,f)
|
|
#endif /* SPI_FLASH_DBG */
|
|
|
|
/*
|
|
* Instruction set:
|
|
* Here lists the most important instructions used by all supported SPI flash,
|
|
* others can be found in vxbSp25FLSpiFlash.h
|
|
*/
|
|
|
|
/* Read command */
|
|
|
|
#define SPI_RDID_9F_CMD (0x9F) /* Read Identification */
|
|
#define SPI_READ_CMD (0x03) /* Read Data Bytes */
|
|
#define SPI_FAST_READ_CMD (0x0B) /* Read Data Bytes at Higher Speed */
|
|
|
|
/* Write Enable */
|
|
|
|
#define SPI_WREN_CMD (0x06) /* Write Enable */
|
|
#define SPI_WRDI_CMD (0x04) /* Write Disable */
|
|
#define SPI_RDSR_CMD (0x05) /* Read Status Register */
|
|
#define SPI_WRSR_CMD (0x01) /* Write Status Register */
|
|
|
|
/* Page Program */
|
|
|
|
#define SPI_PP_CMD (0x02) /* Page Program */
|
|
|
|
/* Erase */
|
|
|
|
#define SPI_BE_CMD (0xC7) /* Chip Erase */
|
|
#define SPI_SE_CMD (0xD8) /* Sector(block) Erase */
|
|
|
|
/* Enter/Exit 4-byte mode */
|
|
|
|
#define SPI_EN4B_CMD (0xB7) /* Enter 4-byte mode */
|
|
#define SPI_EX4B_CMD (0xE9) /* Exit 4-byte mode */
|
|
|
|
/* locals */
|
|
|
|
LOCAL BOOL spS25Probe (VXB_DEVICE_ID pDev);
|
|
LOCAL int s25NameMatch (VXB_DEVICE_ID pDev);
|
|
LOCAL STATUS enter4BMode (VXB_DEVICE_ID pDev, int enable);
|
|
LOCAL void cfiShow (struct cfi_ident * cfi, int verbose);
|
|
LOCAL void spS25spiFlashShow (VXB_DEVICE_ID pDev, int verbose);
|
|
LOCAL FLASH_CHIP_ID vxbFlashChipInfoGet(VXB_DEVICE_ID pDev, UINT32 chipId);
|
|
|
|
LOCAL int vxbFlashRead (FLASH_CHIP_ID, FLASH_ADDR_T, UINT32, FLASH_SIZE_T, UINT8 **, void *);
|
|
LOCAL int vxbFlashRead2 (FLASH_CHIP_ID, FLASH_ADDR_T, UINT32, FLASH_SIZE_T, UINT8 **, void *);
|
|
LOCAL int vxbFlashWrite (FLASH_CHIP_ID, FLASH_ADDR_T, UINT32, FLASH_SIZE_T, UINT8 **, void *);
|
|
LOCAL int vxbFlashSstWrite (FLASH_CHIP_ID, FLASH_ADDR_T, UINT32, FLASH_SIZE_T, UINT8 **, void *);
|
|
LOCAL int vxbFlashErase(FLASH_CHIP_ID, FLASH_ADDR_T, UINT32);
|
|
|
|
/* VxBus methods */
|
|
|
|
LOCAL void spS25SpiFlashInstInit (VXB_DEVICE_ID pDev);
|
|
LOCAL void spS25SpiFlashInstInit2 (VXB_DEVICE_ID pDev);
|
|
LOCAL void spS25SpiFlashInstConnect (VXB_DEVICE_ID pDev);
|
|
LOCAL STATUS spS25SpiFlashInstUnlink (VXB_DEVICE_ID pDev, void * unused);
|
|
|
|
/* externs */
|
|
|
|
IMPORT void vxbUsDelay (int delayTime);
|
|
|
|
/* Structs */
|
|
|
|
LOCAL struct drvBusFuncs spS25SpiFlashFuncs = {
|
|
spS25SpiFlashInstInit, /* devInstanceInit */
|
|
spS25SpiFlashInstInit2, /* devInstanceInit2 */
|
|
spS25SpiFlashInstConnect /* devConnect */
|
|
};
|
|
|
|
/* Publish the methods for the resources controlled with this file */
|
|
|
|
LOCAL struct vxbDeviceMethod spS25SpiFlashMethods[] = {
|
|
DEVMETHOD (vxbFlashChipInfoGet, vxbFlashChipInfoGet),
|
|
DEVMETHOD (busDevShow, spS25spiFlashShow),
|
|
DEVMETHOD (vxbDrvUnlink, spS25SpiFlashInstUnlink),
|
|
{ 0, 0 }
|
|
};
|
|
|
|
LOCAL VXB_PARAMETERS spiFlashParamDefaults[] =
|
|
{
|
|
{"ppTime", VXB_PARAM_INT32, {(void *)DEFAULT_PP_TIME}},
|
|
{"chipSize", VXB_PARAM_INT32, {(void *)0}},
|
|
{"pageSize", VXB_PARAM_INT32, {(void *)0}},
|
|
{"sectorSize", VXB_PARAM_INT32, {(void *)0}},
|
|
{NULL, VXB_PARAM_END_OF_LIST, {NULL}}
|
|
};
|
|
|
|
LOCAL struct vxbSpiRegister spS25SpiFlashRegister = {
|
|
{
|
|
NULL, /* pNext */
|
|
VXB_DEVID_DEVICE, /* devID */
|
|
VXB_BUSID_SPI, /* busID = SPI */
|
|
VXB_VER_4_0_0, /* vxbVersion */
|
|
"spiFlash", /* drvName */
|
|
&spS25SpiFlashFuncs, /* pDrvBusFuncs */
|
|
spS25SpiFlashMethods, /* pMethods */
|
|
spS25Probe, /* devProbe */
|
|
spiFlashParamDefaults, /* pParamDefaults */
|
|
},
|
|
};
|
|
|
|
/*
|
|
* NOTE: double check command sets and memory organization when you add
|
|
* more flash chips.
|
|
*/
|
|
|
|
LOCAL const struct spiFlash_info spiFlashList[] =
|
|
{
|
|
|
|
/* name, manuId, devId, extId, pageSize, sectorSize, sectorNum, flags */
|
|
|
|
/* CFI & JEDEC */
|
|
|
|
{ "sp25probe", 0, 0, 0, 0, 0, 0, 0},
|
|
/* KM02 use this flash */
|
|
{ "SM25QU256E", 0x20, 0x7019, 0, 256, 64 * 1024, 512, JEDECID_NO_EXT},
|
|
{ "GD25LQ256" , 0xc8, 0x6019, 0, 256, 64 * 1024, 512, JEDECID_NO_EXT},
|
|
|
|
/* SPANSION S25FLXX serials */
|
|
|
|
{ "s25sl004a", 0x01, 0x0212, 0, 256, 64 * 1024, 8, 0},
|
|
{ "s25sl008a", 0x01, 0x0213, 0, 256, 64 * 1024, 16, 0},
|
|
{ "s25sl016a", 0x01, 0x0214, 0, 256, 64 * 1024, 32, 0},
|
|
{ "s25sl032a", 0x01, 0x0215, 0, 256, 64 * 1024, 64, 0},
|
|
{ "s25sl032p", 0x01, 0x0215, 0x4d00, 256, 64 * 1024, 64, 0},
|
|
{ "s25sl064a", 0x01, 0x0216, 0, 256, 64 * 1024, 128, 0},
|
|
{ "s25sl064p", 0x01, 0x0216, 0x4d00, 256, 64 * 1024, 128, 0},
|
|
{ "s25sl128p0", 0x01, 0x2018, 0x0300, 256, 256 * 1024, 64, 0},
|
|
{ "s25sl128p1", 0x01, 0x2018, 0x0301, 256, 64 * 1024, 256, 0},
|
|
|
|
{ "s25fl040a", 0x01, 0x0212, 0, 256, 64 * 1024, 8, 0},
|
|
{ "s25fl129p0", 0x01, 0x2018, 0x4d00, 256, 256 * 1024, 64, 0},
|
|
{ "s25fl129p1", 0x01, 0x2018, 0x4d01, 256, 64 * 1024, 256, 0},
|
|
|
|
{ "s25fs256s", 0x01, 0x0219, 0x4d01, 256, 64 * 1024, 512, 0},
|
|
|
|
|
|
/* MICRO M25PXXX serials */
|
|
|
|
{ "m25p05", 0x20, 0x2010, 0, 256, 32 * 1024, 2, 0},
|
|
{ "m25p10", 0x20, 0x2011, 0, 256, 32 * 1024, 4, 0},
|
|
{ "m25p16", 0x20, 0x2015, 0, 256, 64 * 1024, 32, 0},
|
|
{ "m25p20", 0x20, 0x2012, 0, 256, 64 * 1024, 4, 0},
|
|
{ "m25p32", 0x20, 0x2016, 0, 256, 64 * 1024, 64, 0},
|
|
{ "m25p40", 0x20, 0x2013, 0, 256, 64 * 1024, 8, 0},
|
|
{ "m25p64", 0x20, 0x2017, 0, 256, 64 * 1024, 128, 0},
|
|
{ "m25p64", 0x20, 0x2017, 0x1004, 256, 64 * 1024, 128, 0},
|
|
{ "m25p80", 0x20, 0x2014, 0, 256, 64 * 1024, 16, 0},
|
|
{ "m25p128", 0x20, 0x2018, 0, 256, 256 * 1024, 64, 0},
|
|
|
|
{ "m25pe10", 0x20, 0x8011, 0, 256, 64 * 1024, 2, 0},
|
|
{ "m25pe16", 0x20, 0x8015, 0, 256, 64 * 1024, 32, 0},
|
|
{ "m25pe20", 0x20, 0x8012, 0, 256, 64 * 1024, 4, 0},
|
|
{ "m25pe40", 0x20, 0x8013, 0, 256, 64 * 1024, 8, 0},
|
|
{ "m25pe80", 0x20, 0x8014, 0, 256, 64 * 1024, 16, 0},
|
|
|
|
{ "m25px16", 0x20, 0x7115, 0, 256, 64 * 1024, 32, 0},
|
|
{ "m25px32", 0x20, 0x7116, 0, 256, 64 * 1024, 64, 0},
|
|
{ "m25px32-s0", 0x20, 0x7316, 0, 256, 64 * 1024, 64, 0},
|
|
{ "m25px32-s1", 0x20, 0x6316, 0, 256, 64 * 1024, 64, 0},
|
|
{ "m25px64", 0x20, 0x7117, 0, 256, 64 * 1024, 128, 0},
|
|
{ "m25px80", 0x20, 0x7114, 0, 256, 64 * 1024, 16, 0},
|
|
|
|
{ "m45pe10", 0x20, 0x4011, 0, 256, 64 * 1024, 2, 0},
|
|
{ "m45pe16", 0x20, 0x4015, 0, 256, 64 * 1024, 32, 0},
|
|
{ "m45pe20", 0x20, 0x4012, 0, 256, 64 * 1024, 4, 0},
|
|
{ "m45pe40", 0x20, 0x4013, 0, 256, 64 * 1024, 8, 0},
|
|
{ "m45pe80", 0x20, 0x4014, 0, 256, 64 * 1024, 16, 0},
|
|
|
|
{ "n25q00", 0x20, 0xba21, 0x1000, 256, 64 * 1024, 512, 0},
|
|
{ "n25q32", 0x20, 0xbb16, 0x1000, 256, 64 * 1024, 64, 0},
|
|
{ "n25q64", 0x20, 0xbb17, 0x1000, 256, 64 * 1024, 128, 0},
|
|
{ "n25q128", 0x20, 0xba18, 0x1000, 256, 64 * 1024, 256, 0},
|
|
{ "n25q128a", 0x20, 0xbb18, 0, 256, 64 * 1024, 256, JEDECID_NO_EXT},
|
|
{ "n25q256", 0x20, 0xba19, 0x1000, 256, 64 * 1024, 512, 0},
|
|
{ "n25q512", 0x20, 0xbb20, 0x1000, 256, 64 * 1024, 1024, 0},
|
|
|
|
/* WINBOND W25XXXX serials */
|
|
|
|
{ "w25x05", 0xef, 0x3010, 0, 256, 64 * 1024, 1, 0},
|
|
{ "w25x10", 0xef, 0x3011, 0, 256, 64 * 1024, 2, 0},
|
|
{ "w25x20", 0xef, 0x3012, 0, 256, 64 * 1024, 4, 0},
|
|
{ "w25x40", 0xef, 0x3013, 0, 256, 64 * 1024, 8, 0},
|
|
{ "w25x80", 0xef, 0x3014, 0, 256, 64 * 1024, 16, 0},
|
|
{ "w25x16", 0xef, 0x3015, 0, 256, 64 * 1024, 32, 0},
|
|
{ "w25x32", 0xef, 0x3016, 0, 256, 64 * 1024, 64, 0},
|
|
{ "w25x64", 0xef, 0x3017, 0, 256, 64 * 1024, 128, 0},
|
|
|
|
{ "w25q32", 0xef, 0x4016, 0, 256, 64 * 1024, 64, 0},
|
|
{ "w25q64", 0xef, 0x4017, 0, 256, 64 * 1024, 128, 0},
|
|
{ "w25q128", 0xef, 0x4018, 0, 256, 64 * 1024, 256, 0},
|
|
{ "w25q256", 0xef, 0x4019, 0, 256, 64 * 1024, 512, 0},
|
|
|
|
/* SST W25XXXX serials */
|
|
|
|
{ "sst25wf020", 0xbf, 0x2503, 0, 1, 64 * 1024, 4, JEDECID_NO_EXT},
|
|
{ "sst25wf040", 0xbf, 0x2504, 0, 1, 64 * 1024, 8, JEDECID_NO_EXT},
|
|
|
|
{ "sst25vf016b", 0xbf, 0x2541, 0, 1, 64 * 1024, 32, JEDECID_NO_EXT},
|
|
{ "sst25vf032b", 0xbf, 0x254a, 0, 1, 64 * 1024, 64, JEDECID_NO_EXT},
|
|
{ "sst25vf064c", 0xbf, 0x254b, 0, 1, 64 * 1024, 128, JEDECID_NO_EXT},
|
|
|
|
{ "sst25pf020b", 0xbf, 0x258c, 0, 1, 64 * 1024, 4, JEDECID_NO_EXT},
|
|
{ "sst25pf040b", 0xbf, 0x258d, 0, 1, 64 * 1024, 8, JEDECID_NO_EXT},
|
|
{ "sst25pf080b", 0xbf, 0x258e, 0, 1, 64 * 1024, 8, JEDECID_NO_EXT},
|
|
|
|
{ "sst26vf016", 0xbf, 0x2601, 0, 256, 64 * 1024, 32, 0},
|
|
{ "sst26vf032", 0xbf, 0x2602, 0, 256, 64 * 1024, 64, 0},
|
|
|
|
/*
|
|
* ATMEL AT25F/AT25FSxxx series
|
|
* The ATMEL 45 series instructions different with the 25 series sets.
|
|
* See the drvier vxbAt45SpiFlash.c
|
|
*/
|
|
|
|
{ "at25df021a", 0x1f, 0x4300, 0, 256, 64 * 1024, 4, 0},
|
|
{ "at25df041a", 0x1f, 0x4401, 0, 256, 64 * 1024, 8, 0},
|
|
{ "at25df081a", 0x1f, 0x4501, 0x0100, 256, 64 * 1024, 16, 0},
|
|
{ "at25dl081", 0x1f, 0x4502, 0, 256, 64 * 1024, 16, 0},
|
|
{ "at25df161", 0x1f, 0x4602, 0, 256, 64 * 1024, 32, 0},
|
|
{ "at25dq161", 0x1f, 0x8600, 0x0100, 256, 64 * 1024, 32, 0},
|
|
{ "at25df321", 0x1f, 0x4701, 0, 256, 64 * 1024, 64, 0},
|
|
{ "at25dq321", 0x1f, 0x8700, 0, 256, 64 * 1024, 64, 0},
|
|
{ "at25df641", 0x1f, 0x4800, 0, 256, 64 * 1024, 128, 0},
|
|
{ "at25df641a", 0x1f, 0x4800, 0x0100, 256, 64 * 1024, 128, 0},
|
|
{ "at25f512b", 0x1f, 0x6500, 0, 256, 32 * 1024, 2, 0},
|
|
{ "at25fs010", 0x1f, 0x6601, 0, 256, 32 * 1024, 4, 0},
|
|
{ "at25fs040", 0x1f, 0x6604, 0, 256, 64 * 1024, 8, 0},
|
|
|
|
/* MXIC MX25LXX serials */
|
|
|
|
{ "mx25l512e", 0xc2, 0x2010, 0, 256, 4 * 1024, 16, 0},
|
|
{ "mx25l1006e", 0xc2, 0x2011, 0, 256, 64 * 1024, 2, 0},
|
|
{ "mx25l2006e", 0xc2, 0x2012, 0, 256, 64 * 1024, 4, 0},
|
|
{ "mx25l4006e", 0xc2, 0x2013, 0, 256, 64 * 1024, 8, 0},
|
|
{ "mx25l8006e", 0xc2, 0x2014, 0, 256, 64 * 1024, 16, 0},
|
|
{ "mx25l160", 0xc2, 0x2015, 0, 256, 64 * 1024, 32, 0},
|
|
{ "mx25l320", 0xc2, 0x2016, 0, 256, 64 * 1024, 64, 0},
|
|
{ "mx25l640", 0xc2, 0x2017, 0, 256, 64 * 1024, 128, 0},
|
|
{ "mx25l12805d", 0xc2, 0x2018, 0, 256, 64 * 1024, 256, 0},
|
|
{ "mx25l12855e", 0xc2, 0x2618, 0, 256, 64 * 1024, 256, 0},
|
|
{ "mx25l25635e", 0xc2, 0x2019, 0, 256, 64 * 1024, 512, 0},
|
|
|
|
/* EON EN25LXX serials */
|
|
|
|
{ "en25f05", 0x1c, 0x3110, 0, 256, 32 * 1024, 2, 0},
|
|
{ "en25f10", 0x1c, 0x3111, 0, 256, 32 * 1024, 4, 0},
|
|
{ "en25f20", 0x1c, 0x3112, 0, 256, 64 * 1024, 4, 0},
|
|
{ "en25f32", 0x1c, 0x3116, 0, 256, 64 * 1024, 64, 0},
|
|
{ "en25p32", 0x1c, 0x2016, 0, 256, 64 * 1024, 64, 0},
|
|
{ "en25f40", 0x1c, 0x3113, 0, 256, 64 * 1024, 8, 0},
|
|
{ "en25f80", 0x1c, 0x3114, 0, 256, 64 * 1024, 16, 0},
|
|
|
|
{ "en25q16", 0x1c, 0x3015, 0, 256, 64 * 1024, 32, 0},
|
|
{ "en25q32", 0x1c, 0x3016, 0, 256, 64 * 1024, 64, 0},
|
|
{ "en25q64", 0x1c, 0x3017, 0, 256, 64 * 1024, 128, 0},
|
|
{ "en25q128", 0x1c, 0x3018, 0, 256, 64 * 1024, 256, 0},
|
|
{ "en25q256", 0x1c, 0x7019, 0, 256, 64 * 1024, 512, 0},
|
|
|
|
/* NO-ID serials */
|
|
|
|
{ "m25p40-nonjedec", 0, 0, 0, 256, 64 * 1024, 8, NO_JEDEC_ID},
|
|
};
|
|
|
|
#define spiFlashTypeNum NELEMENTS(spiFlashList)
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbSpS25SpiFlashRegister - register with the VxBus subsystem
|
|
*
|
|
* This routine registers the driver to VxBus Systems.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*
|
|
* \NOMANUAL
|
|
*/
|
|
|
|
void vxbSp25SpiFlashRegister (void)
|
|
{
|
|
|
|
/* Need not check return status */
|
|
(void)vxbDevRegister ((struct vxbDevRegInfo *) &spS25SpiFlashRegister);
|
|
return;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25SpiFlashInstInit - first level initialization routine of spi flash device
|
|
*
|
|
* This routine creates pDrvCtrl structure, saves the index in spiFlashList[]
|
|
* for the specified Flash device name, and finds the next SPI Flash instance.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL void spS25SpiFlashInstInit
|
|
(
|
|
VXB_DEVICE_ID pDev
|
|
)
|
|
{
|
|
VXB_INST_PARAM_VALUE val;
|
|
SPI_FLASH_DEV * pDrvCtrl;
|
|
|
|
/* Check for vaild parameter */
|
|
VXB_ASSERT_NONNULL_V (pDev);
|
|
|
|
pDrvCtrl = (SPI_FLASH_DEV *) hwMemAlloc (sizeof (SPI_FLASH_DEV));
|
|
|
|
if (pDrvCtrl == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* save instance ID */
|
|
|
|
pDrvCtrl->pDev = pDev;
|
|
pDev->pDrvCtrl = pDrvCtrl;
|
|
|
|
/* save the name match result */
|
|
if ((pDrvCtrl->index = s25NameMatch (pDev)) == ERROR)
|
|
{
|
|
return;
|
|
}
|
|
/*
|
|
* paramDesc {
|
|
* The ppTime parameter specifies how many microseconds the SPI FLASH
|
|
* need delay after Page Program cycle.
|
|
*/
|
|
|
|
if (vxbInstParamByNameGet (pDev, "ppTime", VXB_PARAM_INT32, &val) == ERROR)
|
|
pDrvCtrl->ppTime = DEFAULT_PP_TIME;
|
|
else
|
|
pDrvCtrl->ppTime = val.int32Val;
|
|
|
|
/* find the next instance */
|
|
|
|
vxbNextUnitGet (pDev);
|
|
|
|
return;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vendorGet - transform the manufacture ID to vendor name
|
|
*
|
|
* This routine transforms the manufacture ID to the corresponding vendor name.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL char * vendorGet
|
|
(
|
|
UINT8 manId
|
|
)
|
|
{
|
|
switch (manId)
|
|
{
|
|
case SPANSION:
|
|
return "Spansion";
|
|
|
|
case FUJITSU:
|
|
return "Fujitsu";
|
|
|
|
case EON:
|
|
return "Eon";
|
|
|
|
case ATMEL:
|
|
return "Atmel";
|
|
|
|
case MICRO:
|
|
return "MICRO";
|
|
|
|
case AMIC:
|
|
return "AMIC";
|
|
|
|
case ESI:
|
|
return "ESI";
|
|
|
|
case INTEL:
|
|
return "Intel";
|
|
|
|
case ESMT:
|
|
return "ESMT";
|
|
|
|
case TOSHIBA:
|
|
return "Toshiba";
|
|
|
|
case PMC:
|
|
return "PMC";
|
|
|
|
case HYUNDAI:
|
|
return "Hyundai";
|
|
|
|
case SHARP:
|
|
return "Sharp";
|
|
|
|
case SST:
|
|
return "SST";
|
|
|
|
case MXIC:
|
|
return "MXIC";
|
|
|
|
case WINBOND:
|
|
return "Winbond";
|
|
|
|
case SAMSUNG:
|
|
return "Samsung";
|
|
case GIGADEVICE:
|
|
return "GigaDevice";
|
|
default:
|
|
return "Unknown";
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbFlashChipInfoGet - get Flash chip information
|
|
*
|
|
* This routine returns the Flash chip information for the upper level software.
|
|
*
|
|
* RETURNS: the Flash chip information.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL FLASH_CHIP_ID vxbFlashChipInfoGet
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
UINT32 chipId /* chip index (unused) */
|
|
)
|
|
{
|
|
/* Check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pDev != NULL, NULL)
|
|
|
|
SPI_FLASH_DEV * pDrvCtrl = (SPI_FLASH_DEV *) pDev->pDrvCtrl;
|
|
|
|
return (&pDrvCtrl->mtd);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* s25NameMatch - SPI Flash name match routine
|
|
*
|
|
* This routine compare the device name with the drvier supported devices in
|
|
* spiFlashList[]. If match, return the location in array, otherwise return
|
|
* -1.
|
|
*
|
|
* RETURNS: the index or -1
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL int s25NameMatch
|
|
(
|
|
VXB_DEVICE_ID pDev
|
|
)
|
|
{
|
|
char modelName[MAX_DRV_NAME_LEN];
|
|
int drvLen = strlen ("spiFlash_");
|
|
int index = 0;
|
|
int status = FALSE;
|
|
|
|
/* Check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pDev != NULL, ERROR)
|
|
|
|
memset (modelName, 0, sizeof (modelName));
|
|
memcpy (modelName, (pDev->pName + drvLen), strlen (pDev->pName) - drvLen);
|
|
|
|
while (index < spiFlashTypeNum)
|
|
{
|
|
if (strcmp (spiFlashList[index].name, modelName) == 0)
|
|
{
|
|
status = TRUE;
|
|
break;
|
|
}
|
|
index++;
|
|
}
|
|
|
|
if (status == FALSE)
|
|
{
|
|
index = -1;
|
|
}
|
|
|
|
SPI_FLASH_LOG (1000, "index: %d, match: %s\n", index,
|
|
(_Vx_usr_arg_t) ((index >= 0) ? "yes" : "no"),
|
|
3, 4, 5, 6);
|
|
return index;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25Probe - vxbus sub probe routine
|
|
*
|
|
* This function is vxbus sub-probe routine, it will return the name match
|
|
* result, which means whether the SPI flash is supported by this drvier.
|
|
*
|
|
* RETURNS: TRUE/FALSE
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL BOOL spS25Probe
|
|
(
|
|
VXB_DEVICE_ID pDev
|
|
)
|
|
{
|
|
/* Check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pDev != NULL, FALSE)
|
|
|
|
if (s25NameMatch (pDev) != ERROR)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
SPI_FLASH_LOG (0, "spS25Probe failed\n", 1, 2, 3, 4, 5, 6);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25GetCFIFromRawData - analyse and get cfi data
|
|
*
|
|
* This routine get CFI info from raw data got from the Flash.
|
|
*
|
|
* RETURNS: N/A.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL void spS25GetCFIFromRawData
|
|
(
|
|
UINT8 * ptr,
|
|
UINT8 len,
|
|
void * dest
|
|
)
|
|
{
|
|
UINT16 word1 = 0;
|
|
UINT32 word2 = 0;
|
|
switch (len)
|
|
{
|
|
case 1:
|
|
*(UINT8 *)dest = *ptr;
|
|
break;
|
|
case 2:
|
|
word1 = (*ptr) | (*(ptr + 1) << 8);
|
|
*(UINT16 *)dest = word1;
|
|
break;
|
|
case 4:
|
|
word2 = (*ptr) | (*(ptr + 1) << 8) |
|
|
(*(ptr + 2) << 16) | (*(ptr + 3) << 24);
|
|
*(UINT32 *)dest = word2;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25CfiProbe - CFI probe routine
|
|
*
|
|
* This routine use CFI interface to identifie the Flash, and save the SPI flash
|
|
* infos to the corresponding fields in pDrvCtrl.
|
|
*
|
|
* RETURNS: OK or ERROR if failed.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS spS25CfiProbe
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
int verbose
|
|
)
|
|
{
|
|
UINT8 tmp;
|
|
UINT16 max;
|
|
UINT8 id[SPI_CFI_OFFSET + SPI_CFI_LEN];
|
|
UINT8 * rawPtr = &id[SPI_CFI_OFFSET];
|
|
struct cfi_ident cfi;
|
|
struct cfi_region region[SPI_CFI_ERASE_REGIONS];
|
|
|
|
SPI_FLASH_DEV * pDrvCtrl;
|
|
|
|
/* Check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pDev != NULL, ERROR)
|
|
|
|
pDrvCtrl = (SPI_FLASH_DEV *) pDev->pDrvCtrl;
|
|
|
|
SPI_FLASH_LOG (1000, "spS25CfiProbe(0x08%x) called\n",
|
|
(_Vx_usr_arg_t)pDev, 2, 3, 4, 5, 6);
|
|
/* clear id buf */
|
|
|
|
memset(id, 0, SPI_CFI_OFFSET + SPI_CFI_LEN);
|
|
|
|
/* retrieve ID from the Flash */
|
|
|
|
JEDEC_ID_GET (pDev, id, sizeof (id));
|
|
|
|
memcpy ((struct cfi_ident *) &cfi, &id[SPI_CFI_OFFSET], 3);
|
|
|
|
/* try obtaining the params via CFI instead. */
|
|
|
|
if (cfi.qryStr[0] != 'Q' || cfi.qryStr[1] != 'R' || cfi.qryStr[2] != 'Y')
|
|
{
|
|
SPI_FLASH_LOG (100, "No CFI \n", 1, 2, 3, 4, 5, 6);
|
|
return ERROR;
|
|
}
|
|
|
|
spS25GetCFIFromRawData (rawPtr + OFF_VCCMIN, 1, (void *)&(cfi.vccMin));
|
|
spS25GetCFIFromRawData (rawPtr + OFF_VCCMAX, 1, (void *)&(cfi.vccMax));
|
|
spS25GetCFIFromRawData (rawPtr + OFF_VPPMIN, 1, (void *)&(cfi.vppMin));
|
|
spS25GetCFIFromRawData (rawPtr + OFF_VPPMAX, 1, (void *)&(cfi.vppMax));
|
|
spS25GetCFIFromRawData (rawPtr + OFF_WTO , 1, (void *)&(cfi.wrTimeout));
|
|
spS25GetCFIFromRawData (rawPtr + OFF_WBTO , 1, (void *)&(cfi.wrBufTimeout));
|
|
spS25GetCFIFromRawData (rawPtr + OFF_BETO , 1, (void *)&(cfi.blkEraseTimeout));
|
|
spS25GetCFIFromRawData (rawPtr + OFF_CETO , 1, (void *)&(cfi.chipEraseTimeout));
|
|
spS25GetCFIFromRawData (rawPtr + OFF_WTOM , 1, (void *)&(cfi.wrTimeoutMax));
|
|
spS25GetCFIFromRawData (rawPtr + OFF_WBTOM , 1, (void *)&(cfi.wrBufTimeoutMax));
|
|
spS25GetCFIFromRawData (rawPtr + OFF_BETOM , 1, (void *)&(cfi.blkEraseTimeoutMax));
|
|
spS25GetCFIFromRawData (rawPtr + OFF_CETOM , 1, (void *)&(cfi.chipEraseTimeoutMax));
|
|
spS25GetCFIFromRawData (rawPtr + OFF_DS , 1, (void *)&(cfi.devSize));
|
|
spS25GetCFIFromRawData (rawPtr + OFF_RN , 1, (void *)&(cfi.regionNum));
|
|
spS25GetCFIFromRawData (rawPtr + OFF_PCS , 2, (void *)&(cfi.priCmdSet));
|
|
spS25GetCFIFromRawData (rawPtr + OFF_PETA, 2, (void *)&(cfi.priExtTblAdrs));
|
|
spS25GetCFIFromRawData (rawPtr + OFF_ACS , 2, (void *)&(cfi.altCmdSet));
|
|
spS25GetCFIFromRawData (rawPtr + OFF_AETA, 2, (void *)&(cfi.altExtTblAdrs));
|
|
spS25GetCFIFromRawData (rawPtr + OFF_ID , 2, (void *)&(cfi.ifDesc));
|
|
spS25GetCFIFromRawData (rawPtr + OFF_WBL , 2, (void *)&(cfi.wrBufLen));
|
|
spS25GetCFIFromRawData (rawPtr + OFF_ERI0, 4, (void *)&(cfi.EraseRegionInfo[0]));
|
|
spS25GetCFIFromRawData (rawPtr + OFF_ERI1, 4, (void *)&(cfi.EraseRegionInfo[1]));
|
|
spS25GetCFIFromRawData (rawPtr + OFF_ERI2, 4, (void *)&(cfi.EraseRegionInfo[2]));
|
|
spS25GetCFIFromRawData (rawPtr + OFF_ERI3, 4, (void *)&(cfi.EraseRegionInfo[3]));
|
|
|
|
pDrvCtrl->chipSize = 1 << cfi.devSize;
|
|
|
|
PageSize (pDrvCtrl) = 1 << cfi.wrBufLen;
|
|
|
|
cfi.regionNum = min (cfi.regionNum, (UINT8) SPI_CFI_ERASE_REGIONS);
|
|
|
|
cfiShow (&cfi, verbose);
|
|
|
|
for (tmp = 0; tmp < cfi.regionNum; tmp++)
|
|
{
|
|
region[tmp].blkSize = (UINT16) (cfi.EraseRegionInfo[tmp] >> 16);
|
|
}
|
|
|
|
tmp = 0;
|
|
max = region[0].blkSize;
|
|
while (tmp < cfi.regionNum)
|
|
{
|
|
if (region[tmp].blkSize > max)
|
|
{
|
|
max = region[tmp].blkSize;
|
|
}
|
|
tmp++;
|
|
}
|
|
|
|
SectorSize (pDrvCtrl) = CFI_BLK_SIZE (max);
|
|
SectorNum (pDrvCtrl) = pDrvCtrl->chipSize / SectorSize (pDrvCtrl);
|
|
|
|
strncpy (pDrvCtrl->type, "CFI", MAX_DRV_NAME_LEN);
|
|
|
|
SPI_FLASH_LOG (10, "CFI Probe: found CFI device %dKB, %dKB, %dB, %dRegions\n",
|
|
pDrvCtrl->chipSize >> 10, SectorSize(pDrvCtrl) >> 10,
|
|
PageSize(pDrvCtrl), cfi.regionNum, 5 , 6);
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25NoJedecProbe - probe device without JEDEC ID
|
|
*
|
|
* This function saves the information for the SPI flash without jedec ID
|
|
* to the corresponding fileds in pDrvCtrl.
|
|
*
|
|
* RETURNS: OK
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS spS25NoJedecProbe
|
|
(
|
|
VXB_DEVICE_ID pDev
|
|
)
|
|
{
|
|
SPI_FLASH_DEV * pDrvCtrl;
|
|
|
|
/* Check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pDev != NULL, ERROR)
|
|
|
|
pDrvCtrl = (SPI_FLASH_DEV *) pDev->pDrvCtrl;
|
|
|
|
SectorSize (pDrvCtrl) = spiFlashList[pDrvCtrl->index].sectorSize;
|
|
PageSize (pDrvCtrl) = spiFlashList[pDrvCtrl->index].pageSize;
|
|
SectorNum (pDrvCtrl) = spiFlashList[pDrvCtrl->index].sectorNum;
|
|
pDrvCtrl->chipSize = SectorNum (pDrvCtrl) * SectorSize (pDrvCtrl);
|
|
|
|
SPI_FLASH_LOG (100, "spS25NoJedecProbe: identified known device %s (%d KB)\n",
|
|
spiFlashList[pDrvCtrl->index].name,
|
|
(pDrvCtrl->chipSize >> 10), 3, 4, 5, 6);
|
|
return OK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25JedecProbe - probe device with JEDEC ID
|
|
*
|
|
* This function reads the JEDEC ID from the flash, then compared with the
|
|
* supported device in spiFlashList[]. If match one, return the pageSize,
|
|
* sectorSize and chipSize info to the corresponding filed in pDrvCtrl.
|
|
* Otherwise, return ERROR.
|
|
*
|
|
* RETURNS: OK/ERRROR
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS spS25JedecProbe
|
|
(
|
|
VXB_DEVICE_ID pDev
|
|
)
|
|
{
|
|
SPI_FLASH_DEV * pDrvCtrl;
|
|
UINT8 jedecId[5];
|
|
UINT16 index;
|
|
|
|
/* Check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pDev != NULL, ERROR)
|
|
|
|
pDrvCtrl = (SPI_FLASH_DEV *) pDev->pDrvCtrl;
|
|
|
|
SPI_FLASH_LOG (1000, "MyspS25JedecProbe(0x08%x) called\n",
|
|
(_Vx_usr_arg_t)pDev, 2, 3, 4, 5, 6);
|
|
|
|
memset (jedecId, 0, 5);
|
|
|
|
JEDEC_ID_GET (pDev, jedecId, sizeof (jedecId));
|
|
|
|
SPI_FLASH_LOG (100, "JEDEC Probeing......Device ID: 0x%02x 0x%04x 0x%04x\r\n",
|
|
jedecId[0], (jedecId[1] << 8 | jedecId[2]),
|
|
(jedecId[3] << 8 | jedecId[4]), 4, 5, 6);
|
|
|
|
pDrvCtrl->flash.manuId = jedecId[0];
|
|
pDrvCtrl->flash.devId = (jedecId[1] << 8 | jedecId[2]);
|
|
pDrvCtrl->flash.extId = (jedecId[3] << 8 | jedecId[4]);
|
|
|
|
/*
|
|
* Spansion JEDEC ID info:
|
|
* 1. Byte 0 is Manufacturer ID.
|
|
* 2. Byte 1 and 2 is Device Id.
|
|
* 3. Byte 3 is Extended Device Information String Length, to indicate
|
|
* how many Extended Device Information bytes will follow.
|
|
* 4. Byte 4 indicates uniform 64 KB sector or uniform 256 KB sector device.
|
|
* 5. Bytes 5 and 6 are reserved (do not use).
|
|
* 6. For Bytes 07h-0Fh and 3Dh-3Fh, the data will be read as 0xFF.
|
|
* 7. Bytes 10h-50h are factory programmed per JEDEC standard.
|
|
*/
|
|
|
|
if ((0 == jedecId[0]) &&
|
|
(0 == (jedecId[1] << 8 | jedecId[2])) &&
|
|
(0 == (jedecId[3] << 8 | jedecId[4])))
|
|
{
|
|
SPI_FLASH_LOG (100, "No match item in JEDECID table \n",
|
|
1, 2, 3, 4, 5, 6);
|
|
return ERROR;
|
|
}
|
|
|
|
for (index = 1; index < spiFlashTypeNum; index++)
|
|
{
|
|
if ((spiFlashList[index].manuId == jedecId[0]) &&
|
|
(spiFlashList[index].devId == (jedecId[1] << 8 | jedecId[2])))
|
|
{
|
|
if (!(spiFlashList[index].flags & JEDECID_NO_EXT))
|
|
{
|
|
if (!(spiFlashList[index].extId == (jedecId[3] << 8 | jedecId[4])))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
pDrvCtrl->index = index;
|
|
strncpy (pDrvCtrl->type, spiFlashList[pDrvCtrl->index].name,
|
|
MAX_DRV_NAME_LEN - 1);
|
|
|
|
SPI_FLASH_LOG (100, "****** Found %s flash chip [%s] match ******\r\n",
|
|
vendorGet (spiFlashList[index].manuId),
|
|
spiFlashList[index].name, 3, 4, 5, 6);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
SPI_FLASH_LOG (100, "probing for %s %s, %d KB, ManId 0x%02x, "
|
|
"DevId 0x%04x, ExtId 0x%04x\r\n",
|
|
vendorGet (spiFlashList[index].manuId),
|
|
spiFlashList[index].name,
|
|
(spiFlashList[index].sectorNum *
|
|
spiFlashList[index].sectorSize) >> 10,
|
|
spiFlashList[index].manuId,
|
|
spiFlashList[index].devId,
|
|
spiFlashList[index].extId);
|
|
}
|
|
}
|
|
|
|
if (index == spiFlashTypeNum)
|
|
{
|
|
SectorSize (pDrvCtrl) = 0;
|
|
PageSize (pDrvCtrl) = 0;
|
|
pDrvCtrl->chipSize = 0;
|
|
SPI_FLASH_LOG (100, "No match item in supported JEDECID table\r\n",
|
|
1, 2, 3, 4, 5, 6);
|
|
return ERROR;
|
|
}
|
|
else
|
|
{
|
|
SectorSize (pDrvCtrl) = spiFlashList[pDrvCtrl->index].sectorSize;
|
|
PageSize (pDrvCtrl) = spiFlashList[pDrvCtrl->index].pageSize;
|
|
SectorNum (pDrvCtrl) = spiFlashList[pDrvCtrl->index].sectorNum;
|
|
pDrvCtrl->chipSize = SectorNum (pDrvCtrl) * SectorSize (pDrvCtrl);
|
|
|
|
SPI_FLASH_LOG (10, "JedecProbe: identified known JEDEC "
|
|
"device %s %s (%d KB) \n",
|
|
vendorGet (spiFlashList[pDrvCtrl->index].manuId),
|
|
spiFlashList[pDrvCtrl->index].name,
|
|
(pDrvCtrl->chipSize >> 10), 4, 5, 6);
|
|
return OK;
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25DynamicProbe - probe device dynamically
|
|
*
|
|
* This routine retrieves SPI Flash parameters from hwConf.c dynamically, usr
|
|
* can transmit the right chipSize, sectorSize and pageSize based on datasheet
|
|
* for driver use.
|
|
*
|
|
* RETURNS: OK/ERRROR
|
|
*/
|
|
|
|
LOCAL STATUS spS25DynamicProbe
|
|
(
|
|
VXB_DEVICE_ID pDev
|
|
)
|
|
{
|
|
SPI_FLASH_DEV * pDrvCtrl;
|
|
VXB_INST_PARAM_VALUE val;
|
|
|
|
pDrvCtrl = (SPI_FLASH_DEV *) pDev->pDrvCtrl;
|
|
|
|
/*
|
|
* paramDesc {
|
|
* The chipSize parameter specifies the SPI Flash device totol Chip Size in
|
|
* Byte. }
|
|
*/
|
|
|
|
if (OK == vxbInstParamByNameGet (pDev,
|
|
"chipSize",
|
|
VXB_PARAM_INT32,
|
|
&val))
|
|
pDrvCtrl->chipSize = val.int32Val;
|
|
else
|
|
return ERROR;
|
|
|
|
/*
|
|
* paramDesc {
|
|
* The sectorSize parameter specifies the SPI Flash device erase Sector
|
|
* Size in byte. }
|
|
*/
|
|
|
|
if (OK == vxbInstParamByNameGet (pDev,
|
|
"sectorSize",
|
|
VXB_PARAM_INT32,
|
|
&val))
|
|
SectorSize(pDrvCtrl) = val.int32Val;
|
|
else
|
|
return ERROR;
|
|
|
|
/*
|
|
* paramDesc {
|
|
* The pageSize parameter specifies the SPI Flash write page size in byte.}
|
|
*/
|
|
|
|
if (OK == vxbInstParamByNameGet (pDev,
|
|
"pageSize",
|
|
VXB_PARAM_INT32,
|
|
&val))
|
|
PageSize(pDrvCtrl) = val.int32Val;
|
|
else
|
|
return ERROR;
|
|
|
|
if ((PageSize(pDrvCtrl) == 0) || (SectorSize(pDrvCtrl) == 0) ||
|
|
(pDrvCtrl->chipSize == 0))
|
|
return ERROR;
|
|
|
|
SectorNum (pDrvCtrl) = pDrvCtrl->chipSize / SectorSize (pDrvCtrl);
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25SpiFlashProbe - spi flash probe
|
|
*
|
|
* This routine probe SPI Flash with the CFI, JEDEC, NO-JEDEC and Dynamic methods.
|
|
*
|
|
* RETURNS: OK or ERROR if probe failed
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS spS25SpiFlashProbe
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
int verbose
|
|
)
|
|
{
|
|
int index = 0xffff;
|
|
STATUS sts = ERROR;
|
|
SPI_FLASH_DEV * pDrvCtrl;
|
|
|
|
/* Check for vaild parameter */
|
|
|
|
VXB_ASSERT (pDev != NULL, ERROR)
|
|
|
|
pDrvCtrl = (SPI_FLASH_DEV *) pDev->pDrvCtrl;
|
|
|
|
index = s25NameMatch (pDev);
|
|
|
|
if (index == ERROR)
|
|
return ERROR;
|
|
|
|
/* If match, continue */
|
|
|
|
do
|
|
{
|
|
/*
|
|
* Firstly, CFI probe, then JEDEC probe, if no device match, probing
|
|
* failure. Note: auto probe only used the SPI NOR flash has the
|
|
* JEDEC ID.
|
|
*/
|
|
|
|
if (!((spiFlashList[index].flags) & (NO_JEDEC_ID)))
|
|
{
|
|
/* CFI probe */
|
|
|
|
sts = spS25CfiProbe (pDev, verbose);
|
|
SPI_FLASH_LOG (50, "CFI Probe %s \n",
|
|
(_Vx_usr_arg_t)((sts == ERROR) ? "ERROR" : "OK"),
|
|
2, 3, 4, 5, 6);
|
|
if (sts == OK)
|
|
break;
|
|
|
|
/* JEDEC probe */
|
|
|
|
sts = spS25JedecProbe (pDev);
|
|
SPI_FLASH_LOG (50, "JEDEC Probe %s \n",
|
|
(_Vx_usr_arg_t)((sts == ERROR) ? "ERROR" : "OK"),
|
|
2, 3, 4, 5, 6);
|
|
}
|
|
else
|
|
{
|
|
/* No Id probe */
|
|
|
|
pDrvCtrl->index = index;
|
|
sts = spS25NoJedecProbe (pDev);
|
|
SPI_FLASH_LOG (50, "%s NoJedecProbe OK \n", spiFlashList[index].name,
|
|
2, 3, 4, 5, 6);
|
|
}
|
|
|
|
if (sts == OK)
|
|
break;
|
|
|
|
/* Dynamic Probe via device-specific parameters retrieved from hwConf */
|
|
|
|
sts = spS25DynamicProbe(pDev);
|
|
SPI_FLASH_LOG (50, "DYNAMIC Probe %s \n",
|
|
(_Vx_usr_arg_t) ((sts == ERROR) ? "ERROR" : "OK"),
|
|
2, 3, 4, 5, 6);
|
|
}
|
|
while (FALSE);
|
|
|
|
if (sts == OK)
|
|
{
|
|
/* If the chipSize exceeds 128M bits, the addrWidth is 4 */
|
|
|
|
if (pDrvCtrl->chipSize > SPI_3B_MAX)
|
|
{
|
|
pDrvCtrl->addrWidth = 4;
|
|
enter4BMode (pDev, TRUE);
|
|
}
|
|
else
|
|
pDrvCtrl->addrWidth = 3;
|
|
}
|
|
|
|
return sts;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25spiFlashEnable - SPI flash enable routine
|
|
*
|
|
* This function can finish some initialize work used by mtd layer, it should be
|
|
* implemented in driver.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS spS25spiFlashEnable
|
|
(
|
|
VXB_DEVICE_ID pDev
|
|
)
|
|
{
|
|
/* Check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pDev != NULL, ERROR)
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25spiFlashReset - flash reset routine
|
|
*
|
|
* This function reset flash if needed used by mtd layer, it should be
|
|
* implemented in driver.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS spS25spiFlashReset
|
|
(
|
|
VXB_DEVICE_ID pDev
|
|
)
|
|
{
|
|
/* Check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pDev != NULL, ERROR)
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25SpiFlashInstInit2 - second level initialization routine of spi flash
|
|
*
|
|
* This function implements the VxBus instInit2 handler for a SPI Flash device
|
|
* instance. Once we reach this stage of initialization, it's safe for us to
|
|
* allocate semaphore, so we can create the mutex semaphore.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
|
|
LOCAL void spS25SpiFlashInstInit2
|
|
(
|
|
VXB_DEVICE_ID pDev
|
|
)
|
|
{
|
|
UINT8 jedecId[5];
|
|
FUNCPTR pFunc;
|
|
int bufSize;
|
|
SPI_FLASH_DEV * pDrvCtrl;
|
|
|
|
/* Check for vaild parameter */
|
|
|
|
VXB_ASSERT_NONNULL_V (pDev);
|
|
|
|
pDrvCtrl = (SPI_FLASH_DEV *) pDev->pDrvCtrl;
|
|
|
|
/* Mutex semaphore is initialized and necessary at this point */
|
|
|
|
pDrvCtrl->muteSem = semMCreate (SPIFLASH_MUTEX_OPT);
|
|
|
|
pFunc = vxbDevMethodGet (vxbDevParent(pDev),
|
|
(VXB_METHOD_ID) vxbSpiSpecialGet_desc);
|
|
|
|
/* Retrieve the SPI master special information */
|
|
|
|
if (pFunc != NULL)
|
|
(*pFunc) (vxbDevParent(pDev), &pDrvCtrl->specialInfo);
|
|
|
|
/*
|
|
* Note: the following code start to read or write the SPI flash, the low
|
|
* layer SPI controller should work well, otherwise the Systems maybe hang.
|
|
*/
|
|
|
|
/* Check if the controller done */
|
|
|
|
memset (jedecId, 0, 5);
|
|
|
|
JEDEC_ID_GET (pDev, jedecId, sizeof (jedecId));
|
|
|
|
SPI_FLASH_LOG (1000, "JEDEC Probeing......Device ID: 0x%02x 0x%04x 0x%04x\r\n",
|
|
jedecId[0], (jedecId[1] << 8 | jedecId[2]),
|
|
(jedecId[3] << 8 | jedecId[4]), 4, 5, 6);
|
|
|
|
pDrvCtrl->flash.manuId = jedecId[0];
|
|
pDrvCtrl->flash.devId = (jedecId[1] << 8 | jedecId[2]);
|
|
pDrvCtrl->flash.extId = (jedecId[3] << 8 | jedecId[4]);
|
|
|
|
if (spS25SpiFlashProbe (pDev, 0) == ERROR)
|
|
{
|
|
SPI_FLASH_LOG (0, "spS25SpiFlashProbe ERROR!\n", 1, 2, 3, 4, 5, 6);
|
|
pDrvCtrl->isProbeOk = FALSE;
|
|
return;
|
|
}
|
|
else
|
|
pDrvCtrl->isProbeOk = TRUE;
|
|
|
|
bufSize = MAX_CMD_SIZE + PageSize(pDrvCtrl);
|
|
|
|
pDrvCtrl->pWrBuf = (UINT8 *)malloc (bufSize);
|
|
|
|
if (pDrvCtrl->pWrBuf == NULL)
|
|
{
|
|
SPI_FLASH_LOG (0, "Malloc pWrBuf failed!\r\n", 1, 2, 3, 4, 5, 6);
|
|
return;
|
|
}
|
|
|
|
memset(pDrvCtrl->pWrBuf, 0, sizeof(bufSize));
|
|
|
|
/* Setup Flash information for FS used */
|
|
|
|
pDrvCtrl->mtd.pDev = (void *) pDev;
|
|
|
|
strncpy ((char *)pDrvCtrl->mtd.chipName, pDrvCtrl->type, MAX_DRV_NAME_LEN);
|
|
|
|
pDrvCtrl->mtd.uChipSize = pDrvCtrl->chipSize;
|
|
pDrvCtrl->mtd.uEraseSize = SectorSize (pDrvCtrl);
|
|
pDrvCtrl->mtd.uFlashType = FLASH_CHIP_TYPE_SPI;
|
|
|
|
pDrvCtrl->mtd.uCapability = FLASH_CHIP_CAP_RD |
|
|
FLASH_CHIP_CAP_WR |
|
|
FLASH_CHIP_CAP_BLKERA;
|
|
|
|
pDrvCtrl->mtd.flashOPs.ena = (void *) spS25spiFlashEnable;
|
|
pDrvCtrl->mtd.flashOPs.rst = (void *) spS25spiFlashReset;
|
|
|
|
if ((pDrvCtrl->specialInfo != NULL) &&
|
|
(pDrvCtrl->specialInfo->flag & SPI_TRANS_LIMIT))
|
|
pDrvCtrl->mtd.flashOPs.read = (void *) vxbFlashRead2;
|
|
else
|
|
pDrvCtrl->mtd.flashOPs.read = (void *) vxbFlashRead;
|
|
|
|
pDrvCtrl->mtd.flashOPs.write = (void *) vxbFlashWrite;
|
|
|
|
if (pDrvCtrl->flash.manuId == SST)
|
|
pDrvCtrl->mtd.flashOPs.write = (void *) vxbFlashSstWrite;
|
|
|
|
pDrvCtrl->mtd.flashOPs.blkErase = (void *) vxbFlashErase;
|
|
|
|
return;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25SpiFlashInstUnlink - VxBus unlink handler
|
|
*
|
|
* This function shuts down a SPI Flash device instance in response to an
|
|
* unlink event from VxBus. This may occur if our VxBus instance has been
|
|
* terminated, or if the driver has been unloaded.
|
|
*
|
|
* RETURNS: OK always.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS spS25SpiFlashInstUnlink
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
void * unused
|
|
)
|
|
{
|
|
SPI_FLASH_DEV * pDrvCtrl;
|
|
|
|
/* Check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pDev != NULL, ERROR)
|
|
|
|
pDrvCtrl = (SPI_FLASH_DEV *) pDev->pDrvCtrl;
|
|
|
|
/* Destroy the adapter context. */
|
|
|
|
if (pDrvCtrl->muteSem != NULL)
|
|
(void)semDelete (pDrvCtrl->muteSem);
|
|
|
|
#ifndef _VXBUS_BASIC_HWMEMLIB
|
|
hwMemFree ((char *) pDrvCtrl);
|
|
#endif /* _VXBUS_BASIC_HWMEMLIB */
|
|
|
|
pDev->pDrvCtrl = NULL;
|
|
|
|
/* Goodbye cruel world. */
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25spiFlashWrite - VxBus SPI device write by name support routine
|
|
*
|
|
* This routine firstly finds the VXB_DEVICE_ID for a given instance
|
|
* identified by name and unit number, then call vxbI2cDevWrite() routine to
|
|
* write the device.
|
|
*
|
|
* RETURNS: OK/ERROR
|
|
*
|
|
* ERRNO : N/A
|
|
*/
|
|
|
|
LOCAL STATUS spS25spiFlashWrite
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
UINT8 * txBuf,
|
|
UINT32 txLen,
|
|
UINT32 usDelay
|
|
)
|
|
{
|
|
/* Check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pDev != NULL, ERROR)
|
|
|
|
SPI_TRANSFER transInfo;
|
|
|
|
/* check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pDev != NULL, ERROR)
|
|
|
|
memset(&transInfo, 0, sizeof(SPI_TRANSFER));
|
|
|
|
transInfo.txBuf = txBuf;
|
|
transInfo.txLen = txLen;
|
|
transInfo.usDelay = usDelay;
|
|
|
|
return (vxbSpiTransfer (pDev, &transInfo));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25spiFlashRegRead - read register routine
|
|
*
|
|
* This is the SPI flash status /config register read out routine.
|
|
*
|
|
* RETURNS: status register value.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL INT32 spS25spiFlashRegRead
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
UINT8 cmd
|
|
)
|
|
{
|
|
UINT8 buffer;
|
|
SPI_TRANSFER transInfo;
|
|
|
|
/* check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pDev != NULL, ERROR)
|
|
|
|
memset(&transInfo, 0, sizeof(SPI_TRANSFER));
|
|
|
|
transInfo.txBuf = &cmd;
|
|
transInfo.txLen = sizeof (cmd);
|
|
transInfo.rxBuf = &buffer;
|
|
transInfo.rxLen = sizeof (buffer);
|
|
|
|
if (vxbSpiTransfer (pDev, &transInfo) != OK)
|
|
return ERROR;
|
|
else
|
|
return (buffer);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25spiFlashWaitReady - wait the status ready
|
|
*
|
|
* This routine reads the status register, according to the Write-In-Process bit
|
|
* to judge the transfer finished or not. If the status still didn't finish in
|
|
* timeout, return ERROR.
|
|
*
|
|
* RETURNS: OK or ERROR if there is an error.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS spS25spiFlashWaitReady
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
UINT32 timeout
|
|
)
|
|
{
|
|
/* Check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pDev != NULL, ERROR)
|
|
|
|
while (timeout--)
|
|
{
|
|
if ((spS25spiFlashRegRead (pDev, SPI_RDSR_CMD) & SR_WIP) == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
vxbUsDelay(1);
|
|
}
|
|
|
|
/* Timed out */
|
|
|
|
if (timeout == 0)
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25flxxspS25spiFlashWriteEnable - write enable
|
|
*
|
|
* The Write Enable (WREN) sets the Write Enable Latch (WEL) bit to a 1, which
|
|
* enables the device to accept a Write Status Register, program, or erase
|
|
* command. The WEL bit must be set prior to every Page Program (PP),
|
|
* Quad Page Program (QPP), Parameter Sector Erase (P4E, P8E), Erase(SE or BE),
|
|
* Write Registers (WRR) and OTP Program (OTPP) command
|
|
*
|
|
* RETURNS: OK or ERROR if there is an error.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS spS25spiFlashWriteEnable
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
UINT8 cmd
|
|
)
|
|
{
|
|
/* Check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pDev != NULL, ERROR)
|
|
|
|
/* Send the WREN command */
|
|
|
|
if (spS25spiFlashWrite (pDev, &cmd, sizeof (cmd), 0) != OK)
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
if (spS25spiFlashWaitReady (pDev, TIMEOUT) != OK)
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25spiFlashRegWrite - write register
|
|
*
|
|
* This is the SPI flash status register write routine.
|
|
*
|
|
* RETURNS: OK or ERROR if there is an error.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS spS25spiFlashRegWrite
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
UINT8 status
|
|
)
|
|
{
|
|
UINT8 cmd[2];
|
|
|
|
/* Check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pDev != NULL, ERROR)
|
|
|
|
memset(cmd, 0, 2);
|
|
|
|
/* Write enable is required */
|
|
|
|
if (spS25spiFlashWriteEnable (pDev, SPI_WREN_CMD) != OK)
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
cmd[0] = SPI_WRSR_CMD;
|
|
cmd[1] = status;
|
|
|
|
if (spS25spiFlashWrite (pDev, cmd, sizeof (cmd), 0) != OK)
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
if (spS25spiFlashWaitReady (pDev, TIMEOUT) != OK)
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25SpiFlashInstConnect - third level initialization routine of spi flash
|
|
*
|
|
* This function implements the VxBus instConnect handler for a SPI Flash
|
|
* device instance.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL void spS25SpiFlashInstConnect
|
|
(
|
|
VXB_DEVICE_ID pDev
|
|
)
|
|
{
|
|
SPI_FLASH_DEV * pDrvCtrl;
|
|
|
|
/* Check for vaild parameter */
|
|
|
|
VXB_ASSERT_NONNULL_V (pDev);
|
|
|
|
pDrvCtrl = (SPI_FLASH_DEV *) pDev->pDrvCtrl;
|
|
|
|
switch (pDrvCtrl->flash.manuId)
|
|
{
|
|
/*
|
|
* For SST chips, the default value of the SR is 0x1c, which means the
|
|
* block protect enabled. So clear it before any operation.
|
|
*/
|
|
|
|
case SST:
|
|
spS25spiFlashRegWrite (pDev, 0x0);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* enter4BMode - eEnable/disable 4-byte addressing mode
|
|
*
|
|
* The EN4B instruction enables accessing the address length of 32-bit for the
|
|
* memory area of higher density (larger than 128Mb). The device default is in
|
|
* 24-bit address mode; after sending out the EN4B instruction, the bit2
|
|
* (4BTYE bit) of security register will be automatically set to "1" to indicate
|
|
* the 4-byte address mode has been enabled. Once the 4-byte address mode is
|
|
* enabled, the address length becomes 32-bit instead of the default 24-bit.
|
|
* There are three methods to exit the 4-byte mode: writing exit 4-byte mode
|
|
* (EX4B) instruction, Hardware Reset or power-off.
|
|
*
|
|
* RETURNS: OK or ERROR if there is an error.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS enter4BMode
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
int enable
|
|
)
|
|
{
|
|
SPI_FLASH_DEV * pDrvCtrl;
|
|
UINT8 cmd[MAX_CMD_SIZE];
|
|
|
|
/* Check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pDev != NULL, ERROR)
|
|
|
|
pDrvCtrl = (SPI_FLASH_DEV *) pDev->pDrvCtrl;
|
|
|
|
/* Clear the cmd buffer */
|
|
|
|
memset (cmd, 0, MAX_CMD_SIZE);
|
|
|
|
switch (pDrvCtrl->flash.manuId)
|
|
{
|
|
/* sending EN4B instruction to enter 4-byte mode */
|
|
|
|
case MICRO:
|
|
/* Write enable */
|
|
if (spS25spiFlashWriteEnable (pDev, SPI_WREN_CMD) == OK)
|
|
break;
|
|
else
|
|
return ERROR;
|
|
case GIGADEVICE:
|
|
case MXIC:
|
|
case EON:
|
|
case WINBOND:
|
|
break;
|
|
|
|
case SPANSION:
|
|
if(pDrvCtrl->flash.devId != 0x0219)
|
|
{
|
|
cmd[0] = SPI_WBNK_CMD; /* Bank register write */
|
|
cmd[1] = enable << 7;
|
|
return spS25spiFlashWrite (pDev, cmd, 2, 0);
|
|
}
|
|
break;
|
|
default:
|
|
return ERROR;
|
|
}
|
|
|
|
cmd[0] = enable ? SPI_EN4B_CMD : SPI_EX4B_CMD;
|
|
|
|
return (spS25spiFlashWrite (pDev, cmd, 1, 0));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25spiFlashChipErase - chip erase
|
|
*
|
|
* This is the chip erase routine. The Bulk Erase (BE) command sets
|
|
* all the bits within the entire memory array to logic 1. A WREN
|
|
* command is required prior to writing the BE command.
|
|
*
|
|
* RETURNS: OK or ERROR if there is an error.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS spS25spiFlashChipErase
|
|
(
|
|
VXB_DEVICE_ID pDev
|
|
)
|
|
{
|
|
UINT8 status = 0;
|
|
UINT32 count = 0;
|
|
UINT8 cmd = SPI_BE_CMD;
|
|
UINT32 timeout = 0x1000;
|
|
|
|
/* Check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pDev != NULL, ERROR)
|
|
|
|
/* Check whether the status is right */
|
|
|
|
while (timeout--)
|
|
{
|
|
if ((spS25spiFlashRegRead (pDev, SPI_RDSR_CMD) & SR_SRWD) == 0)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* try to recover the status if needed. Here 0x0 for Spansion
|
|
* SPI flash, please note the value differ from device to device.
|
|
*/
|
|
|
|
spS25spiFlashRegWrite (pDev, 0x0);
|
|
|
|
SPI_FLASH_LOG (10, "Flash status(0x%x) wrong, try to recover..\r\n",
|
|
spS25spiFlashRegRead (pDev, SPI_RDSR_CMD),
|
|
2, 3, 4, 5, 6);
|
|
}
|
|
};
|
|
|
|
/* Write enable */
|
|
|
|
if (spS25spiFlashWriteEnable (pDev, SPI_WREN_CMD) != OK)
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
if (spS25spiFlashWrite (pDev, &cmd, sizeof (cmd), 0) != OK)
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
do
|
|
{
|
|
/* Read the status register */
|
|
|
|
status = spS25spiFlashRegRead (pDev, SPI_RDSR_CMD);
|
|
|
|
SPI_FLASH_LOG (10, "BulkErase: %d s, Status: 0x%x(%s) \r", count, status,
|
|
(_Vx_usr_arg_t) ((status & SR_WIP)?"Busy" : "Idle"),
|
|
0, 0, 0);
|
|
|
|
/* Delay 1 second */
|
|
|
|
taskDelay (sysClkRateGet ());
|
|
|
|
/* Write in progress */
|
|
|
|
if ((status & SR_WIP) == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
count++;
|
|
}
|
|
while (count < (TIMEOUT / 10000));
|
|
|
|
/* Timeout */
|
|
|
|
if (count >= (TIMEOUT / 10000))
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25spiFlashSectorErase - sector erase
|
|
*
|
|
* This is the sector erase routine. The Sector Erase (SE) command sets
|
|
* all bits at all addresses within a specified sector to a logic 1.
|
|
* A WREN command is required prior to writing the SE command.
|
|
*
|
|
* RETURNS: OK or ERROR if there is an error.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS spS25spiFlashSectorErase
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
UINT32 startAddr,
|
|
UINT32 numOfErasableBlocks
|
|
)
|
|
{
|
|
SPI_FLASH_DEV * pDrvCtrl;
|
|
UINT8 cmd[MAX_CMD_SIZE];
|
|
UINT32 offset = 0;
|
|
UINT32 timeout = 0x100;
|
|
UINT32 i = 0;
|
|
STATUS sts = OK;
|
|
|
|
/* Check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pDev != NULL, ERROR)
|
|
|
|
pDrvCtrl = (SPI_FLASH_DEV *) pDev->pDrvCtrl;
|
|
|
|
SPI_FLASH_LOG (500, "Erase %d unit from %d unit\r\n", numOfErasableBlocks,
|
|
startAddr/SectorSize (pDrvCtrl), 3, 4, 5, 6);
|
|
|
|
/* Sanity checks */
|
|
|
|
if (startAddr + numOfErasableBlocks * SectorSize (pDrvCtrl) > ChipSize(pDrvCtrl))
|
|
{
|
|
SPI_FLASH_LOG (0, "Erase exceed range. \r\n", 1, 2, 3, 4, 5, 6);
|
|
return ERROR;
|
|
}
|
|
|
|
if (numOfErasableBlocks == 0)
|
|
return ERROR;
|
|
|
|
/* Mutex semaphore */
|
|
|
|
if (SPIFLASH_LOCK(pDrvCtrl->muteSem) != OK)
|
|
return (ERROR);
|
|
|
|
/* Whole chip erase */
|
|
|
|
if ((startAddr == 0) && (numOfErasableBlocks == SectorNum (pDrvCtrl)))
|
|
{
|
|
if (spS25spiFlashChipErase (pDev) != OK)
|
|
{
|
|
SPI_FLASH_LOG (10, "ChipErase failed, try to sector erase\r\n",
|
|
1, 2, 3, 4, 5, 6);
|
|
}
|
|
else
|
|
{
|
|
/* Release semaphore */
|
|
|
|
if (SPIFLASH_UNLOCK (pDrvCtrl->muteSem) != OK)
|
|
return ERROR;
|
|
|
|
return OK;
|
|
}
|
|
}
|
|
|
|
/* Clear the cmd buffer */
|
|
|
|
memset (cmd, 0, MAX_CMD_SIZE);
|
|
|
|
/* Check whether the status is right */
|
|
|
|
for (i = 0; i < numOfErasableBlocks; i++)
|
|
{
|
|
while (timeout--)
|
|
{
|
|
if ((spS25spiFlashRegRead (pDev, SPI_RDSR_CMD) & SR_SRWD) == 0)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Try to recover the status if needed. Here 0x0 for Spansion
|
|
* SPI flash, note the value differ from device to device.
|
|
*/
|
|
|
|
spS25spiFlashRegWrite (pDev, 0);
|
|
|
|
SPI_FLASH_LOG (10, "Flash status(0x%x) wrong, try to recover\r\n",
|
|
spS25spiFlashRegRead (pDev, SPI_RDSR_CMD),
|
|
2, 3, 4, 5, 6);
|
|
}
|
|
};
|
|
|
|
/* set erase command */
|
|
|
|
cmd[0] = SPI_SE_CMD;
|
|
cmd[1] = (UINT8) (startAddr >> (pDrvCtrl->addrWidth * 8 - 8));
|
|
cmd[2] = (UINT8) (startAddr >> (pDrvCtrl->addrWidth * 8 - 16));
|
|
cmd[3] = (UINT8) (startAddr >> (pDrvCtrl->addrWidth * 8 - 24));
|
|
|
|
if (pDrvCtrl->addrWidth == 4)
|
|
{
|
|
cmd[4] = (UINT8) (offset);
|
|
}
|
|
|
|
/* Write enable */
|
|
|
|
if (spS25spiFlashWriteEnable (pDev, SPI_WREN_CMD) != OK)
|
|
{
|
|
sts = ERROR;
|
|
break;
|
|
}
|
|
|
|
/* Send the SE command */
|
|
|
|
if (spS25spiFlashWrite (pDev, cmd, (pDrvCtrl->addrWidth + 1), 0) != OK)
|
|
{
|
|
sts = ERROR;
|
|
break;
|
|
}
|
|
|
|
/* wait until the device is not busy */
|
|
|
|
if (spS25spiFlashWaitReady (pDev, TIMEOUT) != OK)
|
|
{
|
|
sts = ERROR;
|
|
break;
|
|
}
|
|
|
|
SPI_FLASH_LOG (100, "Formatted %d of %d sectors = %d.%01d %%\r",
|
|
(i + 1),
|
|
numOfErasableBlocks,
|
|
100 * (i + 1) / numOfErasableBlocks,
|
|
1000 * (i + 1) / numOfErasableBlocks % 10, 5, 6);
|
|
|
|
startAddr += SectorSize (pDrvCtrl);
|
|
}
|
|
|
|
/* Release semaphore */
|
|
|
|
if (SPIFLASH_UNLOCK (pDrvCtrl->muteSem) != OK)
|
|
{
|
|
sts = ERROR;
|
|
}
|
|
|
|
return sts;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25spiFlashProgram - SPI flash program
|
|
*
|
|
* This is the SPI flash page program routine.
|
|
*
|
|
* RETURNS: OK or ERROR if there is an error.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS spS25spiFlashProgram
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
UINT32 startAddr,
|
|
UINT32 len,
|
|
UINT8 * buf
|
|
)
|
|
{
|
|
SPI_FLASH_DEV * pDrvCtrl;
|
|
UINT32 dataLen = 0;
|
|
UINT32 offset = 0;
|
|
STATUS rc = ERROR;
|
|
UINT8 * pWrBuf;
|
|
|
|
/* Check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pDev != NULL, ERROR)
|
|
|
|
pDrvCtrl = (SPI_FLASH_DEV *) pDev->pDrvCtrl;
|
|
|
|
/* Make sure that we do not exceed address range */
|
|
|
|
if ((startAddr >= pDrvCtrl->chipSize) || (len == 0) ||
|
|
((startAddr + len) > pDrvCtrl->chipSize))
|
|
return rc;
|
|
|
|
/* Mutex semaphore */
|
|
|
|
if (SPIFLASH_LOCK(pDrvCtrl->muteSem) != OK)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
|
|
do
|
|
{
|
|
pWrBuf = pDrvCtrl->pWrBuf;
|
|
|
|
/* Data must be written in "page Size" chunks */
|
|
|
|
while (offset < len)
|
|
{
|
|
/* Compute the number of data ready to write for one write cycle */
|
|
|
|
dataLen = min (len - offset, PageSize(pDrvCtrl) -
|
|
((startAddr + offset) % PageSize(pDrvCtrl)));
|
|
|
|
/* Set page program command */
|
|
|
|
pWrBuf[0] = SPI_PP_CMD;
|
|
pWrBuf[1] = (UINT8)((offset + startAddr) >> (pDrvCtrl->addrWidth * 8 - 8));
|
|
pWrBuf[2] = (UINT8)((offset + startAddr) >> (pDrvCtrl->addrWidth * 8 - 16));
|
|
pWrBuf[3] = (UINT8)((offset + startAddr) >> (pDrvCtrl->addrWidth * 8 - 24));
|
|
|
|
if (pDrvCtrl->addrWidth == 4)
|
|
pWrBuf[4] = (UINT8)(offset + startAddr);
|
|
|
|
memcpy ((void*)(pWrBuf + (pDrvCtrl->addrWidth + 1)),
|
|
(void*)(buf + offset), dataLen);
|
|
|
|
if (spS25spiFlashWriteEnable (pDev, SPI_WREN_CMD) != OK)
|
|
break;
|
|
|
|
/* Program one page */
|
|
|
|
if (spS25spiFlashWrite (pDev, pWrBuf,
|
|
(dataLen + pDrvCtrl->addrWidth + 1),
|
|
pDrvCtrl->ppTime) != OK)
|
|
break;
|
|
|
|
if (spS25spiFlashWaitReady (pDev, TIMEOUT) != OK)
|
|
break;
|
|
|
|
memset ((void *)pWrBuf, 0,
|
|
sizeof(PageSize(pDrvCtrl)) + pDrvCtrl->addrWidth);
|
|
|
|
offset += dataLen;
|
|
}
|
|
|
|
rc = OK;
|
|
|
|
}while(FALSE);
|
|
|
|
/* Release resources */
|
|
|
|
if (SPIFLASH_UNLOCK (pDrvCtrl->muteSem) != OK)
|
|
{
|
|
rc = ERROR;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* write1Byte - Write one byte to SPI flash
|
|
*
|
|
* This routine writes one byte data to SPI flash.
|
|
*
|
|
* RETURNS: OK or ERROR if there is an error.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS write1Byte
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
UINT32 addr,
|
|
UINT8 data
|
|
)
|
|
{
|
|
UINT8 cmd[MAX_CMD_SIZE];
|
|
|
|
memset(cmd, 0, sizeof(cmd));
|
|
|
|
cmd[0] = SPI_PP_CMD;
|
|
cmd[1] = addr >> 16;
|
|
cmd[2] = addr >> 8;
|
|
cmd[3] = addr;
|
|
cmd[4] = data;
|
|
|
|
if (spS25spiFlashWriteEnable (pDev, SPI_WREN_CMD) != OK)
|
|
return ERROR;
|
|
|
|
/* Program one byte */
|
|
|
|
if (spS25spiFlashWrite (pDev, cmd, MAX_CMD_SIZE, 0) != OK)
|
|
return ERROR;
|
|
|
|
if (spS25spiFlashWaitReady (pDev, TIMEOUT) != OK)
|
|
return ERROR;
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* sst25AAIProgram - SST SPI flash auto address increment word-program
|
|
*
|
|
* This is the SST SPI flash auto address increment(AAI) word-program routine.
|
|
* The AAI program instruction allows multiple bytes of data to be programmed
|
|
* without re-issuing the next sequential address location. Note: The first byte
|
|
* of data (D0) is programmed into the initial address [A23-A1] with A0=0, the
|
|
* second byte of Data (D1) is programmed into the initial address [A23-A1]
|
|
* with A0=1.
|
|
*
|
|
* RETURNS: OK or ERROR if there is an error.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS sst25AAIProgram
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
UINT32 startAddr,
|
|
UINT32 len,
|
|
UINT8 * buf
|
|
)
|
|
{
|
|
SPI_FLASH_DEV * pDrvCtrl;
|
|
UINT32 offset = 0;
|
|
STATUS rc = ERROR;
|
|
UINT8 cmd[6];
|
|
UINT32 actual = startAddr % 2;
|
|
UINT32 i =0;
|
|
|
|
/* Check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pDev != NULL, ERROR)
|
|
|
|
pDrvCtrl = (SPI_FLASH_DEV *) pDev->pDrvCtrl;
|
|
|
|
/* Make sure that we do not exceed address range */
|
|
|
|
if ((startAddr >= pDrvCtrl->chipSize) || (len == 0) ||
|
|
((startAddr + len) > pDrvCtrl->chipSize))
|
|
return rc;
|
|
|
|
/* Mutex semaphore */
|
|
|
|
if (SPIFLASH_LOCK(pDrvCtrl->muteSem) != OK)
|
|
return rc;
|
|
|
|
do
|
|
{
|
|
if ((len == 1) || (len == 2))
|
|
{
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
if (write1Byte (pDev, (startAddr + i), buf[i]) != OK)
|
|
break;
|
|
}
|
|
|
|
rc = OK;
|
|
break;
|
|
}
|
|
|
|
/* Start write from odd address. */
|
|
|
|
if (actual)
|
|
{
|
|
if (write1Byte (pDev, startAddr, buf[0]) != OK)
|
|
break;
|
|
}
|
|
|
|
/* Write the remaining bytes using auto address increment mode */
|
|
|
|
cmd[0] = SST_AAI_WORD_CMD;
|
|
cmd[1] = (startAddr + actual) >> 16;
|
|
cmd[2] = (startAddr + actual) >> 8;
|
|
cmd[3] = (startAddr + actual);
|
|
cmd[4] = buf[actual];
|
|
cmd[5] = buf[actual + 1];
|
|
|
|
if (spS25spiFlashWriteEnable (pDev, SPI_WREN_CMD) != OK)
|
|
break;
|
|
|
|
if (spS25spiFlashWrite (pDev, cmd, sizeof(cmd), 2) != OK)
|
|
break;
|
|
|
|
if (spS25spiFlashWaitReady (pDev, TIMEOUT) != OK)
|
|
break;
|
|
|
|
offset = (2 + actual);
|
|
|
|
for (i = 0; i < (len - 2 - actual) / 2; i++, offset += 2)
|
|
{
|
|
cmd[1] = buf[offset];
|
|
cmd[2] = buf[offset + 1];
|
|
|
|
if (spS25spiFlashWrite (pDev, cmd, 3, 2) != OK)
|
|
break;
|
|
|
|
if (spS25spiFlashWaitReady (pDev, TIMEOUT) != OK)
|
|
break;
|
|
}
|
|
|
|
/* Quit AAI */
|
|
|
|
if (spS25spiFlashWriteEnable (pDev, SPI_WRDI_CMD) != OK)
|
|
break;
|
|
|
|
if (offset != len)
|
|
{
|
|
SPI_FLASH_LOG (10000, "Write the last data %d @ addr %d\r\n",
|
|
buf[len - 1], (offset + startAddr),
|
|
3, 4, 5, 6);
|
|
|
|
if (write1Byte (pDev, (offset + startAddr), buf[len - 1]) != OK)
|
|
break;
|
|
}
|
|
|
|
rc = OK;
|
|
|
|
}while(FALSE);
|
|
|
|
SPI_FLASH_LOG (100000, "Write Done! Status = 0x%x \r\n",
|
|
spS25spiFlashRegRead (pDev, SPI_RDSR_CMD),
|
|
2, 3, 4, 5, 6);
|
|
|
|
/* Release resources */
|
|
|
|
if (SPIFLASH_UNLOCK (pDrvCtrl->muteSem) != OK)
|
|
{
|
|
rc = ERROR;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25spiFlashRead - read SPI flash data
|
|
*
|
|
* This is the SPI flash data read out routine.
|
|
*
|
|
* RETURNS: OK or ERROR if there is an error.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS spS25spiFlashRead
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
UINT32 startAddr,
|
|
UINT32 dataLen,
|
|
UINT8 * dest
|
|
)
|
|
{
|
|
SPI_FLASH_DEV * pDrvCtrl;
|
|
UINT8 cmd[MAX_CMD_SIZE];
|
|
SPI_TRANSFER transInfo;
|
|
|
|
/* check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pDev != NULL, ERROR)
|
|
|
|
pDrvCtrl = (SPI_FLASH_DEV *) pDev->pDrvCtrl;
|
|
|
|
if ((startAddr >= pDrvCtrl->chipSize) || (dataLen == 0) ||
|
|
((startAddr + dataLen) > pDrvCtrl->chipSize))
|
|
return ERROR;
|
|
|
|
memset (cmd, 0, MAX_CMD_SIZE);
|
|
memset (&transInfo, 0, sizeof(SPI_TRANSFER));
|
|
|
|
/* Set read command */
|
|
|
|
cmd[0] = SPI_READ_OPCODE;
|
|
cmd[1] = (UINT8) (startAddr >> (pDrvCtrl->addrWidth * 8 - 8));
|
|
cmd[2] = (UINT8) (startAddr >> (pDrvCtrl->addrWidth * 8 - 16));
|
|
cmd[3] = (UINT8) (startAddr >> (pDrvCtrl->addrWidth * 8 - 24));
|
|
|
|
if (pDrvCtrl->addrWidth == 4)
|
|
cmd[4] = (UINT8)startAddr;
|
|
|
|
/* Mutex semaphore */
|
|
|
|
if (SPIFLASH_LOCK(pDrvCtrl->muteSem) != OK)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
|
|
transInfo.txBuf = cmd;
|
|
transInfo.txLen = READ_CMD_BYTE;
|
|
transInfo.rxBuf = dest;
|
|
transInfo.rxLen = dataLen;
|
|
|
|
SPI_FLASH_LOG (10000, "READ len[0x%x] from 0x%x to buf 0x%x, "
|
|
"READ cmd: 0x%x cmdLen %d\r\n",
|
|
transInfo.rxLen, startAddr, transInfo.rxBuf,
|
|
*(UINT32*)transInfo.txBuf, transInfo.txLen, 6);
|
|
|
|
if (vxbSpiTransfer (pDev, &transInfo) != OK)
|
|
{
|
|
(void)SPIFLASH_UNLOCK (pDrvCtrl->muteSem);
|
|
return ERROR;
|
|
}
|
|
|
|
/* Release resources */
|
|
|
|
if (SPIFLASH_UNLOCK (pDrvCtrl->muteSem) != OK)
|
|
return ERROR;
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25spiFlashRead2 - read SPI flash data by window size
|
|
*
|
|
* Some controller has transaction length limitation such as the Freescale's
|
|
* eSPI controller can only trasmit 0xFFFF bytes one time, so we have to read
|
|
* (0xFFFF) by "window" if the len is more than the limitation.
|
|
*
|
|
* RETURNS: OK or ERROR if there is an error.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS spS25spiFlashRead2
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
UINT32 startAddr,
|
|
UINT32 dataLen,
|
|
UINT8 * dest
|
|
)
|
|
{
|
|
SPI_FLASH_DEV * pDrvCtrl;
|
|
UINT8 cmd[MAX_CMD_SIZE];
|
|
SPI_TRANSFER transInfo;
|
|
UINT32 loop =0;
|
|
UINT32 count = 0;
|
|
UINT32 bytesToRead = 0;
|
|
UINT32 max_transLen = 0;
|
|
|
|
/* check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pDev != NULL, ERROR)
|
|
pDrvCtrl = (SPI_FLASH_DEV *) pDev->pDrvCtrl;
|
|
|
|
if ((startAddr >= pDrvCtrl->chipSize) || (dataLen == 0) ||
|
|
((startAddr + dataLen) > pDrvCtrl->chipSize))
|
|
return ERROR;
|
|
|
|
memset (cmd, 0, MAX_CMD_SIZE);
|
|
memset (&transInfo, 0, sizeof(SPI_TRANSFER));
|
|
|
|
max_transLen = pDrvCtrl->specialInfo->windowSize;
|
|
|
|
loop = (dataLen + READ_CMD_BYTE + startAddr) / max_transLen +
|
|
((dataLen + READ_CMD_BYTE + startAddr) % max_transLen ? 1 : 0);
|
|
|
|
/* Mutex semaphore */
|
|
|
|
if (SPIFLASH_LOCK(pDrvCtrl->muteSem) != OK)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
|
|
do
|
|
{
|
|
/* Set read command */
|
|
|
|
cmd[0] = SPI_READ_OPCODE;
|
|
cmd[1] = (UINT8) (startAddr >> (pDrvCtrl->addrWidth * 8 - 8));
|
|
cmd[2] = (UINT8) (startAddr >> (pDrvCtrl->addrWidth * 8 - 16));
|
|
cmd[3] = (UINT8) (startAddr >> (pDrvCtrl->addrWidth * 8 - 24));
|
|
|
|
if (pDrvCtrl->addrWidth == 4)
|
|
cmd[4] = (UINT8)startAddr;
|
|
|
|
/* Caculate transaction length in a frame */
|
|
|
|
bytesToRead = min (dataLen, max_transLen - READ_CMD_BYTE);
|
|
|
|
transInfo.txBuf = cmd;
|
|
transInfo.txLen = READ_CMD_BYTE;
|
|
transInfo.rxBuf = dest;
|
|
transInfo.rxLen = bytesToRead;
|
|
|
|
SPI_FLASH_LOG (10000, "%d times READ len[0x%x] from 0x%x to buf 0x%x, "
|
|
"READ cmd: 0x%x cmdLen %d\r\n",
|
|
count, transInfo.rxLen, startAddr, transInfo.rxBuf,
|
|
*(UINT32*)transInfo.txBuf, transInfo.txLen);
|
|
|
|
if (vxbSpiTransfer (pDev, &transInfo) != OK)
|
|
{
|
|
(void)SPIFLASH_UNLOCK (pDrvCtrl->muteSem);
|
|
return ERROR;
|
|
}
|
|
|
|
startAddr = startAddr + bytesToRead;
|
|
dest += bytesToRead;
|
|
dataLen -= bytesToRead;
|
|
|
|
count++;
|
|
|
|
} while(count < loop);
|
|
|
|
/* Release resources */
|
|
|
|
if (SPIFLASH_UNLOCK (pDrvCtrl->muteSem) != OK)
|
|
return ERROR;
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbFlashRead - read data from Flash chip
|
|
*
|
|
* This routine reads the data from the Flash chip used by upper(MTD) layer.
|
|
*
|
|
* RETURNS: OK or ERROR if NULL buffer pointer, or out of Flash chip.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL int vxbFlashRead
|
|
(
|
|
FLASH_CHIP_ID pFlashChip,
|
|
FLASH_ADDR_T uAddr, /* offset to Flash */
|
|
UINT32 uBufCount, /* buffer count */
|
|
FLASH_SIZE_T uBufLen, /* length for every buffer */
|
|
UINT8 ** ppBuf, /* pointer to buffer array */
|
|
void * op /* opinion */
|
|
)
|
|
{
|
|
/* check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pFlashChip->pDev != NULL, ERROR);
|
|
|
|
if ((ppBuf == NULL) || (ppBuf[0] == NULL))
|
|
{
|
|
SPI_FLASH_LOG (0, "NULL buffer pointer %d\n", 0, 0, 0, 0, 0, 0);
|
|
return (ERROR);
|
|
}
|
|
|
|
return (spS25spiFlashRead (pFlashChip->pDev, (UINT32)uAddr, (UINT32)uBufLen, ppBuf[0]));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbFlashRead2 - read data from Flash chip
|
|
*
|
|
* This routine reads the data from the Flash chip used by upper(MTD) layer.
|
|
*
|
|
* RETURNS: OK or ERROR if NULL buffer pointer, or out of Flash chip.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL int vxbFlashRead2
|
|
(
|
|
FLASH_CHIP_ID pFlashChip,
|
|
FLASH_ADDR_T uAddr, /* offset to Flash */
|
|
UINT32 uBufCount, /* buffer count */
|
|
FLASH_SIZE_T uBufLen, /* length for every buffer */
|
|
UINT8 ** ppBuf, /* pointer to buffer array */
|
|
void * op /* opinion */
|
|
)
|
|
{
|
|
/* check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pFlashChip->pDev != NULL, ERROR);
|
|
|
|
if ((ppBuf == NULL) || (ppBuf[0] == NULL))
|
|
{
|
|
SPI_FLASH_LOG (0, "NULL buffer pointer %d\n", 0, 0, 0, 0, 0, 0);
|
|
return (ERROR);
|
|
}
|
|
|
|
return (spS25spiFlashRead2 (pFlashChip->pDev, (UINT32)uAddr, (UINT32)uBufLen, ppBuf[0]));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbFlashWrite - write data to Flash chip
|
|
*
|
|
* This routine writes the data from the Flash chip used by upper(MTD) layer.
|
|
*
|
|
* RETURNS: OK or ERROR.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL int vxbFlashWrite
|
|
(
|
|
FLASH_CHIP_ID pFlashChip,
|
|
FLASH_ADDR_T uAddr, /* offset to Flash */
|
|
UINT32 uBufCount, /* buffer count */
|
|
FLASH_SIZE_T uBufLen, /* length for every buffer */
|
|
UINT8 ** ppBuf, /* pointer to buffer array */
|
|
void * op /* opinion */
|
|
)
|
|
{
|
|
/* check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pFlashChip->pDev != NULL, ERROR);
|
|
|
|
if ((ppBuf == NULL) || (ppBuf[0] == NULL))
|
|
{
|
|
SPI_FLASH_LOG (0, "NULL buffer pointer %d\n", 0, 0, 0, 0, 0, 0);
|
|
return (ERROR);
|
|
}
|
|
|
|
return (spS25spiFlashProgram (pFlashChip->pDev, (UINT32)uAddr, (UINT32)uBufLen, ppBuf[0]));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbFlashSstWrite - write data to SST Flash chip
|
|
*
|
|
* This routine writes the data from the SST Flash chip used by upper(MTD) layer.
|
|
*
|
|
* RETURNS: OK or ERROR.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL int vxbFlashSstWrite
|
|
(
|
|
FLASH_CHIP_ID pFlashChip,
|
|
FLASH_ADDR_T uAddr, /* offset to Flash */
|
|
UINT32 uBufCount, /* buffer count */
|
|
FLASH_SIZE_T uBufLen, /* length for every buffer */
|
|
UINT8 ** ppBuf, /* pointer to buffer array */
|
|
void * op /* opinion */
|
|
)
|
|
{
|
|
/* check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pFlashChip->pDev != NULL, ERROR);
|
|
|
|
if ((ppBuf == NULL) || (ppBuf[0] == NULL))
|
|
{
|
|
SPI_FLASH_LOG (0, "NULL buffer pointer %d\n", 0, 0, 0, 0, 0, 0);
|
|
return (ERROR);
|
|
}
|
|
|
|
return (sst25AAIProgram (pFlashChip->pDev, (UINT32)uAddr, (UINT32)uBufLen, ppBuf[0]));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbFlashErase - erase blocks
|
|
*
|
|
* This routine erases the blocks of the Flash chip used by upper(MTD) layer.
|
|
*
|
|
* RETURNS: OK or ERROR.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL int vxbFlashErase
|
|
(
|
|
FLASH_CHIP_ID pFlashChip,
|
|
FLASH_ADDR_T uBlkAdrs, /* block address */
|
|
UINT32 uBlks /* block number */
|
|
)
|
|
{
|
|
/* check if the pDev pointer is valid */
|
|
|
|
VXB_ASSERT (pFlashChip->pDev != NULL, ERROR);
|
|
|
|
return (spS25spiFlashSectorErase (pFlashChip->pDev, (UINT32)uBlkAdrs, uBlks));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* spS25spiFlashShow - show the SPI flash info.
|
|
*
|
|
* This routine show the SPI flash info by vxBusShow.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL void spS25spiFlashShow
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
int verbose
|
|
)
|
|
{
|
|
SPI_FLASH_DEV * pDrvCtrl;
|
|
|
|
/* Check for vaild parameter */
|
|
|
|
VXB_ASSERT_NONNULL_V (pDev);
|
|
|
|
pDrvCtrl = (SPI_FLASH_DEV *) pDev->pDrvCtrl;
|
|
|
|
printf (" %s unit %d on %s @ 0x%08x",
|
|
pDev->pName,
|
|
pDev->unitNumber,
|
|
vxbBusTypeString (pDev->busID),
|
|
pDev);
|
|
printf (" with busInfo %p\n", pDev->u.pSubordinateBus);
|
|
|
|
if (verbose >= 1)
|
|
{
|
|
printf(" BAR0 @ 0x%08x (memory mapped)\n", pDev->pRegBase[0]);
|
|
printf(" pDrvCtrl @ 0x%08x\n", pDev->pDrvCtrl);
|
|
}
|
|
|
|
if (verbose >= 100)
|
|
{
|
|
printf (" ManufacturerID:0x%02x\n", pDrvCtrl->flash.manuId);
|
|
printf (" Device ID: 0x%04x \n", pDrvCtrl->flash.devId);
|
|
printf (" Extend ID: 0x%04x \n", pDrvCtrl->flash.extId);
|
|
}
|
|
|
|
/* continue probe if failed */
|
|
|
|
pDrvCtrl->isProbeOk = (spS25SpiFlashProbe(pDev, verbose) == OK) ? (TRUE) : (FALSE);
|
|
|
|
if (verbose >= 100)
|
|
{
|
|
printf (" Probe: %s \r\n",
|
|
(TRUE == pDrvCtrl->isProbeOk) ? "[OK]":"[FAIL]");
|
|
|
|
if (pDrvCtrl->isProbeOk)
|
|
{
|
|
printf (" Type: %s - %s\n",
|
|
vendorGet(pDrvCtrl->flash.manuId), pDrvCtrl->type);
|
|
printf (" PageSize: %dB \r\n", PageSize(pDrvCtrl));
|
|
printf (" SectorSize: %dKB\r\n",
|
|
SectorSize(pDrvCtrl) >> 10);
|
|
if (pDrvCtrl->chipSize >> 20)
|
|
printf (" ChipSize: %dMB\r\n",
|
|
pDrvCtrl->chipSize >> 20);
|
|
else
|
|
printf (" ChipSize: %dKB\r\n",
|
|
pDrvCtrl->chipSize >> 10);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* cfiShow - show Flash driver deatiled information
|
|
*
|
|
* This routine prints the Flash driver CFI deatiled information.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL void cfiShow
|
|
(
|
|
struct cfi_ident * cfi,
|
|
int verbose
|
|
)
|
|
{
|
|
int i;
|
|
|
|
if (verbose >= 10000)
|
|
{
|
|
printf(" CFI Information Show: \r\n");
|
|
|
|
if (cfi->qryStr[0] != 'Q' || cfi->qryStr[1] != 'R' || cfi->qryStr[2] != 'Y')
|
|
{
|
|
printf (" Invalid CFI ident structure.\n");
|
|
return;
|
|
}
|
|
|
|
printf (" Primary OEM Command Set: %4.4X \n",
|
|
cfi->priCmdSet);
|
|
|
|
if (cfi->priExtTblAdrs)
|
|
{
|
|
printf (" Address for Primary Extended Table at %4.4Xh\n",
|
|
cfi->priExtTblAdrs);
|
|
}
|
|
else
|
|
{
|
|
printf (" No Primary Extended Table\n");
|
|
}
|
|
|
|
printf (" Alternate OEM Command Set: %4.4X (%s)\n",
|
|
cfi->altCmdSet, vendorGet(cfi->altCmdSet));
|
|
|
|
if (cfi->altExtTblAdrs)
|
|
{
|
|
printf (" Address for Alternate OEM Extended Table at "
|
|
"%4.4Xh\n", cfi->altExtTblAdrs);
|
|
}
|
|
else
|
|
{
|
|
printf (" No Alternate Extended Table\n");
|
|
}
|
|
|
|
printf (" Vcc Min: %2d.%d V\n",
|
|
cfi->vccMin >> 4, cfi->vccMin & 0xf);
|
|
printf (" Vcc Max: %2d.%d V\n",
|
|
cfi->vccMax >> 4, cfi->vccMax & 0xf);
|
|
|
|
if (cfi->vppMin)
|
|
{
|
|
printf (" Vpp Min: %2d.%d V\n",
|
|
cfi->vppMin >> 4, cfi->vppMin & 0xf);
|
|
printf (" Vpp Max: %2d.%d V\n",
|
|
cfi->vppMax >> 4, cfi->vppMax & 0xf);
|
|
}
|
|
else
|
|
{
|
|
printf (" No Vpp line\n");
|
|
}
|
|
|
|
printf (" Typical timeout per single byte program: %d us\n",
|
|
1 << cfi->wrTimeout);
|
|
printf (" Maximum timeout per single byte program: %d us\n",
|
|
(1 << cfi->wrTimeoutMax) * (1 << cfi->wrTimeout));
|
|
|
|
if (cfi->wrBufTimeout || cfi->wrBufTimeoutMax)
|
|
{
|
|
printf (" Typical timeout for page program: %d us\n",
|
|
1 << cfi->wrBufTimeout);
|
|
printf (" Maximum timeout for page program: %d us\n",
|
|
(1 << cfi->wrBufTimeoutMax) * (1 << cfi->wrBufTimeout));
|
|
}
|
|
else
|
|
{
|
|
printf (" Page program not supported\n");
|
|
}
|
|
|
|
printf (" Typical individual sector erase timeout: %d ms\n",
|
|
1 << cfi->blkEraseTimeout);
|
|
printf (" Maximum individual sector erase timeout: %d ms\n",
|
|
(1 << cfi->blkEraseTimeoutMax) * (1 << cfi->blkEraseTimeout));
|
|
|
|
if (cfi->chipEraseTimeout || cfi->chipEraseTimeoutMax)
|
|
{
|
|
printf (" Typical full chip erase timeout: %d ms\n",
|
|
1 << cfi->chipEraseTimeout);
|
|
printf (" Maximum full chip erase timeout: %d ms\n",
|
|
(1 << cfi->chipEraseTimeoutMax) * (1 << cfi->chipEraseTimeout));
|
|
}
|
|
else
|
|
{
|
|
printf (" Chip erase not supported\n");
|
|
}
|
|
|
|
printf (" Device size: 0x%X bytes (%d MB)\n",
|
|
1 << cfi->devSize,
|
|
1 << (cfi->devSize - 20));
|
|
printf (" Flash Device Interface Description: 0x%4.4X\n",
|
|
cfi->ifDesc);
|
|
|
|
switch ((UINT8) cfi->ifDesc)
|
|
{
|
|
case CFI_INTERFACE_X8_ASYNC:
|
|
printf (" - x8-only interface\n");
|
|
break;
|
|
|
|
case CFI_INTERFACE_X16_ASYNC:
|
|
printf (" - x16-only interface\n");
|
|
break;
|
|
|
|
case CFI_INTERFACE_X8_BY_X16_ASYNC:
|
|
printf (" - supports x8 and x16 interface\n");
|
|
break;
|
|
|
|
case CFI_INTERFACE_X32_ASYNC:
|
|
printf (" - x32-only interface\n");
|
|
break;
|
|
|
|
case CFI_INTERFACE_SINGLE_IO_SPI_ASYNC:
|
|
printf (" - single I/O SPI, 3-byte address\n");
|
|
break;
|
|
|
|
case CFI_INTERFACE_MULTI_IO_SPI_ASYNC:
|
|
printf (" - Multi I/O SPI, 3-byte address\n");
|
|
break;
|
|
|
|
default:
|
|
printf (" - Unknown\n");
|
|
break;
|
|
}
|
|
|
|
printf (" Max number of bytes in multi-byte write: %d bytes\n",
|
|
1 << cfi->wrBufLen);
|
|
printf (" Number of Erase Block Regions within device: %d\n",
|
|
cfi->regionNum);
|
|
|
|
for (i = 0; i < cfi->regionNum; i++)
|
|
{
|
|
printf (" Region %d - blkSize: %3.3dKB"
|
|
"blkNum: %3.3d range: 0x0-0x%x \r\n",
|
|
i,
|
|
CFI_BLK_SIZE ((UINT16) (cfi->EraseRegionInfo[i]>>16)) >> 10,
|
|
(UINT16)cfi->EraseRegionInfo[i] + 1,
|
|
CFI_BLK_SIZE ((UINT16) (cfi->EraseRegionInfo[i] >> 16)) *
|
|
((UINT16) cfi->EraseRegionInfo[i] + 1));
|
|
}
|
|
}
|
|
|
|
if (verbose >= 100000)
|
|
{
|
|
printf (" cfi->qryStr[0] - 0x%02x\r\n", cfi->qryStr[0]);
|
|
printf (" cfi->qryStr[1] - 0x%02x\r\n", cfi->qryStr[1]);
|
|
printf (" cfi->qryStr[2] - 0x%02x\r\n", cfi->qryStr[2]);
|
|
printf (" cfi->priCmdSet - 0x%04x\r\n", cfi->priCmdSet);
|
|
printf (" cfi->priExtTblAdrs - 0x%04x\r\n", cfi->priExtTblAdrs);
|
|
printf (" cfi->altCmdSet - 0x%04x\r\n", cfi->altCmdSet);
|
|
printf (" cfi->altExtTblAdrs - 0x%04x\r\n", cfi->altExtTblAdrs);
|
|
printf (" cfi->vccMin - 0x%02x\r\n", cfi->vccMin);
|
|
printf (" cfi->vccMax - 0x%02x\r\n", cfi->vccMax);
|
|
printf (" cfi->vppMin - 0x%02x\r\n", cfi->vppMin);
|
|
printf (" cfi->vppMax - 0x%02x\r\n", cfi->vppMax);
|
|
printf (" cfi->wrTimeout - 0x%02x\r\n",
|
|
cfi->wrTimeout);
|
|
printf (" cfi->wrBufTimeout - 0x%02x\r\n", cfi->wrBufTimeout);
|
|
printf (" cfi->blkEraseTimeout - 0x%02x\r\n",
|
|
cfi->blkEraseTimeout);
|
|
printf (" cfi->chipEraseTimeout - 0x%02x\r\n",
|
|
cfi->chipEraseTimeout);
|
|
printf (" cfi->wrTimeoutMax - 0x%02x\r\n",
|
|
cfi->wrTimeoutMax);
|
|
printf (" cfi->wrBufTimeoutMax - 0x%02x\r\n", cfi->wrBufTimeoutMax);
|
|
printf (" cfi->blkEraseTimeoutMax - 0x%02x\r\n",
|
|
cfi->blkEraseTimeoutMax);
|
|
printf (" cfi->chipEraseTimeoutMax - 0x%02x\r\n",
|
|
cfi->chipEraseTimeoutMax);
|
|
printf (" cfi->devSize - 0x%02x\r\n", cfi->devSize);
|
|
printf (" cfi->ifDesc - 0x%02x\r\n", cfi->ifDesc);
|
|
printf (" cfi->wrBufLen - 0x%02x\r\n", cfi->wrBufLen);
|
|
printf (" cfi->regionNum - 0x%02x\r\n", cfi->regionNum);
|
|
printf (" cfi->EraseRegionInfo[0] - 0x%08x\r\n", cfi->EraseRegionInfo[0]);
|
|
printf (" cfi->EraseRegionInfo[1] - 0x%08x\r\n", cfi->EraseRegionInfo[1]);
|
|
}
|
|
return;
|
|
}
|
|
|
|
#define SP25FLASH_TEST
|
|
#ifdef SP25FLASH_TEST
|
|
void sp25test_erase(uint32_t addr)
|
|
{
|
|
STATUS st;
|
|
VXB_DEVICE_ID pDev = vxbInstByNameFind("spiFlash_s25fs256s",0);
|
|
if(NULL == pDev)
|
|
{
|
|
printf("can not find dev: spiFlash_s25fs256s!\r\n");
|
|
return;
|
|
}
|
|
|
|
st = spS25spiFlashSectorErase(pDev,addr,1);
|
|
if(OK ==st)
|
|
{
|
|
printf("successfully erase FLASH.\r\n");
|
|
}
|
|
else
|
|
{
|
|
printf("Failed to erase FLASH!\r\n");
|
|
}
|
|
}
|
|
|
|
void sp25test_write(uint32_t addr, uint32_t len)
|
|
{
|
|
int i = 0;
|
|
UINT8 buf[1024] = {0};
|
|
STATUS st;
|
|
VXB_DEVICE_ID pDev = vxbInstByNameFind("spiFlash_s25fs256s",0);
|
|
|
|
if(len >sizeof(buf))
|
|
{
|
|
printf("Only write max %d bytes. len %d too big!\r\n", sizeof(buf), len);
|
|
return;
|
|
}
|
|
|
|
if(NULL == pDev)
|
|
{
|
|
printf("can not find dev: spiFlash_s25fs256s!\r\n");
|
|
return;
|
|
}
|
|
|
|
for(i = 0; i< len; i++)
|
|
{
|
|
buf[i] = i;
|
|
}
|
|
printf("The buffer content:\r\n");
|
|
d((void*)buf, len, 1);
|
|
|
|
st = spS25spiFlashProgram(pDev,addr,len,buf);
|
|
if(OK ==st)
|
|
{
|
|
printf("successfully write FLASH.\r\n");
|
|
}
|
|
else
|
|
{
|
|
printf("Failed to write FLASH!\r\n");
|
|
}
|
|
}
|
|
|
|
|
|
void sp25test_read(uint32_t addr, uint32_t len)
|
|
{
|
|
STATUS st;
|
|
UINT8 recv[1024] = {0};
|
|
VXB_DEVICE_ID pDev = vxbInstByNameFind("spiFlash_s25fs256s",0);
|
|
|
|
if(len >sizeof(recv))
|
|
{
|
|
printf("Only read max %d bytes. len %d too big!\r\n", sizeof(recv), len);
|
|
return;
|
|
}
|
|
|
|
if(NULL == pDev)
|
|
{
|
|
printf("can not find dev: spiFlash_s25fs256s!\r\n");
|
|
return;
|
|
}
|
|
st = spS25spiFlashRead(pDev,addr,len,recv);
|
|
if(OK ==st)
|
|
{
|
|
printf("read %d bytes from 0x%x: ",len, addr);
|
|
d((void*)recv, len, 1);
|
|
}
|
|
else
|
|
{
|
|
printf("Failed to read FLASH!\r\n");
|
|
}
|
|
}
|
|
|
|
|
|
void sp25test(UINT32 addr, UINT32 len)
|
|
{
|
|
sp25test_erase(addr);
|
|
sp25test_write(addr,len);
|
|
sp25test_read(addr,len);
|
|
}
|
|
#endif
|
|
|