blob: cf899989ea611c848d7fb399bb3bc8e0370777e9 [file] [log] [blame]
/*******************************************************************************
Copyright (C) Marvell International Ltd. and its affiliates
This software file (the "File") is owned and distributed by Marvell
International Ltd. and/or its affiliates ("Marvell") under the following
alternative licensing terms. Once you have made an election to distribute the
File under one of the following license alternatives, please (i) delete this
introductory statement regarding license alternatives, (ii) delete the two
license alternatives that you have not elected to use and (iii) preserve the
Marvell copyright notice above.
********************************************************************************
Marvell Commercial License Option
If you received this File from Marvell and you have entered into a commercial
license agreement (a "Commercial License") with Marvell, the File is licensed
to you under the terms of the applicable Commercial License.
********************************************************************************
Marvell GPL License Option
If you received this File from Marvell, you may opt to use, redistribute and/or
modify this File in accordance with the terms and conditions of the General
Public License Version 2, June 1991 (the "GPL License"), a copy of which is
available along with the File in the license.txt file or by writing to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
DISCLAIMED. The GPL License provides additional details about this warranty
disclaimer.
********************************************************************************
Marvell BSD License Option
If you received this File from Marvell, you may opt to use, redistribute and/or
modify this File under the following licensing terms.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Marvell nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include "mvFlash.h"
#ifdef MV_DEBUG
#define DB(x) x
#else
#define DB(x)
#endif
#define LAST_FLASH 0xFFFFFFFF
/* When inserting a bottom/top flash number of sectors should be the number */
/* of all sector including the "fragmented" sectors. */
/* */
/* Size of the flash must be as spesified in Spec, in case there are 2 dev */
/* in a row the driver will recognize it according to bus and dev width. */
/* */
/* In case of using Bottom flash it should look like this: */
/* MV_U32 IntelSecFrag[]= {_8K, _8K, _8K, _8K, _8K, _8K, _8K, _8K}; */
/* FLASH_STRUCT supFlashAry[]= */
/* { */
/* { */
/* INTEL_MANUF, flash Vendor */
/* INTEL_FID_28F640J3A, flash ID */
/* _4M, flash size */
/* 71, flash secotor number */
/* BOTTOM, flash sector structure (top, bottom, regular) */
/* 8, Number of sector fragments */
/* IntelSecFrag, pointer to sector size fragment list */
/* MV_FALSE Support of HW protection */
/* }, */
/* ....... */
/* } */
/* */
MV_U32 IntelSecFrag[] = { _32K, _32K, _32K, _32K };
FLASH_STRUCT supFlashAry[] = {
/* flashVen flashId size #sec secType #Frag pFragList HWprot HwWrBuff */
{INTEL_MANUF, INTEL_FID_28F256P30B, _32M, 259, BOTTOM, 4, IntelSecFrag, MV_TRUE, 64}
,
{INTEL_MANUF, INTEL_FID_28F640J3A, _8M, 64, REGULAR, 0, NULL, MV_TRUE, 32}
,
{INTEL_MANUF, INTEL_FID_28F128J3A, _16M, 128, REGULAR, 0, NULL, MV_TRUE, 32}
,
{SST_MANUF, SST_39VF_020, _256K, 64, REGULAR, 0, NULL, MV_FALSE, 0}
,
{AMD_MANUF, AMD_FID_LV040B, _512K, 8, REGULAR, 0, NULL, MV_FALSE, 0}
,
{STM_MANUF, STM_FID_29W040B, _512K, 8, REGULAR, 0, NULL, MV_FALSE, 0}
,
{AMD_MANUF, AMD_S29GL128N, _16M, 128, REGULAR, 0, NULL, MV_FALSE}
,
{MX_MANUF, AMD_FID_MIRROR, _16M, 256, REGULAR, 0, NULL, MV_FALSE}
,
{STM_MANUF, AMD_FID_MIRROR, _16M, 256, REGULAR, 0, NULL, MV_FALSE}
,
{LAST_FLASH, LAST_FLASH, 0, 0, REGULAR, 0, NULL, MV_FALSE, 0}
};
static MV_STATUS flashReset(MV_FLASH_INFO *pFlash);
static MV_STATUS flashStructGet(MV_FLASH_INFO *pFlash, MV_U32 manu, MV_U32 id);
static MV_STATUS flashSecsInit(MV_FLASH_INFO *pFlash);
static MV_BOOL flashSecLockGet(MV_FLASH_INFO *pBlock, MV_U32 secNum);
static MV_STATUS mvFlashProg(MV_FLASH_INFO *pFlash, MV_U32 offset, MV_U32 data);
static MV_U32 flashGetHwBuffSize(MV_FLASH_INFO *pFlash);
static MV_STATUS flashHwBufferProg(MV_FLASH_INFO *pFlash, MV_U32 offset, MV_U32 byteCount, MV_U8 *pData);
/*******************************************************************************
* mvFlashInit - Initialize a flash descriptor structure.
*
* DESCRIPTION:
* This function intialize flash info struct with specified flash
* parameters. This structure is used to identify the target flash the
* function refers to. This allow the use of the same API for multiple
* flash devices.
*
*
* INPUT:
* pFlash->baseAddr - Flash base address.
* pFlash->busWidth - Flash bus width (8, 16, 32 bit).
* pFlash->devWidth - Flash device width (8 or 16 bit).
*
* OUTPUT:
* pFlash - Flash identifier structure.
*
* RETURN:
* 32bit describing flash size.
* In case of any error, it returns 0.
*
*******************************************************************************/
MV_U32 mvFlashInit(MV_FLASH_INFO *pFlash)
{
MV_U32 manu = 0, id = 0;
if (NULL == pFlash)
return 0;
DB(mvOsOutput("Flash: mvFlashInit base 0x%x devW %d busW %d\n",
pFlash->baseAddr, pFlash->devWidth, pFlash->busWidth));
/* must init first sector base, before calling flashCmdSet */
pFlash->sector[0].baseOffs = 0;
/* reset flash 0xf0(AMD) 0xff (Intel) */
flashCmdSet(pFlash, 0, 0, 0xf0);
flashCmdSet(pFlash, 0, 0, 0xff);
/* Write auto select command: read Manufacturer ID */
/* AMD seq is: 0x555 0xAA -> 0x2AA 0x55 -> 0x555 0x90 */
/* INTEL seq is dc 0x90 */
flashCmdSet(pFlash, 0x555, 0, 0xAA);
flashCmdSet(pFlash, 0x2AA, 0, 0x55);
flashCmdSet(pFlash, 0x555, 0, 0x90);
/* Write auto select command: read Manufacturer ID */
/* SST seq is: 0x5555 0xAA -> 0x2AAA 0x55 -> 0x5555 0x90 */
flashCmdSet(pFlash, 0x5555, 0, 0xAA);
flashCmdSet(pFlash, 0x2AAA, 0, 0x55);
flashCmdSet(pFlash, 0x5555, 0, 0x90);
DB(mvOsOutput("Flash: mvFlashInit base 0x%x devW %d busW %d\n",
pFlash->baseAddr, pFlash->devWidth, pFlash->busWidth));
/* get flash Manufactor and Id */
manu = flashBusWidthRd(pFlash, mvFlashBaseAddrGet(pFlash));
DB(mvOsOutput("Flash: mvFlashInit base 0x%x devW %d busW %d\n",
pFlash->baseAddr, pFlash->devWidth, pFlash->busWidth));
/* Some Micron flashes don't use A0 address for Identifier and
Lock information, so in order to read Identifier and lock information
properly we will do the following workarround:
If our device width is 1 (x8) then if address 0 equal to address 1
and address 2 equal to address 3 ,then we have this case (A0 is not used)
and then we will issue the address without A0 to read the Identifier and
lock information properly */
DB(mvOsOutput("Flash: mvFlashInit base 0x%x devW %d busW %d\n",
pFlash->baseAddr, pFlash->devWidth, pFlash->busWidth));
if ((pFlash->devWidth == 1) &&
((flashBusWidthRd(pFlash, flashAddrExt(pFlash, 0, 0)) ==
flashBusWidthRd(pFlash, flashAddrExt(pFlash, 1, 0))) &&
(flashBusWidthRd(pFlash, flashAddrExt(pFlash, 2, 0)) ==
flashBusWidthRd(pFlash, flashAddrExt(pFlash, 3, 0))))) {
id = flashBusWidthRd(pFlash, flashAddrExt(pFlash, 2, 0));
} else
id = flashBusWidthRd(pFlash, flashAddrExt(pFlash, 1, 0));
/* check if this flash is Supported, and Init the pFlash flash feild */
if (MV_OK != flashStructGet(pFlash, manu, id)) {
mvOsPrintf("%s: Flash ISN'T supported: manufactor-0x%x, id-0x%x\n", __func__, manu, id);
return 0;
}
DB(mvOsOutput("Flash: mvFlashInit base 0x%x devW %d busW %d\n",
pFlash->baseAddr, pFlash->devWidth, pFlash->busWidth));
/* Init pFlash sectors */
if (MV_OK != flashSecsInit(pFlash)) {
mvOsPrintf("Flash: ERROR mvFlashInit flashSecsInit failed \n");
return 0;
}
DB(mvOsOutput("Flash: mvFlashInit base 0x%x devW %d busW %d\n",
pFlash->baseAddr, pFlash->devWidth, pFlash->busWidth));
/* print all flash information */
DB(flashPrint(pFlash));
/* reset the Flash */
flashReset(pFlash);
DB(mvOsOutput("Flash: mvFlashInit base 0x%x devW %d busW %d\n",
pFlash->baseAddr, pFlash->devWidth, pFlash->busWidth));
return mvFlashSizeGet(pFlash);
}
/* erase */
/*******************************************************************************
* mvFlashErase - Completly Erase a flash.
*
* DESCRIPTION:
* This function completly erase the given flash, by erasing all the
* flash sectors one by one (Currently there is no support for HW
* flash erase).
*
* INPUT:
* pFlash - Flash identifier structure.
*
* OUTPUT:
* None.
*
* RETURN:
* MV_BAD_PARAM if pFlash is NULL,
* MV_OK if erased completed successfully,
* MV_FAIL otherwise.
*
*******************************************************************************/
MV_STATUS mvFlashErase(MV_FLASH_INFO *pFlash)
{
MV_U32 i;
if (NULL == pFlash)
return MV_BAD_PARAM;
DB(mvOsPrintf("Flash: mvFlashErase \n"));
/* erase all sectors in the flash one by one */
for (i = 0; i < mvFlashNumOfSecsGet(pFlash); i++) {
if (MV_OK != mvFlashSecErase(pFlash, i))
return MV_FAIL;
}
return MV_OK;
}
/*******************************************************************************
* flashIsSecErased - Check if a given Sector is erased.
*
* DESCRIPTION:
* Go over the sector and check if its entire data is 0xFF.
* INPUT:
* secNum - sector Number.
* pFlash - flash information.
*
* OUTPUT:
* None
*
* RETURN:
* MV_BAD_PARAM if one of the inputs values is illegal,
* MV_TRUE if sector is already erased,
* MV_FALSE otherwise.
*
*******************************************************************************/
MV_BOOL flashIsSecErased(MV_FLASH_INFO *pFlash, MV_U32 secNum)
{
MV_U32 i;
DB(mvOsPrintf("Flash: flashIsSecErased. \n"));
if ((NULL == pFlash) || (secNum >= mvFlashNumOfSecsGet(pFlash)))
return MV_BAD_PARAM;
/* reset the flash */
flashReset(pFlash);
/* go over the sector */
for (i = mvFlashSecOffsGet(pFlash, secNum);
i < mvFlashSecOffsGet(pFlash, secNum) + mvFlashSecSizeGet(pFlash, secNum); i += 4) {
if (mvFlash32Rd(pFlash, i) != FLASH_WR_ERASED) {
DB(mvOsPrintf("Flash: Not erased addr %x is %x \n", i, mvFlash32Rd(pFlash, i)));
return MV_FALSE;
}
}
return MV_TRUE;
}
/*******************************************************************************
* mvFlashSecErase - Erase a flash sector.
*
* DESCRIPTION:
* This function checks if the sector isn't protected and if the sector
* isn't already erased.
*
* INPUT:
* pFlash - Flash identifier structure.
* sectorNum - secrot number to erase.
*
* OUTPUT:
* None.
*
* RETURN:
* MV_BAD_PARAM if one of the inputs values is illegal,
* MV_OK if erased completed successfully,
* MV_FAIL otherwise (e.g. sector protected).
*
*******************************************************************************/
MV_STATUS mvFlashSecErase(MV_FLASH_INFO *pFlash, MV_U32 sectorNum)
{
MV_U32 status;
DB(mvOsPrintf("Flash: mvFlashSecErase \n"));
/* check parametrs values */
if ((NULL == pFlash) || (sectorNum >= mvFlashNumOfSecsGet(pFlash)))
return MV_BAD_PARAM;
/* check if sector is locked */
if (MV_TRUE == mvFlashSecLockGet(pFlash, sectorNum)) {
mvOsPrintf("Flash: ERROR mvFlashSecErase protected sector.\n");
return MV_FAIL;
}
/* check if already erased */
if (MV_TRUE == flashIsSecErased(pFlash, sectorNum)) {
DB(mvOsPrintf("Flash: FlashSecErase sector already erased \n"));
return MV_OK;
}
/* erase sector using the Flash Ven Alg. */
switch (mvFlashVenIdGet(pFlash)) {
case INTEL_MANUF: /* INTEL/MT */
status = intelFlashSecErase(pFlash, sectorNum);
break;
case AMD_MANUF:
case STM_MANUF:
case SST_MANUF:
case MX_MANUF:
status = amdFlashSecErase(pFlash, sectorNum);
break;
default:
mvOsPrintf("Flash: ERROR mvFlashErase. unsupported flash vendor\n");
return MV_FAIL;
}
/* reset the flash */
flashReset(pFlash);
return status;
}
/* write */
/*******************************************************************************
* mvFlash32Wr - Write 32bit (word) to flash.
*
* DESCRIPTION:
* This function writes 32bit data to a given flash offset.
*
* INPUT:
* pFlash - Flash identifier structure (flash cockie).
* offset - Offset from flash base address.
* data - 32bit data to be written to flash.
*
* OUTPUT:
* None.
*
* RETURN:
* MV_BAD_PARAM if one of the inputs values is illegal,
* MV_OK if write completed successfully,
* MV_FAIL otherwise (e.g. sector protected).
*
*******************************************************************************/
MV_STATUS mvFlash32Wr(MV_FLASH_INFO *pFlash, MV_U32 offset, MV_U32 data)
{
MV_U32 i, status = MV_OK, temp, secNum;
DB(mvOsPrintf("Flash: mvFlash32Wr offset %x data %x \n", offset, data));
/* check that the offset is aligned to 32 bit */
if ((NULL == pFlash) || (offset % 4))
return MV_BAD_PARAM;
secNum = mvFlashInWhichSec(pFlash, offset);
DB(mvOsPrintf("Flash: mvFlashProg \n"));
/* check if offset is in flash range */
if (secNum >= mvFlashNumOfSecsGet(pFlash)) {
DB(mvOsPrintf("Flash: mvFlashProg offset out of flash range \n"));
return MV_BAD_PARAM;
}
/* check if sector is locked */
if (MV_TRUE == mvFlashSecLockGet(pFlash, secNum)) {
mvOsPrintf("Flash: ERROR mvFlashProg protected sector.\n");
return MV_FAIL;
}
/* check if offset is erased enough */
if ((mvFlash32Rd(pFlash, offset) & data) != data) {
mvOsPrintf("%s ERROR: offset 0x%x (sector %d) isn't erased !!!.\n", __func__, offset, secNum);
return MV_FAIL;
}
/* bus width is 32 bit */
if (mvFlashBusWidthGet(pFlash) == 4) {
data = MV_32BIT_BE(data);
status = mvFlashProg(pFlash, offset, data);
if (status != MV_OK)
mvOsPrintf("%s ERROR: mvFlashProg() status %x \n", __func__, status);
}
/* bus width is 16 bit */
else if (mvFlashBusWidthGet(pFlash) == 2) {
for (i = 0; i < 2; i++) {
/* 0x44556677 -> [44][55][66][77] */
temp = MV_16BIT_BE(((data >> (16 * (1 - i))) & FLASH_MASK_16BIT));
if (MV_OK != mvFlashProg(pFlash, offset + (i * 2), temp)) {
status = MV_FAIL;
break;
}
}
}
/* bus width is 8 bit */
else if (mvFlashBusWidthGet(pFlash) == 1) {
for (i = 0; i < 4; i++) {
/* 0x44556677 -> [44][55][66][77] */
temp = ((data >> (8 * (3 - i))) & FLASH_MASK_8BIT);
if (MV_OK != mvFlashProg(pFlash, offset + i, temp))
status = MV_FAIL;
}
}
/* bus width isn't 8/16/32 */
else {
DB(mvOsPrintf("Flash: mvFlashWordWr no support for for bus width %d \n", mvFlashBusWidthGet(pFlash)));
status = MV_FAIL;
}
/* reset the flash */
flashReset(pFlash);
if (status != MV_OK)
mvOsPrintf("mvFlash32Wr: ERROR #### status %x \n", status);
return status;
}
/*******************************************************************************
* mvFlash16Wr - Write 16bit (short) to flash.
*
* DESCRIPTION:
* This function writes 16bit data to a given flash offset.
*
* INPUT:
* pFlash - Flash identifier structure (flash cockie).
* offset - Offset from flash base address.
* sdata - 16bit data to be written to flash.
*
* OUTPUT:
* None.
*
* RETURN:
* MV_BAD_PARAM if one of the inputs values is illegal,
* MV_OK if write completed successfully,
* MV_FAIL otherwise (e.g. sector protected).
*
*******************************************************************************/
MV_STATUS mvFlash16Wr(MV_FLASH_INFO *pFlash, MV_U32 offset, MV_U16 sdata)
{
MV_U32 temp, shiftSdata;
DB(mvOsPrintf("Flash: mvFlash16Wr\n"));
/* check that the offset is aligned to 16 bit */
if ((NULL == pFlash) || (offset % 2))
return MV_BAD_PARAM;
/* sdata shift in 32 bit aligned. i.e. */
/* wr 0x9922 to 0xf4000002 -> 0xf4000000: qqqq9999 */
shiftSdata = (1 - ((offset & 0x2) >> 1)) * 16;
/* read 32 bit aligned */
temp = mvFlash32Rd(pFlash, MV_ALIGN_DOWN(offset, 4)); /* aligned to 32 bit */
/* write 16 bit sdata into 32 bit */
temp &= temp & ~(0xffff << shiftSdata);
temp |= sdata << shiftSdata;
/* write 32 bit */
return mvFlash32Wr(pFlash, MV_ALIGN_DOWN(offset, 4), temp);
}
/*******************************************************************************
* mvFlash8Wr - Write 8bit (char) to flash.
*
* DESCRIPTION:
* This function writes 8bit data to a given flash offset.
*
* INPUT:
* pFlash - Flash identifier structure (flash cockie).
* offset - Offset from flash base address.
* cdata - 8bit data to be written to flash.
*
* OUTPUT:
* None.
*
* RETURN:
* MV_BAD_PARAM if one of the inputs values is illegal,
* MV_OK if write completed successfully,
* MV_FAIL otherwise (e.g. sector protected).
*
*******************************************************************************/
MV_STATUS mvFlash8Wr(MV_FLASH_INFO *pFlash, MV_U32 offset, MV_U8 cdata)
{
MV_U32 temp, shiftCdata;
DB(mvOsPrintf("Flash: mvFlash8Wr\n"));
/* check that the offset is aligned to 16 bit */
if (NULL == pFlash)
return MV_BAD_PARAM;
/* cdata shift in 32 bit aligned. i.e. */
/* wr 0x99 to 0xf4000003 -> 0xf4000000: qqqqqq99 */
shiftCdata = (3 - (offset & 0x3)) * 8;
/* read 32 bit aligned */
temp = mvFlash32Rd(pFlash, MV_ALIGN_DOWN(offset, 4)); /* aligned to 32 bit */
/* write 16 bit sdata into 32 bit */
temp &= temp & ~(0xff << shiftCdata);
temp |= cdata << shiftCdata;
/* write 32 bit */
return mvFlash32Wr(pFlash, MV_ALIGN_DOWN(offset, 4), temp);
}
/*******************************************************************************
* mvFlashBlockUnbufWr - Write a block to flash. Unbuffered
*
* DESCRIPTION:
* This function writes a block of data to a given flash offset.
*
* INPUT:
* pFlash - Flash identifier structure (flash cockie).
* offset - Offset from flash base address.
* blockSize - Size of block in bytes.
* pBlock - Pointer to data block to be written to flash.
*
* OUTPUT:
* None.
*
* RETURN:
* The number of bytes written to flash.
*
*******************************************************************************/
MV_U32 mvFlashBlockUnbufWr(MV_FLASH_INFO *pFlash, MV_U32 offset, MV_U32 blockSize, MV_U8 *pBlock)
{
MV_U32 i, j, temp = 0;
DB(mvOsPrintf("Flash: mvFlashBlockWr\n"));
if (NULL == pFlash)
return 0;
#ifndef CONFIG_MARVELL
if (NULL == pBlock)
return 0;
#endif
for (i = 0; i < blockSize;) {
if (((offset + i) % 4) || ((blockSize - i) < 4)) { /* unaligned to 32 bit */
DB(mvOsPrintf("Flash: mvFlashBlockWr not aligned\n"));
if (MV_OK != mvFlash8Wr(pFlash, offset + i, pBlock[i])) {
DB(mvOsPrintf("Flash: mvFlashBlockWr failed in writing char\n"));
return i;
}
i++;
} else { /* aligned to 32 bit */
temp = 0;
/* to make sure we don't write to un aligned address */
for (j = 0; j < 4; j++) {
/* [44][55][66][77] -> 0x44556677 */
temp |= (pBlock[i + j] & FLASH_MASK_8BIT) << (8 * (3 - j));
}
if (MV_OK != mvFlash32Wr(pFlash, offset + i, temp)) {
DB(mvOsPrintf("Flash: mvFlashBlockWr failed in writing word\n"));
return i;
}
i += 4;
}
}
return i;
}
/*******************************************************************************
* mvFlashBlockWr - Write a block to flash.
*
* DESCRIPTION:
* This function writes a block of data to a given flash offset.
*
* INPUT:
* pFlash - Flash identifier structure (flash cockie).
* offset - Offset from flash base address.
* blockSize - Size of block in bytes.
* pBlock - Pointer to data block to be written to flash.
*
* OUTPUT:
* None.
*
* RETURN:
* The number of bytes written to flash.
*
*******************************************************************************/
MV_U32 mvFlashBlockWr(MV_FLASH_INFO *pFlash, MV_U32 offset, MV_U32 blockSize, MV_U8 *pBlock)
{
MV_U32 numOfBytesWritten = 0;
MV_U32 secNum; /* lastOffset; */
MV_U32 i;
MV_U32 hwBuffSize, sizeToWrite;
MV_U32 unBufWritten = 0;
MV_U8 *pTmpBlock = NULL;
DB(mvOsPrintf("Flash: mvFlashBlockWr\n"));
if (NULL == pFlash)
return 0;
#ifndef CONFIG_MARVELL
if (NULL == pBlock)
return 0;
#endif
/* check if any of the dest sectors is protected */
/*lastOffset = ((MV_U32)pBlock) + blockSize; */
secNum = mvFlashInWhichSec(pFlash, offset);
do {
if (MV_TRUE == mvFlashSecLockGet(pFlash, secNum)) {
mvOsPrintf("Flash: ERROR mvFlashProg protected sector.\n");
return 0;
}
/* next sec base offset */
i = mvFlashSecOffsGet(pFlash, secNum) + mvFlashSecSizeGet(pFlash, secNum);
secNum++;
} while (i < blockSize);
hwBuffSize = flashGetHwBuffSize(pFlash);
/* if no HW buffer support, then call unbuffer routine */
if (hwBuffSize == 0)
return mvFlashBlockUnbufWr(pFlash, offset, blockSize, pBlock);
flashReset(pFlash);
/* now write unbuffered the unaligned data */
while (((offset % hwBuffSize) || (blockSize < hwBuffSize)) && (blockSize)) {
DB(mvOsPrintf("if I: offset = 0x%x, blockSize= 0x%x\n", offset, blockSize));
if ((blockSize < hwBuffSize) ||
((offset + blockSize) < (offset + (2 * hwBuffSize + (offset / hwBuffSize))))) {
sizeToWrite = blockSize;
} else
sizeToWrite = hwBuffSize - (offset % hwBuffSize);
unBufWritten = mvFlashBlockUnbufWr(pFlash, offset, sizeToWrite, pBlock);
flashReset(pFlash);
blockSize -= unBufWritten;
offset += unBufWritten;
pBlock += unBufWritten;
numOfBytesWritten += unBufWritten;
if (unBufWritten != sizeToWrite)
return numOfBytesWritten;
}
if (blockSize) {
/* now write buffered the aligned data */
sizeToWrite = blockSize - (blockSize % hwBuffSize);
/* Check source addr, in case source is in the FLASH */
/* First copy the data to a temporary container in the SDRAM */
/* and only then copy the data from the SDRAM to the FLASH */
if (((MV_U32) pBlock >= mvFlashBaseAddrGet(pFlash)) &&
((MV_U32) pBlock < (mvFlashBaseAddrGet(pFlash) + mvFlashSizeGet(pFlash)))) {
/* Malloc memory */
pTmpBlock = mvOsMalloc(sizeToWrite);
if (NULL == pTmpBlock) {
DB(mvOsPrintf("mvFlashBlockWr: Malloc temporary container failed\n"));
flashReset(pFlash);
return numOfBytesWritten;
}
/* Copy data to SDRAM */
memcpy(pTmpBlock, pBlock, sizeToWrite);
/* Change source pointer to SDRAM */
} else
/* Source address is not in flash */
pTmpBlock = pBlock;
/* Write data to flash */
if (MV_OK != flashHwBufferProg(pFlash, offset, sizeToWrite, pTmpBlock)) {
DB(mvOsPrintf("mvFlashBlockWr: flashHwBufferProg failed\n"));
flashReset(pFlash);
return numOfBytesWritten;
}
/* Free memory only if used SDRAM container */
if (pTmpBlock != pBlock)
mvOsFree(pTmpBlock);
flashReset(pFlash);
blockSize -= sizeToWrite;
offset += sizeToWrite;
pBlock += sizeToWrite;
numOfBytesWritten += sizeToWrite;
}
/* now write unbuffered the rest */
if (blockSize) {
unBufWritten = mvFlashBlockUnbufWr(pFlash, offset, blockSize, pBlock);
flashReset(pFlash);
blockSize -= unBufWritten;
offset += unBufWritten;
pBlock += unBufWritten;
numOfBytesWritten += unBufWritten;
}
return numOfBytesWritten;
}
/* read */
/*******************************************************************************
* mvFlash32Rd - Read a 32bit (word) from flash.
*
* DESCRIPTION:
* This function reads 32bit (word) data from a given flash offset.
*
* INPUT:
* pFlash - Flash identifier structure (flash cockie).
* offset - Offset from flash base address.
*
* OUTPUT:
* None.
*
* RETURN:
* 32bit data read from flash.
*
*******************************************************************************/
MV_U32 mvFlash32Rd(MV_FLASH_INFO *pFlash, MV_U32 offset)
{
MV_U32 val;
DB(mvOsPrintf("Flash: mvFlashWordRd %x\n", offset));
if (NULL == pFlash)
return 0;
val = MV_FL_32_DATA_READ(offset + mvFlashBaseAddrGet(pFlash));
return MV_32BIT_BE(val);
}
/*******************************************************************************
* mvFlash16Rd - Read a 16bit (short) from flash.
*
* DESCRIPTION:
* This function reads 16bit (short) data from a given flash offset.
*
* INPUT:
* pFlash - Flash identifier structure (flash cockie).
* offset - Offset from flash base address.
*
* OUTPUT:
* None.
*
* RETURN:
* 16bit data read from flash.
*
*******************************************************************************/
MV_U16 mvFlash16Rd(MV_FLASH_INFO *pFlash, MV_U32 offset)
{
MV_U32 val;
if (NULL == pFlash)
return 0;
val = MV_FL_16_DATA_READ(offset + mvFlashBaseAddrGet(pFlash));
return MV_16BIT_BE(val);
}
/*******************************************************************************
* mvFlash8Rd - Read a 8bit (char) from flash.
*
* DESCRIPTION:
* This function reads 8bit (char) data from a given flash offset.
*
* INPUT:
* pFlash - Flash identifier structure (flash cockie).
* offset - Offset from flash base address.
*
* OUTPUT:
* None.
*
* RETURN:
* 8bit data read from flash.
* 0 if pflash is NULL.
*
*******************************************************************************/
MV_U8 mvFlash8Rd(MV_FLASH_INFO *pFlash, MV_U32 offset)
{
if (NULL == pFlash)
return 0;
return MV_FL_8_DATA_READ(offset + mvFlashBaseAddrGet(pFlash));
}
/*******************************************************************************
* mvFlashBlockRd - Read a block of data from flash.
*
* DESCRIPTION:
* This function reads a block of data from given flash offset.
*
* INPUT:
* pFlash - Flash identifier structure (flash cockie).
* offset - Offset from flash base address.
* blockSize - Size of block in bytes.
*
* OUTPUT:
* pBlock - Pointer to data block to be read from flash.
*
* RETURN:
* The number of bytes read from flash.
*
*******************************************************************************/
MV_U32 mvFlashBlockRd(MV_FLASH_INFO *pFlash, MV_U32 offset, MV_U32 blockSize, MV_U8 *pBlock)
{
MV_U32 i, j, temp;
if ((NULL == pFlash) || (NULL == pBlock))
return 0;
for (i = 0; i < blockSize;) {
if (((offset + i) % 4) || ((blockSize - i) < 4)) { /* unaligned to 32 bit */
DB(mvOsPrintf("Flash: mvFlashBlockRd not aligned\n"));
pBlock[i] = mvFlash8Rd(pFlash, offset + i);
i++;
} else { /* aligned to 32 bit */
temp = mvFlash32Rd(pFlash, offset + i);
/* to make sure we don't write to un aligned address */
for (j = 0; j < 4; j++) {
/* 0x44556677 -> [44][55][66][77] */
pBlock[i + j] = (MV_U8) ((temp >> (8 * (3 - j))) & FLASH_MASK_8BIT);
}
i += 4;
}
}
return i;
}
/*******************************************************************************
* mvFlashSecLockSet - Lock/Unlock a Sector in the flash for Writing.
*
* DESCRIPTION:
* Lock/Unlock a Sector in the flash for Writing.
*
* INPUT:
* pFlash - Flash identifier structure.
* secNum - Sector Number.
* enable - MV_TRUE for Lock MV_FALSE for un-lock.
*
* OUTPUT:
* None
*
* RETURN:
* MV_BAD_PARAM if pFlash is NULL,
* MV_OK if operation completed successfully,
* MV_FAIL otherwise
*
*******************************************************************************/
MV_STATUS mvFlashSecLockSet(MV_FLASH_INFO *pFlash, MV_U32 secNum, MV_BOOL enable)
{
MV_U32 status = MV_FAIL;
DB(mvOsPrintf("Flash: mvFlashSecLockSet\n"));
if ((NULL == pFlash) || (secNum > mvFlashNumOfSecsGet(pFlash)))
return MV_BAD_PARAM;
/* check if sector is locked */
if (enable == mvFlashSecLockGet(pFlash, secNum)) {
DB(mvOsPrintf("already un/locked\n"));
return MV_OK;
}
/* SW Lock */
if (mvFlashIsHwLock(pFlash) == MV_FALSE) {
pFlash->sector[secNum].protect = enable;
status = MV_OK;
} else { /* HW Lock */
switch (mvFlashVenIdGet(pFlash)) {
case INTEL_MANUF: /* INTEL / MT */
status = intelFlashSecLock(pFlash, secNum, enable);
break;
default:
mvOsPrintf("%s ERROR: No support for flash vendor id=0x%x\n",
__func__, mvFlashVenIdGet(pFlash));
return MV_FAIL;
}
/* if completed successfully, updated SW structure */
if (MV_OK == status)
pFlash->sector[secNum].protect = enable;
/* reset the flash */
flashReset(pFlash);
}
return status;
}
/********************** statics APIs *******************************************/
/*******************************************************************************
* flashReset - Reset the Flash.
* DESCRIPTION:
* Reset the flash (Inset it into read mode).
*
* INPUT:
* pFlash - flash information.
*
* OUTPUT:
* None
*
* RETURN:
* MV_FAIL - if flash Vendor isn't supported MV_OK otherwise.
*
*******************************************************************************/
static MV_STATUS flashReset(MV_FLASH_INFO *pFlash)
{
switch (mvFlashVenIdGet(pFlash)) {
case INTEL_MANUF: /* INTEL/MT */
intelFlashReset(pFlash);
break;
case AMD_MANUF:
case STM_MANUF:
case SST_MANUF:
amdFlashReset(pFlash);
break;
default:
mvOsPrintf("Flash: ERROR mvFlashErase unsupported flash vendor\n");
return MV_FAIL;
}
return MV_OK;
}
/*******************************************************************************
* flashStructGet - return flash structure information.
*
* DESCRIPTION:
* This function goes over the supported flash list and look for a flash
* with manufactor code = manu and id code = id if found it return the flash
* structure.
*
* INPUT:
* manu - Flash Manufactor.
* id - Flash ID.
*
* OUTPUT:
* pFlash - Flash structure.
*
* RETURN:
* MV_BAD_PARAM if pFlash is NULL,
* MV_OK if manufactor and id were found,
* MV_FAIL otherwise
*
*******************************************************************************/
static MV_STATUS flashStructGet(MV_FLASH_INFO *pFlash, MV_U32 manu, MV_U32 id)
{
MV_U32 i = 0;
if (NULL == pFlash)
return MV_BAD_PARAM;
DB(mvOsPrintf("Flash: flashStructGet manu 0x%x id 0x%x \n", manu, id));
/* while its not the last supported flash */
while ((supFlashAry[i].flashVen != LAST_FLASH) || (supFlashAry[i].flashId != LAST_FLASH)) {
/* if supported flash manufactor and Id equal to manu and id break */
if ((flashDataExt(pFlash, supFlashAry[i].flashVen) == manu) &&
(flashDataExt(pFlash, supFlashAry[i].flashId) == id)) {
DB(mvOsPrintf("Flash: flashStructGet flash is supported.\n"));
pFlash->flashSpec = supFlashAry[i];
return MV_OK;
}
i++;
}
/* manu and id are not supported! */
DB(mvOsPrintf("Flash: flashStructGet flash is not supported.\n"));
return MV_FAIL;
}
/*******************************************************************************
* flashSecsInit - Init the flash sector array in pFlash.
*
* DESCRIPTION:
* Init the sector array based on the sector type.
*
* INPUT:
*
* OUTPUT:
* pFlash - Flash sectors information.
*
* RETURN:
* MV_BAD_PARAM if pFlash or frag sector struct(if needed) are NULL,
* MV_OK otherwise
*
*******************************************************************************/
static MV_STATUS flashSecsInit(MV_FLASH_INFO *pFlash)
{
MV_U32 i, temp, base = 0;
MV_U32 restSecSize, initSize = 0;
MV_U32 *pSecFrag, numSecFrag, firstSec, lastSec, flashDevNum;
if (NULL == pFlash)
return MV_BAD_PARAM;
/* first Init the bottom or top sectors */
if (mvFlashSecTypeGet(pFlash) != REGULAR) { /* BOTTOM or TOP */
/* init sectors fragments parameters */
numSecFrag = pFlash->flashSpec.secFragNum;
pSecFrag = pFlash->flashSpec.pSecSizeFragList;
if (NULL == pSecFrag) {
mvOsPrintf("Flash: flashSecsInit missing frag sector list.\n");
return MV_BAD_PARAM;
}
/* In case we got more then one flash in parallel then each */
/* fragment size will be "duplicated" */
flashDevNum = mvFlashNumOfDevGet(pFlash);
/* caculate the size of each sector in the rest of the flash sector */
temp = 0;
for (i = 0; i < numSecFrag; i++)
temp += pSecFrag[i] * flashDevNum;
restSecSize = (mvFlashSizeGet(pFlash) - temp) / (mvFlashNumOfSecsGet(pFlash) - numSecFrag);
if (mvFlashSecTypeGet(pFlash) == TOP) { /* TOP */
/* if TOP sec type the the last sector is fragmented */
DB(mvOsPrintf("FLASH: initFlashSecs TOP Sector Type \n"));
base = mvFlashSizeGet(pFlash) - restSecSize;
temp = mvFlashNumOfSecsGet(pFlash) - numSecFrag;
for (i = 0; i < numSecFrag; i++) {
pFlash->sector[temp + i].baseOffs = base;
pFlash->sector[temp + i].size = pSecFrag[(numSecFrag - 1) - i] * flashDevNum;
/* Init Protect feild */
if (pFlash->flashSpec.HwProtect == MV_FALSE) { /* SW Protect */
pFlash->sector[i].protect = MV_FALSE;
} else { /* HW protect */
pFlash->sector[i].protect = flashSecLockGet(pFlash, temp + i);
}
/*increment base and size of initialized sectors */
base += pSecFrag[(numSecFrag - 1) - i] * flashDevNum;
initSize += pSecFrag[(numSecFrag - 1) - i] * flashDevNum;
}
/* prepare for rest of sector init */
firstSec = 0;
lastSec = mvFlashNumOfSecsGet(pFlash) - numSecFrag;
base = 0;
} else if (mvFlashSecTypeGet(pFlash) == BOTTOM) { /* BOTTOM */
/* if BOTTOM sec type the the first sector is fragmented */
DB(mvOsPrintf("FLASH: initFlashSecs BOTTOM Sector Type \n"));
for (i = 0; i < numSecFrag; i++) {
pFlash->sector[i].baseOffs = base;
pFlash->sector[i].size = pSecFrag[i] * flashDevNum;
/* Init Protect feild */
if (pFlash->flashSpec.HwProtect == MV_FALSE) { /* SW Protect */
pFlash->sector[i].protect = MV_FALSE;
} else { /* HW protect */
pFlash->sector[i].protect = flashSecLockGet(pFlash, i);
}
/*increment base and size of initialized sectors */
base += pSecFrag[i] * flashDevNum;
initSize += pSecFrag[i] * flashDevNum;
}
/* prepare for rest of sector init */
firstSec = numSecFrag;
lastSec = mvFlashNumOfSecsGet(pFlash);
} else { /* unknown Type */
mvOsPrintf("FLASH: initFlashSecs Sector Type %d is unsupported\n.", pFlash->flashSpec.secType);
return MV_BAD_PARAM;
}
} else { /* REGULAR */
DB(mvOsPrintf("FLASH: initFlashSecs REGULAR Sector Type \n"));
restSecSize = mvFlashSizeGet(pFlash) / mvFlashNumOfSecsGet(pFlash);
firstSec = 0;
lastSec = mvFlashNumOfSecsGet(pFlash);
}
/* init the rest of the sectors */
DB(mvOsPrintf("Flash: flashSecsInit main sector loop %d - %d \n", firstSec, lastSec));
for (i = firstSec; i < lastSec; i++) {
pFlash->sector[i].baseOffs = base;
pFlash->sector[i].size = restSecSize;
/* Init Protect feild */
if (pFlash->flashSpec.HwProtect == MV_FALSE) { /* SW Protect */
pFlash->sector[i].protect = MV_FALSE;
} else { /* HW protect */
pFlash->sector[i].protect = flashSecLockGet(pFlash, i);
}
/*increment base */
base += restSecSize;
}
return MV_OK;
}
/*******************************************************************************
* flashSecLockGet - Return a sector Lock Bit status.
*
* DESCRIPTION:
* Return a sector Lock Bit status.
*
*
* INPUT:
* pFlash - Flash structure.
* secNum - Sector Number.
*
* OUTPUT:
* None.
*
* RETURN:
* MV_TRUE if lock is set
* MV_FALSE if lock isn't set
*
*******************************************************************************/
static MV_BOOL flashSecLockGet(MV_FLASH_INFO *pFlash, MV_U32 secNum)
{
MV_U32 status;
/* check if sector is locked */
if ((NULL == pFlash) || (secNum >= mvFlashNumOfSecsGet(pFlash)))
return MV_BAD_PARAM;
switch (mvFlashVenIdGet(pFlash)) {
case INTEL_MANUF: /* INTEL / MT */
status = intelFlashSecLockGet(pFlash, secNum);
break;
default:
mvOsPrintf("Flash: ERROR flashSecLockGet unsupported vendor\n");
return MV_FAIL;
}
/* reset the flash */
flashReset(pFlash);
return status;
}
/*******************************************************************************
* mvFlashProg - Prog busWidth Bits into the address offest in the flash.
*
* DESCRIPTION:
* This function writes busWidth data to a given flash offset.
*
* INPUT:
* pFlash - Flash identifier structure (flash cockie).
* offset - Offset from flash base address.
* data - 32bit data to be written to flash.
*
* OUTPUT:
* None.
*
* RETURN:
* MV_BAD_PARAM if one of the inputs values is illegal,
* MV_OK if program completed successfully,
* MV_FAIL otherwise (e.g. sector protected).
*
*******************************************************************************/
static MV_STATUS mvFlashProg(MV_FLASH_INFO *pFlash, MV_U32 offset, MV_U32 data)
{
MV_U32 status;
switch (mvFlashVenIdGet(pFlash)) {
case INTEL_MANUF: /* INTEL / MT */
status = intelFlashProg(pFlash, offset, data);
break;
case AMD_MANUF:
case STM_MANUF:
case SST_MANUF:
status = amdFlashProg(pFlash, offset, data);
break;
default:
mvOsPrintf("Flash: ERROR mvFlashProg unsupported flash vendor\n");
return MV_FAIL;
}
return status;
}
/*******************************************************************************
* flashHwBufferProg - Prog flash via hw flash hw buffer
*
* DESCRIPTION:
* This function writes to a given flash offset using flash hw buffer.
*
* INPUT:
* pFlash - Flash identifier structure (flash cockie).
* offset - Offset from flash base address.
* data - 32bit data to be written to flash.
*
* OUTPUT:
* None.
*
* RETURN:
* MV_BAD_PARAM if one of the inputs values is illegal,
* MV_OK if program completed successfully,
* MV_FAIL otherwise (e.g. sector protected).
*
*******************************************************************************/
static MV_STATUS flashHwBufferProg(MV_FLASH_INFO *pFlash, MV_U32 offset, MV_U32 byteCount, MV_U8 *pData)
{
MV_U32 status;
switch (mvFlashVenIdGet(pFlash)) {
case INTEL_MANUF: /* INTEL / MT */
status = intelFlashHwBufferProg(pFlash, offset, byteCount, pData);
break;
default:
mvOsPrintf("Flash: ERROR flashHwBufferProg unsupported flash vendor\n");
return MV_FAIL;
}
return status;
}
/*******************************************************************************
* flashGetHwBuffSize - get supported flash write buffer size.
* DESCRIPTION:
* Returns supported flash write buffer size.
*
* INPUT:
* pFlash - flash information.
*
* OUTPUT:
* None
*
* RETURN:
* MV_U32 - supported buffer size
*
*******************************************************************************/
static MV_U32 flashGetHwBuffSize(MV_FLASH_INFO *pFlash)
{
switch (mvFlashVenIdGet(pFlash)) {
case INTEL_MANUF: /* INTEL / MT */
return intelFlashGetHwBuffSize(pFlash);
break;
default:
return 0;
}
}