/******************************************************************************* 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 "mflash/mvMFlash.h" #include "mflash/mvMFlashSpec.h" #include "mflash/mvPMFlash.h" #include "mflash/mvPMFlashSpec.h" #include "ctrlEnv/mvCtrlEnvLib.h" /*#define MV_DEBUG*/ #ifdef MV_DEBUG #define DB(x) x #else #define DB(x) #endif /* MACROS */ /* Static Functions */ static MV_STATUS waitOnCmdDone (MV_VOID); static MV_STATUS waitOnEraseBitClear (MV_VOID); static MV_STATUS waitOnInfReadBitClear (MV_VOID); static MV_STATUS mvPMFlashReadSR (MV_U8 * pStatusReg); static MV_STATUS mvPMFlashReadRegSeq (MV_U32 prgCmnd, MV_U8 * pStatusReg); static MV_STATUS mvPMFlashWriteRegSeq (MV_U32 prgCmnd, MV_U32 reg); static MV_STATUS mvPMFlashProgSeq (MV_MFLASH_INFO *pFlash, MV_U32 prgCmnd, MV_U32 offset, MV_U8 *pBlock); static MV_STATUS mvPMFlashEraseSeq (MV_MFLASH_INFO *pFlash, MV_U32 eraseCmnd); static MV_STATUS mvPMFlashIndirectReadSeq (MV_MFLASH_INFO *pFlash, MV_U32 readCmnd, MV_U8* p8Bytes); /******************************************************************************* * waitOnCmdDone - Wait for command done bit * * DESCRIPTION: * Block waiting for command done. Returns Error Status * ********************************************************************************/ static MV_STATUS waitOnCmdDone(MV_VOID) { MV_U32 i; /* loop over waiting for the command done bit to be set */ for (i=0; i> 16) & 0xFFFF)); /* set commnand opcode = prgCmnd */ temp = MV_REG_READ(MV_PMFLASH_CMD_OPCODE_REG); temp = ((temp & ~MV_PMFLASH_CMD_OPCD_MASK) | prgCmnd | MV_PMFLASH_EAD9_8_MASK); MV_REG_WRITE(MV_PMFLASH_CMD_OPCODE_REG, temp); /* start the programming operation - set bit 12 to 1 */ MV_REG_BIT_SET(MV_PMFLASH_CMD_OPCODE_REG, MV_PMFLASH_WR_OPER_STRT_MASK); /* serialize the whole 64 byte buffer */ pBuff = (MV_U16*)pBlock; for (i=0; i (pFlash->sectorNumber * pFlash->sectorSize)) { DB(mvOsPrintf("%s WARNING: Read allignment problem!\n", __FUNCTION__);) return MV_BAD_PARAM; } /* Read using direct access */ mvOsMemcpy(pBlock, (MV_VOID*)(pFlash->baseAddr + offset), blockSize); return MV_OK; } /******************************************************************************* * mvPMFlashBlockInfRd - Read a block of Memory from the Information region * * DESCRIPTION: * Read a block of Memory from the information region * * INPUT: * pFlash: Structure with Marvell Flash information * offset: offset to read from the main region of the MFlash * blockSize: number of bytes to read from the offset * * OUTPUT: * pBlock: pointer of the buffer to fill * * RETURN: * Success or Error code. * * *******************************************************************************/ MV_STATUS mvPMFlashBlockInfRd (MV_MFLASH_INFO *pFlash, MV_U32 offset, MV_U32 blockSize, MV_U8 *pBlock) { MV_STATUS ret; MV_U8 tempBuff[MV_PMFLASH_IREAD_CHUNK_SIZE]; MV_U32 data2read = blockSize; MV_U32 preAllOfst = (offset & MV_PMFLASH_IREAD_ALIGN_MASK); MV_U32 preAllSz = (preAllOfst ? (MV_PMFLASH_IREAD_CHUNK_SIZE - preAllOfst) : 0); MV_U32 readOffset = (offset & ~MV_PMFLASH_IREAD_ALIGN_MASK); /* Check for null pointer */ if ((pFlash == NULL) || (pBlock == NULL)) { mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); return MV_BAD_PARAM; } /* sanity check on sizes and offsets based on chip model */ if ((offset + blockSize) > pFlash->infoSize) { DB(mvOsPrintf("%s WARNING: Read exceeds flash size!\n", __FUNCTION__);) return MV_BAD_PARAM; } /* set the ADDDRESS HI to zero - since only the low address is needed */ MV_REG_WRITE(MV_PMFLASH_ADDR_HI_REG, 0); /* only low address is needed */ /* check if the total block size is less than the first chunk remainder */ if (data2read < preAllSz) preAllSz = data2read; /* Check if read offset is not alligned to 8bytes; then perform a read alligned to 8 bytes and copy only the necessary data */ if (preAllOfst) { /* set the read offset address in the flash address Low */ MV_REG_WRITE(MV_PMFLASH_ADDR_LOW_REG, readOffset); if ((ret = mvPMFlashIndirectReadSeq(pFlash, MV_PMFLASH_OPCD_IREAD, tempBuff)) != MV_OK) return ret; /* copy to the buffer only the needed data */ mvOsMemcpy (pBlock, &tempBuff[preAllOfst], preAllSz); /* increment the pointers and offsets */ data2read -= preAllSz; readOffset += MV_PMFLASH_IREAD_CHUNK_SIZE; pBlock += preAllSz; } /* perform all reads that are alligned to 8bytes and full 8bytes */ while (data2read >= MV_PMFLASH_IREAD_CHUNK_SIZE) { /* set the read offset address in the flash address Low */ MV_REG_WRITE(MV_PMFLASH_ADDR_LOW_REG, readOffset); if ((ret = mvPMFlashIndirectReadSeq(pFlash, MV_PMFLASH_OPCD_IREAD, pBlock)) != MV_OK) return ret; /* increment the pointers and offsets */ data2read -= MV_PMFLASH_IREAD_CHUNK_SIZE; readOffset += MV_PMFLASH_IREAD_CHUNK_SIZE; pBlock += MV_PMFLASH_IREAD_CHUNK_SIZE; } /* check if we need to perform a partial read at the end */ if (data2read) { /* set the read offset address in the flash address Low */ MV_REG_WRITE(MV_PMFLASH_ADDR_LOW_REG, readOffset); if ((ret = mvPMFlashIndirectReadSeq(pFlash, MV_PMFLASH_OPCD_IREAD, tempBuff)) != MV_OK) return ret; /* copy to the buffer only the needed data */ mvOsMemcpy (pBlock, tempBuff, data2read); } return MV_OK; } /******************************************************************************* * mvPMFlashReadConfig1 - Read the Configuration register * * DESCRIPTION: * Perform the Read CONFIG1 register RAB * * INPUT: * pFlash: Structure with Marvell Flash information * pConfigReg: pointer to the variable to fill * * OUTPUT: * pConfigReg: pointer to the variable holding the register value * * RETURN: * Success or Error code. * ********************************************************************************/ MV_STATUS mvPMFlashReadConfig1(MV_MFLASH_INFO *pFlash, MV_U8 * pConfigReg) { if ((pFlash == NULL) || (pConfigReg == NULL)) { mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); return MV_BAD_PARAM; } return mvPMFlashReadRegSeq(MV_PMFLASH_OPCD_READ_CFG1, pConfigReg); } /******************************************************************************* * mvPMFlashReadConfig2 - Read the Configuration register * * DESCRIPTION: * Perform the Read CONFIG2 register RAB * * INPUT: * pFlash: Structure with Marvell Flash information * pConfigReg: pointer to the variable to fill * * OUTPUT: * pConfigReg: pointer to the variable holding the register value * * RETURN: * Success or Error code. * ********************************************************************************/ MV_STATUS mvPMFlashReadConfig2(MV_MFLASH_INFO *pFlash, MV_U8 * pConfigReg) { if ((pFlash == NULL) || (pConfigReg == NULL)) { mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); return MV_BAD_PARAM; } return mvPMFlashReadRegSeq(MV_PMFLASH_OPCD_READ_CFG2, pConfigReg); } /******************************************************************************* * mvPMFlashReadConfig3 - Read the Configuration register * * DESCRIPTION: * Perform the Read CONFIG3 register RAB * * INPUT: * pFlash: Structure with Marvell Flash information * pConfigReg: pointer to the variable to fill * * OUTPUT: * pConfigReg: pointer to the variable holding the register value * * RETURN: * Success or Error code. * ********************************************************************************/ MV_STATUS mvPMFlashReadConfig3(MV_MFLASH_INFO *pFlash, MV_U8 * pConfigReg) { if ((pFlash == NULL) || (pConfigReg == NULL)) { mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); return MV_BAD_PARAM; } return mvPMFlashReadRegSeq(MV_PMFLASH_OPCD_READ_CFG3, pConfigReg); } /******************************************************************************* * mvPMFlashReadConfig4 - Read the Configuration register * * DESCRIPTION: * Perform the Read CONFIG4 register RAB * * INPUT: * pFlash: Structure with Marvell Flash information * pConfigReg: pointer to the variable to fill * * OUTPUT: * pConfigReg: pointer to the variable holding the register value * * RETURN: * Success or Error code. * ********************************************************************************/ MV_STATUS mvPMFlashReadConfig4(MV_MFLASH_INFO *pFlash, MV_U8 * pConfigReg) { if ((pFlash == NULL) || (pConfigReg == NULL)) { mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); return MV_BAD_PARAM; } return mvPMFlashReadRegSeq(MV_PMFLASH_OPCD_READ_CFG4, pConfigReg); } /******************************************************************************* * mvPMFlashSetConfig1 - Write the Configuration register * * DESCRIPTION: * Perform the SET CONFIG1 register RAB * * INPUT: * pFlash: Structure with Marvell Flash information * configReg: value to set in the configuration register * * OUTPUT: * None. * * RETURN: * Success or Error code. * ********************************************************************************/ MV_STATUS mvPMFlashSetConfig1(MV_MFLASH_INFO *pFlash, MV_U8 configReg) { if (pFlash == NULL) { mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); return MV_BAD_PARAM; } return mvPMFlashWriteRegSeq(MV_PMFLASH_OPCD_SET_CFG1, configReg); } /******************************************************************************* * mvPMFlashSetConfig2 - Write the Configuration register * * DESCRIPTION: * Perform the SET CONFIG2 register RAB * * INPUT: * pFlash: Structure with Marvell Flash information * configReg: value to set in the configuration register * * OUTPUT: * None. * * RETURN: * Success or Error code. * ********************************************************************************/ MV_STATUS mvPMFlashSetConfig2(MV_MFLASH_INFO *pFlash, MV_U8 configReg) { if (pFlash == NULL) { mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); return MV_BAD_PARAM; } return mvPMFlashWriteRegSeq(MV_PMFLASH_OPCD_SET_CFG2, configReg); } /******************************************************************************* * mvPMFlashSetConfig3 - Write the Configuration register * * DESCRIPTION: * Perform the SET CONFIG3 register RAB * * INPUT: * pFlash: Structure with Marvell Flash information * configReg: value to set in the configuration register * * OUTPUT: * None. * * RETURN: * Success or Error code. * ********************************************************************************/ MV_STATUS mvPMFlashSetConfig3(MV_MFLASH_INFO *pFlash, MV_U8 configReg) { if (pFlash == NULL) { mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); return MV_BAD_PARAM; } return mvPMFlashWriteRegSeq(MV_PMFLASH_OPCD_SET_CFG3, configReg); } /******************************************************************************* * mvPMFlashSetConfig4 - Write the Configuration register * * DESCRIPTION: * Perform the SET CONFIG4 register RAB * * INPUT: * pFlash: Structure with Marvell Flash information * configReg: value to set in the configuration register * * OUTPUT: * None. * * RETURN: * Success or Error code. * ********************************************************************************/ MV_STATUS mvPMFlashSetConfig4(MV_MFLASH_INFO *pFlash, MV_U8 configReg) { if (pFlash == NULL) { mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); return MV_BAD_PARAM; } return mvPMFlashWriteRegSeq(MV_PMFLASH_OPCD_SET_CFG4, configReg); } /******************************************************************************* * mvPMFlashSetConfig4 - Write the Configuration register * * DESCRIPTION: * Perform the SET CONFIG4 register RAB * * INPUT: * pFlash: Structure with Marvell Flash information * configReg: value to set in the configuration register * * OUTPUT: * None. * * RETURN: * Success or Error code. * ********************************************************************************/ MV_STATUS mvPMFlashSetSlewRate (MV_MFLASH_INFO *pFlash, MV_U8 configReg) { if (pFlash == NULL) { mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); return MV_BAD_PARAM; } return mvPMFlashWriteRegSeq(MV_PMFLASH_OPCD_SET_SLEW, configReg); } /******************************************************************************* * mvPMFlashWriteProtectSet - Set the write protection feature status * * DESCRIPTION: * Enable or disable the write protection * * INPUT: * pFlash: Structure with Marvell Flash information * wp: write protection status (enable = MV_TRUE, disable = MVFALSE) * * OUTPUT: * None. * * RETURN: * Success or Error code. * * *******************************************************************************/ MV_STATUS mvPMFlashWriteProtectSet (MV_MFLASH_INFO *pFlash, MV_BOOL wp) { MV_STATUS ret; MV_U8 tempReg; if (pFlash == NULL) { mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); return MV_BAD_PARAM; } /* Read the original value */ if ((ret = mvPMFlashReadConfig4(pFlash, &tempReg)) != MV_OK) { DB(mvOsPrintf("%s WARNING: Failed to read Config register!\n", __FUNCTION__);) return ret; } /* set the WP bit */ if (wp) /* write protect active hi */ tempReg |= MV_PMFLASH_CFG4_WP_MASK; else tempReg &= ~MV_PMFLASH_CFG4_WP_MASK; /* write the new register value */ if ((ret = mvPMFlashSetConfig4(pFlash, tempReg)) != MV_OK) return ret; return MV_OK; } /******************************************************************************* * mvPMFlashWriteProtectGet - Get the write protection feature status * * DESCRIPTION: * Read from the h/w the write protection status * * INPUT: * pFlash: Structure with Marvell Flash information * pWp: pointer to the variable to read in the write protection status * * OUTPUT: * pWp: pointer to the variable holding the write protection status * * RETURN: * Success or Error code. * * *******************************************************************************/ MV_STATUS mvPMFlashWriteProtectGet(MV_MFLASH_INFO *pFlash, MV_BOOL * pWp) { MV_STATUS ret; MV_U8 tempReg; if (pFlash == NULL) { mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); return MV_BAD_PARAM; } /* Read the original value */ if ((ret = mvPMFlashReadConfig4(pFlash, &tempReg)) != MV_OK) { DB(mvOsPrintf("%s WARNING: Failed to read Config register!\n", __FUNCTION__);) return ret; } /* Read the WP bit */ if (tempReg &= ~MV_PMFLASH_CFG4_WP_MASK) *pWp = MV_TRUE; else *pWp = MV_FALSE; return MV_OK; } /******************************************************************************* * mvPMFlashSectorSizeSet - Set the sector size (4K or 32K) * * DESCRIPTION: * Set the sector size of the MFLASH main region * * INPUT: * pFlash: Structure with Marvell Flash information * secSize: size of sector in bytes (either 4K or 32K) * * OUTPUT: * None. * * RETURN: * Success or Error code. * * *******************************************************************************/ MV_STATUS mvPMFlashSectorSizeSet (MV_MFLASH_INFO *pFlash, MV_U32 secSize) { MV_STATUS ret; MV_U8 tempReg; if (pFlash == NULL) { mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); return MV_BAD_PARAM; } /* Read the original value */ if ((ret = mvPMFlashReadConfig4(pFlash, &tempReg)) != MV_OK) return ret; /* set the sector size bit */ switch (secSize) { case MV_MFLASH_SECTOR_SIZE_SMALL: tempReg |= MV_PMFLASH_CFG4_PG_SZ_MASK; /* 1 - 4K */ break; case MV_MFLASH_SECTOR_SIZE_BIG: tempReg &= ~MV_PMFLASH_CFG4_PG_SZ_MASK; /* 0 - 32K */ break; default: DB(mvOsPrintf("%s WARNING: Invalid parameter sector size!\n", __FUNCTION__);) return MV_BAD_PARAM; } /* write the new register value */ if ((ret = mvPMFlashSetConfig4(pFlash, tempReg)) != MV_OK) return ret; return MV_OK; } /******************************************************************************* * mvPMFlashPrefetchSet - Set the Prefetch mode enable/disable * * DESCRIPTION: * Enable (MV_TRUE) or Disable (MV_FALSE) the prefetch mode * * INPUT: * pFlash: Structure with Marvell Flash information * prefetch: enable/disable (true/false) * * OUTPUT: * None. * * RETURN: * Success or Error code. * * *******************************************************************************/ MV_STATUS mvPMFlashPrefetchSet (MV_MFLASH_INFO *pFlash, MV_BOOL prefetch) { MV_STATUS ret; MV_U8 tempReg; if (pFlash == NULL) { mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); return MV_BAD_PARAM; } /* Read the original value */ if ((ret = mvPMFlashReadConfig2(pFlash, &tempReg)) != MV_OK) return ret; /* set the prefetch enable bit */ if (prefetch) tempReg |= MV_PMFLASH_CFG2_PRFTCH_MASK; /* prefetch mode active HI */ else tempReg &= ~MV_PMFLASH_CFG2_PRFTCH_MASK; /* write the new register value */ if ((ret = mvPMFlashSetConfig2(pFlash, tempReg)) != MV_OK) return ret; return MV_OK; } /******************************************************************************* * mvPMFlashShutdownSet - Shutdown the voltage regulator in the flash device * * DESCRIPTION: * Causes the device to enter in a power save mode untill the next access * to the flash. * * INPUT: * pFlash: Structure with Marvell Flash information * * OUTPUT: * None. * * RETURN: * Success or Error code. * * *******************************************************************************/ MV_STATUS mvPMFlashShutdownSet(MV_MFLASH_INFO *pFlash) { if (pFlash == NULL) { mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); return MV_BAD_PARAM; } return mvPMFlashEraseSeq(pFlash, MV_PMFLASH_OPCD_SHUTDOWN); } /******************************************************************************* * mvPMFlashIdGet - Retreive the MFlash manufacturer and device IDs * * DESCRIPTION: * Read from the Mflash the 32bit manufacturer ID and the 16bit devide Id. * * INPUT: * pFlash: Structure with Marvell Flash information * pManfCode: pointer to the 32bit to fill the manufacturer Id * pDevCode: pointer to the 16bit to fill the device Id * * OUTPUT: * pManfCode: pointer to the 32bit holding the manufacturer Id * pDevCode: pointer to the 16bit holding the device Id * * RETURN: * Success or Error code. * * *******************************************************************************/ MV_STATUS mvPMFlashIdGet (MV_MFLASH_INFO *pFlash, MV_U32 * pManfCode, MV_U16 * pDevCode) { MV_U32 temp; MV_STATUS ret; if ((pFlash == NULL) || (pManfCode == NULL) || (pDevCode == NULL)) { mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); return MV_BAD_PARAM; } /* first confiure the Inf Read Data length = 3 (i.e 3*16bit = 6bytes) This is because we need to read 6 bytes (4bytes Manuf. ID and 2 bytes Dev ID) */ MV_REG_WRITE(MV_PMFLASH_IF_CTRL_REG, MV_PMFLASH_READ_ID_16BIT_COUNT); /* set commnand opcode = prgCmnd */ temp = MV_REG_READ(MV_PMFLASH_CMD_OPCODE_REG); temp = ((temp & ~MV_PMFLASH_CMD_OPCD_MASK) | MV_PMFLASH_OPCD_READ_ID | MV_PMFLASH_EAD9_8_MASK); MV_REG_WRITE(MV_PMFLASH_CMD_OPCODE_REG, temp); /* Trigger the erase operation - set bit 13 to 1 */ MV_REG_BIT_SET(MV_PMFLASH_CMD_OPCODE_REG, MV_PMFLASH_INF_READ_STRT_MASK); /* block waiting for bit to be cleared by hardware */ if ((ret = waitOnInfReadBitClear()) != MV_OK) return ret; /* read the 6bytes from the Data register into the buffer in 3 iterations */ /* First re-organize the Manufacturer ID */ *pManfCode = 0; temp = MV_REG_READ(MV_PMFLASH_DATA_REG); /* First 16bit */ *pManfCode |= ((temp << 24) & 0xFF000000); *pManfCode |= ((temp << 8) & 0x00FF0000); temp = MV_REG_READ(MV_PMFLASH_DATA_REG); /* Second 16bit */ *pManfCode |= ((temp << 8) & 0x0000FF00); *pManfCode |= ((temp >> 8) & 0x000000FF); /* Then re-organize the Device ID */ *pDevCode = 0; temp = MV_REG_READ(MV_PMFLASH_DATA_REG); /* Third 16bit */ *pDevCode |= ((temp << 8) & 0x0000FF00); *pDevCode |= ((temp >> 8) & 0x000000FF); /* Set the word count back to the defualt for IREAD commands = 4*16bit */ MV_REG_WRITE(MV_PMFLASH_IF_CTRL_REG, MV_PMFLASH_IREAD_16BIT_COUNT); return MV_OK; }