summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/usr/pnor/pnordd.C197
-rw-r--r--src/usr/pnor/pnordd.H53
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
OpenPOWER on IntegriCloud