diff options
Diffstat (limited to 'src/usr/pnor/pnordd.C')
-rw-r--r-- | src/usr/pnor/pnordd.C | 197 |
1 files changed, 151 insertions, 46 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; +} /* |