diff options
-rw-r--r-- | src/usr/pnor/pnordd.C | 197 | ||||
-rw-r--r-- | src/usr/pnor/pnordd.H | 53 |
2 files changed, 198 insertions, 52 deletions
diff --git a/src/usr/pnor/pnordd.C b/src/usr/pnor/pnordd.C index e54cb401a..d579dcf79 100644 --- a/src/usr/pnor/pnordd.C +++ b/src/usr/pnor/pnordd.C @@ -44,6 +44,7 @@ #include <pnor/pnor_reasoncodes.H> #include <sys/time.h> #include <initservice/initserviceif.H> +#include <util/align.H> // Uncomment this to enable smart writing //#define SMART_WRITE @@ -440,7 +441,7 @@ uint32_t PnorDD::cv_hw_workaround = 0; //Hardware Workaround flags */ void PnorDD::sfcInit( ) { - TRACDCOMP(g_trac_pnor, "PnorDD::sfcInit> iv_mode=0x%.8x", iv_mode ); + TRACFCOMP(g_trac_pnor, "PnorDD::sfcInit> iv_mode=0x%.8x", iv_mode ); errlHndl_t l_err = NULL; //Initial configuration settings for SFC: @@ -467,9 +468,10 @@ void PnorDD::sfcInit( ) l_err = readRegSfc(SFC_CMD_SPACE, - SFC_REG_ERASMS, + SFC_REG_ERASMS, iv_erasesize_bytes); if(l_err) { break; } + TRACFCOMP(g_trac_pnor,"iv_erasesize_bytes=%X",iv_erasesize_bytes); cv_sfcInitDone = true; @@ -571,6 +573,8 @@ void PnorDD::sfcInit( ) "PnorDD::sfcInit> Committing error log"); errlCommit(l_err,PNOR_COMP_ID); } + + TRACFCOMP(g_trac_pnor, "< PnorDD::sfcInit" ); } bool PnorDD::usingL3Cache( ) @@ -723,8 +727,8 @@ errlHndl_t PnorDD::pollSfcOpComplete(uint64_t i_pollTime) // want to start out incrementing by small numbers then get bigger // to avoid a really tight loop in an error case so we'll increase // the wait each time through - nanosleep( 0, SFC_POLL_INCR_NS*(++loop) ); ++loop; + nanosleep( 0, SFC_POLL_INCR_NS*loop ); poll_time += SFC_POLL_INCR_NS*loop; } if( l_err ) { break; } @@ -1113,13 +1117,14 @@ errlHndl_t PnorDD::micronFlagStatus(uint64_t i_pollTime) //Configure Get "Chip ID" command in SFC to check special //Micron 'flag status' register - uint32_t confData = SPI_MICRON_FLAG_STAT << 24; - confData |= 0x00800001; // 8-> read, 1->1 bytes - TRACDCOMP( g_trac_pnor, "PnorDD::micronFlagStatus> confData=0x%.8x", - confData ); + SfcCustomReg_t readflag_cmd; + readflag_cmd.data32 = 0; + readflag_cmd.opcode = SPI_MICRON_FLAG_STAT; + readflag_cmd.read = 1; + readflag_cmd.length = 1; l_err = writeRegSfc(SFC_CMD_SPACE, SFC_REG_CHIPIDCONF, - confData); + readflag_cmd.data32); if(l_err) { break; } @@ -1139,6 +1144,10 @@ errlHndl_t PnorDD::micronFlagStatus(uint64_t i_pollTime) sfc_cmd.data32); if(l_err) { break; } + //Poll for complete status + l_err = pollSfcOpComplete(); + if(l_err) { break; } + //Read the Status from the Command Buffer l_err = readRegSfc(SFC_CMDBUF_SPACE, 0, //Offset into CMD BUFF space in bytes @@ -1162,6 +1171,10 @@ errlHndl_t PnorDD::micronFlagStatus(uint64_t i_pollTime) } if( l_err ) { break; } + TRACDCOMP(g_trac_pnor, + "PnorDD::micronFlagStatus> (0x%.8X)", + opStatus); + // check for ready and no errors // bit 0 = ready, bit 2=erase fail, bit 3=Program (Write) failure if( (opStatus & 0xB0000000) != 0x80000000) @@ -1170,6 +1183,26 @@ errlHndl_t PnorDD::micronFlagStatus(uint64_t i_pollTime) "PnorDD::micronFlagStatus> Error or timeout from Micron Flag Status Register (0x%.8X)", opStatus); + //Read SFDP + uint32_t outdata[4]; + SfcCustomReg_t new_cmd; + new_cmd.data32 = 0; + new_cmd.opcode = SPI_MICRON_READ_SFDP; + new_cmd.read = 1; + new_cmd.needaddr = 1; + new_cmd.clocks = 8; + new_cmd.length = 16; + l_err = readRegFlash( new_cmd, + outdata, + 0 ); + if(l_err) { break; } + + //Loop around and grab all 16 bytes + for( size_t x=0; x<4; x++ ) + { + TRACFCOMP( g_trac_pnor, "SFDP[%d]=%.8X", x, outdata[x] ); + } + /*@ * @errortype * @moduleid PNOR::MOD_PNORDD_MICRONFLAGSTATUS @@ -1206,24 +1239,29 @@ errlHndl_t PnorDD::micronFlagStatus(uint64_t i_pollTime) confData ); errlHndl_t tmp_err = NULL; tmp_err = writeRegSfc(SFC_CMD_SPACE, - SFC_REG_CHIPIDCONF, - confData); + SFC_REG_CHIPIDCONF, + confData); if(tmp_err) { - delete tmp_err; + //commit this error and return the original + tmp_err->setSev(ERRORLOG::ERRL_SEV_INFORMATIONAL); + tmp_err->plid(l_err->plid()); + ERRORLOG::errlCommit(tmp_err,PNOR_COMP_ID); } //Issue Get Chip ID command (clearing flag status) SfcCmdReg_t sfc_cmd; sfc_cmd.opcode = SFC_OP_CHIPID; sfc_cmd.length = 0; - tmp_err = writeRegSfc(SFC_CMD_SPACE, SFC_REG_CMD, sfc_cmd.data32); if(tmp_err) { - delete tmp_err; + //commit this error and return the original + tmp_err->setSev(ERRORLOG::ERRL_SEV_INFORMATIONAL); + tmp_err->plid(l_err->plid()); + ERRORLOG::errlCommit(tmp_err,PNOR_COMP_ID); } //Poll for complete status @@ -1253,7 +1291,7 @@ errlHndl_t PnorDD::getNORChipId(uint32_t& o_chipId, uint32_t i_spiOpcode) { errlHndl_t l_err = NULL; - TRACDCOMP( g_trac_pnor, "PnorDD::getNORChipId> i_spiOpcode=0x%.8x", + TRACFCOMP( g_trac_pnor, "PnorDD::getNORChipId> i_spiOpcode=0x%.8x", i_spiOpcode ); do { @@ -1296,42 +1334,30 @@ errlHndl_t PnorDD::getNORChipId(uint32_t& o_chipId, //so need to set a flag for later use //We can't read all 6 bytes above because not all MFG //support that operation. - if(o_chipId == MICRON_NOR_ID) + if( o_chipId == MICRON_NOR_ID ) { + // Assume all Micron chips have this bug + cv_hw_workaround |= HWWK_MICRON_EXT_READ; + + uint32_t outdata[4]; + //Change ChipID command to read back 6 bytes. + SfcCustomReg_t new_cmd; + new_cmd.opcode = SPI_GET_CHIPID_OP; + new_cmd.read = 1; + new_cmd.length = 6; + l_err = readRegFlash( new_cmd, + outdata ); + if(l_err) { break; } + //If bit 1 is set in 2nd word of cmd buffer data, then //We must do the workaround. //Ex: CCCCCCLL 40000000 // CCCCCC -> Industry Standard Chip ID - // LL -> Lenght of Micron extended data - // 4 -> Bit to indicate we must to erase/write workaround - confData = i_spiOpcode << 24; - confData |= 0x00800006; // 8-> read, 6->6 bytes - l_err = writeRegSfc(SFC_CMD_SPACE, - SFC_REG_CHIPIDCONF, - confData); - if(l_err) { break; } - - //Issue Get Chip ID command - SfcCmdReg_t sfc_cmd; - sfc_cmd.opcode = SFC_OP_CHIPID; - sfc_cmd.length = 0; - - l_err = writeRegSfc(SFC_CMD_SPACE, - SFC_REG_CMD, - sfc_cmd.data32); - if(l_err) { break; } - - uint32_t extIdData = 0; - - //Read the Extended from the Command Buffer - l_err = readRegSfc(SFC_CMDBUF_SPACE, - 4, //Offset into CMD BUFF space in bytes - extIdData); - if(l_err) { - break; - } - if((extIdData & 0x40000000) == 0x00000000) + // LL -> Length of Micron extended data + // 4 -> Bit to indicate we must do erase/write workaround + TRACFCOMP( g_trac_pnor, "PnorDD::getNORChipId> ExtId = %.8X %.8X", outdata[0], outdata[1] ); + if((outdata[1] & 0x40000000) == 0x00000000) { TRACFCOMP( g_trac_pnor, "PnorDD::getNORChipId> Setting Micron workaround flag" @@ -1340,6 +1366,28 @@ errlHndl_t PnorDD::getNORChipId(uint32_t& o_chipId, cv_hw_workaround |= HWWK_MICRON_WRT_ERASE; } + + //Read SFDP for FFDC + new_cmd.data32 = 0; + new_cmd.opcode = SPI_MICRON_READ_SFDP; + new_cmd.read = 1; + new_cmd.needaddr = 1; + new_cmd.clocks = 8; + new_cmd.length = 16; + l_err = readRegFlash( new_cmd, + outdata, + 0 ); + if(l_err) { break; } + + //Loop around and grab all 16 bytes + for( size_t x=0; x<4; x++ ) + { + TRACFCOMP( g_trac_pnor, "SFDP[%d]=%.8X", x, outdata[x] ); + } + + //Prove this works + l_err = micronFlagStatus(); + if(l_err) { delete l_err; } } @@ -1354,7 +1402,7 @@ errlHndl_t PnorDD::getNORChipId(uint32_t& o_chipId, * @brief Load SFC command buffer with data from PNOR */ errlHndl_t PnorDD::loadSfcBuf(uint32_t i_addr, - size_t i_size) + size_t i_size) { errlHndl_t l_err = NULL; TRACDCOMP( g_trac_pnor, "PnorDD::loadSfcBuf> i_addr=0x%.8x, i_size=0x%.8x", @@ -1602,7 +1650,7 @@ errlHndl_t PnorDD::readSfcBuffer(size_t i_size, // SFC Command Buffer is accessed 32-bits at a time uint32_t* word_ptr = static_cast<uint32_t*>(o_data); - uint32_t word_size = i_size/4; + uint32_t word_size = (ALIGN_4(i_size))/4; for( uint32_t words_read = 0; words_read < word_size; words_read ++ ) @@ -2147,6 +2195,63 @@ errlHndl_t PnorDD::eraseFlash(uint32_t i_address) return l_err; } +/** + * @brief Read a user-defined Flash Register + */ +errlHndl_t PnorDD::readRegFlash( SfcCustomReg_t i_cmd, + uint32_t* o_data, + uint32_t i_addr ) +{ + errlHndl_t l_err = NULL; + + do + { + //Do a read of flash address zero to workaround + // a micron bug with extended reads + if( (HWWK_MICRON_EXT_READ & cv_hw_workaround) + && (i_cmd.length > 4) ) + { + l_err = loadSfcBuf( 0, 1 ); + if(l_err) { break; } + } + + //Change ChipID command + l_err = writeRegSfc(SFC_CMD_SPACE, + SFC_REG_CHIPIDCONF, + i_cmd.data32); + if(l_err) { break; } + + //Setup the address (ADR) if needed + if( i_cmd.needaddr ) + { + l_err = writeRegSfc(SFC_CMD_SPACE, + SFC_REG_ADR, + i_addr); + if(l_err) { break; } + } + + //Issue (new) Get Chip ID command + SfcCmdReg_t sfc_cmd; + sfc_cmd.opcode = SFC_OP_CHIPID; + sfc_cmd.length = i_cmd.length; + l_err = writeRegSfc(SFC_CMD_SPACE, + SFC_REG_CMD, + sfc_cmd.data32); + if(l_err) { break; } + + //Poll for complete status + l_err = pollSfcOpComplete(); + if(l_err) { break; } + + //Go get the data + l_err = readSfcBuffer( i_cmd.length, + o_data ); + if(l_err) { break; } + + } while(0); + + return l_err; +} /* diff --git a/src/usr/pnor/pnordd.H b/src/usr/pnor/pnordd.H index 8d3f53486..bccd4a3c7 100644 --- a/src/usr/pnor/pnordd.H +++ b/src/usr/pnor/pnordd.H @@ -132,11 +132,13 @@ class PnorDD SPI_GET_CHIPID_OP = 0x9F, /**< Default Op code for getting NOR ChipID */ SPI_START4BA = 0x37, /**< Enable Macronix 4-Byte addressing */ - /*This command is only use on Micron NOR chips which require special - * procedure to check write & erase op complete + /* + * Micron Flash Commands */ - SPI_MICRON_FLAG_STAT = 0x70, /**< Check complete on Micron */ - SPI_MICRON_CLRFLAG_STAT = 0x50, /**< Clear Micron Flag Status reg */ + SPI_MICRON_FLAG_STAT = 0x70, /**< Check write/erase complete */ + SPI_MICRON_CLRFLAG_STAT = 0x50, /**< Clear write/erase Status reg */ + SPI_MICRON_READ_SFDP = 0x5A, /**< Read Serial Flash Disc Parms */ + SPI_MICRON_CHIPID = 0x9F, /**< Read ChipID */ SPI_SIM_SM_ERASE_OP = 0x00000020, /**< Simics Op Code for Small Erase */ SPI_SIM_SM_ERASE_SZ = 0x1000, /**< Simics Small Erase Size */ @@ -151,6 +153,7 @@ class PnorDD /* Note: Simics currently models Micron NOR */ MICRON_NOR_ID = 0x20ba2000, /**< Micron NOR chip ID */ VPO_NOR_ID = 0x20201800, /**< VPO NOR chip ID */ + MACRONIX_NOR_ID = 0xC2201A00, /**< Macronix NOR chip ID */ ID_MASK = 0xFFFFFF00, /**< Only look at 3 bytes */ }; @@ -246,7 +249,13 @@ class PnorDD * Flags used to trigger Hardware workarounds */ enum { - HWWK_MICRON_WRT_ERASE = 0x00000001, /**< Micron Wrt/Erase workaround */ + // Must perform 'read flag status' commands after + // any write or erase + HWWK_MICRON_WRT_ERASE = 0x00000001, + + // Must do a read of a low flash address before issuing read + // commands that return more than 1 word of data + HWWK_MICRON_EXT_READ = 0x00000002, }; /** @@ -289,6 +298,7 @@ class PnorDD /** +<<<<<<< HEAD * @brief LPC Slave Registers * These are offsets within the LPC Slave Register Space */ @@ -342,7 +352,24 @@ class PnorDD LBUS2OPB_TIMEOUT_ERR = 0b101, /**< Timeout Error */ }; - + /** + * @brief SFC ConfId Register Layout + */ + union SfcCustomReg_t + { + uint32_t data32; + struct + { + uint32_t opcode : 8; + uint32_t read : 1; + uint32_t write : 1; + uint32_t needaddr : 1; + uint32_t clocks : 5; + uint32_t reserved : 8; + uint32_t length : 8; + }; + SfcCustomReg_t() : data32(0) {}; + }; /** * @brief Write a SFC Register @@ -371,6 +398,20 @@ class PnorDD uint32_t& o_data); /** + * @brief Read a user-defined Flash Register + * + * @parm i_cmd Custom command + * @parm o_data Data being read + * @parm i_addr Address to use with command + * + * @return Error from operation + */ + errlHndl_t readRegFlash(SfcCustomReg_t i_cmd, + uint32_t* o_data, + uint32_t i_addr = 0); + + + /** * @brief Poll for SFC Op Complete * * @parm i_pollTime Amount of time to Poll, default SFC_POLL_TIME_NS |