1188 lines
32 KiB
C
1188 lines
32 KiB
C
|
/*
|
||
|
* nor.c - NOR flash functions
|
||
|
*
|
||
|
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
||
|
*
|
||
|
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
||
|
* Copyright 2008 Texas Instruments, Inc. <www.ti.com>
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 2 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program; if not, write to the Free Software
|
||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||
|
*/
|
||
|
|
||
|
#include "common.h"
|
||
|
#include "davinci.h"
|
||
|
#include "util.h"
|
||
|
#include "uart.h"
|
||
|
#include "nor.h"
|
||
|
|
||
|
/* Bit masks */
|
||
|
#define BIT0 0x00000001
|
||
|
#define BIT1 0x00000002
|
||
|
#define BIT2 0x00000004
|
||
|
#define BIT3 0x00000008
|
||
|
#define BIT4 0x00000010
|
||
|
#define BIT5 0x00000020
|
||
|
#define BIT6 0x00000040
|
||
|
#define BIT7 0x00000080
|
||
|
#define BIT8 0x00000100
|
||
|
#define BIT9 0x00000200
|
||
|
#define BIT10 0x00000400
|
||
|
#define BIT11 0x00000800
|
||
|
#define BIT12 0x00001000
|
||
|
#define BIT13 0x00002000
|
||
|
#define BIT14 0x00004000
|
||
|
#define BIT15 0x00008000
|
||
|
#define BIT16 0x00010000
|
||
|
#define BIT17 0x00020000
|
||
|
#define BIT18 0x00040000
|
||
|
#define BIT19 0x00080000
|
||
|
#define BIT20 0x00100000
|
||
|
#define BIT21 0x00200000
|
||
|
#define BIT22 0x00400000
|
||
|
#define BIT23 0x00800000
|
||
|
#define BIT24 0x01000000
|
||
|
#define BIT25 0x02000000
|
||
|
#define BIT26 0x04000000
|
||
|
#define BIT27 0x08000000
|
||
|
#define BIT28 0x10000000
|
||
|
#define BIT29 0x20000000
|
||
|
#define BIT30 0x40000000
|
||
|
#define BIT31 0x80000000
|
||
|
|
||
|
#define BUS_8BIT 0x01
|
||
|
#define BUS_16BIT 0x02
|
||
|
#define BUS_32BIT 0x04
|
||
|
|
||
|
/**************** DEFINES for AMD Basic Command Set **************/
|
||
|
#define AMD_CMD0 0xAA // AMD CMD PREFIX 0
|
||
|
#define AMD_CMD1 0x55 // AMD CMD PREFIX 1
|
||
|
#define AMD_CMD0_ADDR 0x555 // AMD CMD0 Offset
|
||
|
#define AMD_CMD1_ADDR 0x2AA // AMD CMD1 Offset
|
||
|
#define AMD_CMD2_ADDR 0x555 // AMD CMD2 Offset
|
||
|
#define AMD_ID_CMD 0x90 // AMD ID CMD
|
||
|
#define AMD_MANFID_ADDR 0x00 // Manufacturer ID offset
|
||
|
#define AMD_DEVID_ADDR0 0x01 // First device ID offset
|
||
|
#define AMD_DEVID_ADDR1 0x0E // Offset for 2nd byte of 3 byte ID
|
||
|
#define AMD_DEVID_ADDR2 0x0F // Offset for 3rd byte of 3 byte ID
|
||
|
#define AMD_ID_MULTI 0x7E // First-byte ID value for 3-byte ID
|
||
|
#define AMD_RESET 0xF0 // AMD Device Reset Command
|
||
|
#define AMD_BLK_ERASE_SETUP_CMD 0x80 // Block erase setup
|
||
|
#define AMD_BLK_ERASE_CMD 0x30 // Block erase confirm
|
||
|
#define AMD_BLK_ERASE_DONE 0xFFFF // Block erase check value
|
||
|
#define AMD_PROG_CMD 0xA0 // AMD simple Write command
|
||
|
#define AMD_WRT_BUF_LOAD_CMD 0x25 // AMD write buffer load command
|
||
|
#define AMD_WRT_BUF_CONF_CMD 0x29 // AMD write buffer confirm command
|
||
|
|
||
|
/**************** DEFINES for Intel Basic Command Set **************/
|
||
|
#define INTEL_ID_CMD 0x90 // Intel ID CMD
|
||
|
#define INTEL_MANFID_ADDR 0x00 // Manufacturer ID offset
|
||
|
#define INTEL_DEVID_ADDR 0x01 // Device ID offset
|
||
|
#define INTEL_RESET 0xFF // Intel Device Reset Command
|
||
|
#define INTEL_ERASE_CMD0 0x20 // Intel Erase command
|
||
|
#define INTEL_ERASE_CMD1 0xD0 // Intel Erase command
|
||
|
#define INTEL_WRITE_CMD 0x40 // Intel simple write command
|
||
|
#define INTEL_WRT_BUF_LOAD_CMD 0xE8 // Intel write buffer load command
|
||
|
#define INTEL_WRT_BUF_CONF_CMD 0xD0 // Intel write buffer confirm command
|
||
|
#define INTEL_LOCK_CMD0 0x60 // Intel lock mode command
|
||
|
#define INTEL_LOCK_BLOCK_CMD 0x01 // Intel lock command
|
||
|
#define INTEL_UNLOCK_BLOCK_CMD 0xD0 // Intel unlock command
|
||
|
#define INTEL_CLEARSTATUS_CMD 0x50 // Intel clear status command
|
||
|
|
||
|
|
||
|
/**************** DEFINES for CFI Commands and Table **************/
|
||
|
|
||
|
// CFI Entry and Exit commands
|
||
|
#define CFI_QRY_CMD 0x98U
|
||
|
#define CFI_EXIT_CMD 0xF0U
|
||
|
|
||
|
// CFI address locations
|
||
|
#define CFI_QRY_CMD_ADDR 0x55U
|
||
|
|
||
|
// CFI Table Offsets in Bytes
|
||
|
#define CFI_Q 0x10
|
||
|
#define CFI_R 0x11
|
||
|
#define CFI_Y 0x12
|
||
|
#define CFI_CMDSET 0x13
|
||
|
#define CFI_CMDSETADDR 0x15
|
||
|
#define CFI_ALTCMDSET 0x17
|
||
|
#define CFI_ALTCMDSETADDR 0x19
|
||
|
#define CFI_MINVCC 0x1B
|
||
|
#define CFI_MAXVCC 0x1C
|
||
|
#define CFI_MINVPP 0x1D
|
||
|
#define CFI_MAXVPP 0x1E
|
||
|
#define CFI_TYPBYTEPGMTIME 0x1F
|
||
|
#define CFI_TYPBUFFERPGMTIME 0x20
|
||
|
#define CFI_TYPBLOCKERASETIME 0x21
|
||
|
#define CFI_TYPCHIPERASETIME 0x22
|
||
|
#define CFI_MAXBYTEPGMTIME 0x23
|
||
|
#define CFI_MAXBUFFERPGMTIME 0x24
|
||
|
#define CFI_MAXBLOCKERASETIME 0x25
|
||
|
#define CFI_MAXCHIPERASETIME 0x26
|
||
|
#define CFI_DEVICESIZE 0x27
|
||
|
#define CFI_INTERFACE 0x28
|
||
|
#define CFI_WRITESIZE 0x2A
|
||
|
#define CFI_NUMBLKREGIONS 0x2C
|
||
|
#define CFI_BLKREGIONS 0x2D
|
||
|
#define CFI_BLKREGIONSIZE 0x04
|
||
|
|
||
|
// Maximum number of block regions supported
|
||
|
#define CFI_MAXREGIONS 0x06
|
||
|
|
||
|
/*********************** Enumerated types *************************/
|
||
|
// Supported Flash Manufacturers
|
||
|
enum flash_manufacturer_id_t {
|
||
|
UNKNOWN_ID = 0x00,
|
||
|
AMD = 0x01,
|
||
|
FUJITSU = 0x04,
|
||
|
INTEL = 0x89,
|
||
|
MICRON = 0x2C,
|
||
|
SAMSUNG = 0xEC,
|
||
|
SHARP = 0xB0
|
||
|
};
|
||
|
|
||
|
typedef enum flash_manufacturer_id_t MANFID;
|
||
|
|
||
|
// Supported CFI command sets
|
||
|
enum FlashCommandSet {
|
||
|
UNKNOWN_CMDSET = 0x0000,
|
||
|
INTEL_EXT_CMDSET = 0x0001,
|
||
|
AMD_BASIC_CMDSET = 0x0002,
|
||
|
INTEL_BASIC_CMDSET = 0x0003,
|
||
|
AMD_EXT_CMDSET = 0x0004,
|
||
|
MITSU_BASIC_CMDSET = 0x0100,
|
||
|
MITSU_EXT_CMDSET = 0x0101
|
||
|
|
||
|
};
|
||
|
typedef enum FlashCommandSet CMDSET;
|
||
|
|
||
|
/*************************** Structs *********************************/
|
||
|
// Struct to hold discovered flash parameters
|
||
|
typedef struct _NOR_MEDIA_STRUCT_ {
|
||
|
uint32_t flashBase; // 32-bit address of flash start
|
||
|
uint8_t busWidth; // 8-bit or 16-bit bus width
|
||
|
uint8_t chipOperatingWidth; // The operating width of each chip
|
||
|
uint8_t maxTotalWidth; // Maximum extent of width of all chips combined - determines offset shifts
|
||
|
uint32_t flashSize; // Size of NOR flash regions in bytes (numberDevices * size of one device)
|
||
|
uint32_t bufferSize; // Size of write buffer
|
||
|
CMDSET commandSet; // command set id (see CFI documentation)
|
||
|
uint8_t numberDevices; // Number of deives used in parallel
|
||
|
uint8_t numberRegions; // Number of regions of contiguous regions of same block size
|
||
|
uint32_t numberBlocks[CFI_MAXREGIONS]; // Number of blocks in a region
|
||
|
uint32_t blockSize[CFI_MAXREGIONS]; // Size of the blocks in a region
|
||
|
enum flash_manufacturer_id_t manfID; // Manufacturer's ID
|
||
|
uint16_t devID1; // Device ID
|
||
|
uint16_t devID2; // Used for AMD 3-byte ID devices
|
||
|
} NOR_INFO, *PNOR_INFO;
|
||
|
|
||
|
typedef union {
|
||
|
uint8_t c;
|
||
|
uint16_t w;
|
||
|
uint32_t l;
|
||
|
} FLASHData;
|
||
|
|
||
|
typedef union {
|
||
|
volatile uint8_t *cp;
|
||
|
volatile uint16_t *wp;
|
||
|
volatile uint32_t *lp;
|
||
|
} FLASHPtr;
|
||
|
|
||
|
//External and global static variables
|
||
|
extern uint32_t __NORFlash;
|
||
|
|
||
|
static volatile NOR_INFO gNorInfo;
|
||
|
|
||
|
// ----------------- Bus Width Agnostic commands -------------------
|
||
|
volatile uint8_t *flash_make_addr (uint32_t blkAddr, uint32_t offset)
|
||
|
{
|
||
|
return ((volatile uint8_t *) ( blkAddr + (offset * gNorInfo.maxTotalWidth)));
|
||
|
}
|
||
|
|
||
|
void flash_make_cmd (uint8_t cmd, void *cmdbuf)
|
||
|
{
|
||
|
int32_t i;
|
||
|
uint8_t *cp = (uint8_t *) cmdbuf;
|
||
|
|
||
|
for (i = gNorInfo.busWidth; i > 0; i--)
|
||
|
*cp++ = (i & (gNorInfo.chipOperatingWidth - 1)) ? 0x00 : cmd;
|
||
|
}
|
||
|
|
||
|
void flash_write_cmd (uint32_t blkAddr, uint32_t offset, uint8_t cmd)
|
||
|
{
|
||
|
volatile FLASHPtr addr;
|
||
|
FLASHData cmdword;
|
||
|
|
||
|
addr.cp = flash_make_addr (blkAddr, offset);
|
||
|
flash_make_cmd ( cmd, &cmdword);
|
||
|
switch (gNorInfo.busWidth)
|
||
|
{
|
||
|
case BUS_8BIT:
|
||
|
*addr.cp = cmdword.c;
|
||
|
break;
|
||
|
case BUS_16BIT:
|
||
|
*addr.wp = cmdword.w;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void flash_write_data(uint32_t address, uint32_t data)
|
||
|
{
|
||
|
volatile FLASHPtr pAddr;
|
||
|
FLASHData dataword;
|
||
|
dataword.l = data;
|
||
|
|
||
|
pAddr.cp = (volatile uint8_t*) address;
|
||
|
|
||
|
switch (gNorInfo.busWidth)
|
||
|
{
|
||
|
case BUS_8BIT:
|
||
|
*pAddr.cp = dataword.c;
|
||
|
break;
|
||
|
case BUS_16BIT:
|
||
|
*pAddr.wp = dataword.w;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void flash_write_databuffer(uint32_t* address, void* data, uint32_t numBytes)
|
||
|
{
|
||
|
volatile FLASHPtr pAddr, pData;
|
||
|
volatile uint8_t* endAddress;
|
||
|
|
||
|
pData.cp = (volatile uint8_t*) data;
|
||
|
pAddr.cp = (volatile uint8_t*) *address;
|
||
|
endAddress =(volatile uint8_t*)((*address)+numBytes);
|
||
|
while (pAddr.cp < endAddress)
|
||
|
{
|
||
|
switch (gNorInfo.busWidth)
|
||
|
{
|
||
|
case BUS_8BIT:
|
||
|
*pAddr.cp++ = *pData.cp++;
|
||
|
break;
|
||
|
case BUS_16BIT:
|
||
|
*pAddr.wp++ = *pData.wp++;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Put last data written at start of data buffer - For AMD verification
|
||
|
switch (gNorInfo.busWidth)
|
||
|
{
|
||
|
case BUS_8BIT:
|
||
|
*address = (uint32_t)(endAddress-1);
|
||
|
break;
|
||
|
case BUS_16BIT:
|
||
|
*address = (uint32_t)(endAddress-2);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
uint32_t flash_verify_databuffer(uint32_t address, void* data, uint32_t numBytes)
|
||
|
{
|
||
|
volatile FLASHPtr pAddr, pData;
|
||
|
volatile uint8_t* endAddress;
|
||
|
|
||
|
pData.cp = (volatile uint8_t*) data;
|
||
|
pAddr.cp = (volatile uint8_t*) address;
|
||
|
endAddress =(volatile uint8_t*)(address+numBytes);
|
||
|
while (pAddr.cp < endAddress)
|
||
|
{
|
||
|
switch (gNorInfo.busWidth)
|
||
|
{
|
||
|
case BUS_8BIT:
|
||
|
if ( (*pAddr.cp++) != (*pData.cp++) )
|
||
|
return E_FAIL;
|
||
|
break;
|
||
|
case BUS_16BIT:
|
||
|
if ( (*pAddr.wp++) != (*pData.wp++) )
|
||
|
return E_FAIL;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return E_PASS;
|
||
|
}
|
||
|
|
||
|
uint32_t flash_read_data(uint32_t address, uint32_t offset)
|
||
|
{
|
||
|
volatile FLASHPtr pAddr;
|
||
|
FLASHData dataword;
|
||
|
dataword.l = 0x00000000;
|
||
|
|
||
|
pAddr.cp = flash_make_addr(address, offset);
|
||
|
|
||
|
switch (gNorInfo.busWidth)
|
||
|
{
|
||
|
case BUS_8BIT:
|
||
|
dataword.c = *pAddr.cp;
|
||
|
break;
|
||
|
|
||
|
case BUS_16BIT:
|
||
|
dataword.w = *pAddr.wp;
|
||
|
break;
|
||
|
}
|
||
|
return dataword.l;
|
||
|
}
|
||
|
|
||
|
FLASHData flash_read_CFI_bytes (uint32_t blkAddr, uint32_t offset, uint8_t numBytes)
|
||
|
{
|
||
|
int32_t i;
|
||
|
FLASHData readword;
|
||
|
uint8_t* pReadword = &readword.c;
|
||
|
|
||
|
for (i = 0; i < numBytes; i++)
|
||
|
{
|
||
|
*pReadword++ = *(flash_make_addr (blkAddr, offset+i));
|
||
|
}
|
||
|
|
||
|
return readword;
|
||
|
}
|
||
|
|
||
|
Bool flash_data_isequal (uint32_t blkAddr, uint32_t offset, uint32_t val)
|
||
|
{
|
||
|
FLASHData testword_a, testword_b;
|
||
|
Bool retval = FALSE;
|
||
|
|
||
|
testword_a.l = val;
|
||
|
testword_b.l = flash_read_data(blkAddr, offset);
|
||
|
|
||
|
switch (gNorInfo.busWidth)
|
||
|
{
|
||
|
case BUS_8BIT:
|
||
|
retval = (testword_a.c == testword_b.c);
|
||
|
break;
|
||
|
case BUS_16BIT:
|
||
|
retval = (testword_a.w == testword_b.w);
|
||
|
break;
|
||
|
}
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
Bool flash_CFI_isequal (uint32_t blkAddr, uint32_t offset, uint8_t val)
|
||
|
{
|
||
|
volatile FLASHPtr addr;
|
||
|
FLASHData testword;
|
||
|
|
||
|
Bool retval = TRUE;
|
||
|
|
||
|
addr.cp = flash_make_addr (blkAddr, offset);
|
||
|
flash_make_cmd ( val, &testword);
|
||
|
switch (gNorInfo.busWidth)
|
||
|
{
|
||
|
case BUS_8BIT:
|
||
|
retval = (testword.c == *addr.cp);
|
||
|
break;
|
||
|
case BUS_16BIT:
|
||
|
retval = (testword.w == *addr.wp);
|
||
|
break;
|
||
|
}
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
Bool flash_issetall (uint32_t blkAddr, uint32_t offset, uint8_t mask)
|
||
|
{
|
||
|
volatile FLASHPtr addr;
|
||
|
FLASHData maskword;
|
||
|
maskword.l = 0x00000000;
|
||
|
|
||
|
Bool retval = TRUE;
|
||
|
|
||
|
addr.cp = flash_make_addr (blkAddr, offset);
|
||
|
flash_make_cmd ( mask, &maskword);
|
||
|
switch (gNorInfo.busWidth)
|
||
|
{
|
||
|
case BUS_8BIT:
|
||
|
retval = ((maskword.c & *addr.cp) == maskword.c);
|
||
|
break;
|
||
|
case BUS_16BIT:
|
||
|
retval = ((maskword.w & *addr.wp) == maskword.w);
|
||
|
break;
|
||
|
}
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
Bool flash_issetsome (uint32_t blkAddr, uint32_t offset, uint8_t mask)
|
||
|
{
|
||
|
volatile FLASHPtr addr;
|
||
|
FLASHData maskword;
|
||
|
|
||
|
Bool retval = TRUE;
|
||
|
|
||
|
addr.cp = flash_make_addr (blkAddr, offset);
|
||
|
flash_make_cmd ( mask, &maskword);
|
||
|
switch (gNorInfo.busWidth)
|
||
|
{
|
||
|
case BUS_8BIT:
|
||
|
retval = (maskword.c & *addr.cp);
|
||
|
break;
|
||
|
case BUS_16BIT:
|
||
|
retval = (maskword.w & *addr.wp);
|
||
|
break;
|
||
|
}
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
//Initialize the AEMIF subsystem and settings
|
||
|
uint32_t NOR_Init()
|
||
|
{
|
||
|
uint8_t width = ( ( (SYSTEM->BOOTCFG) >> 5) & 0x1 );
|
||
|
|
||
|
// Select ASYNC EMIF Address Lines
|
||
|
SYSTEM->PINMUX[0] = 0xC1F;
|
||
|
|
||
|
// Program Asynchronous Wait Cycles Configuration Control Register
|
||
|
#warning "To check: AEMIF->AWCCR |= 0x0;"
|
||
|
AEMIF->AWCCR |= 0x0;
|
||
|
|
||
|
// Program Asynchronous Bank3-5 Register
|
||
|
AEMIF->A1CR = 0x3FFFFFFC | width;
|
||
|
AEMIF->A2CR = 0x3FFFFFFC | width;
|
||
|
AEMIF->A3CR = 0x3FFFFFFC | width;
|
||
|
AEMIF->A4CR = 0x3FFFFFFC | width;
|
||
|
|
||
|
/*AEMIF->A1CR = 0
|
||
|
| ( 0 << 31 ) // selectStrobe = 0;
|
||
|
| ( 0 << 30 ) // extWait = 0;
|
||
|
| ( 0 << 26 ) // writeSetup = 0; // 0 ns
|
||
|
| ( 3 << 20 ) // writeStrobe = 3; // 35 ns
|
||
|
| ( 0 << 17 ) // writeHold = 0; // 0 ns
|
||
|
| ( 3 << 13 ) // readSetup = 3; // 30 ns
|
||
|
| ( 10<< 7 ) // readStrobe = 10; // 120 ns
|
||
|
| ( 0 << 4 ) // readHold = 0; // 0 ns
|
||
|
| ( 3 << 2 ) // turnAround = 3; // ?? ns ( MAX TIMEOUT )
|
||
|
| ( 1 << 0 ) // asyncSize = 1; // 16-bit bus
|
||
|
;*/
|
||
|
|
||
|
//Init the FlashInfo structure
|
||
|
gNorInfo.flashBase = (uint32_t) &(__NORFlash);
|
||
|
|
||
|
// Set width to 8 or 16
|
||
|
gNorInfo.busWidth = (width)?BUS_16BIT:BUS_8BIT;
|
||
|
|
||
|
// Perform CFI Query
|
||
|
if (QueryCFI(gNorInfo.flashBase) == E_PASS)
|
||
|
{
|
||
|
// Below is specifically needed to check for AMD flash on DVEVM (rev. D or earlier)
|
||
|
// since it's top address line is not connected (don't ask me why)
|
||
|
if (gNorInfo.numberRegions == 1)
|
||
|
{
|
||
|
if ( QueryCFI( gNorInfo.flashBase+(gNorInfo.flashSize>>1) ) == E_PASS )
|
||
|
{
|
||
|
gNorInfo.flashSize >>= 1;
|
||
|
gNorInfo.numberBlocks[0] >>= 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
log_info("CFI query failed.");
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
// Setup function pointers
|
||
|
|
||
|
log_info("NOR Initialization:");
|
||
|
|
||
|
uart_send_str(" Command Set: ");
|
||
|
switch (gNorInfo.commandSet)
|
||
|
{
|
||
|
case AMD_BASIC_CMDSET:
|
||
|
case AMD_EXT_CMDSET:
|
||
|
Flash_Erase = &AMD_Erase;
|
||
|
Flash_BufferWrite = &AMD_BufferWrite;
|
||
|
Flash_Write = &AMD_Write;
|
||
|
Flash_ID = &AMD_ID;
|
||
|
log_info("AMD");
|
||
|
break;
|
||
|
case INTEL_BASIC_CMDSET:
|
||
|
case INTEL_EXT_CMDSET:
|
||
|
Flash_Erase = &Intel_Erase;
|
||
|
Flash_BufferWrite = &Intel_BufferWrite;
|
||
|
Flash_Write = &Intel_Write;
|
||
|
Flash_ID = &Intel_ID;
|
||
|
log_info("Intel");
|
||
|
break;
|
||
|
default:
|
||
|
Flash_Write = &Unsupported_Write;
|
||
|
Flash_BufferWrite = &Unsupported_BufferWrite;
|
||
|
Flash_Erase = &Unsupported_Erase;
|
||
|
Flash_ID = &Unsupported_ID;
|
||
|
log_info("Unknown");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( (*Flash_ID)(gNorInfo.flashBase) != E_PASS)
|
||
|
{
|
||
|
log_info("NOR ID failed.");
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
uart_send_str(" Manufacturer: ");
|
||
|
switch(gNorInfo.manfID)
|
||
|
{
|
||
|
case AMD:
|
||
|
uart_send_str("AMD");
|
||
|
break;
|
||
|
case FUJITSU:
|
||
|
uart_send_str("FUJITSU");
|
||
|
break;
|
||
|
case INTEL:
|
||
|
uart_send_str("INTEL");
|
||
|
break;
|
||
|
case MICRON:
|
||
|
uart_send_str("MICRON");
|
||
|
break;
|
||
|
case SAMSUNG:
|
||
|
uart_send_str("SAMSUNG");
|
||
|
break;
|
||
|
case SHARP:
|
||
|
uart_send_str("SHARP");
|
||
|
break;
|
||
|
default:
|
||
|
uart_send_str("Unknown");
|
||
|
break;
|
||
|
}
|
||
|
uart_send_lf();
|
||
|
uart_send_str(" Size (in bytes): ");
|
||
|
uart_send_hexnum(gNorInfo.flashSize, 8);
|
||
|
uart_send_lf();
|
||
|
|
||
|
return E_PASS;
|
||
|
}
|
||
|
|
||
|
// Query the chip to check for CFI table and data
|
||
|
uint32_t QueryCFI( uint32_t baseAddress )
|
||
|
{
|
||
|
int32_t i;
|
||
|
uint32_t blkVal;
|
||
|
|
||
|
// Six possible NOR Flash Configurations of DM644x
|
||
|
// 1) Bus in x8 mode, x8 only device
|
||
|
// 2) Bus in x8 mode, single x8/x16 flash operating in x8 mode
|
||
|
// 3) Bus in x16 mode, single x8/x16 or x16-only flash operating in x16 mode
|
||
|
// 4) Bus in x16 mode, two x8 flash operating in parallel.
|
||
|
// 5) Bus in x16 mode, two x8/x16 flash, each in x8 mode, operating in parallel
|
||
|
// 6) Bus in x16 mode, single x16/x32 flash operating in x16 mode
|
||
|
|
||
|
for (gNorInfo.chipOperatingWidth = BUS_8BIT; gNorInfo.chipOperatingWidth <= gNorInfo.busWidth; gNorInfo.chipOperatingWidth <<= 1)
|
||
|
{
|
||
|
for (gNorInfo.maxTotalWidth = gNorInfo.busWidth; gNorInfo.maxTotalWidth <= (gNorInfo.busWidth*2); gNorInfo.maxTotalWidth <<= 1)
|
||
|
{
|
||
|
// Specify number of devices
|
||
|
gNorInfo.numberDevices = 0;
|
||
|
while ( gNorInfo.numberDevices * gNorInfo.chipOperatingWidth < gNorInfo.busWidth)
|
||
|
gNorInfo.numberDevices++;
|
||
|
|
||
|
// Enter the CFI Query mode
|
||
|
flash_write_cmd (baseAddress, 0, CFI_EXIT_CMD);
|
||
|
flash_write_cmd (baseAddress, CFI_QRY_CMD_ADDR, CFI_QRY_CMD);
|
||
|
|
||
|
// Check for Query QRY values
|
||
|
if ( flash_CFI_isequal ( baseAddress, CFI_Q, 'Q') &&
|
||
|
flash_CFI_isequal ( baseAddress, CFI_R, 'R') &&
|
||
|
flash_CFI_isequal ( baseAddress, CFI_Y, 'Y') )
|
||
|
{
|
||
|
gNorInfo.commandSet = (CMDSET) (flash_read_CFI_bytes(baseAddress,CFI_CMDSET,2).w);
|
||
|
gNorInfo.flashSize = 0x1 << flash_read_CFI_bytes(baseAddress,CFI_DEVICESIZE,1).c * gNorInfo.numberDevices;
|
||
|
gNorInfo.numberRegions = flash_read_CFI_bytes(baseAddress,CFI_NUMBLKREGIONS,1).c;
|
||
|
gNorInfo.bufferSize = 0x1 << flash_read_CFI_bytes(baseAddress,CFI_WRITESIZE,2).w * gNorInfo.numberDevices;
|
||
|
|
||
|
// Get info on sector sizes in each erase region of device
|
||
|
for (i = 0;i < gNorInfo.numberRegions; i++)
|
||
|
{
|
||
|
blkVal = flash_read_CFI_bytes(baseAddress,(CFI_BLKREGIONS+i*CFI_BLKREGIONSIZE),4).l;
|
||
|
gNorInfo.numberBlocks[i] = (blkVal&0x0000FFFF) + 1;
|
||
|
gNorInfo.blockSize[i] = ((blkVal&0xFFFF0000) ? ( ((blkVal>>16)&0xFFFF) * 256) : 128) * gNorInfo.numberDevices;
|
||
|
}
|
||
|
|
||
|
// Exit CFI mode
|
||
|
flash_write_cmd (baseAddress, 0, CFI_EXIT_CMD);
|
||
|
|
||
|
return E_PASS;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
flash_write_cmd (baseAddress, 0, CFI_EXIT_CMD);
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
|
||
|
// -------------------------------------------------------------------------
|
||
|
// Manufacturer Specific Commands
|
||
|
// -------------------------------------------------------------------------
|
||
|
|
||
|
// ------------------------ Default Empty ---------------------------
|
||
|
uint32_t Unsupported_Write( uint32_t address, volatile uint32_t data)
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
uint32_t Unsupported_BufferWrite(uint32_t address, volatile uint8_t data[], uint32_t length )
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
uint32_t Unsupported_Erase(uint32_t address)
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
uint32_t Unsupported_ID(uint32_t address)
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
|
||
|
// -------------------- Begin of Intel specific commands -----------------------
|
||
|
|
||
|
//ID flash
|
||
|
uint32_t Intel_ID( uint32_t baseAddress )
|
||
|
{
|
||
|
// Intel Exit back to read array mode
|
||
|
Intel_Soft_Reset_Flash();
|
||
|
|
||
|
// Write ID command
|
||
|
flash_write_cmd(baseAddress, 0, INTEL_ID_CMD);
|
||
|
|
||
|
//Read Manufacturer's ID
|
||
|
gNorInfo.manfID = (enum flash_manufacturer_id_t) flash_read_data(baseAddress, INTEL_MANFID_ADDR);
|
||
|
|
||
|
// Read Device ID
|
||
|
gNorInfo.devID1 = (uint16_t) (enum flash_manufacturer_id_t) flash_read_data(baseAddress, INTEL_DEVID_ADDR);
|
||
|
gNorInfo.devID2 = 0x0000;
|
||
|
|
||
|
// Intel Exit back to read array mode
|
||
|
Intel_Soft_Reset_Flash();
|
||
|
|
||
|
return E_PASS;
|
||
|
}
|
||
|
|
||
|
// Reset back to Read array mode
|
||
|
void Intel_Soft_Reset_Flash()
|
||
|
{
|
||
|
// Intel Exit back to read array mode
|
||
|
flash_write_cmd(gNorInfo.flashBase,0,INTEL_RESET);
|
||
|
}
|
||
|
|
||
|
// Clear status register
|
||
|
void Intel_Clear_Status()
|
||
|
{
|
||
|
// Intel clear status
|
||
|
flash_write_cmd(gNorInfo.flashBase,0,INTEL_CLEARSTATUS_CMD);
|
||
|
}
|
||
|
|
||
|
// Remove block write protection
|
||
|
uint32_t Intel_Clear_Lock(volatile uint32_t blkAddr)
|
||
|
{
|
||
|
|
||
|
// Write the Clear Lock Command
|
||
|
flash_write_cmd(blkAddr,0,INTEL_LOCK_CMD0);
|
||
|
|
||
|
flash_write_cmd(blkAddr,0,INTEL_UNLOCK_BLOCK_CMD);
|
||
|
|
||
|
// Check Status
|
||
|
return Intel_Lock_Status_Check();
|
||
|
}
|
||
|
|
||
|
// Write-protect a block
|
||
|
uint32_t Intel_Set_Lock(volatile uint32_t blkAddr)
|
||
|
{
|
||
|
// Write the Set Lock Command
|
||
|
flash_write_cmd(blkAddr,0,INTEL_LOCK_CMD0);
|
||
|
|
||
|
flash_write_cmd(blkAddr,0,INTEL_LOCK_BLOCK_CMD);
|
||
|
|
||
|
// Check Status
|
||
|
return Intel_Lock_Status_Check();
|
||
|
}
|
||
|
|
||
|
void Intel_Wait_For_Status_Complete()
|
||
|
{
|
||
|
while ( !flash_issetall(gNorInfo.flashBase, 0, BIT7) );
|
||
|
}
|
||
|
|
||
|
uint32_t Intel_Lock_Status_Check()
|
||
|
{
|
||
|
uint32_t retval = E_PASS;
|
||
|
//uint8_t status;
|
||
|
|
||
|
Intel_Wait_For_Status_Complete();
|
||
|
|
||
|
//status = flash_read_uint16((uint32_t)gNorInfo.flashBase,0);
|
||
|
//if ( status & BIT5 )
|
||
|
if (flash_issetsome(gNorInfo.flashBase, 0, (BIT5 | BIT3)))
|
||
|
{
|
||
|
retval = E_FAIL;
|
||
|
/*if ( status & BIT4 )
|
||
|
{
|
||
|
uart_send_str("Command Sequence Error\r\n");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
uart_send_str("Clear Lock Error\r\n");
|
||
|
}*/
|
||
|
}
|
||
|
/*if ( status & BIT3 )
|
||
|
{
|
||
|
retval = E_FAIL;
|
||
|
//uart_send_str("Voltage Range Error\n");
|
||
|
}*/
|
||
|
|
||
|
// Clear status
|
||
|
Intel_Clear_Status();
|
||
|
|
||
|
// Put chip back into read array mode.
|
||
|
Intel_Soft_Reset_Flash();
|
||
|
|
||
|
// Set Timings back to Optimum for Read
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
// Erase Block
|
||
|
uint32_t Intel_Erase(volatile uint32_t blkAddr)
|
||
|
{
|
||
|
uint32_t retval = E_PASS;
|
||
|
|
||
|
// Clear Lock Bits
|
||
|
retval |= Intel_Clear_Lock(blkAddr);
|
||
|
|
||
|
// Send Erase commands
|
||
|
flash_write_cmd(blkAddr,0,INTEL_ERASE_CMD0);
|
||
|
flash_write_cmd(blkAddr,0,INTEL_ERASE_CMD1);
|
||
|
|
||
|
// Wait until Erase operation complete
|
||
|
Intel_Wait_For_Status_Complete();
|
||
|
|
||
|
// Verify successful erase
|
||
|
if ( flash_issetsome(gNorInfo.flashBase, 0, BIT5) )
|
||
|
retval = E_FAIL;
|
||
|
|
||
|
// Put back into Read Array mode.
|
||
|
Intel_Soft_Reset_Flash();
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
// Write data
|
||
|
uint32_t Intel_Write( uint32_t address, volatile uint32_t data )
|
||
|
{
|
||
|
uint32_t retval = E_PASS;
|
||
|
|
||
|
// Send Write command
|
||
|
flash_write_cmd(address,0,INTEL_WRITE_CMD);
|
||
|
flash_write_data(address, data);
|
||
|
|
||
|
// Wait until Write operation complete
|
||
|
Intel_Wait_For_Status_Complete();
|
||
|
|
||
|
// Verify successful program
|
||
|
if ( flash_issetsome(gNorInfo.flashBase, 0, (BIT4|BIT3)) )
|
||
|
{
|
||
|
//uart_send_str("Write Op Failed.\r\n");
|
||
|
retval = E_FAIL;
|
||
|
}
|
||
|
|
||
|
// Lock the block
|
||
|
//retval |= Intel_Set_Lock(blkAddr);
|
||
|
|
||
|
// Put back into Read Array mode.
|
||
|
Intel_Soft_Reset_Flash();
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
// Buffer write data
|
||
|
uint32_t Intel_BufferWrite(uint32_t address, volatile uint8_t data[], uint32_t numBytes )
|
||
|
{
|
||
|
uint32_t startAddress = address;
|
||
|
uint32_t retval = E_PASS;
|
||
|
uint32_t timeoutCnt = 0, shift;
|
||
|
|
||
|
// Send Write_Buff_Load command
|
||
|
do {
|
||
|
flash_write_cmd(address,0,INTEL_WRT_BUF_LOAD_CMD);
|
||
|
timeoutCnt++;
|
||
|
}while( (!flash_issetall(gNorInfo.flashBase, 0, BIT7)) && (timeoutCnt < 0x00010000) );
|
||
|
|
||
|
if (timeoutCnt >= 0x10000)
|
||
|
{
|
||
|
// uart_send_str("Write Op Failed.\r\n");
|
||
|
retval = E_TIMEOUT;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//Establish correct shift value
|
||
|
shift = 0;
|
||
|
while ((gNorInfo.busWidth >> shift) > 1)
|
||
|
shift++;
|
||
|
|
||
|
// Write Length (either numBytes or numBytes/2)
|
||
|
flash_write_cmd(startAddress, 0, (numBytes >> shift) - 1);
|
||
|
|
||
|
// Write buffer length
|
||
|
//flash_write_data(startAddress, (length - 1));
|
||
|
|
||
|
// Write buffer data
|
||
|
flash_write_databuffer(&address,(void*)data,numBytes);
|
||
|
|
||
|
// Send write buffer confirm command
|
||
|
flash_write_cmd(startAddress,0,INTEL_WRT_BUF_CONF_CMD);
|
||
|
|
||
|
// Check status
|
||
|
Intel_Wait_For_Status_Complete();
|
||
|
// Verify program was successful
|
||
|
|
||
|
//if ( flash_read_uint8(gNorInfo.flashBase,0) & BIT4 )
|
||
|
if ( flash_issetsome(gNorInfo.flashBase, 0, BIT4) )
|
||
|
{
|
||
|
#ifdef NOR_DEBUG
|
||
|
log_info("Write Buffer Op Failed.");
|
||
|
#endif
|
||
|
retval = E_FAIL;
|
||
|
}
|
||
|
|
||
|
// Put back into Read Array mode.
|
||
|
Intel_Soft_Reset_Flash();
|
||
|
}
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
// -------------------- End of Intel specific commands ----------------------
|
||
|
|
||
|
|
||
|
// -------------------- Begin of AMD specific commands -----------------------
|
||
|
// Identify the Manufacturer and Device ID
|
||
|
uint32_t AMD_ID( uint32_t baseAddress )
|
||
|
{
|
||
|
// Exit back to read array mode
|
||
|
AMD_Soft_Reset_Flash();
|
||
|
|
||
|
// Write ID commands
|
||
|
AMD_Prefix_Commands();
|
||
|
flash_write_cmd(baseAddress, AMD_CMD2_ADDR, AMD_ID_CMD);
|
||
|
|
||
|
// Read manufacturer's ID
|
||
|
gNorInfo.manfID = (enum flash_manufacturer_id_t) flash_read_data(baseAddress, AMD_MANFID_ADDR);
|
||
|
|
||
|
// Read device ID
|
||
|
gNorInfo.devID1 = (uint16_t) flash_read_data(baseAddress, AMD_DEVID_ADDR0);
|
||
|
|
||
|
// Read additional ID bytes if needed
|
||
|
if ( (gNorInfo.devID1 & 0xFF ) == AMD_ID_MULTI )
|
||
|
gNorInfo.devID2 = flash_read_CFI_bytes(baseAddress, AMD_DEVID_ADDR1, 2).w;
|
||
|
else
|
||
|
gNorInfo.devID2 = 0x0000;
|
||
|
|
||
|
// Exit back to read array mode
|
||
|
AMD_Soft_Reset_Flash();
|
||
|
|
||
|
return E_PASS;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void AMD_Soft_Reset_Flash()
|
||
|
{
|
||
|
// Reset Flash to be in Read Array Mode
|
||
|
flash_write_cmd(gNorInfo.flashBase,AMD_CMD2_ADDR,AMD_RESET);
|
||
|
}
|
||
|
|
||
|
// AMD Prefix Commands
|
||
|
void AMD_Prefix_Commands()
|
||
|
{
|
||
|
flash_write_cmd(gNorInfo.flashBase, AMD_CMD0_ADDR, AMD_CMD0);
|
||
|
flash_write_cmd(gNorInfo.flashBase, AMD_CMD1_ADDR, AMD_CMD1);
|
||
|
}
|
||
|
|
||
|
// Erase Block
|
||
|
uint32_t AMD_Erase(uint32_t blkAddr)
|
||
|
{
|
||
|
uint32_t retval = E_PASS;
|
||
|
|
||
|
// Send commands
|
||
|
AMD_Prefix_Commands();
|
||
|
flash_write_cmd(gNorInfo.flashBase, AMD_CMD2_ADDR, AMD_BLK_ERASE_SETUP_CMD);
|
||
|
AMD_Prefix_Commands();
|
||
|
flash_write_cmd(blkAddr, AMD_CMD2_ADDR, AMD_BLK_ERASE_CMD);
|
||
|
|
||
|
// Poll DQ7 and DQ15 for status
|
||
|
while ( !flash_issetall(blkAddr, 0, BIT7) );
|
||
|
|
||
|
// Check data
|
||
|
if ( !flash_data_isequal(blkAddr, 0, AMD_BLK_ERASE_DONE) )
|
||
|
retval = E_FAIL;
|
||
|
|
||
|
/* Flash Mode: Read Array */
|
||
|
AMD_Soft_Reset_Flash();
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
// AMD Flash Write
|
||
|
uint32_t
|
||
|
AMD_Write(uint32_t address, volatile uint32_t data)
|
||
|
{
|
||
|
uint32_t retval = E_PASS;
|
||
|
|
||
|
// Send Commands
|
||
|
AMD_Prefix_Commands();
|
||
|
flash_write_cmd(gNorInfo.flashBase, AMD_CMD2_ADDR, AMD_PROG_CMD);
|
||
|
flash_write_data(address, data);
|
||
|
|
||
|
// Wait for ready.
|
||
|
while(TRUE) {
|
||
|
if ((flash_read_data(address, 0 ) & (BIT7 | BIT15) ) == (data & (BIT7 | BIT15))) {
|
||
|
break;
|
||
|
} else {
|
||
|
if (flash_issetall(address, 0, BIT5)) {
|
||
|
if ((flash_read_data(address, 0 ) & (BIT7 | BIT15) ) != (data & (BIT7 | BIT15))) {
|
||
|
log_info("Timeout occurred.");
|
||
|
retval = E_FAIL;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Return Read Mode
|
||
|
AMD_Soft_Reset_Flash();
|
||
|
|
||
|
// Verify the data.
|
||
|
if ((retval == E_PASS) && (flash_read_data(address, 0) != data))
|
||
|
retval = E_FAIL;
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
// AMD flash buffered write
|
||
|
uint32_t
|
||
|
AMD_BufferWrite(uint32_t address, volatile uint8_t data[], uint32_t numBytes)
|
||
|
{
|
||
|
uint32_t startAddress = address;
|
||
|
uint32_t blkAddress, blkSize;
|
||
|
uint32_t data_temp;
|
||
|
uint32_t retval = E_PASS;
|
||
|
uint32_t shift;
|
||
|
|
||
|
// Get block base address and size
|
||
|
DiscoverBlockInfo(address, &blkSize, &blkAddress);
|
||
|
|
||
|
// Write the Write Buffer Load command
|
||
|
AMD_Prefix_Commands();
|
||
|
flash_write_cmd(blkAddress, 0, AMD_WRT_BUF_LOAD_CMD);
|
||
|
|
||
|
//Establish correct shift value
|
||
|
shift = 0;
|
||
|
while ((gNorInfo.busWidth >> shift) > 1)
|
||
|
shift++;
|
||
|
|
||
|
// Write Length (either numBytes or numBytes/2)
|
||
|
flash_write_cmd(blkAddress, 0, (numBytes >> shift) - 1);
|
||
|
|
||
|
// Write Data
|
||
|
flash_write_databuffer(&address,(void*)data, numBytes);
|
||
|
|
||
|
// Program Buffer to Flash Confirm Write
|
||
|
flash_write_cmd(blkAddress, 0, AMD_WRT_BUF_CONF_CMD);
|
||
|
|
||
|
// Read last data item
|
||
|
data_temp = flash_read_data((uint32_t) (data + (address - startAddress)), 0);
|
||
|
|
||
|
while (true) {
|
||
|
//temp1 = flash_read_data(address, 0 );
|
||
|
if ((flash_read_data(address, 0 ) & (BIT7 | BIT15)) == (data_temp & (BIT7 | BIT15))) {
|
||
|
break;
|
||
|
} else {
|
||
|
// Timeout has occurred
|
||
|
if(flash_issetall(address, 0, BIT5)) {
|
||
|
if ((flash_read_data(address, 0 ) & (BIT7 | BIT15)) != (data_temp & (BIT7 | BIT15))) {
|
||
|
log_info("Timeout occurred.");
|
||
|
retval = E_FAIL;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
// Abort has occurred
|
||
|
if (flash_issetall(address, 0, BIT1)) {
|
||
|
if ((flash_read_data(address, 0 ) & (BIT7 | BIT15)) != (data_temp & (BIT7 | BIT15))) {
|
||
|
log_info("Abort occurred.");
|
||
|
retval = E_FAIL;
|
||
|
AMD_Write_Buf_Abort_Reset_Flash ();
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Put chip back into read array mode.
|
||
|
AMD_Soft_Reset_Flash();
|
||
|
if (retval == E_PASS)
|
||
|
retval = flash_verify_databuffer(startAddress,(void*)data, numBytes);
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
// AMD Write Buf Abort Reset Flash
|
||
|
void
|
||
|
AMD_Write_Buf_Abort_Reset_Flash(void)
|
||
|
{
|
||
|
// Reset Flash to be in Read Array Mode
|
||
|
AMD_Prefix_Commands();
|
||
|
AMD_Soft_Reset_Flash();
|
||
|
}
|
||
|
|
||
|
// Get info on block address and sizes
|
||
|
uint32_t
|
||
|
DiscoverBlockInfo(uint32_t address,uint32_t* blockSize, uint32_t* blockAddr)
|
||
|
{
|
||
|
int32_t i;
|
||
|
uint32_t currRegionAddr, nextRegionAddr;
|
||
|
|
||
|
currRegionAddr = (uint32_t) gNorInfo.flashBase;
|
||
|
if ((address < currRegionAddr) || (address >= (currRegionAddr+gNorInfo.flashSize))) {
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < (gNorInfo.numberRegions); i++) {
|
||
|
nextRegionAddr = currRegionAddr + (gNorInfo.blockSize[i] * gNorInfo.numberBlocks[i]);
|
||
|
if ( (currRegionAddr <= address) && (nextRegionAddr > address) ) {
|
||
|
*blockSize = gNorInfo.blockSize[i];
|
||
|
*blockAddr = address & (~((*blockSize) - 1));
|
||
|
break;
|
||
|
}
|
||
|
currRegionAddr = nextRegionAddr;
|
||
|
}
|
||
|
|
||
|
return E_PASS;
|
||
|
}
|
||
|
|
||
|
uint32_t
|
||
|
NOR_GlobalErase(void)
|
||
|
{
|
||
|
return NOR_Erase((volatile uint32_t) gNorInfo.flashBase, (volatile uint32_t) gNorInfo.flashSize);
|
||
|
}
|
||
|
|
||
|
|
||
|
uint32_t
|
||
|
nor_get_flashbase(void)
|
||
|
{
|
||
|
return gNorInfo.flashBase;
|
||
|
}
|
||
|
|
||
|
uint32_t
|
||
|
NOR_Erase(volatile uint32_t start_address, volatile uint32_t size)
|
||
|
{
|
||
|
volatile uint32_t addr = start_address;
|
||
|
volatile uint32_t range = start_address + size;
|
||
|
uint32_t blockSize, blockAddr;
|
||
|
|
||
|
log_info("Erasing the NOR Flash");
|
||
|
|
||
|
while (addr < range) {
|
||
|
if (DiscoverBlockInfo(addr, &blockSize, &blockAddr) != E_PASS) {
|
||
|
uart_send_str("Address out of range");
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
//Increment to the next block
|
||
|
if ( (*Flash_Erase)(blockAddr) != E_PASS) {
|
||
|
uart_send_str("Erase failure at block address ");
|
||
|
uart_send_hexnum(blockAddr, 8);
|
||
|
uart_send_lf();
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
addr = blockAddr + blockSize;
|
||
|
|
||
|
// Show status messages
|
||
|
uart_send_str("Erased through ");
|
||
|
uart_send_hexnum(addr, 8);
|
||
|
uart_send_lf();
|
||
|
}
|
||
|
|
||
|
log_info("Erase Completed");
|
||
|
|
||
|
return(E_PASS);
|
||
|
}
|
||
|
|
||
|
// NOR_WriteBytes
|
||
|
uint32_t
|
||
|
NOR_WriteBytes(uint32_t writeAddress, uint32_t numBytes, uint32_t readAddress)
|
||
|
{
|
||
|
uint32_t blockSize, blockAddr;
|
||
|
int i;
|
||
|
uint32_t retval = E_PASS;
|
||
|
|
||
|
log_info("Writing the NOR Flash");
|
||
|
|
||
|
// Make numBytes even if needed
|
||
|
if (numBytes & 0x00000001)
|
||
|
numBytes++;
|
||
|
|
||
|
if (DiscoverBlockInfo(writeAddress, &blockSize, &blockAddr) != E_PASS) {
|
||
|
uart_send_str("Address out of range");
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
while (numBytes > 0) {
|
||
|
if ( (numBytes < gNorInfo.bufferSize) || (writeAddress & (gNorInfo.bufferSize-1) )) {
|
||
|
if ((*Flash_Write)(writeAddress, flash_read_data(readAddress,0) ) != E_PASS) {
|
||
|
log_info("\r\nNormal Write Failed.");
|
||
|
retval = E_FAIL;
|
||
|
} else {
|
||
|
numBytes -= gNorInfo.busWidth;
|
||
|
writeAddress += gNorInfo.busWidth;
|
||
|
readAddress += gNorInfo.busWidth;
|
||
|
}
|
||
|
} else {
|
||
|
// Try to use buffered writes
|
||
|
if ((*Flash_BufferWrite)(writeAddress, (volatile uint8_t *)readAddress, gNorInfo.bufferSize) == E_PASS) {
|
||
|
numBytes -= gNorInfo.bufferSize;
|
||
|
writeAddress += gNorInfo.bufferSize;
|
||
|
readAddress += gNorInfo.bufferSize;
|
||
|
}
|
||
|
else {
|
||
|
// Try normal writes as a backup
|
||
|
for (i = 0; i<(gNorInfo.bufferSize>>1); i++) {
|
||
|
if ((*Flash_Write)(writeAddress, flash_read_data(readAddress,0) ) != E_PASS) {
|
||
|
log_info("\r\nNormal write also failed");
|
||
|
retval = E_FAIL;
|
||
|
break;
|
||
|
} else {
|
||
|
numBytes -= gNorInfo.busWidth;
|
||
|
writeAddress += gNorInfo.busWidth;
|
||
|
readAddress += gNorInfo.busWidth;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Output status info on the write operation
|
||
|
if (retval == E_PASS) {
|
||
|
if ( ((writeAddress & (~((blockSize>>4)-1))) == writeAddress) || (numBytes == 0) ) {
|
||
|
uart_send_str("NOR Write OK through ");
|
||
|
uart_send_hexnum(writeAddress, 8);
|
||
|
uart_send_lf();
|
||
|
|
||
|
if (DiscoverBlockInfo(writeAddress, &blockSize, &blockAddr) != E_PASS) {
|
||
|
uart_send_str("Address out of range");
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
log_info("NOR Write Failed... Aborting");
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return retval;
|
||
|
}
|