| /******************************************************************************* |
| 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 "mvFlashCom.h" |
| #include "mvIntelFlash.h" |
| #include "mvAmdFlash.h" |
| |
| #undef MV_DEBUG |
| |
| #ifdef MV_DEBUG |
| #define DB(x) x |
| #else |
| #define DB(x) |
| #endif |
| |
| static MV_VOID sizePrint(MV_U32 size, MV_U8 *s); |
| |
| /******************************************************************************* |
| * mvFlashInWhichSec - Return which Sector rap the offset address. |
| * |
| * DESCRIPTION: |
| * |
| * INPUT: |
| * pFlash - Flash identifier structure. |
| * offset - offset address. |
| * |
| * OUTPUT: |
| * None |
| * |
| * RETURN: |
| * MV_U32 - The Sector Number that the offset sits in. |
| * BAD_SEC_NUM if not found. |
| * |
| *******************************************************************************/ |
| MV_U32 mvFlashInWhichSec(MV_FLASH_INFO *pFlash, MV_U32 offset) |
| { |
| MV_U32 secNum; |
| if (NULL == pFlash) |
| return 0; |
| |
| for (secNum = 0; secNum < mvFlashNumOfSecsGet(pFlash); secNum++) { |
| if ((offset >= mvFlashSecOffsGet(pFlash, secNum)) && |
| (offset < mvFlashSecOffsGet(pFlash, secNum) + mvFlashSecSizeGet(pFlash, secNum))) { |
| return secNum; |
| } |
| } |
| /* return illegal sector Number */ |
| return FLASH_BAD_SEC_NUM; |
| } |
| |
| /**************************************************/ |
| /* get information from the MV_FLASH_INFO struct */ |
| /**************************************************/ |
| /* get the Number of Device which sits in parallel on the bus */ |
| MV_U32 mvFlashNumOfDevGet(MV_FLASH_INFO *pFlash) |
| { |
| if (NULL == pFlash) |
| return 0; |
| if (mvFlashBusWidthGet(pFlash) >= mvFlashDevWidthGet(pFlash)) |
| return mvFlashBusWidthGet(pFlash) / mvFlashDevWidthGet(pFlash); |
| return 1; |
| } |
| |
| /* get the Flash Lock type HW/SW */ |
| MV_BOOL mvFlashIsHwLock(MV_FLASH_INFO *pFlash) |
| { |
| if (NULL == pFlash) |
| return MV_FALSE; |
| |
| return pFlash->flashSpec.HwProtect; |
| } |
| |
| /* get the lock status of a sector in the flash */ |
| MV_BOOL mvFlashSecLockGet(MV_FLASH_INFO *pFlash, MV_U32 secNum) |
| { |
| if ((NULL == pFlash) || (secNum > mvFlashNumOfSecsGet(pFlash))) |
| return MV_FALSE; |
| |
| return pFlash->sector[secNum].protect; |
| } |
| |
| /* get the size of a sector in the flash */ |
| MV_U32 mvFlashSecSizeGet(MV_FLASH_INFO *pFlash, MV_U32 secNum) |
| { |
| if ((NULL == pFlash) || (secNum > mvFlashNumOfSecsGet(pFlash))) |
| return 0; |
| |
| return pFlash->sector[secNum].size; |
| } |
| |
| /* get the num of sectors in the flash */ |
| MV_U32 mvFlashNumOfSecsGet(MV_FLASH_INFO *pFlash) |
| { |
| if (NULL == pFlash) |
| return 0; |
| |
| return pFlash->flashSpec.sectorNum; |
| } |
| |
| /* get the flash size */ |
| MV_U32 mvFlashSizeGet(MV_FLASH_INFO *pFlash) |
| { |
| if (NULL == pFlash) |
| return 0; |
| |
| return pFlash->flashSpec.size * mvFlashNumOfDevGet(pFlash); |
| } |
| |
| /* get the sector offset */ |
| MV_U32 mvFlashSecOffsGet(MV_FLASH_INFO *pFlash, MV_U32 secNum) |
| { |
| if ((NULL == pFlash) || (secNum > mvFlashNumOfSecsGet(pFlash))) |
| return 0; |
| |
| return pFlash->sector[secNum].baseOffs; |
| } |
| |
| /* get the sector types TOP/BOT/REG */ |
| FLASH_SEC_TYPE mvFlashSecTypeGet(MV_FLASH_INFO *pFlash) |
| { |
| if (NULL == pFlash) |
| return 0; |
| |
| return pFlash->flashSpec.secType; |
| } |
| |
| /* get the flash Vendor ID */ |
| MV_U32 mvFlashVenIdGet(MV_FLASH_INFO *pFlash) |
| { |
| if (NULL == pFlash) |
| return 0; |
| |
| return pFlash->flashSpec.flashVen; |
| } |
| |
| /* get the flash device id */ |
| MV_U32 mvFlashDevIdGet(MV_FLASH_INFO *pFlash) |
| { |
| if (NULL == pFlash) |
| return 0; |
| |
| return pFlash->flashSpec.flashId; |
| } |
| |
| /* get the flash base address */ |
| MV_U32 mvFlashBaseAddrGet(MV_FLASH_INFO *pFlash) |
| { |
| if (NULL == pFlash) |
| return 0; |
| |
| return pFlash->baseAddr; |
| } |
| |
| /* get the flash bus width */ |
| MV_U32 mvFlashBusWidthGet(MV_FLASH_INFO *pFlash) |
| { |
| if (NULL == pFlash) |
| return 0; |
| |
| return pFlash->busWidth; |
| } |
| |
| /* get the flash device width */ |
| MV_U32 mvFlashDevWidthGet(MV_FLASH_INFO *pFlash) |
| { |
| if (NULL == pFlash) |
| return 0; |
| |
| return pFlash->devWidth; |
| } |
| |
| /******************************************************************************* |
| * flashDataExt - Extend Data. |
| * DESCRIPTION: |
| * Should be used only for FLASH CFI command sequence. |
| * |
| * Prepare the Data according to the Flash Width and Bus Width. |
| * If flash width = 2 and bus width = 1 data = 0x55 -> data = 0x55 |
| * If flash width = 2 and bus width = 4 data = 0x55 -> data = 0x550055 |
| * If flash width = 1 and bus width = 4 data = 0x55 -> data = 0x55555555 |
| * |
| * INPUT: |
| * data - Data to be expended. |
| * pFlash - flash information. |
| * |
| * OUTPUT: |
| * None |
| * |
| * RETURN: |
| * MV_U32 - Data after extension. |
| * OxFFFFFFFF if pFlash is Null |
| * |
| *******************************************************************************/ |
| MV_U32 flashDataExt(MV_FLASH_INFO *pFlash, MV_U32 data) |
| { |
| MV_U32 i; |
| if (NULL == pFlash) |
| return 0xFFFFFFFF; |
| |
| for (i = 0; i < pFlash->busWidth; i += pFlash->devWidth) |
| data |= data << 8 * i; |
| return data; |
| } |
| |
| /****************************************************************************** |
| * flashAddrExt - Extend Addr. |
| * DESCRIPTION: |
| * Should be used only for FLASH CFI command sequence. |
| * |
| * Prepare the Addr according to the Flash width and the bus width, |
| * and add the sector offset. |
| * If flash width = 2 and bus width = 1 then it means we are using 16 Bit |
| * flash in 8 Bit mode, we should make sure that we shift the addr in 1 bit |
| * since in 16 Bit flash A0 isn't connected. and A1 of the MV dev address will |
| * go to A1 of the Flash. |
| * If flash width = 2 and bus width = 4 then it means we are using 2 16 Bit |
| * flash, (for the 16 Bit flash A0 isn't connected) and since when we refer to |
| * address 0x4 we actually want to refer to 0x2 of each device, then we will |
| * connect A2 of the MV Dev addres to A1 of the flash. |
| * |
| * INPUT: |
| * addr - Addr to be expended. |
| * pFlash - flash information. |
| * secNum - Sector Number. |
| * |
| * OUTPUT: |
| * None |
| * |
| * RETURN: |
| * MV_U32 - Data after extension. |
| * 0 if pFlash is Null. |
| * |
| *******************************************************************************/ |
| MV_U32 flashAddrExt(MV_FLASH_INFO *pFlash, MV_U32 addr, MV_U32 secNum) |
| { |
| MV_U32 shift; |
| if (NULL == pFlash) |
| return 0; |
| |
| shift = (pFlash->busWidth > pFlash->devWidth) ? pFlash->busWidth : pFlash->devWidth; |
| addr = addr * shift; |
| |
| /* Add flash sector Offset. */ |
| addr += (mvFlashSecOffsGet(pFlash, secNum) + mvFlashBaseAddrGet(pFlash)); |
| |
| return addr; |
| } |
| |
| /******************************************************************************* |
| * flashCmdSet - Write converted data to the flash converted address+sector base. |
| * |
| * DESCRIPTION: |
| * Convert data based on the bus width and the flash device width |
| * and write it to secoffset + converted address. |
| * Should be used only for FLASH command sequence. |
| * |
| * INPUT: |
| * addr - Address offset. |
| * secNum - In which sector the address is sitting. |
| * data - Data to be written. |
| * pFlash - flash information. |
| * |
| * OUTPUT: |
| * None |
| * |
| * RETURN: |
| * None |
| * |
| *******************************************************************************/ |
| MV_VOID flashCmdSet(MV_FLASH_INFO *pFlash, MV_U32 addr, MV_U32 secNum, MV_U32 data) |
| { |
| if (NULL == pFlash) |
| return; |
| |
| /* prepare the Data according to the Flash Width and Bus Width. */ |
| data = flashDataExt(pFlash, data); |
| addr = flashAddrExt(pFlash, addr, secNum); |
| |
| flashBusWidthWr(pFlash, addr, data); |
| |
| return; |
| } |
| |
| /******************************************************************************* |
| * flashBusWidthRd - read BusWidth Bits from address. |
| * |
| * DESCRIPTION: |
| * read BusWidth Bits from address. Note that access to Flash registers |
| * is always in LE mode as the Flash registers are in LE mode. |
| * |
| * INPUT: |
| * addr - Address offset. |
| * pFlash - flash information. |
| * |
| * OUTPUT: |
| * None |
| * |
| * RETURN: |
| * MV_U32 - contain the Bus Width Bits read from the address. |
| * |
| *******************************************************************************/ |
| MV_U32 flashBusWidthRd(MV_FLASH_INFO *pFlash, MV_U32 addr) |
| { |
| MV_U32 val; |
| |
| switch (pFlash->busWidth) { |
| case 1: |
| val = (MV_U32) MV_FL_8_READ(addr); |
| break; |
| case 2: |
| val = (MV_U32) MV_FL_16_READ(addr); |
| break; |
| case 4: |
| val = MV_FL_32_READ(addr); |
| break; |
| default: |
| mvOsPrintf("%s ERROR: Bus Width %d Bytes isn't supported.\n", __func__, pFlash->busWidth); |
| return 0; |
| } |
| /* mvOsPrintf("Addr = 0x%x, val = 0x%x, width %d\n", addr, val, pFlash->busWidth); */ |
| |
| return val; |
| } |
| |
| /******************************************************************************* |
| * flashBusWidthWr - write BusWidth Bits from address. |
| * |
| * DESCRIPTION: |
| * write BusWidth Bits to address. Note that access to Flash registers |
| * is always in LE mode as the Flash registers are in LE mode. |
| * |
| * INPUT: |
| * addr - Address offset. |
| * data - data to be written. |
| * pFlash - flash information. |
| * |
| * OUTPUT: |
| * None |
| * |
| * RETURN: |
| * None |
| * |
| *******************************************************************************/ |
| MV_VOID flashBusWidthWr(MV_FLASH_INFO *pFlash, MV_U32 addr, MV_U32 data) |
| { |
| /* mvOsPrintf("Addr = 0x%x, data = 0x%x, width %d\n", addr, data, pFlash->busWidth); */ |
| switch (pFlash->busWidth) { |
| case 1: |
| MV_FL_8_WRITE(addr, (MV_U8) data); |
| break; |
| case 2: |
| MV_FL_16_WRITE(addr, (MV_U16) data); |
| break; |
| case 4: |
| MV_FL_32_WRITE(addr, data); |
| break; |
| default: |
| mvOsPrintf("%s ERROR: Bus Width %d Bytes isn't supported.\n", __func__, pFlash->busWidth); |
| return; |
| } |
| |
| return; |
| } |
| |
| /******************************************************************************* |
| * flashBusWidthDataWr - write BusWidth Bits of data from address. |
| * |
| * DESCRIPTION: |
| * This function is used to perform data write to Flash, not like |
| * flashBusWidthWr which is used for commands. |
| * |
| * INPUT: |
| * addr - Address offset. |
| * data - data to be written. |
| * pFlash - flash information. |
| * |
| * OUTPUT: |
| * None |
| * |
| * RETURN: |
| * None |
| * |
| *******************************************************************************/ |
| MV_VOID flashBusWidthDataWr(MV_FLASH_INFO *pFlash, MV_U32 addr, MV_U32 data) |
| { |
| /*mvOsPrintf("Addr = 0x%x, data = 0x%x, width %d\n", addr, data, pFlash->busWidth); */ |
| switch (pFlash->busWidth) { |
| case 1: |
| MV_FL_8_DATA_WRITE(addr, (MV_U8) data); |
| break; |
| case 2: |
| MV_FL_16_DATA_WRITE(addr, (MV_U16) data); |
| break; |
| case 4: |
| MV_FL_32_DATA_WRITE(addr, data); |
| break; |
| default: |
| mvOsPrintf("%s ERROR: Bus Width %d Bytes isn't supported.\n", __func__, pFlash->busWidth); |
| return; |
| } |
| |
| return; |
| } |
| |
| /******************************************************************************* |
| * flashPrint - Print flash information structure. |
| * |
| * DESCRIPTION: |
| * Prints all the feilds in the flash info structure. |
| * |
| * INPUT: |
| * pFlash - Flash information. |
| * |
| * OUTPUT: |
| * None |
| * |
| * RETURN: |
| * None |
| * |
| *******************************************************************************/ |
| MV_VOID flashPrint(MV_FLASH_INFO *pFlash) |
| { |
| MV_U32 i; |
| |
| if ((NULL == pFlash) || (mvFlashVenIdGet(pFlash) == 0)) { |
| mvOsOutput("missing or unknown FLASH type\n"); |
| return; |
| } |
| |
| switch (mvFlashVenIdGet(pFlash)) { |
| case STM_MANUF: |
| mvOsOutput("STM "); |
| break; |
| case AMD_MANUF: |
| mvOsOutput("AMD "); |
| break; |
| case FUJ_MANUF: |
| mvOsOutput("FUJITSU "); |
| break; |
| case INTEL_MANUF: |
| mvOsOutput("INTEL "); |
| break; |
| case SST_MANUF: |
| mvOsOutput("SST "); |
| break; |
| case MX_MANUF: |
| mvOsOutput("MX "); |
| break; |
| default: |
| mvOsOutput("Unknown Vendor 0x%x", mvFlashVenIdGet(pFlash)); |
| break; |
| } |
| |
| switch (mvFlashDevIdGet(pFlash)) { |
| case AMD_FID_LV040B: |
| mvOsOutput("AM29LV040B (4 Mbit, bottom boot sect)"); |
| break; |
| case AMD_FID_LV400B: |
| mvOsOutput("AM29LV400B (4 Mbit, bottom boot sect)"); |
| break; |
| case AMD_FID_LV400T: |
| mvOsOutput("AM29LV400T (4 Mbit, top boot sector)"); |
| break; |
| case AMD_FID_LV800B: |
| mvOsOutput("AM29LV800B (8 Mbit, bottom boot sect)"); |
| break; |
| case AMD_FID_LV800T: |
| mvOsOutput("AM29LV800T (8 Mbit, top boot sector)"); |
| break; |
| case AMD_FID_LV160B: |
| mvOsOutput("AM29LV160B (16 Mbit, bottom boot sect)"); |
| break; |
| case AMD_FID_LV160T: |
| mvOsOutput("AM29LV160T (16 Mbit, top boot sector)"); |
| break; |
| case AMD_FID_LV320B: |
| mvOsOutput("AM29LV320B (32 Mbit, bottom boot sect)"); |
| break; |
| case AMD_FID_LV320T: |
| mvOsOutput("AM29LV320T (32 Mbit, top boot sector)"); |
| break; |
| case AMD_S29GL128N: |
| mvOsOutput("SPANSION S29GL128N (128 Mbit) - AMD MirrorBit-compat"); |
| break; |
| case STM_FID_29W040B: |
| mvOsOutput("M29W040B (4Mbit = 512K x 8) "); |
| break; |
| case INTEL_FID_28F320J3A: |
| mvOsOutput("28F320J3A (32 Mbit)"); |
| break; |
| case INTEL_FID_28F640J3A: |
| mvOsOutput("28F640J3A (64 Mbit)"); |
| break; |
| case INTEL_FID_28F128J3A: |
| mvOsOutput("28F128J3A (128 Mbit)"); |
| break; |
| case INTEL_FID_28F128P30T: |
| mvOsOutput("28F128P30 TOP (128 Mbit)"); |
| break; |
| case INTEL_FID_28F128P30B: |
| mvOsOutput("28F128P30 BOTTOM (128 Mbit)"); |
| break; |
| case INTEL_FID_28F256P30T: |
| mvOsOutput("28F256P30 TOP (256 Mbit)"); |
| break; |
| #if defined(DB_88F1281) |
| case INTEL_FID_28F256P30B: |
| mvOsOutput("28F256P30 BOTTOM (128 Mbit)"); |
| break; |
| #else |
| case INTEL_FID_28F256P30B: |
| mvOsOutput("28F256P30 BOTTOM (256 Mbit)"); |
| break; |
| #endif |
| case SST_39VF_020: |
| mvOsOutput("SST39VF020 (2 Mbit)"); |
| break; |
| default: |
| mvOsOutput("Unknown Chip Type id 0x%x", mvFlashDevIdGet(pFlash)); |
| break; |
| } |
| if (mvFlashNumOfDevGet(pFlash) > 1) |
| mvOsOutput(" X %d", mvFlashNumOfDevGet(pFlash)); |
| |
| mvOsOutput("\nSize: "); |
| sizePrint(mvFlashSizeGet(pFlash), (MV_U8 *) " in "); |
| mvOsOutput("%d Sectors\n", mvFlashNumOfSecsGet(pFlash)); |
| mvOsOutput("Bus Width: %dbit, device Width: %dbit, type: ", |
| (8 * mvFlashBusWidthGet(pFlash)), (8 * mvFlashDevWidthGet(pFlash))); |
| |
| switch (mvFlashSecTypeGet(pFlash)) { |
| case TOP: |
| mvOsOutput("TOP"); |
| break; |
| case BOTTOM: |
| mvOsOutput("BOTTOM"); |
| break; |
| case REGULAR: |
| mvOsOutput("REGULAR"); |
| break; |
| default: |
| mvOsOutput("Unknown Type"); |
| break; |
| } |
| mvOsOutput(".\n"); |
| |
| mvOsOutput(" Sector Start Addresses:"); |
| for (i = 0; i < mvFlashNumOfSecsGet(pFlash); ++i) { |
| if ((i % 5) == 0) |
| mvOsOutput("\n "); |
| mvOsOutput(" %08lX%s", |
| (mvFlashSecOffsGet(pFlash, i) + mvFlashBaseAddrGet(pFlash)), |
| mvFlashSecLockGet(pFlash, i) ? " (RO)" : " "); |
| } |
| mvOsOutput("\n"); |
| |
| return; |
| } |
| |
| /*************************************************************************** |
| * print sizes as "xxx kB", "xxx.y kB", "xxx MB" or "xxx.y MB" as needed; |
| * allow for optional trailing string (like "\n") |
| ***************************************************************************/ |
| static MV_VOID sizePrint(MV_U32 size, MV_U8 *s) |
| { |
| MV_U32 m, n; |
| MV_U32 d = 1 << 20; /* 1 MB */ |
| MV_U8 c = 'M'; |
| |
| if (size < d) { /* print in kB */ |
| c = 'k'; |
| d = 1 << 10; |
| } |
| |
| n = size / d; |
| |
| m = (10 * (size - (n * d)) + (d / 2)) / d; |
| |
| if (m >= 10) { |
| m -= 10; |
| n += 1; |
| } |
| |
| mvOsOutput("%2d", n); |
| if (m) |
| mvOsOutput(".%d", m); |
| mvOsOutput(" %cB%s", c, s); |
| } |