summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rwxr-xr-xsrc/build/debug/simics-debug-framework.pl66
-rw-r--r--src/include/usr/lpc/lpcif.H8
-rw-r--r--src/include/usr/pnor/pnor_reasoncodes.H77
-rw-r--r--src/include/usr/pnor/pnorif.H4
-rw-r--r--src/usr/errl/plugins/errludlogregister.H13
-rw-r--r--src/usr/lpc/lpcdd.C83
-rw-r--r--src/usr/lpc/lpcdd.H3
-rw-r--r--src/usr/pnor/HBconfig22
-rw-r--r--src/usr/pnor/makefile11
-rw-r--r--src/usr/pnor/nor_micron.C198
-rw-r--r--src/usr/pnor/norflash.H164
-rw-r--r--src/usr/pnor/pnordd.C2181
-rw-r--r--src/usr/pnor/pnordd.H634
-rw-r--r--src/usr/pnor/pnorrp.C5
-rw-r--r--src/usr/pnor/pnorrp.H3
-rw-r--r--src/usr/pnor/pnorvalid.C2
-rw-r--r--src/usr/pnor/sfc_ast2400.C856
-rw-r--r--src/usr/pnor/sfc_ast2400.H295
-rw-r--r--src/usr/pnor/sfc_fake.C295
-rw-r--r--src/usr/pnor/sfc_fake.H151
-rw-r--r--src/usr/pnor/sfc_ibm.C1290
-rw-r--r--src/usr/pnor/sfc_ibm.H502
-rw-r--r--src/usr/pnor/sfcdd.C120
-rw-r--r--src/usr/pnor/sfcdd.H231
-rw-r--r--src/usr/pnor/test/makefile12
-rw-r--r--src/usr/pnor/test/pnorddtest.H662
-rw-r--r--src/usr/pnor/test/pnorrptest.H13
-rw-r--r--src/usr/pnor/test/sfc_ast2400test.H305
-rw-r--r--src/usr/pnor/test/sfc_ibmtest.H174
30 files changed, 5053 insertions, 3328 deletions
diff --git a/.gitignore b/.gitignore
index 329d35317..384632979 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,3 +18,4 @@ testdata
hbsandboxrc
*.__afs*
*~
+_SYNCAPP/
diff --git a/src/build/debug/simics-debug-framework.pl b/src/build/debug/simics-debug-framework.pl
index 1d15e7ec2..9572d1efc 100755
--- a/src/build/debug/simics-debug-framework.pl
+++ b/src/build/debug/simics-debug-framework.pl
@@ -6,7 +6,10 @@
#
# OpenPOWER HostBoot Project
#
-# COPYRIGHT International Business Machines Corp. 2011,2014
+# Contributors Listed Below - COPYRIGHT 2011,2014
+# [+] Google Inc.
+# [+] International Business Machines Corp.
+#
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -301,41 +304,10 @@ sub getHRMOR
}
-use constant PNOR_MODE_UNKNOWN => 0;
-use constant PNOR_MODE_MEMCPY => PNOR_MODE_UNKNOWN + 1;
-use constant PNOR_MODE_LPC_MEM => PNOR_MODE_MEMCPY + 1;
-use constant PNOR_MODE_REAL_CMD => PNOR_MODE_LPC_MEM + 1;
-use constant PNOR_MODE_REAL_MMIO => PNOR_MODE_REAL_CMD + 1;
-my $extImageMode = PNOR_MODE_UNKNOWN;
-my $extImageOffset = 0;
-
-use constant PNOR_DD_MODE_OFFSET => 8;
-use constant PNOR_DD_FAKESTART_OFFSET => PNOR_DD_MODE_OFFSET + 16;
-
use constant PNOR_RP_HBEXT_SECTION => 1;
use constant PNOR_RP_SECTIONDATA_SIZE => 3 * 8 + 2;
use constant PNOR_RP_SECTIONDATA_FLASHADDR_OFFSET => 2 * 8;
-sub determineExtImageInfo
-{
- my ($pnorDDAddr, $pnorDDSize) =
- ::findSymbolAddress("Singleton<PnorDD>::instance()::instance");
-
- $extImageMode = read32($pnorDDAddr + PNOR_DD_MODE_OFFSET);
- if ((PNOR_MODE_MEMCPY == $extImageMode) ||
- (PNOR_MODE_LPC_MEM == $extImageMode))
- {
- $extImageOffset = read32($pnorDDAddr + PNOR_DD_FAKESTART_OFFSET);
- }
-
- my ($pnorRPAddr, $pnorRPSize) =
- ::findSymbolAddress("Singleton<PnorRP>::instance()::instance");
-
- $extImageOffset +=
- read32($pnorRPAddr +
- (PNOR_RP_SECTIONDATA_SIZE * PNOR_RP_HBEXT_SECTION) +
- PNOR_RP_SECTIONDATA_FLASHADDR_OFFSET);
-}
# @sub readExtImage
#
@@ -348,26 +320,24 @@ sub readExtImage
my $addr = shift;
my $size = shift;
- if ($extImageMode == PNOR_MODE_UNKNOWN) { determineExtImageInfo(); }
+ my ($pnorRPAddr, $pnorRPSize) =
+ ::findSymbolAddress("Singleton<PnorRP>::instance()::instance");
- if ((PNOR_MODE_MEMCPY == $extImageMode) ||
- (PNOR_MODE_LPC_MEM == $extImageMode))
- {
- $addr += getHRMOR() + $extImageOffset;
- return readData($addr, $size);
- }
- else
- {
- $addr += $extImageOffset;
- sendIPCMsg("read-pnor", "$addr,$size");
+ my $extImageOffset +=
+ read32($pnorRPAddr +
+ (PNOR_RP_SECTIONDATA_SIZE * PNOR_RP_HBEXT_SECTION) +
+ PNOR_RP_SECTIONDATA_FLASHADDR_OFFSET);
- my ($type, $data) = recvIPCMsg();
+ $addr += $extImageOffset;
+ sendIPCMsg("read-pnor", "$addr,$size");
- if (length($data) == $size)
- {
- return $data;
- }
+ my ($type, $data) = recvIPCMsg();
+
+ if (length($data) == $size)
+ {
+ return $data;
}
+
return "";
}
diff --git a/src/include/usr/lpc/lpcif.H b/src/include/usr/lpc/lpcif.H
index f7cf9f6de..eb3eeef2c 100644
--- a/src/include/usr/lpc/lpcif.H
+++ b/src/include/usr/lpc/lpcif.H
@@ -36,10 +36,10 @@ namespace LPC
* @brief LPC Transaction Types
*/
enum TransType {
- TRANS_IO,
- TRANS_MEM,
- TRANS_FW,
- TRANS_REG, // LPCHC Register space
+ TRANS_IO, // LPC IO Space
+ TRANS_MEM, // LPC Memory Space
+ TRANS_FW, // LPC Firmware Space
+ TRANS_REG, // LPCHC Register space
TRANS_ABS, // Address parm is absolute
TRANS_LAST //Invalid, used for looping and tests
};
diff --git a/src/include/usr/pnor/pnor_reasoncodes.H b/src/include/usr/pnor/pnor_reasoncodes.H
index 2d6b272ee..96483086c 100644
--- a/src/include/usr/pnor/pnor_reasoncodes.H
+++ b/src/include/usr/pnor/pnor_reasoncodes.H
@@ -32,34 +32,55 @@ namespace PNOR
{
enum PNORModuleId
{
- MOD_PNORRP_WAITFORMESSAGE = 0x01, /**< pnorrp.C : PnorRP::waitForMessage */
- MOD_PNORRP_COMPUTEDEVICEADDR = 0x02, /**< pnorrp.C : PnorRP::computeDeviceAddr */
- MOD_PNORRP_GETSECTIONINFO = 0x03, /**< pnorrp.C : PnorRP::getSectionInfo */
- MOD_PNORRP_COMPUTESECTION = 0x04, /**< pnorrp.C : PnorRP::computeSection */
- MOD_PNORRP_INITDAEMON = 0x05, /**< pnorrp.C : PnorRP::initDaemon */
- MOD_PNORRP_READTOC = 0x06, /**< pnorrp.C : PnorRP::readTOC */
- MOD_PNORRP_READFROMDEVICE = 0x07, /**< pnorrp.C : PnorRP::readFromDevice */
- MOD_PNORRP_WRITETODEVICE = 0x08, /**< pnorrp.C : PnorRP::writeToDevice */
- MOD_PNORRP_DIDSTARTUPFAIL = 0x1C, /** didStartupFail(rc) */
+ // pnorrp.C
+ MOD_PNORRP_WAITFORMESSAGE = 0x01, /**< PnorRP::waitForMessage */
+ MOD_PNORRP_COMPUTEDEVICEADDR = 0x02, /**< PnorRP::computeDeviceAddr */
+ MOD_PNORRP_GETSECTIONINFO = 0x03, /**< PnorRP::getSectionInfo */
+ MOD_PNORRP_COMPUTESECTION = 0x04, /**< PnorRP::computeSection */
+ MOD_PNORRP_INITDAEMON = 0x05, /**< PnorRP::initDaemon */
+ MOD_PNORRP_READTOC = 0x06, /**< PnorRP::readTOC */
+ MOD_PNORRP_READFROMDEVICE = 0x07, /**< PnorRP::readFromDevice */
+ MOD_PNORRP_WRITETODEVICE = 0x08, /**< PnorRP::writeToDevice */
+ MOD_PNORRP_DIDSTARTUPFAIL = 0x09, /**< didStartupFail(rc) */
- MOD_PNORDD_VERIFYADDRESSRANGE = 0x11, /**< pnordd.C : PnorDD::verifyAddressRange */
- MOD_PNORDD_READFLASH = 0x12, /**< pnordd.C : PnorDD::readFlash */
- MOD_PNORDD_WRITEFLASH = 0x13, /**< pnordd.C : PnorDD::writeFlash */
- MOD_PNORDD_POLLSFCOPCOMPLETE = 0x14, /**< pnordd.C : PnorDD::pollSfcOpComplete */
- MOD_PNORDD_SFCINIT = 0x15, /**< pnordd.C : PnorDD::sfcInit */
- MOD_PNORDD_READREGSPI = 0x16, /**< pnordd.C : PnorDD::readRegSPI */
- MOD_PNORDD_WRITEREGSPI = 0x17, /**< pnordd.C : PnorDD::writeRegSPI */
- MOD_PNORDD_READLPC = 0x18, /**< pnordd.C : PnorDD::readLPC */
- MOD_PNORDD_WRITELPC = 0x19, /**< pnordd.C : PnorDD::writeLPC */
- MOD_PNORDD_ERASEFLASH = 0x1A, /**< pnordd.C : PnorDD::eraseFlash */
- MOD_PNORDD_MICRONFLAGSTATUS = 0x1B, /**< pnordd.C : PnorDD::micronFlagStatus */
- MOD_PNORDD_CHECKFORSFCERRORS = 0x1D, /**< pnordd.C : PnorDD::checkForErrors */
- MOD_PNORDD_CHECKFOROPBERRORS = 0x1E, /**< pnordd.C : PnorDD::checkForErrors */
- MOD_PNORDD_HANDLEECCBERROR = 0x1F, /**< pnordd.C : PnorDD::handleEccbError */
- MOD_PNORDD_RESETPNOR = 0x20, /**< pnordd.C : PnorDD::resetPnor */
- MOD_PNORVALID_MAIN = 0x21, /**< pnorvalid.C : Main Function */
- MOD_PNORVALID_MAGIC = 0x22, /**< pnorvalid.C : Magic Function */
+ // pnorvalid.C
+ MOD_PNORVALID_MAIN = 0x0E, /**< validateAltMaster */
+ MOD_PNORVALID_MAGIC = 0x0F, /**< validateAltMaster */
+ // pnordd.C
+ MOD_PNORDD_VERIFYADDRESSRANGE = 0x11, /**< PnorDD::verifyAddressRange */
+ MOD_PNORDD_READFLASH = 0x12, /**< PnorDD::readFlash */
+ MOD_PNORDD_WRITEFLASH = 0x13, /**< PnorDD::writeFlash */
+ MOD_PNORDD_SFCINIT = 0x14, /**< PnorDD::sfcInit */
+ MOD_PNORDD_ERASEFLASH = 0x15, /**< PnorDD::eraseFlash */
+ MOD_PNORDD_CHECKFORERRORS = 0x16, /**< PnorDD::checkForErrors */
+
+ // sfc_ibm.C
+ MOD_SFCIBM_VERIFYADDRESSRANGE = 0x40, /**< SfcIBM::verifyAddressRange */
+ MOD_SFCIBM_READFLASH = 0x41, /**< SfcIBM::readFlash */
+ MOD_SFCIBM_WRITEFLASH = 0x42, /**< SfcIBM::writeFlash */
+ MOD_SFCIBM_POLLOPCOMPLETE = 0x43, /**< SfcIBM::pollSfcOpComplete */
+ MOD_SFCIBM_SFCINIT = 0x44, /**< SfcIBM::sfcInit */
+ MOD_SFCIBM_ERASEFLASH = 0x45, /**< SfcIBM::eraseFlash */
+ MOD_SFCIBM_CHECKFORERRORS = 0x46, /**< SfcIBM::checkForErrors */
+ MOD_SFCIBM_HWRESET = 0x47, /**< SfcIBM::hwReset */
+
+ // sfc_fake.C
+ MOD_SFCFAKE_VERIFYADDRESSRANGE = 0x60, /**< SfcFake::verifyAddressRange */
+ MOD_SFCFAKE_READFLASH = 0x61, /**< SfcFake::readFlash */
+ MOD_SFCFAKE_WRITEFLASH = 0x62, /**< SfcFake::writeFlash */
+ MOD_SFCFAKE_ERASEFLASH = 0x63, /**< SfcFake::eraseFlash */
+ MOD_SFCFAKE_SENDSPICMD = 0x64, /**< SfcFake::sendSpiCmd */
+
+ // sfc_ast2400.C
+ MOD_SFCAST2400_ENABLEWRITEMODE = 0x80, /**< SfcAST2400::verifyAddressRange */
+ MOD_SFCAST2400_READFLASH = 0x81, /**< SfcAST2400::readFlash */
+ MOD_SFCAST2400_WRITEFLASH = 0x82, /**< SfcAST2400::writeFlash */
+ MOD_SFCAST2400_POLLOPCOMPLETE = 0x83, /**< SfcAST2400::pollSfcOpComplete */
+ MOD_SFCAST2400_ERASEFLASH = 0x84, /**< SfcAST2400::eraseFlash */
+
+ // nor_micron.C
+ MOD_NORMICRON_MICRONFLAGSTATUS = 0xA0, /**< micronFlagStatus */
};
enum PNORReasonCode
@@ -88,6 +109,10 @@ namespace PNOR
//termination_rc
RC_REINITIALIZE_SFC = PNOR_COMP_ID | 0x11,
RC_SFC_ERROR = PNOR_COMP_ID | 0x12,
+ //termination_rc
+ RC_PNOR_INIT_FAILURE = PNOR_COMP_ID | 0x13,
+ RC_CANNOT_ENABLE_WRITES = PNOR_COMP_ID | 0x14,
+ RC_SFC_TIMEOUT = PNOR_COMP_ID | 0x15,
};
enum UserDetailsTypes
diff --git a/src/include/usr/pnor/pnorif.H b/src/include/usr/pnor/pnorif.H
index 37c17d424..6aed66234 100644
--- a/src/include/usr/pnor/pnorif.H
+++ b/src/include/usr/pnor/pnorif.H
@@ -55,7 +55,9 @@ enum SectionId
MODULE_VPD, /**< Module VPD */
CENTAUR_VPD, /**< Centaur VPD */
ATTR_OVER, /**< Attribute Override */
+ NVRAM, /**< Opal NVRAM */
TEST, /**< Scratch space for PNOR test cases */
+
NUM_SECTIONS, /**< Number of defined sections */
FIRST_SECTION = TOC, /**< First section (for looping) */
@@ -116,6 +118,4 @@ const uint32_t pnorTestSec_BMCAttrOverride_offset = 0x200;
}
-
-
#endif
diff --git a/src/usr/errl/plugins/errludlogregister.H b/src/usr/errl/plugins/errludlogregister.H
index 87450fad6..f795a9643 100644
--- a/src/usr/errl/plugins/errludlogregister.H
+++ b/src/usr/errl/plugins/errludlogregister.H
@@ -5,7 +5,10 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* COPYRIGHT International Business Machines Corp. 2012,2014 */
+/* Contributors Listed Below - COPYRIGHT 2013,2014 */
+/* [+] Google Inc. */
+/* [+] International Business Machines Corp. */
+/* */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); */
/* you may not use this file except in compliance with the License. */
@@ -142,6 +145,14 @@ public:
addrParams.push_back(" I2C slave device address");
addrParams.push_back(" EEPROM chip number");
break;
+ case DeviceFW::LPC: // driverif.H
+ i_parser.PrintString("AccessType", "DeviceFW::LPC");
+ i_parser.PrintString("Ranges",
+ "0=IO,1=MEM,2=FW,3=REG,4=ABS");
+ numArgs = 2;
+ addrParams.push_back(" Range");
+ addrParams.push_back(" Addr");
+ break;
// three parameters
case DeviceFW::I2C: // driverif.H
i_parser.PrintString("AccessType", "DeviceFW::I2C");
diff --git a/src/usr/lpc/lpcdd.C b/src/usr/lpc/lpcdd.C
index 9124f0803..db217bda4 100644
--- a/src/usr/lpc/lpcdd.C
+++ b/src/usr/lpc/lpcdd.C
@@ -92,9 +92,10 @@ errlHndl_t lpcRead(DeviceFW::OperationType i_opType,
uint64_t l_addr = va_arg(i_args,uint64_t);
errlHndl_t l_err = NULL;
- assert( io_buflen == sizeof(uint8_t) ||
- io_buflen == sizeof(uint16_t) ||
- io_buflen == sizeof(uint32_t) );
+ // Only able to do 1,2,4 byte LPC operations
+ assert( (io_buflen == sizeof(uint8_t)) ||
+ (io_buflen == sizeof(uint16_t)) ||
+ (io_buflen == sizeof(uint32_t)) );
// if the request is for something besides the master sentinel
// then we have to use our special side copy of the driver
@@ -180,9 +181,10 @@ errlHndl_t lpcWrite(DeviceFW::OperationType i_opType,
uint64_t l_addr = va_arg(i_args,uint64_t);
errlHndl_t l_err = NULL;
- assert( io_buflen == sizeof(uint8_t) ||
- io_buflen == sizeof(uint16_t) ||
- io_buflen == sizeof(uint32_t) );
+ // Only able to do 1,2,4 byte LPC operations
+ assert( (io_buflen == sizeof(uint8_t)) ||
+ (io_buflen == sizeof(uint16_t)) ||
+ (io_buflen == sizeof(uint32_t)) );
// if the request is for something besides the master sentinel
// then we have to use our special side copy of the driver
@@ -236,7 +238,6 @@ errlHndl_t lpcWrite(DeviceFW::OperationType i_opType,
}
return l_err;
-
}
// Register LPC access functions to DD framework
@@ -442,6 +443,22 @@ errlHndl_t LpcDD::hwReset( ResetLevels i_resetLevel )
break;
}
+ case RESET_INIT:
+ {
+ // Set OPB LPCM FIR Mask
+ // hostboot will monitor these FIR bits
+ size_t scom_size = sizeof(uint64_t);
+ uint64_t fir_mask_data = OPB_LPCM_FIR_ERROR_MASK;
+ // Write FIR Register
+ l_err = deviceOp( DeviceFW::WRITE,
+ iv_proc,
+ &(fir_mask_data),
+ scom_size,
+ DEVICE_SCOM_ADDRESS(
+ OPB_LPCM_FIR_MASK_WO_OR_REG));
+ if( l_err ) { break; }
+ }
+
case RESET_ECCB:
{
// Write Reset Register to reset FW Logic registers
@@ -558,7 +575,6 @@ errlHndl_t LpcDD::hwReset( ResetLevels i_resetLevel )
0,
true /*SW error*/);
- l_err->collectTrace(PNOR_COMP_NAME);
l_err->collectTrace(LPC_COMP_NAME);
break;
@@ -567,7 +583,7 @@ errlHndl_t LpcDD::hwReset( ResetLevels i_resetLevel )
if ( l_err )
{
- // Indicate that we weren't successful in resetting LPC
+ // Indicate that we weren't successful in resetting
iv_errorRecoveryFailed = true;
TRACFCOMP( g_trac_lpc,ERR_MRK"LpcDD::hwReset> Fail doing LPC reset at level 0x%X (recovery count=%d): eid=0x%X", i_resetLevel, iv_errorHandledCount, l_err->eid());
}
@@ -621,19 +637,9 @@ errlHndl_t LpcDD::checkAddr(LPC::TransType i_type,
*o_addr = i_addr + LPCHC_MEM_SPACE;
break;
case LPC::TRANS_FW:
- if( i_addr < LPCHC_FW_SPACE )
- {
- invalid_address = true;
- break;
- }
- *o_addr = i_addr;
+ *o_addr = i_addr + LPCHC_FW_SPACE;
break;
case LPC::TRANS_REG:
- if( i_addr >= 0x100 )
- {
- invalid_address = true;
- break;
- }
*o_addr = i_addr + LPCHC_REG_SPACE;
break;
case LPC::TRANS_ABS:
@@ -646,6 +652,7 @@ errlHndl_t LpcDD::checkAddr(LPC::TransType i_type,
if( invalid_address )
{
+ TRACFCOMP( g_trac_lpc, "LpcDD::checkAddr() Invalid address : i_type=%d, i_addr=%X", i_type, i_addr );
/*@
* @errortype
* @moduleid LPC::MOD_LPCDD_CHECKADDR
@@ -777,9 +784,6 @@ errlHndl_t LpcDD::_writeLPC(LPC::TransType i_type,
break;
}
- LPC_TRACFCOMP(g_trac_lpc, "writeLPC> %08X[%d] = %08X", l_addr, io_buflen,
- eccb_data >> (32 + 8 * (4 - io_buflen)));
-
// Write data out
size_t scom_size = sizeof(uint64_t);
l_err = deviceOp( DeviceFW::WRITE,
@@ -913,7 +917,6 @@ errlHndl_t LpcDD::pollComplete(const ControlReg_t &i_ctrl,
addFFDC(l_err);
l_err->collectTrace(LPC_COMP_NAME);
- l_err->collectTrace(PNOR_COMP_NAME);
l_err->collectTrace(XSCOM_COMP_NAME);
// Reset ECCB - handled below
@@ -932,18 +935,26 @@ errlHndl_t LpcDD::pollComplete(const ControlReg_t &i_ctrl,
if ( l_err && ( l_resetLevel != RESET_CLEAR ) )
{
errlHndl_t tmp_err = hwReset(l_resetLevel);
-
if ( tmp_err )
{
// Commit reset error since we have original error l_err
TRACFCOMP(g_trac_lpc, "LpcDD::pollComplete> Error from reset() after previous error eid=0x%X. Committing reset() error log eid=0x%X.", l_err->eid(), tmp_err->eid());
tmp_err->setSev(ERRORLOG::ERRL_SEV_INFORMATIONAL);
- tmp_err->collectTrace(PNOR_COMP_NAME);
tmp_err->collectTrace(LPC_COMP_NAME);
tmp_err->plid(l_err->plid());
errlCommit(tmp_err, LPC_COMP_ID);
}
+
+ // Limited in callout: no LPC sub-target, so calling out processor
+ l_err->addHwCallout( iv_proc,
+ HWAS::SRCI_PRIORITY_HIGH,
+ HWAS::NO_DECONFIG,
+ HWAS::GARD_NULL );
+
+ addFFDC(l_err);
+ l_err->collectTrace(LPC_COMP_NAME);
+ l_err->collectTrace(XSCOM_COMP_NAME);
}
return l_err;
@@ -964,19 +975,15 @@ void LpcDD::addFFDC(errlHndl_t & io_errl)
ERRORLOG::ErrlUserDetailsLogRegister l_eud(iv_proc);
- do {
- // Add ECCB Status Register
- l_eud.addData(DEVICE_SCOM_ADDRESS(ECCB_STAT_REG));
+ // Add ECCB Status Register
+ l_eud.addData(DEVICE_SCOM_ADDRESS(ECCB_STAT_REG));
- // Add OPB LPC Master FIR
- l_eud.addData(DEVICE_SCOM_ADDRESS(OPB_LPCM_FIR_REG));
-
- //@todo - add more LPC regs RTC:37744
- //LPCIRQ_STATUS = 0x38
- //SYS_ERR_ADDR = 0x40
-
- } while(0);
+ // Add OPB LPC Master FIR
+ l_eud.addData(DEVICE_SCOM_ADDRESS(OPB_LPCM_FIR_REG));
+ //@todo - add more LPC regs RTC:37744
+ //LPCIRQ_STATUS = 0x38
+ //SYS_ERR_ADDR = 0x40
l_eud.addToLog(io_errl);
@@ -1117,7 +1124,6 @@ errlHndl_t LpcDD::checkForOpbErrors( ResetLevels &o_resetLevel )
fir_reg.data64,
o_resetLevel );
- // Limited in callout: no PNOR target, so calling out processor
l_err->addHwCallout( iv_proc,
HWAS::SRCI_PRIORITY_HIGH,
HWAS::NO_DECONFIG,
@@ -1133,7 +1139,6 @@ errlHndl_t LpcDD::checkForOpbErrors( ResetLevels &o_resetLevel )
l_eud.addToLog(l_err);
addFFDC(l_err);
- l_err->collectTrace(PNOR_COMP_NAME);
l_err->collectTrace(LPC_COMP_NAME);
}
diff --git a/src/usr/lpc/lpcdd.H b/src/usr/lpc/lpcdd.H
index 074c5da98..3fa8388f2 100644
--- a/src/usr/lpc/lpcdd.H
+++ b/src/usr/lpc/lpcdd.H
@@ -85,8 +85,7 @@ class LpcDD
RESET_ECCB = 0x00000001, /**< ECCB FW Logic */
RESET_OPB_LPCHC_SOFT = 0x00000002, /**< OPB LPCHC Clear Errors */
RESET_OPB_LPCHC_HARD = 0x00000004, /**< OPB LPCHC Reset Logic */
-
- RESET_INIT = RESET_CLEAR, // Nothing to do for initial boot yet
+ RESET_INIT = 0x00000008, /**< Initial HW setup */
};
diff --git a/src/usr/pnor/HBconfig b/src/usr/pnor/HBconfig
index e25089cef..bc1ebc9dd 100644
--- a/src/usr/pnor/HBconfig
+++ b/src/usr/pnor/HBconfig
@@ -1,16 +1,20 @@
config SFC_IS_IBM_DPSS
- default y if !SFC_IS_AST2400
- depends on !SFC_IS_AST2400
+ default y
+ depends on !SFC_IS_AST2400 && !SFC_IS_FAKE
help
The Serial Flash Controller is the IBM DPSS FPGA.
config SFC_IS_AST2400
default n
- depends on !SFC_IS_IBM_DPSS && BMC_DOES_SFC_INIT
+ depends on !SFC_IS_IBM_DPSS && !SFC_IS_FAKE
help
The Serial Flash Controller is the AST2400 BMC.
-
+config SFC_IS_FAKE
+ default n
+ depends on !SFC_IS_IBM_DPSS && !SFC_IS_AST2400
+ help
+ The Serial Flash Controller is emulated using memory.
config BMC_DOES_SFC_INIT
default y
@@ -19,3 +23,13 @@ config BMC_DOES_SFC_INIT
SFC before Hostboot is started. The BMC is also responsible for doing
any repairs or recovery for the SFC.
+config ALLOW_MICRON_PNOR
+ default y
+ help
+ Include support for Micron PNOR chips
+
+config ALLOW_MACRONIX_PNOR
+ default y
+ help
+ Include support for Macronix PNOR chips
+
diff --git a/src/usr/pnor/makefile b/src/usr/pnor/makefile
index c9a37cc3e..e6585c123 100644
--- a/src/usr/pnor/makefile
+++ b/src/usr/pnor/makefile
@@ -6,6 +6,7 @@
# OpenPOWER HostBoot Project
#
# Contributors Listed Below - COPYRIGHT 2011,2014
+# [+] Google Inc.
# [+] International Business Machines Corp.
#
#
@@ -29,6 +30,16 @@ OBJS += pnorrp.o
OBJS += pnordd.o
OBJS += pnorvalid.o
OBJS += ecc.o
+OBJS += sfcdd.o
+
+#SFC Implementations
+OBJS += $(if $(CONFIG_SFC_IS_IBM_DPSS),sfc_ibm.o)
+OBJS += $(if $(CONFIG_SFC_IS_AST2400),sfc_ast2400.o)
+OBJS += $(if $(CONFIG_SFC_IS_FAKE),sfc_fake.o)
+
+#NOR Implementations
+OBJS += $(if $(CONFIG_ALLOW_MICRON_PNOR),nor_micron.o)
+
SUBDIRS += test.d
diff --git a/src/usr/pnor/nor_micron.C b/src/usr/pnor/nor_micron.C
new file mode 100644
index 000000000..817b1d3fd
--- /dev/null
+++ b/src/usr/pnor/nor_micron.C
@@ -0,0 +1,198 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/pnor/nor_micron.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2014 */
+/* [+] Google Inc. */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#include "norflash.H"
+#include "sfcdd.H"
+#include <pnor/pnor_reasoncodes.H>
+#include <errl/errlentry.H>
+#include <errl/errlmanager.H>
+#include <errl/errlreasoncodes.H>
+
+// Initialized in pnorrp.C
+extern trace_desc_t* g_trac_pnor;
+
+
+namespace PNOR {
+
+/**
+ * @brief Check the version of the part to see if it has any
+ * known errors that require a workaround.
+ */
+errlHndl_t micronCheckForWorkarounds( SfcDD* i_sfc,
+ uint32_t& o_workarounds )
+{
+ errlHndl_t l_err = NULL;
+
+ do {
+ // Assume all Micron chips have this bug
+ o_workarounds |= HWWK_MICRON_EXT_READ;
+
+ uint32_t outdata[4];
+
+ //Read back full 6 bytes of chipid
+ l_err = i_sfc->sendSpiCmd( PNOR::SPI_JEDEC_CHIPID,
+ SfcDD::NO_ADDRESS,
+ 0, NULL,
+ 6, reinterpret_cast<uint8_t*>(outdata) );
+ if(l_err) { break; }
+
+ //If bit 1 (indicates 45nm new part) is set in 2nd word of cmd buffer
+ // data, then we do not need the workaround.
+ //Ex: CCCCCCLL 40000000
+ // CCCCCC -> Industry Standard Chip ID
+ // LL -> Length of Micron extended data
+ // 4 -> Bit to indicate we do not need the erase/write workaround
+ TRACFCOMP( g_trac_pnor, "micronCheckForWorkarounds> ExtId = %.8X %.8X", outdata[0], outdata[1] );
+ if((outdata[1] & 0x40000000) == 0x00000000)
+ {
+ TRACFCOMP( g_trac_pnor, "micronCheckForWorkarounds> Setting Micron workaround flag" );
+ //Set Micron workaround flag
+ o_workarounds |= HWWK_MICRON_WRT_ERASE;
+ }
+
+ //Prove this works
+ l_err = micronFlagStatus( i_sfc );
+ if(l_err) { delete l_err; }
+
+ } while(0);
+
+ return l_err;
+}
+
+/**
+ * @brief Check flag status bit on Micron NOR chips
+ * Some versions of Micron parts require the Flag
+ * Status register be read after a write or erase operation,
+ * otherwise all future operations won't work..
+ */
+errlHndl_t micronFlagStatus( SfcDD* i_sfc )
+{
+ errlHndl_t l_err = NULL;
+ TRACDCOMP( g_trac_pnor, "micronFlagStatus>" );
+
+ do {
+ //Read Micron 'flag status' register
+ uint8_t flagstat = 0;
+ l_err = i_sfc->sendSpiCmd( SPI_MICRON_FLAG_STAT,
+ SfcDD::NO_ADDRESS,
+ 0, NULL,
+ sizeof(flagstat), &flagstat );
+ if(l_err) { break; }
+
+ TRACDCOMP(g_trac_pnor,
+ "micronFlagStatus> (0x%.2X)",
+ flagstat);
+
+ // check for ready and no errors
+ // bit 0 = ready, bit 2=erase fail, bit 3=Program (Write) failure
+ if( (flagstat & 0xB0) != 0x80)
+ {
+ TRACFCOMP(g_trac_pnor, "micronFlagStatus> Error or timeout from Micron Flag Status Register (0x%.2X)", flagstat);
+
+ //Read back full 6 bytes of chipid
+ uint32_t outdata[2];
+ l_err = i_sfc->sendSpiCmd( PNOR::SPI_JEDEC_CHIPID,
+ SfcDD::NO_ADDRESS,
+ 0, NULL,
+ 6, reinterpret_cast<uint8_t*>(outdata) );
+ if( l_err ) { delete l_err; }
+
+ /*@
+ * @errortype
+ * @moduleid PNOR::MOD_NORMICRON_MICRONFLAGSTATUS
+ * @reasoncode PNOR::RC_MICRON_INCOMPLETE
+ * @userdata1[0:31] Micron Flag status register
+ * @userdata2 NOR Flash Chip ID
+ * @devdesc micronFlagStatus> Error or timeout from
+ * Micron Flag Status Register
+ * @custdesc Hardware error accessing flash during IPL
+ */
+ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ PNOR::MOD_NORMICRON_MICRONFLAGSTATUS,
+ PNOR::RC_MICRON_INCOMPLETE,
+ TWO_UINT32_TO_UINT64(flagstat,0),
+ TWO_UINT32_TO_UINT64(outdata[0],
+ outdata[1]) );
+
+ // Limited in callout: no PNOR target, so calling out processor
+ l_err->addHwCallout(
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ HWAS::SRCI_PRIORITY_HIGH,
+ HWAS::NO_DECONFIG,
+ HWAS::GARD_NULL );
+ i_sfc->addFFDC(l_err);
+
+ //Read out SFDP
+ uint8_t sfdp[16];
+ l_err = i_sfc->sendSpiCmd( PNOR::SPI_JEDEC_READ_SFDP,
+ 0,
+ 0, NULL,
+ 16, sfdp );
+ if( l_err )
+ {
+ delete l_err;
+ }
+ else
+ {
+ //@fixme-RTC:115212 - Create userdetails class
+ l_err->addFFDC( PNOR_COMP_ID,
+ sfdp,
+ sizeof(sfdp),
+ 0, // Version
+ ERRORLOG::ERRL_UDT_NOFORMAT,
+ false ); // merge
+ }
+
+ //Erase & Program error bits are sticky,
+ // so they need to be cleared.
+ uint8_t flagstat = 0;
+ errlHndl_t tmp_err = i_sfc->sendSpiCmd( SPI_MICRON_CLRFLAG_STAT,
+ SfcDD::NO_ADDRESS,
+ sizeof(flagstat),
+ &flagstat,
+ 0,
+ NULL );
+ if(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);
+ }
+
+ l_err->collectTrace(PNOR_COMP_NAME);
+
+ break;
+ }
+
+
+ }while(0);
+
+ return l_err;
+
+}
+
+
+};//namespace PNOR
diff --git a/src/usr/pnor/norflash.H b/src/usr/pnor/norflash.H
new file mode 100644
index 000000000..4ab2628fe
--- /dev/null
+++ b/src/usr/pnor/norflash.H
@@ -0,0 +1,164 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/pnor/norflash.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2014 */
+/* [+] Google Inc. */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __PNOR_NORFLASH_H
+#define __PNOR_NORFLASH_H
+#include <config.h>
+#include <errl/errlentry.H>
+
+class SfcDD;
+
+/** @file norflash.H
+ * @brief Contains constants related to specific types of
+ * of NOR flash chips
+ */
+
+namespace PNOR {
+
+/**
+ * @brief Supported NOR Chip IDs
+ */
+enum NorChipIDs
+{
+ UNKNOWN_NOR_ID = 0x12345600, /**< Initial value before read */
+
+ MICRON_MFG_ID = 0x20000000, /**< Micron Mfg ID */
+ MICRON_NOR_ID = 0x20ba2000, /**< Micron NOR */
+
+ MACRONIX_MFG_ID = 0xC2000000, /**< Macronix Mfg ID */
+ MACRONIX32_NOR_ID = 0xC2201A00, /**< Macronix NOR MXxxL51235F */
+ MACRONIX64_NOR_ID = 0xC2201900, /**< Macronix NOR MXxxL25635F */
+
+ /* Note: Simics currently models Micron NOR */
+ VPO_NOR_ID = 0x20201800, /**< VPO NOR chip ID */
+ FAKE_NOR_ID = 0xBADBAD00, /**< ID used during fake pnor */
+
+ ID_MASK = 0xFFFFFF00, /**< Only look at 3 bytes */
+ MFGID_MASK = 0xFF000000, /**< Manufacturer ID is the first byte */
+};
+
+/**
+ * @brief SPI Config Info
+ * OP Codes and other MISC info for configuring SFC
+ */
+enum SpiConfigInfo
+{
+ SPI_NO_OPCODE = 0x00, /**< Undefined value */
+
+ /*
+ * Micron Flash Commands
+ */
+ SPI_MICRON_FLAG_STAT = 0x70, /**< Check write/erase complete */
+ SPI_MICRON_CLRFLAG_STAT = 0x50, /**< Clear write/erase Status reg */
+
+ /*
+ * Macronix Flash Commands
+ */
+ SPI_MACRONIX_EN4B = 0xB7, /**< Enable Macronix 4-Byte addressing */
+
+ /* SPI protocol commands */
+ SPI_JEDEC_WRITE_STATUS = 0x01, //WRSR
+ SPI_JEDEC_PAGE_PROGRAM = 0x02, //PP
+ SPI_JEDEC_READ = 0x03, //READ
+ SPI_JEDEC_WRITE_DISABLE = 0x04, //WRDI
+ SPI_JEDEC_READ_STATUS = 0x05, //RDSR
+ SPI_JEDEC_WRITE_ENABLE = 0x06, //WREN
+ SPI_JEDEC_FAST_READ = 0x0B, //FAST_READ
+ SPI_JEDEC_SECTOR_ERASE = 0x20, //SE
+ SPI_JEDEC_READ_SFDP = 0x5A, //RDSFDP
+ SPI_JEDEC_CHIPID = 0x9F, //RDID
+ SPI_JEDEC_BLOCK_ERASE = 0xD8, //BE
+
+};
+
+/**
+ * Common format of Status Register
+ */
+union NorStatusReg_t
+{
+ uint8_t data8;
+ struct
+ {
+ uint8_t writeProtect : 1; //0
+ uint8_t rsvd : 5; //1:5
+ uint8_t writeEnable : 1; //6
+ uint8_t writeInProgress : 1; //7
+ };
+ NorStatusReg_t() : data8(0x00) { };
+};
+
+/**
+ * Flags used to trigger Hardware workarounds
+ */
+enum VendorWorkarounds
+{
+ // No workarounds present
+ HWWK_NO_WORKAROUNDS = 0x00000000,
+
+ // 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,
+};
+
+
+/*
+ * Vendor-specific interfaces
+ */
+#ifdef CONFIG_ALLOW_MICRON_PNOR
+
+/**
+ * @brief Check the version of the part to see if it has any
+ * known errors that require a workaround.
+ *
+ * @parm i_sfc SFC driver to operate on
+ * @parm o_workarounds Function will OR in any flags it discovers
+ *
+ * @return error from operation
+ */
+errlHndl_t micronCheckForWorkarounds( SfcDD* i_sfc,
+ uint32_t& o_workarounds );
+
+/**
+ * @brief Check flag status bit on Micron NOR chips
+ * The current version of Micron parts require the Flag
+ * Status register be read after a read or erase operation,
+ * otherwise all future operations won't work..
+ *
+ * @parm i_sfc SFC driver to operate on
+ *
+ * @return Error from operation
+ */
+errlHndl_t micronFlagStatus( SfcDD* i_sfc );
+
+#endif
+
+
+};//namespace PNOR
+
+#endif
diff --git a/src/usr/pnor/pnordd.C b/src/usr/pnor/pnordd.C
index 2d9bc1854..e5b8bd7f3 100644
--- a/src/usr/pnor/pnordd.C
+++ b/src/usr/pnor/pnordd.C
@@ -53,7 +53,7 @@
#include <util/align.H>
#include <lpc/lpcif.H>
#include <config.h>
-
+#include "sfcdd.H"
/*****************************************************************************/
// D e f i n e s
@@ -66,11 +66,6 @@ extern trace_desc_t* g_trac_pnor;
namespace PNOR
{
- enum {
- VPO_MODE_MEMCPY = 0xFAC0FAC0FAC0FAC0,
- VPO_MODE_MMIO = 0xDAB0DAB0DAB0DAB0,
- };
-
/**
* @brief Performs an PNOR Read Operation
* This function performs a PNOR Read operation. It follows a pre-defined
@@ -150,10 +145,10 @@ errlHndl_t ddRead(DeviceFW::OperationType i_opType,
*/
errlHndl_t ddWrite(DeviceFW::OperationType i_opType,
TARGETING::Target* i_target,
- void* io_buffer,
- size_t& io_buflen,
- int64_t i_accessType,
- va_list i_args)
+ void* io_buffer,
+ size_t& io_buflen,
+ int64_t i_accessType,
+ va_list i_args)
{
errlHndl_t l_err = NULL;
uint64_t l_addr = va_arg(i_args,uint64_t);
@@ -223,28 +218,14 @@ errlHndl_t PnorDD::readFlash(void* o_buffer,
uint64_t i_address)
{
//TRACDCOMP(g_trac_pnor, "PnorDD::readFlash(i_address=0x%llx)> ", i_address);
- errlHndl_t l_err = NULL;
- do{
- //mask off chip select for now, will probably break up fake PNOR into
- //multiple fake chips eventually
- uint64_t l_address = i_address & 0x00000000FFFFFFFF;
+ //mask off chip select for now, will probably break up fake PNOR into
+ //multiple fake chips eventually
+ uint64_t l_address = i_address & 0x00000000FFFFFFFF;
- // skip everything in MEMCPY mode
- if( MODEL_MEMCPY == iv_mode )
- {
- read_fake_pnor( l_address, o_buffer, io_buflen );
- break;
- }
-
- //If we get here we're doing either MODEL_LPC_MEM, MODEL_REAL_CMD, or MODEL_REAL_MMIO
- mutex_lock(iv_mutex_ptr);
- l_err = bufferedSfcRead(i_address, io_buflen, o_buffer);
- mutex_unlock(iv_mutex_ptr);
-
- if(l_err) { break;}
-
- }while(0);
+ mutex_lock(iv_mutex_ptr);
+ errlHndl_t l_err = _readFlash( l_address, io_buflen, o_buffer );
+ mutex_unlock(iv_mutex_ptr);
return l_err;
}
@@ -266,36 +247,14 @@ errlHndl_t PnorDD::writeFlash(void* i_buffer,
//multiple fake chips eventually
uint64_t l_address = i_address & 0x00000000FFFFFFFF;
- // skip everything in MEMCPY mode
- if( MODEL_MEMCPY == iv_mode )
- {
- write_fake_pnor( l_address, i_buffer, io_buflen );
- break;
- }
-
- //If we get here we're doing either MODEL_LPC_MEM, MODEL_REAL_CMD, or MODEL_REAL_MMIO
-
- //If we're in VPO, just do the write directly (no erases)
- if(0 != iv_vpoMode)
- {
- mutex_lock(iv_mutex_ptr);
- l_err = bufferedSfcWrite(static_cast<uint32_t>(l_address),
- 8,
- i_buffer);
- mutex_unlock(iv_mutex_ptr);
- break;
- }
-
-
- // LPC is accessed 32-bits at a time, but SFC has a 256byte buffer
- // but we also need to be smart about handling erases. In NOR
- // flash we can clear bits without an erase but we cannot set them.
- // When we erase we have to erase an entire block of data at a time.
+ // In NOR flash we can clear bits without an erase but we
+ // cannot set them. When we erase we have to erase an entire
+ // block of data at a time.
uint32_t cur_writeStart_addr = static_cast<uint32_t>(l_address);
uint32_t cur_blkStart_addr = findEraseBlock(cur_writeStart_addr);
- uint32_t cur_blkEnd_addr = cur_blkStart_addr + iv_erasesize_bytes;
- uint32_t write_bytes = iv_erasesize_bytes;
+ uint32_t cur_blkEnd_addr = cur_blkStart_addr + iv_eraseSizeBytes;
+ uint32_t write_bytes = iv_eraseSizeBytes;
uint64_t num_blocks = getNumAffectedBlocks(cur_writeStart_addr,io_buflen);
uint64_t bytes_left = io_buflen;
@@ -310,9 +269,9 @@ errlHndl_t PnorDD::writeFlash(void* i_buffer,
// writing at a block boundary, just write the whole thing
if( cur_writeStart_addr == cur_blkStart_addr )
{
- if( bytes_left > iv_erasesize_bytes )
+ if( bytes_left > iv_eraseSizeBytes )
{
- write_bytes = iv_erasesize_bytes;
+ write_bytes = iv_eraseSizeBytes;
}
else
{
@@ -347,8 +306,10 @@ errlHndl_t PnorDD::writeFlash(void* i_buffer,
if( l_err ) { break; }
- cur_blkStart_addr = cur_blkEnd_addr; //move start to end of current erase block
- cur_blkEnd_addr += iv_erasesize_bytes;; //increment end by erase block size.
+ //move start to end of current erase block
+ cur_blkStart_addr = cur_blkEnd_addr;
+ //increment end by erase block size.
+ cur_blkEnd_addr += iv_eraseSizeBytes;
cur_writeStart_addr += write_bytes;
bytes_left -= write_bytes;
@@ -375,37 +336,20 @@ errlHndl_t PnorDD::writeFlash(void* i_buffer,
********************/
mutex_t PnorDD::cv_mutex = MUTEX_INITIALIZER;
-//
-// @note fake pnor no longer needs to allow from for SLW
-// image so it is now 4MB.
-//
-#define FAKE_PNOR_START (4*MEGABYTE)
-#define FAKE_PNOR_END (8*MEGABYTE)
-#define FAKE_PNOR_SIZE (FAKE_PNOR_END-FAKE_PNOR_START)
-
/**
* @brief Constructor
*/
-PnorDD::PnorDD( PnorMode_t i_mode,
- uint64_t i_fakeStart,
- uint64_t i_fakeSize,
- TARGETING::Target* i_target )
-: iv_mode(i_mode)
-, iv_vpoMode(0)
-, iv_nor_chipid(0)
-, iv_hw_workaround(0)
-, iv_sfcInitDone(false)
-, iv_ffdc_active(false)
-, iv_error_handled_count(0x0)
-, iv_error_recovery_failed(false)
-, iv_reset_active(false)
+PnorDD::PnorDD( TARGETING::Target* i_target )
+: iv_eraseSizeBytes(ERASESIZE_BYTES_DEFAULT)
+, iv_norChipId(0)
+, iv_sfc(NULL)
{
- iv_erasesize_bytes = ERASESIZE_BYTES_DEFAULT;
+ TRACFCOMP(g_trac_pnor, ENTER_MRK "PnorDD::PnorDD()" );
+ errlHndl_t l_err = NULL;
//Zero out erase counter
memset(iv_erases, 0xff, sizeof(iv_erases));
-
// Use i_target if all of these apply
// 1) not NULL
// 2) not MASTER_PROCESSOR_CHIP_TARGET_SENTINEL
@@ -438,1367 +382,57 @@ PnorDD::PnorDD( PnorMode_t i_mode,
iv_mutex_ptr = &(cv_mutex);
}
- //Use real PNOR for everything except VPO
- if(0 == iv_vpoMode)
- {
- iv_vpoMode = mmio_scratch_read(MMIO_SCRATCH_PNOR_MODE);
- }
- //@fixme-RTC:95130
- //Force to not be in VPO mode
- iv_vpoMode = 0;
-
- //In the normal case we will choose the mode for the caller
- if( MODEL_UNKNOWN == iv_mode )
- {
- if(iv_vpoMode == PNOR::VPO_MODE_MEMCPY)
- {
- //VPO override set -- use fastest method -- memcpy
- TRACFCOMP(g_trac_pnor,"PNORDD: Running in MEMCPY mode for VPO");
- iv_mode = MODEL_MEMCPY;
- }
- else if(iv_vpoMode == PNOR::VPO_MODE_MMIO)
- {
- //VPO override set -- use MMIO mode
- TRACFCOMP(g_trac_pnor,"PNORDD: Running in VPO Mode, writes will not trigger erase attempts");
- iv_mode = MODEL_REAL_MMIO;
- }
- else
- {
- //Normal mode
- iv_mode = MODEL_REAL_MMIO;
- }
- }
-
- if( (MODEL_MEMCPY == iv_mode) ||
- (MODEL_LPC_MEM == iv_mode) )
- {
- //Only use input fake values if they are != zero
- iv_fakeStart = (i_fakeStart != 0) ? i_fakeStart : FAKE_PNOR_START;
- iv_fakeSize = (i_fakeSize != 0) ? i_fakeSize : FAKE_PNOR_SIZE;
- }
-
- if( (MODEL_REAL_CMD == iv_mode) ||
- (MODEL_REAL_MMIO == iv_mode) )
- {
-
- // @todo RTC 97493 - make sure sfcInit only gets called once per target
- sfcInit( );
- }
-
- TRACFCOMP(g_trac_pnor, "PnorDD::PnorDD()> Using mode %d, vpo=%d", iv_mode, iv_vpoMode);
-}
-
-/**
- * @brief Destructor
- */
-PnorDD::~PnorDD()
-{
-
-}
-
-
-/**
- * STATIC
- * @brief Static Initializer
- */
-void PnorDD::sfcInit( )
-{
- TRACFCOMP(g_trac_pnor, "PnorDD::sfcInit> iv_mode=0x%.8x", iv_mode );
- errlHndl_t l_err = NULL;
-
- mutex_lock(iv_mutex_ptr);
-
- do {
-#ifdef CONFIG_SFC_IS_AST2400
- TRACFCOMP( g_trac_pnor, "PnorDD::sfcInit> Nothing to do yet for AST2400" );
- break;
- //@todo RTC:106881 - Fix up to support erase/write later
-#endif //CONFIG_SFC_IS_AST2400
-
- if(!iv_sfcInitDone)
- {
-#ifdef CONFIG_BMC_DOES_SFC_INIT
-
- // Set OPB LPCM FIR Mask - hostboot will monitor these FIR bits
- size_t scom_size = sizeof(uint64_t);
- uint64_t fir_mask_data = OPB_LPCM_FIR_ERROR_MASK;
-
- l_err = deviceOp( DeviceFW::WRITE,
- iv_target,
- &(fir_mask_data),
- scom_size,
- DEVICE_SCOM_ADDRESS(OPB_LPCM_FIR_MASK_WO_OR_REG));
- if( l_err ) { break; }
-
- //Determine NOR Flash type - triggers vendor specific workarounds
- //We also use the chipID in some FFDC situations.
- l_err = getNORChipId(iv_nor_chipid);
- if(l_err) { break; }
- TRACFCOMP(g_trac_pnor,
- "PnorDD::sfcInit: iv_nor_chipid=0x%.8x> ",
- iv_nor_chipid );
-
- // Re-initialize internal erase size cached value.
- l_err = readRegSfc(SFC_CMD_SPACE,
- SFC_REG_ERASMS,
- iv_erasesize_bytes);
- if(l_err) { break; }
- TRACFCOMP(g_trac_pnor,"PnorDD::sfcInit: iv_erasesize_bytes=%X",iv_erasesize_bytes);
-
-#else //==!CONFIG_BMC_DOES_SFC_INIT
-
- TRACFCOMP( g_trac_pnor, INFO_MRK "Initializing SFC registers -- unsupported!!!" );
- //@todo RTC:97493 - Add SFC initialization from Host
- INITSERVICE::doShutdown( PNOR::RC_UNSUPPORTED_MODE);
-
-#endif //CONFIG_BMC_DOES_SFC_INIT
-
- iv_sfcInitDone = true;
- }
-
- }while(0);
-
- mutex_unlock(iv_mutex_ptr);
-
- if( l_err )
- {
- TRACFCOMP( g_trac_pnor, ERR_MRK
- "PnorDD::sfcInit> Committing error log");
- errlCommit(l_err,PNOR_COMP_ID);
- }
-
- TRACFCOMP(g_trac_pnor, "< PnorDD::sfcInit" );
-}
-
-bool PnorDD::usingL3Cache( )
-{
- TRACDCOMP(g_trac_pnor,
- "PnorDD::usingL3Cache> iv_mode=0x%.8x", iv_mode );
-
- //If we are in one of the fake PNOR modes,
- //than we are using L3 CAche
- if( (MODEL_MEMCPY == iv_mode) ||
- (MODEL_LPC_MEM == iv_mode) )
- {
- return true;
- }
- else
- {
- return false;
- }
-}
-
-/**
- * @brief Write a SFC Register
- */
-errlHndl_t PnorDD::writeRegSfc(SfcRange i_range,
- uint32_t i_addr,
- uint32_t i_data)
-{
- errlHndl_t l_err = NULL;
- uint32_t lpc_addr = 0;
-
- switch(i_range)
- {
- case SFC_MMIO_SPACE:
- {
- lpc_addr = LPC_SFC_MMIO_OFFSET | i_addr;
- break;
- }
- case SFC_CMD_SPACE:
- {
- lpc_addr = LPC_SFC_CMDREG_OFFSET | i_addr;
- break;
- }
- case SFC_CMDBUF_SPACE:
- {
- lpc_addr = LPC_SFC_CMDBUF_OFFSET | i_addr;
- break;
- }
- case SFC_LPC_SPACE:
- {
- lpc_addr = LPCHC_FW_SPACE | i_addr;
- break;
- }
- default:
- {
- TRACFCOMP(g_trac_pnor, ERR_MRK"PnorDD::writeRegSfc> Unsupported SFC Address Range: i_range=0x%.16X, i_addr=0x%.8X. Calling doShutdown(PNOR::RC_UNSUPPORTED_SFCRANGE)",
- i_range, i_addr);
-
- //Can't function without PNOR, initiate shutdown.
- INITSERVICE::doShutdown( PNOR::RC_UNSUPPORTED_SFCRANGE);
- break;
- }
- } //end switch
-
- TRACDCOMP( g_trac_pnor, "PnorDD::writeRegSfc> lpc_addr=0x%.8x, i_data=0x%.8x",
- lpc_addr, i_data );
- l_err = writeLPC(lpc_addr, i_data);
-
- return l_err;
-}
-
-/**
- * @brief Read a SFC Register
- */
-errlHndl_t PnorDD::readRegSfc(SfcRange i_range,
- uint32_t i_addr,
- uint32_t& o_data)
-{
- errlHndl_t l_err = NULL;
- uint32_t lpc_addr = 0;
-
- switch(i_range)
- {
- case SFC_MMIO_SPACE:
- {
- lpc_addr = LPC_SFC_MMIO_OFFSET | i_addr;
- break;
- }
- case SFC_CMD_SPACE:
- {
- lpc_addr = LPC_SFC_CMDREG_OFFSET | i_addr;
- break;
- }
- case SFC_CMDBUF_SPACE:
- {
- lpc_addr = LPC_SFC_CMDBUF_OFFSET | i_addr;
- break;
- }
- case SFC_LPC_SPACE:
- {
- lpc_addr = LPCHC_FW_SPACE | i_addr;
- break;
- }
- default:
- {
- TRACFCOMP(g_trac_pnor, ERR_MRK"PnorDD::readRegSfc> Unsupported SFC Address Range: i_range=0x%.16X, i_addr=0x%.8X. Calling doShutdown(PNOR::RC_UNSUPPORTED_SFCRANGE)",
- i_range, i_addr);
-
- //Can't function without PNOR, initiate shutdown.
- INITSERVICE::doShutdown( PNOR::RC_UNSUPPORTED_SFCRANGE);
- break;
- }
- } //end switch
-
- l_err = readLPC(lpc_addr, o_data);
- TRACDCOMP( g_trac_pnor, "PnorDD::readRegSfc> lpc_addr=0x%.8x, o_data=0x%.8x",
- lpc_addr, o_data );
-
- return l_err;
-}
-
-
-/**
- * @brief Poll for SFC Op Complete
- */
-errlHndl_t PnorDD::pollSfcOpComplete(uint64_t i_pollTime)
-{
- errlHndl_t l_err = NULL;
- ResetLevels pnorResetLevel = RESET_CLEAR;
-
- TRACDCOMP( g_trac_pnor, "PnorDD::pollSfcOpComplete> i_pollTime=0x%.8x",
- i_pollTime );
-
do {
- //Poll for complete status
- SfcStatReg_t sfc_stat;
- uint64_t poll_time = 0;
- uint64_t loop = 0;
- while( poll_time < i_pollTime )
- {
- l_err = readRegSfc(SFC_CMD_SPACE,
- SFC_REG_STATUS,
- sfc_stat.data32);
- if(l_err) { break; }
-
- if( ( sfc_stat.done == 1 ) ||
- ( sfc_stat.timeout == 1 ) ||
- ( sfc_stat.illegal == 1 ) )
- {
- break;
- }
-
- // 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
- ++loop;
- nanosleep( 0, SFC_POLL_INCR_NS*loop );
- poll_time += SFC_POLL_INCR_NS*loop;
- }
+ //Instantiate the appropriate SFC object
+ l_err = PNOR::create_SfcDD( iv_sfc,
+ iv_target );
if( l_err ) { break; }
- l_err = checkForSfcErrors( pnorResetLevel );
+ //Initialize the SFC hardware if needed
+#ifndef BMC_DOES_SFC_INIT
+ l_err = iv_sfc->hwInit();
if( l_err ) { break; }
+#endif
- // If no errors AND done bit not set, call out undefined error
- if( (sfc_stat.done == 0) )
- {
- TRACFCOMP(g_trac_pnor,
- "PnorDD::pollSfcOpComplete> Error or timeout from SFC Status Register"
- );
-
- /*@
- * @errortype
- * @moduleid PNOR::MOD_PNORDD_POLLSFCOPCOMPLETE
- * @reasoncode PNOR::RC_SFC_ERROR
- * @userdata1[0:31] NOR Flash Chip ID
- * @userdata1[32:63] Total poll time (ns)
- * @userdata2[0:31] ECCB Status Register
- * @devdesc PnorDD::pollSfcOpComplete> Error or timeout from
- * SFC Status Register
- * @custdesc Hardware error accessing flash during IPL
- */
- l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- PNOR::MOD_PNORDD_POLLSFCOPCOMPLETE,
- PNOR::RC_SFC_ERROR,
- TWO_UINT32_TO_UINT64(iv_nor_chipid,
- poll_time),
- TWO_UINT32_TO_UINT64(sfc_stat.data32,0));
-
- // Limited in callout: no PNOR target, so calling out processor
- l_err->addHwCallout(
- iv_target,
- HWAS::SRCI_PRIORITY_HIGH,
- HWAS::NO_DECONFIG,
- HWAS::GARD_NULL );
-
- addFFDCRegisters(l_err);
- l_err->collectTrace(PNOR_COMP_NAME);
- l_err->collectTrace(XSCOM_COMP_NAME);
-
- // Reset LPC Slave since it appears to be hung - handled below
- pnorResetLevel = RESET_LPC_SLAVE;
-
- break;
- }
- TRACDCOMP(g_trac_pnor,"pollSfcOpComplete> command took %d ns", poll_time);
-
- }while(0);
-
- // If we have an error that requires a reset, do that here
- if ( l_err && ( pnorResetLevel != RESET_CLEAR ) )
- {
- errlHndl_t tmp_err = NULL;
- tmp_err = resetPnor(pnorResetLevel);
-
- if ( tmp_err )
- {
- // Commit reset error as informational since we have
- // original error l_err
- TRACFCOMP(g_trac_pnor, "PnorDD::pollSfcOpComplete> Error from resetPnor() after previous error eid=0x%X. Committing resetPnor() error log eid=0x%X.",
- l_err->eid(), tmp_err->eid());
- tmp_err->setSev(ERRORLOG::ERRL_SEV_INFORMATIONAL);
- tmp_err->collectTrace(PNOR_COMP_NAME);
- tmp_err->plid(l_err->plid());
- errlCommit(tmp_err, PNOR_COMP_ID);
- }
- }
-
- return l_err;
-
-}
-
-/**
- * @brief Check For Errors in SFC Status Registers
- */
-errlHndl_t PnorDD::checkForSfcErrors( ResetLevels &o_pnorResetLevel )
-{
- errlHndl_t l_err = NULL;
- bool errorFound = false;
-
- // Used to set Reset Levels, if necessary
- o_pnorResetLevel = RESET_CLEAR;
-
- // Default status values in case we fail in reading the registers
- LpcSlaveStatReg_t lpc_slave_stat;
- lpc_slave_stat.data32 = 0xDEADBEEF;
- SfcStatReg_t sfc_stat;
- sfc_stat.data32 = 0xDEADBEEF;
-
- do {
-
- // First Read LPC Slave Status Register
- l_err = readRegSfc(SFC_LPC_SPACE,
- LPC_SLAVE_REG_STATUS,
- lpc_slave_stat.data32);
-
- // If we can't read status register, exit out
- if( l_err ) { break; }
-
- TRACDCOMP( g_trac_pnor, INFO_MRK"PnorDD::checkForSfcErrors> LPC Slave status reg: 0x%08llx",
- lpc_slave_stat.data32);
-
- // Start with lighter reset level
- if( 1 == lpc_slave_stat.lbusparityerror )
- {
- errorFound = true;
- o_pnorResetLevel = RESET_LPC_SLAVE_ERRS;
- TRACFCOMP( g_trac_pnor, ERR_MRK"PnorDD::checkForSfcErrors> LPC Slave Local Bus Parity Error: status reg: 0x%08llx, ResetLevel=%d",
- lpc_slave_stat.data32, o_pnorResetLevel);
- }
-
- // Check for more stronger reset level
- if( 0 != lpc_slave_stat.lbus2opberr )
- {
- errorFound = true;
- // All of these errors require the SFC Local Bus Reset
- o_pnorResetLevel = RESET_SFC_LOCAL_BUS;
-
- if ( LBUS2OPB_ADDR_PARITY_ERR == lpc_slave_stat.lbus2opberr )
- {
- // This error also requires LPC Slave Errors to be Cleared
- o_pnorResetLevel = RESET_SFCBUS_LPCSLAVE_ERRS;
- TRACFCOMP( g_trac_pnor, ERR_MRK"PnorDD::checkForSfcErrors> LBUS2OPB Address Parity Error: LPC Slave status reg: 0x%08llx, ResetLevel=%d",
- lpc_slave_stat.data32, o_pnorResetLevel);
-
- }
-
- else if ( LBUS2OPB_INVALID_SELECT_ERR == lpc_slave_stat.lbus2opberr)
- {
- TRACFCOMP( g_trac_pnor, ERR_MRK"PnorDD::checkForSfcErrors> LBUS2OPB Invalid Select Error: LPC Slave status reg: 0x%08llx, ResetLevel=%d",
- lpc_slave_stat.data32, o_pnorResetLevel);
-
- }
- else if ( LBUS2OPB_DATA_PARITY_ERR == lpc_slave_stat.lbus2opberr )
- {
- // This error also requires LPC Slave Errors to be Cleared
- o_pnorResetLevel = RESET_SFCBUS_LPCSLAVE_ERRS;
- TRACFCOMP( g_trac_pnor, ERR_MRK"PnorDD::checkForSfcErrors> LBUS2OPB Data Parity Error: LPC Slave status reg: 0x%08llx, ResetLevel=%d",
- lpc_slave_stat.data32, o_pnorResetLevel);
-
- }
- else if ( LBUS2OPB_MONITOR_ERR == lpc_slave_stat.lbus2opberr )
- {
- TRACFCOMP( g_trac_pnor, ERR_MRK"PnorDD::checkForSfcErrors> LBUS2OPB Monitor Error: LPC Slave status reg: 0x%08llx, ResetLevel=%d",
- lpc_slave_stat.data32, o_pnorResetLevel);
-
- }
-
- else if ( LBUS2OPB_TIMEOUT_ERR == lpc_slave_stat.lbus2opberr )
- {
- TRACFCOMP( g_trac_pnor, ERR_MRK"PnorDD::checkForSfcErrors> LBUS2OPB Timeout Error: LPC Slave status reg: 0x%08llx, ResetLevel=%d",
- lpc_slave_stat.data32, o_pnorResetLevel);
-
- }
- else
- {
- // Just in case, clear LPC Slave Errors
- o_pnorResetLevel = RESET_LPC_SLAVE_ERRS;
- TRACFCOMP( g_trac_pnor, ERR_MRK"PnorDD::checkForSfcErrors> LBUS2OPB UNKNOWN Error: LPC Slave status reg: 0x%08llx, ResetLevel=%d",
- lpc_slave_stat.data32, o_pnorResetLevel);
- }
-
- }
-
- // Second Read SFC and check for error bits
- l_err = readRegSfc(SFC_CMD_SPACE,
- SFC_REG_STATUS,
- sfc_stat.data32);
-
- // If we can't read status register, exit out
+ //Figure out what kind of flash chip we have
+ l_err = iv_sfc->getNORChipId(iv_norChipId);
if( l_err ) { break; }
- TRACDCOMP( g_trac_pnor, INFO_MRK"PnorDD::checkForSfcErrors> SFC status reg(0x%X): 0x%08llx",
- SFC_CMD_SPACE|SFC_REG_STATUS,sfc_stat.data32);
-
- // No resets needed for these errors
- if( 1 == sfc_stat.eccerrcntr )
- {
- errorFound = true;
- TRACFCOMP( g_trac_pnor, ERR_MRK"PnorDD::checkForSfcErrors> Threshold of SRAM ECC Errors Reached: SFC status reg: 0x%08llx, ResetLevel=%d",
- sfc_stat.data32, o_pnorResetLevel);
- }
-
- if( 1 == sfc_stat.eccues )
- {
- errorFound = true;
- TRACFCOMP( g_trac_pnor, ERR_MRK"PnorDD::checkForSfcErrors> SRAM Command Uncorrectable ECC Error: SFC status reg: 0x%08llx, ResetLevel=%d",
- sfc_stat.data32, o_pnorResetLevel);
- }
-
- if( 1 == sfc_stat.illegal )
- {
- errorFound = true;
- TRACFCOMP( g_trac_pnor, ERR_MRK"PnorDD::checkForSfcErrors> Previous Operation was Illegal: SFC status reg: 0x%08llx, ResetLevel=%d",
- sfc_stat.data32, o_pnorResetLevel);
- }
-
- if( 1 == sfc_stat.eccerrcntn )
- {
- errorFound = true;
- TRACFCOMP( g_trac_pnor, ERR_MRK"PnorDD::checkForSfcErrors> Threshold for Flash ECC Errors Reached: SFC status reg: 0x%08llx, ResetLevel=%d",
-
- sfc_stat.data32, o_pnorResetLevel);
- }
-
- if( 1 == sfc_stat.eccuen )
- {
- errorFound = true;
- TRACFCOMP( g_trac_pnor, ERR_MRK"PnorDD::checkForSfcErrors> Flash Command Uncorrectable ECC Error: SFC status reg: 0x%08llx, ResetLevel=%d",
- sfc_stat.data32, o_pnorResetLevel);
- }
-
- if( 1 == sfc_stat.timeout )
- {
- errorFound = true;
- TRACFCOMP( g_trac_pnor, ERR_MRK"PnorDD::checkForSfcErrors> Timeout: SFC status reg: 0x%08llx, ResetLevel=%d",
- sfc_stat.data32, o_pnorResetLevel);
- }
-
- }while(0);
-
+ //Keep track of the size of the erase block
+ iv_eraseSizeBytes = iv_sfc->eraseSizeBytes();
+ //We only support 4K erase blocks for now
+ assert(iv_eraseSizeBytes == ERASESIZE_BYTES_DEFAULT);
+ } while(0);
- // If there is any error create an error log
- if ( errorFound )
+ if( l_err )
{
- // If we failed on a register read above, but still found an error,
- // delete register read error log and create an original error log
- // for the found error
- if ( l_err )
- {
- TRACFCOMP( g_trac_pnor, ERR_MRK"PnorDD::checkForSfcErrors> Deleting register read error. Returning error created for the found error");
- delete l_err;
- }
-
-
- /*@
- * @errortype
- * @moduleid PNOR::MOD_PNORDD_CHECKFORSFCERRORS
- * @reasoncode PNOR::RC_ERROR_IN_STATUS_REG
- * @userdata1[0:31] SFC Status Register
- * @userdata1[32:63] LPC Slave Status Register
- * @userdata2 Reset Level
- * @devdesc PnorDD::checkForSfcErrors> Error(s) found in SFC
- * and/or LPC Slave Status Registers
- * @custdesc Hardware error accessing flash during IPL
- */
- l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- PNOR::MOD_PNORDD_CHECKFORSFCERRORS,
- PNOR::RC_ERROR_IN_STATUS_REG,
- TWO_UINT32_TO_UINT64(
- sfc_stat.data32,
- lpc_slave_stat.data32),
- o_pnorResetLevel );
-
- // Limited in callout: no PNOR target, so calling out processor
- l_err->addHwCallout(
- iv_target,
- HWAS::SRCI_PRIORITY_HIGH,
- HWAS::NO_DECONFIG,
- HWAS::GARD_NULL );
-
- addFFDCRegisters(l_err);
+ TRACFCOMP( g_trac_pnor, "Failure to initialize the PNOR logic, shutting down :: RC=%.4X", ERRL_GETRC_SAFE(l_err) );
l_err->collectTrace(PNOR_COMP_NAME);
+ ERRORLOG::errlCommit(l_err,PNOR_COMP_ID);
+ INITSERVICE::doShutdown( PNOR::RC_PNOR_INIT_FAILURE );
}
- return l_err;
-
-}
-
-/**
- * @brief Add Error Registers to an existing Error Log
- */
-void PnorDD::addFFDCRegisters(errlHndl_t & io_errl)
-{
-
- errlHndl_t tmp_err = NULL;
- uint32_t data32 = 0;
- uint64_t data64 = 0;
- size_t size64 = sizeof(data64);
- size_t size32 = sizeof(data32);
-
- // check iv_ffdc_active to avoid infinite loops
- if ( iv_ffdc_active == false )
- {
- iv_ffdc_active = true;
-
- TRACFCOMP( g_trac_pnor, ENTER_MRK"PnorDD::addFFDCRegisters> adding FFDC to Error Log EID=0x%X, PLID=0x%X",
- io_errl->eid(), io_errl->plid() );
-
- ERRORLOG::ErrlUserDetailsLogRegister
- l_eud(iv_target);
-
- do {
- //@fixme - RTC:107788 Seems like this might not belong here,
- // instead only in the LPC layer...
- // Add ECCB Status Register
- tmp_err = deviceOp( DeviceFW::READ,
- iv_target,
- &(data64),
- size64,
- DEVICE_SCOM_ADDRESS(ECCB_STAT_REG) );
-
- if( tmp_err )
- {
- delete tmp_err;
- TRACFCOMP( g_trac_pnor, "PnorDD::addFFDCRegisters> Fail reading ECCB_STAT_REG");
- }
- else
- {
- l_eud.addDataBuffer(&data64, size64,
- DEVICE_SCOM_ADDRESS(ECCB_STAT_REG));
- }
-
- // Add OPB Fir Register
- tmp_err = deviceOp( DeviceFW::READ,
- iv_target,
- &(data64),
- size64,
- DEVICE_SCOM_ADDRESS(OPB_LPCM_FIR_REG) );
-
- if( tmp_err )
- {
- delete tmp_err;
- TRACFCOMP( g_trac_pnor, "PnorDD::addFFDCRegisters> Fail reading OPB_LPCM_FIR_REG");
- }
- else
- {
- l_eud.addDataBuffer(&data64, size64,
- DEVICE_SCOM_ADDRESS(OPB_LPCM_FIR_REG));
- }
-
- // Add LPC Slave Status Register
- LpcSlaveStatReg_t lpc_slave_stat;
-
- tmp_err = readRegSfc(SFC_LPC_SPACE,
- LPC_SLAVE_REG_STATUS,
- lpc_slave_stat.data32);
-
- if ( tmp_err )
- {
- delete tmp_err;
- TRACFCOMP( g_trac_pnor, "PnorDD::addFFDCRegisters> Fail reading LPC Slave Status Register");
- }
- else
- {
- l_eud.addDataBuffer(&lpc_slave_stat.data32, size32,
- DEVICE_SCOM_ADDRESS( LPCHC_FW_SPACE |
- LPC_SLAVE_REG_STATUS));
- }
-
- // Add SFC Registers
- uint32_t sfc_regs[] = {
- SFC_REG_STATUS,
- SFC_REG_CONF,
- SFC_REG_CMD,
- SFC_REG_ADR,
- SFC_REG_ERASMS,
- SFC_REG_ERASLGS,
- SFC_REG_CONF4,
- SFC_REG_CONF5,
- SFC_REG_ADRCBF,
- SFC_REG_ADRCMF,
- SFC_REG_OADRNB,
- SFC_REG_OADRNS,
- SFC_REG_CHIPIDCONF,
- SFC_REG_ERRCONF,
- SFC_REG_ERRTAG,
- SFC_REG_ERROFF,
- SFC_REG_ERRSYN,
- SFC_REG_ERRDATH,
- SFC_REG_ERRDATL,
- SFC_REG_ERRCNT,
- SFC_REG_CLRCNT,
- SFC_REG_ERRINJ,
- SFC_REG_PROTA,
- SFC_REG_PROTM,
- SFC_REG_ECCADDR,
- SFC_REG_ECCRNG,
- SFC_REG_ERRORS,
- SFC_REG_INTMSK,
- SFC_REG_INTENM,
- SFC_REG_CONF2,
- SFC_REG_CONF3
- };
-
-
- for( size_t x=0; x<(sizeof(sfc_regs)/sizeof(sfc_regs[0])); x++ )
- {
- tmp_err = readRegSfc( SFC_CMD_SPACE,
- sfc_regs[x],
- data32 );
-
- if( tmp_err )
- {
- delete tmp_err;
- }
- else
- {
- l_eud.addDataBuffer(&data32, size32,
- DEVICE_SCOM_ADDRESS(LPC_SFC_CMDREG_OFFSET
- | sfc_regs[x]));
- }
- }
-
- }while(0);
-
- l_eud.addToLog(io_errl);
-
- TRACFCOMP( g_trac_pnor, EXIT_MRK"PnorDD::addFFDCRegisters> Information added to error log");
-
- // reset FFDC active flag
- iv_ffdc_active = false;
- }
-
- return;
-}
-
-
-/**
- * @brief Check flag status bit on Micron NOR chips
- * The current version of Micron parts require the Flag
- * Status register be read after a write or erase operation,
- * otherwise all future operations won't work..
- */
-errlHndl_t PnorDD::micronFlagStatus(uint64_t i_pollTime)
-{
- errlHndl_t l_err = NULL;
- TRACDCOMP( g_trac_pnor, "PnorDD::micronFlagStatus> i_pollTime=0x%.8x",
- i_pollTime );
-
- do {
-
- //Configure Get "Chip ID" command in SFC to check special
- //Micron 'flag status' register
- 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,
- readflag_cmd.data32);
- if(l_err) { break; }
-
-
- //Check flag status bit.
- uint32_t opStatus = 0;
- uint64_t poll_time = 0;
- uint64_t loop = 0;
- while( poll_time < i_pollTime )
- {
- //Issue Get Chip ID command (reading flag status)
- 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; }
-
- //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
- opStatus);
- if(l_err) { break; }
-
- //check for complete or error
- // bit 0 = ready, bit 2=erase fail, bit 3=Program (Write) failure
- if( (opStatus & 0xB0000000))
- {
- break;
- }
-
- // 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
- //TODO tmp remove for VPO, need better polling strategy -- RTC43738
- //nanosleep( 0, SFC_POLL_INCR_NS*(++loop) );
- ++loop;
- poll_time += SFC_POLL_INCR_NS*loop;
- }
- 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)
- {
- TRACFCOMP(g_trac_pnor,
- "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
- * @reasoncode PNOR::RC_MICRON_INCOMPLETE
- * @userdata1[0:31] NOR Flash Chip ID
- * @userdata1[32:63] Total poll time (ns)
- * @userdata2[0:31] Micron Flag status register
- * @devdesc PnorDD::micronFlagStatus> Error or timeout from
- * Micron Flag Status Register
- * @custdesc Hardware error accessing flash during IPL
- */
- l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- PNOR::MOD_PNORDD_MICRONFLAGSTATUS,
- PNOR::RC_MICRON_INCOMPLETE,
- TWO_UINT32_TO_UINT64(iv_nor_chipid,
- poll_time),
- TWO_UINT32_TO_UINT64(opStatus,0));
-
- // Limited in callout: no PNOR target, so calling out processor
- l_err->addHwCallout(
- iv_target,
- HWAS::SRCI_PRIORITY_HIGH,
- HWAS::NO_DECONFIG,
- HWAS::GARD_NULL );
-
- addFFDCRegisters(l_err);
-
- //Erase & Program error bits are sticky, so they need to be cleared.
-
- //Configure Get "Chip ID" command in SFC to clear special
- //Micron 'flag status' register. remaining bits are all zero
- // since we just need to issue the SPI command.
- uint32_t confData = SPI_MICRON_CLRFLAG_STAT << 24;
- TRACDCOMP( g_trac_pnor, "PnorDD::micronFlagStatus> confData=0x%.8x",
- confData );
- errlHndl_t tmp_err = NULL;
- tmp_err = writeRegSfc(SFC_CMD_SPACE,
- SFC_REG_CHIPIDCONF,
- confData);
- if(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)
- {
- //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
- tmp_err = pollSfcOpComplete();
- if(tmp_err)
- {
- delete tmp_err;
- }
-
- l_err->collectTrace(PNOR_COMP_NAME);
- l_err->collectTrace(XSCOM_COMP_NAME);
-
- break;
- }
-
-
- }while(0);
-
- return l_err;
-
-}
-
-/**
- * @brief Read the NOR FLash ChipID
- */
-errlHndl_t PnorDD::getNORChipId(uint32_t& o_chipId,
- uint32_t i_spiOpcode)
-{
- errlHndl_t l_err = NULL;
- errlHndl_t original_err = NULL;
- uint8_t retry = 0;
-
- TRACFCOMP( g_trac_pnor, "PnorDD::getNORChipId> i_spiOpcode=0x%.8x",
- i_spiOpcode );
-
-
- // reset class variable since we're starting a new operation
- iv_error_recovery_failed = false;
-
- /***********************************************************/
- /* This do-while loop supports retries */
- /***********************************************************/
- do {
-
- // group this block together with do-while
- do{
- //Configure Get Chip ID opcode
- uint32_t confData = i_spiOpcode << 24;
- confData |= 0x00800003; // 8-> read, 3->3 bytes
- TRACDCOMP( g_trac_pnor, "PnorDD::getNORChipId> confData=0x%.8x",
- confData );
- 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; }
-
- //Poll for complete status
- l_err = pollSfcOpComplete();
- if(l_err) { break; }
-
- //Read the ChipID from the Command Buffer
- l_err = readRegSfc(SFC_CMDBUF_SPACE,
- 0, //Offset into CMD BUFF space in bytes
- o_chipId);
- if(l_err) { break; }
-
- // Only look at a portion of the data that is returned
- o_chipId &= ID_MASK;
-
- //Some micron chips require a special workaround required
- //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 )
- {
- // Assume all Micron chips have this bug
- iv_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 -> 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");
- //Set Micron workaround flag
- iv_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; }
- }
-
- }while(0); // group of commands
-
- // end of operation - check for retry
- } while ( shouldRetry(RETRY_getNORChipId, l_err, original_err, retry) );
-
- return l_err;
-}
-
-
-/**
- * @brief Load SFC command buffer with data from PNOR
- */
-errlHndl_t PnorDD::loadSfcBuf(uint32_t i_addr,
- size_t i_size)
-{
- errlHndl_t l_err = NULL;
- TRACDCOMP( g_trac_pnor, "PnorDD::loadSfcBuf> i_addr=0x%.8x, i_size=0x%.8x",
- i_addr, i_size );
-
- do {
- //Write flash address to ADR reg
- l_err = writeRegSfc(SFC_CMD_SPACE,
- SFC_REG_ADR,
- i_addr);
- if(l_err) { break; }
-
- //Issue ReadRaw command with size to read
- SfcCmdReg_t sfc_cmd;
- sfc_cmd.opcode = SFC_OP_READRAW;
- sfc_cmd.length = i_size;
-
- 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; }
-
- }while(0);
-
- return l_err;
-
-}
-
-/**
- * @brief Flush SFC command buffer data to PNOR Flash
- */
-errlHndl_t PnorDD::flushSfcBuf(uint32_t i_addr,
- size_t i_size)
-{
- errlHndl_t l_err = NULL;
- TRACDCOMP( g_trac_pnor,
- "PnorDD::flushSfcBuf> i_addr=0x%.8x, i_size=0x%.8x",
- i_addr, i_size );
-
- do {
- //Write flash address to ADR reg
- l_err = writeRegSfc(SFC_CMD_SPACE,
- SFC_REG_ADR,
- i_addr);
- if(l_err) { break; }
-
- //Issue WriteRaw command + size to write
- SfcCmdReg_t sfc_cmd;
- sfc_cmd.opcode = SFC_OP_WRITERAW;
- sfc_cmd.length = i_size;
-
- 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; }
-
- //check for special Micron Flag Status reg
- if(iv_hw_workaround & HWWK_MICRON_WRT_ERASE)
- {
- l_err = micronFlagStatus();
- if(l_err) { break; }
- }
-
- }while(0);
-
- return l_err;
-
-}
-
-/**
- * @brief Perform command based read of PNOR, maximizing use of
- * SFC Command buffer..
- */
-errlHndl_t PnorDD::bufferedSfcRead(uint32_t i_addr,
- size_t i_size,
- void* o_data)
-{
- TRACDCOMP( g_trac_pnor, "PnorDD::bufferedSfcRead> i_addr=0x%.8x, i_size=0x%.8x",
- i_addr, i_size );
-
- errlHndl_t l_err = NULL;
- errlHndl_t original_err = NULL;
- uint8_t retry = 0;
-
- // reset class variable since we're starting a new operation
- iv_error_recovery_failed = false;
-
- /***********************************************************/
- /* This do-while loop supports retries */
- /***********************************************************/
- do {
-
- switch(iv_mode)
- {
- case MODEL_REAL_MMIO:
- {
- //Read directly from MMIO space
- uint32_t* word_ptr = static_cast<uint32_t*>(o_data);
- uint32_t word_size = i_size/4;
- for( uint32_t words_read = 0;
- words_read < word_size;
- words_read ++ )
- {
- l_err = readRegSfc(
- SFC_MMIO_SPACE,
- i_addr+words_read*4, //MMIO Address offset
- word_ptr[words_read]);
- if( l_err ) { break; }
- }
-
- break;
- }
- case MODEL_REAL_CMD:
- {
-
- // Command based reads are buffered 256 bytes at a time.
- uint32_t chunk_size = 0;
- uint64_t addr = i_addr;
- uint64_t end_addr = i_addr + i_size;
-
- while(addr < end_addr)
- {
- chunk_size = SFC_CMDBUF_SIZE;
- if( (addr + SFC_CMDBUF_SIZE) > end_addr)
- {
- chunk_size = end_addr - addr;
- }
-
- //Read data via SFC CMD Buffer
- l_err = loadSfcBuf(addr, chunk_size);
- if(l_err) { break;}
-
- //read SFC CMD Buffer via MMIO
- l_err = readSfcBuffer(
- chunk_size,
- (void*)((uint64_t)o_data + (addr-i_addr)));
- if(l_err) { break;}
-
- addr += chunk_size;
- }
- break;
- }
- case MODEL_LPC_MEM:
- {
- read_fake_pnor( i_addr,
- o_data,
- i_size );
- break;
- }
- default:
- {
- TRACFCOMP(g_trac_pnor, ERR_MRK"PnorDD::bufferedSfcRead> Unsupported mode: iv_mode=0x%.16X, i_addr=0x%.8X. Calling doShutdown(PNOR::RC_UNSUPPORTED_MODE)",
- iv_mode, i_addr);
-
- //Can't function without PNOR, initiate shutdown.
- INITSERVICE::doShutdown( PNOR::RC_UNSUPPORTED_MODE);
- break;
- }
- } //end switch
-
- // end of operation - check for retry
- } while ( shouldRetry(RETRY_bufferedSfcRead, l_err, original_err, retry) );
-
- return l_err;
-
-}
-
-
-/**
- * @brief Perform command based write of PNOR, maximizing use of
- * SFC Command buffer..
- */
-errlHndl_t PnorDD::bufferedSfcWrite(uint32_t i_addr,
- size_t i_size,
- void* i_data)
-{
- TRACDCOMP( g_trac_pnor, "PnorDD::bufferedSfcWrite> i_addr=0x%.8x, i_size=0x%.8x",
- i_addr, i_size );
-
- errlHndl_t l_err = NULL;
- errlHndl_t original_err = NULL;
- uint8_t retry = 0;
-
- // reset class variable since we're starting a new operation
- iv_error_recovery_failed = false;
-
- /***********************************************************/
- /* This do-while loop supports retries */
- /***********************************************************/
- do {
- switch(iv_mode)
- {
- case MODEL_REAL_CMD:
- case MODEL_REAL_MMIO:
- {
- // Note: MODEL_REAL_CMD or MODEL_REAL_MMIO both used command
- // based writes, thus the common code path here
-
- // Command based reads are buffered 256 bytes at a time.
- uint32_t chunk_size = 0;
- uint64_t addr = i_addr;
- uint64_t end_addr = i_addr + i_size;
-
- while(addr < end_addr)
- {
- chunk_size = SFC_CMDBUF_SIZE;
- if( (addr + SFC_CMDBUF_SIZE) > end_addr)
- {
- chunk_size = end_addr - addr;
- }
-
- //write data to SFC CMD Buffer via MMIO
- l_err = writeSfcBuffer(chunk_size,
- (void*)((uint64_t)i_data + (addr-i_addr)));
- if(l_err) { break;}
-
- //Fetch bits into SFC CMD Buffer
- l_err = flushSfcBuf(addr, chunk_size);
- if(l_err) { break;}
-
- addr += chunk_size;
- }
- break;
- }
- case MODEL_LPC_MEM:
- {
- write_fake_pnor( i_addr,
- i_data,
- i_size );
- break;
- }
- default:
- {
- TRACFCOMP(g_trac_pnor, ERR_MRK"PnorDD::bufferedSfcWrite> Unsupported mode: iv_mode=0x%.16X, i_addr=0x%.8X. Calling doShutdown(PNOR::RC_UNSUPPORTED_MODE)",
- iv_mode, i_addr);
-
- //Can't function without PNOR, initiate shutdown.
- INITSERVICE::doShutdown( PNOR::RC_UNSUPPORTED_MODE);
- }
- } // end of switch statement
-
- // end of operation - check for retry
- } while ( shouldRetry(RETRY_bufferedSfcWrite, l_err, original_err, retry) );
-
- return l_err;
-}
-
-
-/**
- * @brief Read data in SFC Command buffer and put into buffer
- */
-errlHndl_t PnorDD::readSfcBuffer(size_t i_size,
- void* o_data)
-{
- errlHndl_t l_err = NULL;
- TRACDCOMP( g_trac_pnor, "PnorDD::readSfcBuffer> i_size=0x%.8x",
- 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 = (ALIGN_4(i_size))/4;
- for( uint32_t words_read = 0;
- words_read < word_size;
- words_read ++ )
- {
- l_err = readRegSfc(SFC_CMDBUF_SPACE,
- words_read*4, //Offset into CMD BUFF space in bytes
- word_ptr[words_read]);
- TRACDCOMP( g_trac_pnor, "PnorDD::readSfcBuffer: Read offset=0x%.8x, data_read=0x%.8x",
- words_read*4, word_ptr[words_read] );
-
- if( l_err ) { break; }
- }
-
- return l_err;
+ TRACFCOMP(g_trac_pnor, EXIT_MRK "PnorDD::PnorDD()" );
}
/**
- * @brief Write data to SFC Command buffer
+ * @brief Destructor
*/
-errlHndl_t PnorDD::writeSfcBuffer(size_t i_size,
- void* i_data)
+PnorDD::~PnorDD()
{
- errlHndl_t l_err = NULL;
- TRACDCOMP( g_trac_pnor, "PnorDD::writeSfcBuffer> i_size=0x%.8x",
- i_size );
-
- // SFC Command Buffer is accessed 32-bits at a time
- uint32_t* word_ptr = static_cast<uint32_t*>(i_data);
- uint32_t word_size = i_size/4;
- for( uint32_t words_read = 0;
- words_read < word_size;
- words_read ++ )
+ if( iv_sfc )
{
- l_err = writeRegSfc(SFC_CMDBUF_SPACE,
- words_read*4, //Offset into CMD BUFF space in bytes
- word_ptr[words_read]);
- if( l_err ) { break; }
+ delete iv_sfc;
}
-
- return l_err;
-}
-
-/**
- * @brief Read an address from LPC space
- */
-errlHndl_t PnorDD::readLPC(uint32_t i_addr,
- uint32_t& o_data)
-{
- size_t reg_size = sizeof(uint32_t);
- errlHndl_t l_err = deviceOp( DeviceFW::READ,
- iv_target,
- &o_data,
- reg_size,
- DEVICE_LPC_ADDRESS(LPC::TRANS_ABS,i_addr) );
- return l_err;
}
/**
- * @brief Write an address from LPC space
+ * @brief Informs caller if PNORDD is using
+ * L3 Cache for fake PNOR or not.
*/
-errlHndl_t PnorDD::writeLPC(uint32_t i_addr,
- uint32_t i_data)
+bool PnorDD::usingL3Cache( void )
{
- size_t reg_size = sizeof(uint32_t);
- errlHndl_t l_err = deviceOp( DeviceFW::WRITE,
- iv_target,
- &i_data,
- reg_size,
- DEVICE_LPC_ADDRESS(LPC::TRANS_ABS,i_addr) );
- TRACDCOMP(g_trac_pnor, "writeLPC> %.8X = %.8X", i_addr, i_data );
-
- return l_err;
+ return iv_sfc->usingL3Cache();
}
/**
@@ -1815,20 +449,21 @@ errlHndl_t PnorDD::compareAndWriteBlock(uint32_t i_blockStart,
uint8_t* read_data = NULL;
do {
-
// remember any data we read so we don't have to reread it later
- read_data = new uint8_t[iv_erasesize_bytes];
+ read_data = new uint8_t[iv_eraseSizeBytes];
// remember if we need to erase the block or not
bool need_erase = false;
bool need_write = false;
- //STEP 1: Read data in PNOR for compares (only read section we want to write)
+ //STEP 1: Read data in PNOR for compares (only read section we
+ // want to write)
//read_start needs to be uint32* for bitwise word compares later
- uint32_t* read_start = (uint32_t*)(read_data + i_writeStart-i_blockStart);
- l_err = bufferedSfcRead(i_writeStart,
- i_bytesToWrite,
- (void*) read_start);
+ uint32_t* read_start = (uint32_t*)(read_data
+ + i_writeStart-i_blockStart);
+ l_err = _readFlash( i_writeStart,
+ i_bytesToWrite,
+ (void*) read_start );
if( l_err ) { break; }
//STEP 2: walk through the write data to see if we need to do an erase
@@ -1857,12 +492,12 @@ errlHndl_t PnorDD::compareAndWriteBlock(uint32_t i_blockStart,
if(need_write == false)
{
//No write actually needed, break out here
- TRACDCOMP(g_trac_pnor,"compareAndWriteBlock> NO Write Needed! Exiting Function");
+ TRACFCOMP(g_trac_pnor,"compareAndWriteBlock> NO Write Needed! Exiting Function");
break;
}
-
- //STEP 3: If the need to erase was detected, read out the rest of the Erase block
+ //STEP 3: If the need to erase was detected, read out the
+ // rest of the Erase block
if(need_erase)
{
TRACFCOMP(g_trac_pnor,"compareAndWriteBlock> Need to perform Erase");
@@ -1871,63 +506,76 @@ errlHndl_t PnorDD::compareAndWriteBlock(uint32_t i_blockStart,
{
TRACDCOMP(g_trac_pnor,"compareAndWriteBlock> Reading beginning data i_blockStart=0x%.8x, readLen=0x%.8x",
i_blockStart, i_writeStart-i_blockStart);
- l_err = bufferedSfcRead(i_blockStart,
- i_writeStart-i_blockStart,
- read_data);
+ l_err = _readFlash( i_blockStart,
+ i_writeStart-i_blockStart,
+ read_data );
if( l_err ) { break; }
}
//Get data after write section
- if((i_writeStart+i_bytesToWrite) < (i_blockStart + iv_erasesize_bytes))
- {
- uint32_t tail_length = i_blockStart + iv_erasesize_bytes - (i_writeStart+i_bytesToWrite);
- uint8_t* tail_buffer = read_data + i_writeStart-i_blockStart + i_bytesToWrite;
+ if( (i_writeStart+i_bytesToWrite)
+ < (i_blockStart + iv_eraseSizeBytes) )
+ {
+ uint32_t tail_length =
+ i_blockStart
+ + iv_eraseSizeBytes
+ - (i_writeStart+i_bytesToWrite);
+ uint8_t* tail_buffer =
+ read_data
+ + i_writeStart-i_blockStart
+ + i_bytesToWrite;
TRACDCOMP(g_trac_pnor,"compareAndWriteBlock> Reading tail data. addr=0x%.8x, tail_length=0x%.8x",
i_writeStart+i_bytesToWrite, tail_length);
- l_err = bufferedSfcRead(i_writeStart+i_bytesToWrite,
- tail_length,
- tail_buffer);
+ l_err = _readFlash( i_writeStart+i_bytesToWrite,
+ tail_length,
+ tail_buffer );
if( l_err ) { break; }
}
// erase the flash
TRACDCOMP(g_trac_pnor,"compareAndWriteBlock> Calling eraseFlash:. i_blockStart=0x%.8x", i_blockStart);
- l_err = eraseFlash( i_blockStart );
+ l_err = _eraseFlash( i_blockStart );
if( l_err ) { break; }
+ //STEP 4: Write the data back out - need to write everything
+ // since we erased the block
- //STEP 4: Write the data back out -
- // need to write everything since we erased the block
- // re-write data before new data to write
+ //re-write data before new data to write
if(i_writeStart > i_blockStart)
{
TRACDCOMP(g_trac_pnor,"compareAndWriteBlock> Writing beginning data i_blockStart=0x%.8x, readLen=0x%.8x",
i_blockStart, i_writeStart-i_blockStart);
- l_err = bufferedSfcWrite(i_blockStart,
- i_writeStart-i_blockStart,
- read_data);
+ l_err = _writeFlash(i_blockStart,
+ i_writeStart-i_blockStart,
+ read_data);
if( l_err ) { break; }
}
//Write data after new data to write
- if((i_writeStart+i_bytesToWrite) < (i_blockStart + iv_erasesize_bytes))
- {
- uint32_t tail_length = i_blockStart + iv_erasesize_bytes - (i_writeStart+i_bytesToWrite);
- uint8_t* tail_buffer = read_data + i_writeStart-i_blockStart + i_bytesToWrite;
-
- TRACDCOMP(g_trac_pnor,"compareAndWriteBlock> Writing tail data. addr=0x%.8x, tail_length=0x%.8x",
- i_writeStart+i_bytesToWrite, tail_length);
- l_err = bufferedSfcWrite(i_writeStart+i_bytesToWrite,
- tail_length,
- tail_buffer);
+ if( (i_writeStart+i_bytesToWrite)
+ < (i_blockStart + iv_eraseSizeBytes) )
+ {
+ uint32_t tail_length =
+ i_blockStart
+ + iv_eraseSizeBytes
+ - (i_writeStart+i_bytesToWrite);
+ uint8_t* tail_buffer =
+ read_data +
+ i_writeStart-i_blockStart
+ + i_bytesToWrite;
+
+ TRACDCOMP(g_trac_pnor,"compareAndWriteBlock> Writing tail data. addr=0x%.8x, tail_length=0x%.8x", i_writeStart+i_bytesToWrite, tail_length);
+ l_err = _writeFlash(i_writeStart+i_bytesToWrite,
+ tail_length,
+ tail_buffer);
if( l_err ) { break; }
}
//Write the new data - always do this
- l_err = bufferedSfcWrite(i_writeStart,
- i_bytesToWrite,
- i_data);
+ l_err = _writeFlash(i_writeStart,
+ i_bytesToWrite,
+ i_data);
if( l_err ) { break; }
}
else //
@@ -1941,9 +589,9 @@ errlHndl_t PnorDD::compareAndWriteBlock(uint32_t i_blockStart,
if(read_start[cword] ^ i_dataWord[cword] )
{
//Write the new data - always do this
- l_err = bufferedSfcWrite(i_writeStart + (cword*4),
- 4,
- &i_dataWord[cword]);
+ l_err = _writeFlash(i_writeStart + (cword*4),
+ 4,
+ &i_dataWord[cword]);
if( l_err ) { break; }
}
if( l_err ) { break; }
@@ -1964,16 +612,14 @@ errlHndl_t PnorDD::compareAndWriteBlock(uint32_t i_blockStart,
return l_err;
}
+
/**
* @brief Erase a block of flash
*/
errlHndl_t PnorDD::eraseFlash(uint32_t i_address)
{
- TRACFCOMP(g_trac_pnor, ">>PnorDD::eraseFlash> Block 0x%.8X", i_address );
-
errlHndl_t l_err = NULL;
- errlHndl_t original_err = NULL;
- uint8_t retry = 0;
+ TRACFCOMP(g_trac_pnor, ">>PnorDD::eraseFlash> Block 0x%.8X", i_address );
do {
if( findEraseBlock(i_address) != i_address )
@@ -1982,7 +628,7 @@ errlHndl_t PnorDD::eraseFlash(uint32_t i_address)
* @errortype
* @moduleid PNOR::MOD_PNORDD_ERASEFLASH
* @reasoncode PNOR::RC_INVALID_ADDRESS
- * @userdata1 LPC Address
+ * @userdata1 Flash Address
* @userdata2 Nearest Erase Boundary
* @devdesc PnorDD::eraseFlash> Address not on erase boundary
* @custdesc Firmware error accessing flash during IPL
@@ -1997,176 +643,37 @@ errlHndl_t PnorDD::eraseFlash(uint32_t i_address)
break;
}
- /***********************************************************/
- /* Attempt erase multiple times */
- /***********************************************************/
- // reset class variable since we're starting a new operation
- iv_error_recovery_failed = false;
-
- // This do-while loop supports retries
- do {
-
- for(uint32_t idx = 0; idx < ERASE_COUNT_MAX; idx++ )
+ for(uint32_t idx = 0; idx < ERASE_COUNT_MAX; idx++ )
+ {
+ if(iv_erases[idx].addr == i_address)
{
- if(iv_erases[idx].addr == i_address)
- {
- iv_erases[idx].count++;
- TRACFCOMP(g_trac_pnor,"PnorDD::eraseFlash> Block 0x%.8X has %d erasures",
- i_address, iv_erases[idx].count );
- break;
-
- }
- //iv_erases is init to all 0xff,
- // so can use ~0 to check for an unused position
- else if(iv_erases[idx].addr == ~0u)
- {
- iv_erases[idx].addr = i_address;
- iv_erases[idx].count = 1;
- TRACFCOMP(g_trac_pnor,"PnorDD::eraseFlash> Block 0x%.8X has %d erasures",
- i_address, iv_erases[idx].count );
- break;
- }
- else if( idx == (ERASE_COUNT_MAX - 1))
- {
- TRACFCOMP(g_trac_pnor,"PnorDD::eraseFlash> Erase counter full! Block 0x%.8X Erased",
- i_address );
- break;
- }
- }
+ iv_erases[idx].count++;
+ TRACFCOMP(g_trac_pnor,
+ "PnorDD::eraseFlash> Block 0x%.8X has %d erasures",
+ i_address, iv_erases[idx].count );
+ break;
- if( (MODEL_MEMCPY == iv_mode) || (MODEL_LPC_MEM == iv_mode))
- {
- erase_fake_pnor( i_address, iv_erasesize_bytes );
- break; //all done
}
-
- else if(iv_nor_chipid != 0)
+ //iv_erases is init to all 0xff,
+ // so can use ~0 to check for an unused position
+ else if(iv_erases[idx].addr == ~0u)
{
-
- // group this block together with do-while
- do{
- TRACDCOMP(g_trac_pnor, "PnorDD::eraseFlash> Erasing flash for iv_nor_chipid=0x%.8x, iv_mode=0x%.8x",
- iv_nor_chipid, iv_mode);
-
- //Write erase address to ADR reg
- l_err = writeRegSfc(SFC_CMD_SPACE,
- SFC_REG_ADR,
- i_address);
-
- if(l_err) { break; }
-
- //Issue Erase command
- SfcCmdReg_t sfc_cmd;
- sfc_cmd.opcode = SFC_OP_ERASM;
- sfc_cmd.length = 0; //Not used for erase
-
- 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; }
-
- //check for special Micron Flag Status reg
- if(iv_hw_workaround & HWWK_MICRON_WRT_ERASE)
- {
- l_err = micronFlagStatus();
- if(l_err) { break; }
- }
-
- }while(0); // group of commands
-
+ iv_erases[idx].addr = i_address;
+ iv_erases[idx].count = 1;
+ TRACFCOMP(g_trac_pnor,
+ "PnorDD::eraseFlash> Block 0x%.8X has %d erasures",
+ i_address, iv_erases[idx].count );
+ break;
}
- else
+ else if( idx == (ERASE_COUNT_MAX - 1))
{
- TRACFCOMP(g_trac_pnor,"PnorDD::eraseFlash> Erase not supported for iv_nor_chipid=%d",
- iv_nor_chipid );
-
- /*@
- * @errortype
- * @moduleid PNOR::MOD_PNORDD_ERASEFLASH
- * @reasoncode PNOR::RC_UNSUPPORTED_OPERATION
- * @userdata1 NOR Chip ID
- * @userdata2 LPC Address to erase
- * @devdesc PnorDD::eraseFlash> No support for MODEL_REAL
- */
- l_err = new ERRORLOG::ErrlEntry(
- ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- PNOR::MOD_PNORDD_ERASEFLASH,
- PNOR::RC_UNSUPPORTED_OPERATION,
- static_cast<uint64_t>(iv_nor_chipid),
- i_address,
- true /*Add HB SW Callout*/ );
- l_err->collectTrace(PNOR_COMP_NAME);
-
- // this error can't be fixed with a retry, so just break
- if(l_err) { break; }
-
+ TRACFCOMP(g_trac_pnor, "PnorDD::eraseFlash> Erase counter full! Block 0x%.8X Erased", i_address );
+ break;
}
-
- // end of operation - check for retry
- } while ( shouldRetry(RETRY_eraseFlash, l_err, original_err, retry) );
-
- if(l_err) { break;}
-
- } while(0);
-
- 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 & iv_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 );
+ // actually do the erase
+ l_err = _eraseFlash(i_address);
if(l_err) { break; }
} while(0);
@@ -2175,336 +682,11 @@ errlHndl_t PnorDD::readRegFlash( SfcCustomReg_t i_cmd,
}
-/*
- This code is used in the MODEL_MEMCPY and MODEL_LPC_MEM modes
-*/
-/**
- * @brief Write to fake PNOR
- */
-void PnorDD::write_fake_pnor( uint64_t i_pnorAddr,
- void* i_buffer,
- size_t i_size )
-{
- //create a pointer to the offset start.
- char * destPtr = (char *)(iv_fakeStart+i_pnorAddr);
-
- if( (i_pnorAddr+i_size) > iv_fakeSize )
- {
- TRACFCOMP(g_trac_pnor,
- "PnorDD write_fake_pnor> Write goes past end of fake-PNOR, skipping write. i_pnorAddr=0x%X, i_size=0x%X",
- i_pnorAddr, i_size );
- }
- else
- {
- //copy data from memory into the buffer.
- memcpy(destPtr, i_buffer, i_size);
- }
-}
/**
- * @brief Read from fake PNOR
+ * @brief Returns if an operation should be retried and handles
+ * the error logs
*/
-void PnorDD::read_fake_pnor( uint64_t i_pnorAddr,
- void* o_buffer,
- size_t i_size )
-{
- //create a pointer to the offset start.
- char * srcPtr = (char *)(iv_fakeStart+i_pnorAddr);
-
- if( (i_pnorAddr+i_size) > iv_fakeSize )
- {
- TRACFCOMP(g_trac_pnor,
- "PnorDD read_fake_pnor> Read goes past end of fake-PNOR, skipping read. i_pnorAddr=0x%X, i_size=0x%X",
- i_pnorAddr, i_size );
- }
- else
- {
- //copy data from memory into the buffer.
- memcpy(o_buffer, srcPtr, i_size);
- }
-
-}
-
-/**
- * @brief Erase chunk of fake PNOR
- */
-void PnorDD::erase_fake_pnor( uint64_t i_pnorAddr,
- size_t i_size )
-{
- //create a pointer to the offset start.
- char * srcPtr = (char *)(iv_fakeStart+i_pnorAddr);
-
- if( (i_pnorAddr+i_size) > iv_fakeSize )
- {
- TRACFCOMP(g_trac_pnor,
- "PnorDD erase_fake_pnor> Erase goes past end of fake-PNOR, skipping erase. i_pnorAddr=0x%X, i_size=0x%X",
- i_pnorAddr, i_size );
- }
- else
- {
- //Zero out memory
- memset( srcPtr, 0, i_size );
- }
-}
-
-
-
-errlHndl_t PnorDD::resetPnor( ResetLevels i_pnorResetLevel )
-{
- errlHndl_t l_err = NULL;
-
- // check iv_reset_active to avoid infinite loops
- // and don't reset if in the middle of FFDC collection
- if ( ( iv_reset_active == false ) &&
- ( iv_ffdc_active == false ) )
- {
- iv_reset_active = true;
-
- TRACFCOMP(g_trac_pnor, "PnorDD::resetPnor> i_pnorResetLevel=0x%.8X", i_pnorResetLevel);
-
- do {
-#if 0
- // 32 bits for address and data for LPC operations
- uint32_t lpc_addr=0;
- uint32_t lpc_data=0;
-#endif
-
- // To Avoid Infinite Loop - skip recovery if it already failed
- if ( iv_error_recovery_failed == true )
- {
- TRACFCOMP(g_trac_pnor, "PnorDD::resetPnor> Recovery Previously Failed (%d). Skipping reset to avoid infinite loop", iv_error_recovery_failed);
- break;
- }
-
- /***************************************/
- /* Handle the different reset levels */
- /***************************************/
- switch(i_pnorResetLevel)
- {
- case RESET_CLEAR:
- {// Nothing to do here, so just break
- break;
- }
-
- //@fixme RTC:109859 -- All SFC recovery should move into SFC classes
- case RESET_LPC_SLAVE:
- {
- // @todo RTC 109999 - Skipping because SFC resets can
- // cause problems on subsequent reads and writes
- TRACFCOMP(g_trac_pnor, "PnorDD::resetPnor> Skipping RESET_LPC_SLAVE");
-
-#if 0
- TRACFCOMP(g_trac_pnor, "PnorDD::resetPnor> Writing bit0 of LPC_SLAVE_REG_RESET to reset LPC Slave Logic");
- lpc_addr = LPC_SLAVE_REG_RESET;
- lpc_data = 0x80000000;
-
- l_err = writeLPC(lpc_addr, lpc_data);
-#endif
- break;
- }
-
- //@fixme RTC:109859 -- All SFC recovery should move into SFC classes
- case RESET_LPC_SLAVE_ERRS:
- {
- // @todo RTC 109999 - Skipping because SFC resets can
- // cause problems on subsequent reads and writes
- TRACFCOMP(g_trac_pnor, "PnorDD::resetPnor> Skipping RESET_LPC_SLAVE_ERRS");
-#if 0
- TRACFCOMP(g_trac_pnor, "PnorDD::resetPnor> Writing bit1 of LPC_SLAVE_REG_RESET to reset LPC Slave Errors");
- lpc_addr = LPC_SLAVE_REG_RESET;
- lpc_data = 0x40000000;
-
- l_err = writeLPC(lpc_addr, lpc_data);
-#endif
- break;
- }
-
-
- //@fixme RTC:109859 -- All SFC recovery should move into SFC classes
- case RESET_SFC_LOCAL_BUS:
- {
- // @todo RTC 109999 - Skipping because SFC resets can
- // cause problems on subsequent reads and writes
- TRACFCOMP(g_trac_pnor, "PnorDD::resetPnor> Skipping RESET_SFC_LPC_LOCAL_BUS");
-#if 0
- TRACFCOMP(g_trac_pnor, "PnorDD::resetPnor> Writing bit2 of LPC_SLAVE_REG_RESET to reset Local SFC Bus. Requires PNOR reinitialization");
- lpc_addr = LPC_SLAVE_REG_RESET;
- lpc_data = 0x20000000;
-
- l_err = writeLPC(lpc_addr, lpc_data);
-
- if (l_err) { break; }
-
- l_err = PnorDD::reinitializeSfc();
-#endif
- break;
- }
-
- //@fixme RTC:109859 -- All SFC recovery should move into SFC classes
- case RESET_SFCBUS_LPCSLAVE_ERRS:
- {
- // @todo RTC 109999 - Skipping because SFC resets can
- // cause problems on subsequent reads and writes
- TRACFCOMP(g_trac_pnor, "PnorDD::resetPnor> Skipping RESET_SFCBUS_LPCSLAVE_ERRS");
-#if 0
- // Must handle both errors
- TRACFCOMP(g_trac_pnor, "PnorDD::resetPnor> Writing bits1,2 of LPC_SLAVE_REG_RESET to reset LPC Slave Errors and Local SFC Bus. Requires PNOR reinitialization");
- lpc_addr = LPC_SLAVE_REG_RESET;
- lpc_data = 0x60000000;
-
- l_err = writeLPC(lpc_addr, lpc_data);
-
- if (l_err) { break; }
-
- l_err = PnorDD::reinitializeSfc();
-#endif
- break;
- }
-
- // else - unsupported reset level
- default:
- {
-
- TRACFCOMP( g_trac_pnor, ERR_MRK"PnorDD::resetPnor> Unsupported Reset Level Passed In: 0x%X", i_pnorResetLevel);
-
- /*@
- * @errortype
- * @moduleid PNOR::MOD_PNORDD_RESETPNOR
- * @reasoncode PNOR::RC_UNSUPPORTED_OPERATION
- * @userdata1 Unsupported Reset Level Parameter
- * @userdata2 <unused>
- * @devdesc PnorDD::resetPnor> Unsupported Reset Level
- * requested
- */
- l_err = new ERRORLOG::ErrlEntry(
- ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- PNOR::MOD_PNORDD_RESETPNOR,
- PNOR::RC_UNSUPPORTED_OPERATION,
- i_pnorResetLevel,
- 0,
- true /*SW error*/);
-
- l_err->collectTrace(PNOR_COMP_NAME);
- break;
- }
- }// end switch
-
- if ( l_err )
- {
- // Indicate that we weren't successful in resetting PNOR
- iv_error_recovery_failed = true;
- TRACFCOMP( g_trac_pnor,ERR_MRK"PnorDD::resetPnor>> Fail doing PNOR reset at level 0x%X (recovery count=%d): eid=0x%X", i_pnorResetLevel, iv_error_handled_count, l_err->eid());
- }
- else
- {
- // Successful, so increment recovery count
- iv_error_handled_count++;
-
- TRACFCOMP( g_trac_pnor,INFO_MRK"PnorDD::resetPnor>> Successful PNOR reset at level 0x%X (recovery count=%d)", i_pnorResetLevel, iv_error_handled_count);
- }
-
-
- } while(0);
-
- // reset RESET active flag
- iv_reset_active = false;
- }
-
- return l_err;
-}
-
-
-
-//@fixme RTC:109859 -- All SFC recovery should move into SFC classes
-errlHndl_t PnorDD::reinitializeSfc( void )
-{
- TRACFCOMP(g_trac_pnor, "PnorDD::reinitializeSfc>");
-
- errlHndl_t l_err = NULL;
-
- //Initial configuration settings for SFC:
- #define oadrnb_init 0x0C000000 //Set MMIO/Direct window to start at 64MB
- #define oadrns_init 0x0000000F //Set the MMIO/Direct window size to 64MB
- #define adrcbf_init 0x00000000 //Set the flash index to 0
- #define adrcmf_init 0x0000000F //Set the flash size to 64MB
- #define conf_init 0x00000002 //Disable Direct Access Cache
-
- do {
-
-#ifdef CONFIG_BMC_DOES_SFC_INIT
-
- TRACFCOMP( g_trac_pnor, ERR_MRK"PnorDD::reinitializeSfc> Need to Re-Initialize SFC. Calling doShutdown(PNOR::RC_REINITIALIZE_SFC)");
-
- l_err = NULL; // to avoid compiler warnings
-
- //Shutdown if SFC needs to be re-initialized
- INITSERVICE::doShutdown( PNOR::RC_REINITIALIZE_SFC);
-
-#else
-
-
- // Clear member variable in case we don't successfully
- // reinitialize PNOR
- iv_sfcInitDone = false;
-
- l_err = writeRegSfc(SFC_CMD_SPACE,
- SFC_REG_OADRNB,
- oadrnb_init);
- if(l_err) { break; }
-
- l_err = writeRegSfc(SFC_CMD_SPACE,
- SFC_REG_OADRNS,
- oadrns_init);
- if(l_err) { break; }
-
- l_err = writeRegSfc(SFC_CMD_SPACE,
- SFC_REG_ADRCBF,
- adrcbf_init);
- if(l_err) { break; }
-
- l_err = writeRegSfc(SFC_CMD_SPACE,
- SFC_REG_ADRCMF,
- adrcmf_init);
- if(l_err) { break; }
-
- l_err = writeRegSfc(SFC_CMD_SPACE,
- SFC_REG_CONF,
- conf_init);
- if(l_err) { break; }
-
-
- //Determine NOR Flash type - triggers vendor specific workarounds
- //We also use the chipID in some FFDC situations.
- l_err = getNORChipId(iv_nor_chipid);
- if(l_err) { break; }
-
- TRACFCOMP(g_trac_pnor,
- "PnorDD::reinitializeSfc> iv_nor_chipid=0x%.8x> ",
- iv_nor_chipid );
-
- l_err = readRegSfc(SFC_CMD_SPACE,
- SFC_REG_ERASMS,
- iv_erasesize_bytes);
- if(l_err) { break; }
-
- // Good path if you made it here: reset class variable
- iv_sfcInitDone = true;
-
-#endif
-
- } while(0);
-
- if (l_err)
- {
- TRACFCOMP( g_trac_pnor,INFO_MRK"PnorDD::reinitializeSfc> SFC reinitialization FAILED - l_err rc=0x%X, eid=%d", l_err->reasonCode(), l_err->eid());
- iv_error_recovery_failed = true;
-
- }
-
- return l_err;
-}
-
-
bool PnorDD::shouldRetry( RetryOp i_op,
errlHndl_t& io_err,
errlHndl_t& io_original_err,
@@ -2514,10 +696,9 @@ bool PnorDD::shouldRetry( RetryOp i_op,
bool should_retry = false;
- if ( ( io_err == NULL ) || ( iv_error_recovery_failed == true ) )
+ if ( io_err == NULL )
{
- // Either Operation was successful OR error recovery failed -
- // either way don't retry
+ // Operation was successful so don't retry
should_retry = false;
// Error logs handled below
@@ -2604,3 +785,83 @@ bool PnorDD::shouldRetry( RetryOp i_op,
return should_retry;
}
+
+/**
+ * @brief Calls the SFC to perform a PNOR Write Operation
+ */
+errlHndl_t PnorDD::_writeFlash( uint32_t i_addr,
+ size_t i_size,
+ void* i_data )
+{
+ TRACDCOMP(g_trac_pnor, ENTER_MRK"PnorDD::_writeFlash(i_addr=0x%.8X)> ", i_addr);
+ errlHndl_t l_err = NULL;
+ errlHndl_t original_err = NULL;
+ uint8_t retry = 0;
+
+ do
+ {
+ // Call over to the SFC code to do the actual write
+ l_err = iv_sfc->writeFlash( i_addr, i_size, i_data );
+
+ // end of operation - check for retry
+ } while( shouldRetry(RETRY_writeFlash, l_err, original_err, retry) );
+
+ if( l_err )
+ {
+ l_err->collectTrace(PNOR_COMP_NAME);
+ }
+
+ return l_err;
+}
+
+/**
+ * @brief Calls the SFC to perform a PNOR Read Operation
+ */
+errlHndl_t PnorDD::_readFlash( uint32_t i_addr,
+ size_t i_size,
+ void* o_data )
+{
+ //TRACDCOMP(g_trac_pnor, "PnorDD::_readFlash(i_address=0x%.8X)> ", i_addr);
+ errlHndl_t l_err = NULL;
+ errlHndl_t original_err = NULL;
+ uint8_t retry = 0;
+
+ do{
+ //Send command over to the flash controller to do the work
+ l_err = iv_sfc->readFlash(i_addr, i_size, o_data);
+
+ // end of operation - check for retry
+ } while( shouldRetry(RETRY_readFlash, l_err, original_err, retry) );
+
+ if( l_err )
+ {
+ l_err->collectTrace(PNOR_COMP_NAME);
+ }
+
+ return l_err;
+}
+
+/**
+ * @brief Calls the SFC to perform a PNOR Read Operation
+ */
+errlHndl_t PnorDD::_eraseFlash( uint32_t i_addr )
+{
+ TRACDCOMP(g_trac_pnor, "PnorDD::_eraseFlash(i_address=0x%.8X)> ", i_addr);
+ errlHndl_t l_err = NULL;
+ errlHndl_t original_err = NULL;
+ uint8_t retry = 0;
+
+ do{
+ //Send command over to the flash controller to do the work
+ l_err = iv_sfc->eraseFlash(i_addr);
+
+ // end of operation - check for retry
+ } while( shouldRetry(RETRY_eraseFlash, l_err, original_err, retry) );
+
+ if( l_err )
+ {
+ l_err->collectTrace(PNOR_COMP_NAME);
+ }
+
+ return l_err;
+}
diff --git a/src/usr/pnor/pnordd.H b/src/usr/pnor/pnordd.H
index 31b3d8d7d..4b086e36b 100644
--- a/src/usr/pnor/pnordd.H
+++ b/src/usr/pnor/pnordd.H
@@ -29,6 +29,7 @@
#include <limits.h>
#include <config.h>
namespace PNOR { class UdPnorDDParms; }
+class SfcDD;
/** @file pnordd.H
* @brief Provides the interfaces to the PNOR Device Driver
@@ -43,13 +44,6 @@ class PnorDD
public:
/**
- * @brief Initializer called by PnorRP::init() to init the SFC
- *
- * @return void
- */
- void sfcInit( );
-
- /**
* @brief Performs a PNOR Read Operation
*
* @parm o_buffer Buffer to read data into
@@ -100,16 +94,10 @@ class PnorDD
/**
* @brief Constructor
*
- * @parm i_mode o_buffer Buffer to read data into
- * @parm i_fakeStart Input: Number of bytes to read,
- * @parm i_fakeSize Output: Number of bytes actually read
* @parm i_target Processor Target connected to PNOR
- * NOTE: i_target can only be used when targetting is loaded
+ * NOTE: i_target can only be used after targeting is loaded
*/
- PnorDD( PnorMode_t i_mode = MODEL_UNKNOWN,
- uint64_t i_fakeStart = 0,
- uint64_t i_fakeSize = 0,
- TARGETING::Target* i_target = NULL );
+ PnorDD( TARGETING::Target* i_target = NULL );
/**
@@ -126,430 +114,18 @@ class PnorDD
};
/**
- * @brief SPI Config Info
- * OP Codes and other MISC info for configuring SFC
- */
- enum SpiConfigInfo {
- SPI_GET_CHIPID_OP = 0x9F, /**< Default Op code for getting NOR ChipID */
- SPI_START4BA = 0x37, /**< Enable Macronix 4-Byte addressing */
-
- /*
- * Micron Flash Commands
- */
- 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 protocol command bytes */
- SPI_JEDEC_FAST_READ = 0x0B,
- SPI_JEDEC_SECTOR_ERASE = 0x20,
- SPI_JEDEC_BLOCK_ERASE = 0xD8,
-
- SPI_SIM_SM_ERASE_OP = 0x00000020, /**< Simics Op Code for Small Erase */
- SPI_SIM_SM_ERASE_SZ = 0x1000, /**< Simics Small Erase Size */
- };
-
- /**
- * @brief Supported NOR Chip IDs
- *
- */
- enum NorChipIDs
- {
- /* Note: Simics currently models Micron NOR */
- UNKNOWN_NOR_ID = 0, /**< Unknown NOR chip ID */
- 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 */
- };
-
-
- enum SfcRange {
- SFC_CMD_SPACE, /**< Indicate accessing command reg */
- SFC_CMDBUF_SPACE, /**< Indicate accessing command buffer space */
- SFC_MMIO_SPACE, /**< Indicate accessing MMIO based Direct Reads */
- SFC_LPC_SPACE, /**< Indicate LPC Slave Space */
- };
-
- /**
- * @brief SFC Registers
- * These are offsets within the SFC Register Space
- */
- enum SfcRegAddr {
- SFC_REG_CONF = 0x10, /**< CONF: Direct Access Configuration */
- SFC_REG_STATUS = 0x0C, /**< STATUS : Status Reg */
- SFC_REG_SPICLK = 0x3C, /**< SPICLK: SPI clock rate config */
- SFC_REG_CMD = 0x40, /**< CMD : Command */
- SFC_REG_ADR = 0x44, /**< ADR : Address */
- SFC_REG_ERASMS = 0x48, /**< ERASMS : Small Erase Block Size */
- SFC_REG_ERASLGS = 0x4C, /**< ERALGS : Large Erase Block Size */
- SFC_REG_CONF4 = 0x54, /**< CONF4 : SPI Op Code for Small Erase */
- SFC_REG_CONF5 = 0x58, /**< CONF5 : Small Erase Size config reg */
- SFC_REG_CONF8 = 0x64, /**< CONF8 : Read Command */
- SFC_REG_ADRCBF = 0x80, /**< ADRCBF : First Intf NOR Addr Offset */
- SFC_REG_ADRCMF = 0x84, /**< ADRCMF : First Intf NOR Allocation */
- SFC_REG_ADRCBS = 0x88, /**< ADRCBS : Second Intf NOR Addr Offset */
- SFC_REG_ADRCMS = 0x8C, /**< ADRCMS : Second Intf NOR Allocation */
- SFC_REG_OADRNB = 0x90, /**< OADRNB : Direct Access OBP Window Base Address */
- SFC_REG_OADRNS = 0x94, /**< OADRNS : DIrect Access OPB Window Size */
- SFC_REG_CHIPIDCONF = 0x9C, /**< CHIPIDCONF : config ChipId CMD */
- SFC_REG_ERRCONF = 0x6C, /**< ERRCONF : Configures error counts that
- cause interupts */
- SFC_REG_ERRTAG = 0x1C, /**< ERRTAG : Holds Control Info of Error */
- SFC_REG_ERROFF = 0x20, /**< ERROFF : Holds Address Info of Error */
- SFC_REG_ERRSYN = 0x24, /**< ERRSYN : Holds Syndrome That Caused Error*/
- SFC_REG_ERRDATH = 0x28, /**< ERRDATH : Holds Most Signifcant Word of
- Double Word That Caused Error */
- SFC_REG_ERRDATL = 0x2C, /**< ERRDATL : Holds Least Signifcant Word of
- Double Word That Caused Error */
- SFC_REG_ERRCNT = 0x30, /**< ERRCNT : Counts The Number Of Errors */
- SFC_REG_CLRCNT = 0x34, /**< CLRCNT : Which Bits To Clear In ERRCNT */
- SFC_REG_ERRINJ = 0x38, /**< ERRINJ : Force Errors Into Read Paths */
- SFC_REG_PROTA = 0x70, /**< PROTA : Write Protect Range Address Base */
- SFC_REG_PROTM = 0x74, /**< PROTM : Write Protect Range Size */
- SFC_REG_ECCADDR = 0x78, /**< ECCADDR : ECC Disable Range Base Address */
- SFC_REG_ECCRNG = 0x7C, /**< ECCRNG : ECC Disable Range Size */
- SFC_REG_ERRORS = 0x00, /**< ERRORS : Collection of Error Status Bits */
- SFC_REG_INTMSK = 0x04, /**< INTMSK : Record of Events That Could Lead
- To Interupt */
- SFC_REG_INTENM = 0x14, /**< INTENM : Controls Which Events Lead
- To Interupts */
- SFC_REG_CONF2 = 0x18, /**< CONF2 : SPI Configuration */
- SFC_REG_CONF3 = 0x50, /**< CONF3 : SPI Recovery */
-
- };
-
- /**
- * @brief SFC Op Codes
- * OP Codes for the SFC Command Register
- */
- enum SfcOpCodes {
- SFC_OP_READRAW = 0x03, /**< Read Raw */
- SFC_OP_WRITERAW = 0x02, /**< Write Raw */
- SFC_OP_ERASM = 0x32, /**< Erase Small */
- SFC_OP_ERALG = 0x34, /**< Erase Large */
- SFC_OP_ENWRITPROT = 0x53, /**< Enable WRite Protect */
- SFC_OP_CHIPID = 0x1F, /**< Get Chip ID */
- SFC_OP_STATUS = 0x05, /**< Get Status */
- SFC_OP_TURNOFF = 0x5E, /**< Turn Off */
- SFC_OP_TURNON = 0x50, /**< Turn On */
- SFC_OP_ABORT = 0x6F, /**< Super-Abort */
- SFC_OP_START4BA = 0x37, /**< Start 4BA */
- SFC_OP_END4BA = 0x69, /**< End 4BA */
- SFC_OP_INVALID = 0x00, /**< Invalid - used for testing */
- };
-
-
- enum {
- SFC_CMDBUF_SIZE = 256, /**< SFC Command buffer is
- 0x100/256 bytes/0x40 words */
-
- //@todo-RTC:95125 Find out Max time to wait*/
- SFC_POLL_TIME_NS = 1000000000, /**< Max time to wait for SFC Op */
- SFC_POLL_INCR_NS = 10, /**< minimum increment during poll */
-
- };
-
-
- /**
- * Flags used to trigger Hardware workarounds
- */
- enum {
- // 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,
- };
-
- /**
- * Enums for different levels of resetting PNOR communication levels
- */
- enum ResetLevels {
- RESET_CLEAR = 0x00000000, /**< Clear Reset Level */
- RESET_LPC_SLAVE = 0x00000008, /**< LPC Slave Logic on SFC */
- RESET_LPC_SLAVE_ERRS = 0x00000010, /**< LPC Slave Errors on SFC */
- RESET_SFC_LOCAL_BUS = 0x00000020, /**< SFC Local Bus */
- // Known possible combination:
- RESET_SFCBUS_LPCSLAVE_ERRS = 0x00000030, /**< Bus and LPC Slave Errs */
- };
-
- /**
* Enums for different operations that might be re-tried
*/
- enum RetryOp {
- RETRY_NOOP = 0,
- RETRY_getNORChipId = 1,
- RETRY_bufferedSfcRead = 2,
- RETRY_bufferedSfcWrite = 3,
- RETRY_eraseFlash = 4,
- };
-
-
- /**
- * @brief SFC Command Register Layout
- */
- union SfcCmdReg_t
- {
- uint32_t data32;
- struct
- {
- uint32_t reserved : 16; /**< 0:15 = Reserved */
- uint32_t opcode : 7; /**< 16:22 = OpCode */
- uint32_t length : 9; /**< 22:31 = Num bytes for Read/Write Raw */
- };
- SfcCmdReg_t() : data32(0) {};
- };
-
- /**
- * @brief SFC Status Register Layout
- */
- union SfcStatReg_t
- {
- uint32_t data32;
- struct
- {
- uint32_t unused : 20; /**< 0:19 = Not Currently Used */
- uint32_t eccerrcntr : 1; /**< 20 Threshold for SRAM ECC errors */
- uint32_t eccues : 1; /**< 21 SRAM cmd uncorrectable ECC error*/
- uint32_t unused_22 : 3; /**< 22:24 = Not Currently Used */
- uint32_t cmdexe : 1; /**< 25 Previous cmd is in progress */
- uint32_t cmdwait : 1; /**< 26 Previous cmd waiting to execute */
- uint32_t illegal : 1; /**< 27 Previous op illegal */
- uint32_t eccerrcntn : 1; /**< 28 Threshold for Flash ECC errors */
- uint32_t eccuen : 1; /**< 29 Flash cmd uncorrectable ECC err */
- uint32_t timeout : 1; /**< 30 Timeout */
- uint32_t done : 1; /**< 31 Done */
- };
- SfcStatReg_t() : data32(0) {};
- };
-
- /**
- * @brief LPC Slave Registers
- * These are offsets within the LPC Slave Register Space
- */
- enum LpcSlaveRegAddr {
- LPC_SLAVE_REG_STATUS = 0x14, /**< STATUS: read-only */
- LPC_SLAVE_REG_RESET = 0x14, /**< RESET : write-only */
- };
-
- /**
- * @brief LPC Slave Status Register Layout
- */
- union LpcSlaveStatReg_t
- {
- uint32_t data32;
- struct
- {
- uint32_t lbusowner : 2; /**< 0:1 = Local Bus Owner */
- uint32_t lbusparityerror : 1; /**< 2 = Local Bus Parity Error */
- uint32_t lbus2opberr : 3; /**< 3:5 = Errors From LBUS2OPB */
- uint32_t unused : 26; /**< 6:21 = Not Currently Used */
- };
- LpcSlaveStatReg_t() : data32(0) {};
- };
-
- /**
- * @brief LPC Slave Reset Register Layout
- */
- union LpcSlaveResetReg_t
- {
- uint32_t data32;
- struct
- {
- uint32_t lpcslave : 1; /**< 0 Reset LPC Slave */
- uint32_t lpcslaveerrs : 1; /**< 1 Reset LPC Slave Errors */
- uint32_t localbus : 1; /**< 2 Reset Local Bus */
- uint32_t unused : 29; /**< 4:31 = Not Currently Used */
- };
- LpcSlaveResetReg_t() : data32(0) {};
- };
-
-
- /**
- * @brief LPC Slave LBUS2OPB Errors
- * Translation of LPC Slave Status Register Bits 3:5
- */
- enum LpcSlaveLbus2OpbErrors {
- LBUS2OPB_ADDR_PARITY_ERR = 0b010, /**< Address Parity Error */
- LBUS2OPB_INVALID_SELECT_ERR = 0b001, /**< Invalid Select Error */
- LBUS2OPB_DATA_PARITY_ERR = 0b011, /**< Data Parity Error */
- LBUS2OPB_MONITOR_ERR = 0b100, /**< Monitor Error */
- LBUS2OPB_TIMEOUT_ERR = 0b101, /**< Timeout Error */
- };
-
- /**
- * @brief SFC ConfId Register Layout
- */
- union SfcCustomReg_t
+ enum RetryOp
{
- 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) {};
+ RETRY_NOOP = 0,
+ RETRY_writeFlash = 1,
+ RETRY_readFlash = 2,
+ RETRY_eraseFlash = 3,
};
/**
- * @brief Write a SFC Register
- *
- * @parm i_range SFC Address Range
- * @parm i_addr SFC Register to write
- * @parm i_data Data to write
- *
- * @return Error from operation
- */
- errlHndl_t writeRegSfc(SfcRange i_range,
- uint32_t i_addr,
- uint32_t i_data);
-
- /**
- * @brief Read a SFC Register
- *
- * @parm i_range SFC Address Range
- * @parm i_addr SFC Register to read
- * @parm o_data Data to write
- *
- * @return Error from operation
- */
- errlHndl_t readRegSfc(SfcRange i_range,
- uint32_t i_addr,
- 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
- *
- * @return Error from operation
- */
- errlHndl_t pollSfcOpComplete(uint64_t i_pollTime = SFC_POLL_TIME_NS);
-
- /**
- * @brief Check flag status bit on Micron NOR chips
- * The current version of Micron parts require the Flag
- * Status register be read after a read or erase operation,
- * otherwise all future operations won't work..
- *
- * @parm i_pollTime Amount of time to Poll, default SFC_POLL_TIME_NS
- *
- * @return Error from operation
- */
- errlHndl_t micronFlagStatus(uint64_t i_pollTime = SFC_POLL_TIME_NS);
-
- /**
- * @brief Read the NOR FLash ChipID
- *
- * @parm o_chipId NOR Flash ChipID
- * @parm i_spiOpcode SPI OpCode to use to get Chip ID
- *
- * @return Error from operation
- */
- errlHndl_t getNORChipId(uint32_t& o_chipId,
- uint32_t i_spiOpcode = SPI_GET_CHIPID_OP);
-
- /**
- * @brief Load SFC command buffer with data from PNOR
- *
- * @parm i_addr PNOR flash Address to read
- * @parm i_size Number of bytes to read.to command buffer
- *
- * @return Error from operation
- */
- errlHndl_t loadSfcBuf(uint32_t i_addr,
- size_t i_size);
-
- /**
- * @brief Flush SFC command buffer contents to PNOR Flash
- *
- * @parm i_addr PNOR flash Address to write
- * @parm i_size Number of bytes to write.to command buffer
- *
- * @return Error from operation
- */
- errlHndl_t flushSfcBuf(uint32_t i_addr,
- size_t i_size);
-
- /**
- * @brief Read data in SFC Command buffer and put into buffer
- *
- * @parm i_size Amount of data in Cmd Buffer to read, in bytes.
- * @parm o_data Buffer to read data into
- *
- * @return Error from operation
- */
- errlHndl_t readSfcBuffer(size_t i_size,
- void* o_data);
-
- /**
- * @brief Write data to SFC Command buffer
- *
- * @parm i_size Amount of data in Cmd Buffer to write, in bytes.
- * @parm o_data Buffer to read data from
- *
- * @return Error from operation
- */
- errlHndl_t writeSfcBuffer(size_t i_size,
- void* i_data);
-
-
- /**
- * @brief Perform command based read of PNOR, maximizing use of
- * SFC Command buffer..
- *
- * @parm i_addr PNOR flash Address to read
- * @parm i_size Amount of data to read, in bytes.
- * @parm o_data Buffer to read data into
- *
- * @return Error from operation
- */
- errlHndl_t bufferedSfcRead(uint32_t i_addr,
- size_t i_size,
- void* o_data);
-
- /**
- * @brief Perform command based write of PNOR, maximizing use of
- * SFC Command buffer..
- *
- * @parm i_addr PNOR flash Address to write
- * @parm i_size Amount of data to write, in bytes.
- * @parm i_data Buffer containing data to write
- *
- * @return Error from operation
- */
- errlHndl_t bufferedSfcWrite(uint32_t i_addr,
- size_t i_size,
- void* i_data);
-
-
- /**
* @brief Some general constants
- *
*/
enum {
LPCHC_FW_SPACE = 0xF0000000, /**< LPC Host Controller FW Space */
@@ -559,11 +135,6 @@ class PnorDD
LPC_SFC_CMDREG_OFFSET = 0xF0000C00, /** LPC Offest to SFC Cmd Regs */
LPC_SFC_CMDBUF_OFFSET = 0xF0000D00, /** LPC Off to SFC Cmd Buf space */
-#ifdef CONFIG_SFC_IS_AST2400
- LPC_SFC_MMIO_OFFSET = 0xFE000000, /** LPC Off to SFC Direct Read space*/
-#else //default to IBM DPSS controller
- LPC_SFC_MMIO_OFFSET = 0xFC000000, /** LPC Off to SFC Direct Read space*/
-#endif
LPC_TOP_OF_FLASH_OFFSET = 0xFFFFFFFF,
ECCB_STAT_REG = 0x000B0022, /**< ECCB Status Reg (FW) */
@@ -612,6 +183,7 @@ class PnorDD
/**
* @brief Erase a block of flash
+ * @pre Mutex should already be locked before calling
*
* @parm i_address Offset into flash to erase, aligned to erase block
*
@@ -622,6 +194,7 @@ class PnorDD
/**
* @brief Compare the existing data in 1 erase block of the flash with
* the incoming data and write or erase as needed
+ * @pre Mutex should already be locked before calling
*
* @parm i_blockStart Start of Erase Block we're writing to
* @parm i_writeStart Starting address where we want to write data.
@@ -644,7 +217,7 @@ class PnorDD
*/
uint32_t findEraseBlock(uint32_t i_address)
{
- return (i_address - i_address%iv_erasesize_bytes);
+ return (i_address - i_address%iv_eraseSizeBytes);
};
/**
@@ -664,87 +237,11 @@ class PnorDD
while( findEraseBlock(addr) < (i_address+i_byteSize) )
{
blocks++;
- addr += iv_erasesize_bytes;
+ addr += iv_eraseSizeBytes;
}
return blocks;
};
- // These are used to cheat and use a chunk of our cache as a PNOR
- // iv_mode == MODEL_MEMCPY,MODEL_LPC_MEM
- /**
- * @brief write to fake PNOR
- *
- * @parm i_pnorAddr Offset into fake PNOR
- * @parm i_buffer Buffer of data to write
- * @param i_size Amount to write.
- */
- void write_fake_pnor( uint64_t i_pnorAddr,
- void* i_buffer, size_t i_size );
-
- /**
- * @brief Read from fake PNOR
- *
- * @parm i_pnorAddr Offset into fake PNOR
- * @parm i_buffer Buffer to return read data
- * @param i_size Amount to read.
- */
- void read_fake_pnor( uint64_t i_pnorAddr,
- void* o_buffer,
- size_t i_size );
-
- /**
- * @brief Erase fake PNOR
- *
- * @parm i_pnorAddr Offset to start erase
- * @param i_size Amount to erase.
- */
- void erase_fake_pnor( uint64_t i_pnorAddr,
- size_t i_size );
-
- /**
- * @brief Check For Errors in SFC Status Registers
- *
- * @parm o_pnorResetLevel if error, reset level to clear error
- * @return Error log if error found
- */
- errlHndl_t checkForSfcErrors( ResetLevels &o_pnorResetLevel );
-
-
- /**
- * @brief Check For Errors in OPB and LPCHC Status Registers
- *
- * @parm o_pnorResetLevel if error, reset level to clear error
- * @return Error log if error found
- */
- errlHndl_t checkForOpbErrors( ResetLevels &o_pnorResetLevel );
-
-
- /**
- * @brief Add FFDC Error Registers to an existing Error Log
- *
- * @parm io_errl Error Log To Add FFDC To
- *
- */
- void addFFDCRegisters(errlHndl_t & io_errl);
-
- /**
- * @brief Reset PNOR Logic At The Specified Level
- *
- * @parm i_pnorResetLevel Level of PNOR to Reset
- *
- * @return Error log if error found
- */
- errlHndl_t resetPnor( ResetLevels i_pnorResetLevel );
-
-
- /**
- * @brief Reinitialize the SFC
- *
- * @return Error log if error found
- */
- errlHndl_t reinitializeSfc( void );
-
-
/**
* @brief Returns if an operation should be retried and handles
* the error logs
@@ -803,11 +300,48 @@ class PnorDD
uint8_t& io_retry_count );
+ /**
+ * @brief Call SFC to write data to the PNOR flash, doing retries
+ * as needed
+ * @pre Mutex should already be locked before calling
+ *
+ * @parm[in] i_addr PNOR flash Address to write
+ * @parm[in] i_size Amount of data to write, in bytes.
+ * @parm[in] i_data Buffer containing data to write
+ *
+ * @return Error from operation
+ */
+ errlHndl_t _writeFlash( uint32_t i_addr,
+ size_t i_size,
+ void* i_data );
- private: // Variables
+ /**
+ * @brief Call SFC to read data from the PNOR flash, doing retries
+ * as needed
+ * @pre Mutex should already be locked before calling
+ *
+ * @parm[in] i_addr PNOR flash Address to read
+ * @parm[in] i_size Amount of data to read, in bytes.
+ * @parm[out] o_data Buffer to read data into
+ *
+ * @return Error from operation
+ */
+ errlHndl_t _readFlash( uint32_t i_addr,
+ size_t i_size,
+ void* o_data );
+
+ /**
+ * @brief Call SFC to erase the PNOR flash, doing retries
+ * as needed
+ * @pre Mutex should already be locked before calling
+ *
+ * @parm i_address Offset into flash to erase, aligned to erase block
+ *
+ * @return Error from operation
+ */
+ errlHndl_t _eraseFlash( uint32_t i_address );
- // NOTE: The layout of the variables in this class must be maintained
- // along with the offsets in the debug framework.
+ private: // Variables
/**
* @brief Global Mutex to prevent concurrent PNOR accesses to Master Proc
@@ -834,76 +368,22 @@ class PnorDD
EraseInfo_t iv_erases[ERASE_COUNT_MAX];
/**
- * @brief Determine how much of the PNOR logic to use,
- * this is required due to different model functionality
- * in the current VPO and Simics models
- */
- PnorMode_t iv_mode;
-
- /**
- * @brief Flag to drive special behavior in VPO.
- */
- uint64_t iv_vpoMode;
-
- /**
* @brief describes the erase block size, set based on NOR chip type
*
*/
- uint32_t iv_erasesize_bytes;
+ uint32_t iv_eraseSizeBytes;
/**
* @brief CHIP ID or the NOR chip attached to SFC.
*
*/
- uint32_t iv_nor_chipid;
-
- /**
- * @brief Hardware workarounds
- *
- */
- uint32_t iv_hw_workaround;
-
- /**
- * @brief indicates if SFC initialization has been performed.
- *
- */
- bool iv_sfcInitDone;
-
- /**
- * @brief Start of Fake PNOR address range..
- *
- */
- uint64_t iv_fakeStart;
-
- /**
- * @brief Size of Fake PNOR address range..
- *
- */
- uint64_t iv_fakeSize;
-
- /**
- * @brief Indicates if class is currently collecting FFDC data
- *
- */
- bool iv_ffdc_active;
-
- /**
- * @brief Number of times recovered from an error
- *
- */
- uint32_t iv_error_handled_count;
-
- /**
- * @brief Indicates recovery from an error has failed
- *
- */
- bool iv_error_recovery_failed;
+ uint32_t iv_norChipId;
/**
- * @brief Indicates if class is currently doing a RESET procedure
+ * @brief Associated Serial Flash Controller
*
*/
- bool iv_reset_active;
+ SfcDD* iv_sfc;
/**
* @brief Processor Target used to access PNOR device
@@ -913,6 +393,8 @@ class PnorDD
// Needed for testcases
friend class PnorDdTest;
+ friend class SfcIBMTest;
+ friend class SfcAST2400Test;
// let the UserDetails classes see internal structures
friend class PNOR::UdPnorDDParms;
diff --git a/src/usr/pnor/pnorrp.C b/src/usr/pnor/pnorrp.C
index 3b6790d88..aec79ba59 100644
--- a/src/usr/pnor/pnorrp.C
+++ b/src/usr/pnor/pnorrp.C
@@ -46,7 +46,7 @@
// Trace definition
trace_desc_t* g_trac_pnor = NULL;
-TRAC_INIT(&g_trac_pnor, PNOR_COMP_NAME, 2*KILOBYTE, TRACE::BUFFER_SLOW); //2K
+TRAC_INIT(&g_trac_pnor, PNOR_COMP_NAME, 4*KILOBYTE, TRACE::BUFFER_SLOW); //2K
// Easy macro replace for unit testing
//#define TRACUCOMP(args...) TRACFCOMP(args)
@@ -72,7 +72,8 @@ const char* cv_EYECATCHER[] = {
"MVPD", /**< PNOR::MODULE_VPD : Module VPD */
"CVPD", /**< PNOR::CENTAUR_VPD : Centaur VPD */
"ATTROVER", /**< PNOR::ATTR_OVER : Attribute Override */
- "TEST", /**< PNOR::TEST : Test space for PNOR*/
+ "NVRAM", /**< PNOR::NVRAM : OPAL Storage */
+ "TEST", /**< PNOR::TEST : Test space for PNOR*/
//Not currently used
// "XXX", /**< NUM_SECTIONS : Used as invalid entry */
diff --git a/src/usr/pnor/pnorrp.H b/src/usr/pnor/pnorrp.H
index 38043f875..f11a2644d 100644
--- a/src/usr/pnor/pnorrp.H
+++ b/src/usr/pnor/pnorrp.H
@@ -6,6 +6,7 @@
/* OpenPOWER HostBoot Project */
/* */
/* Contributors Listed Below - COPYRIGHT 2011,2014 */
+/* [+] Google Inc. */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -260,6 +261,8 @@ class PnorRP
// allow testcase to see inside
friend class PnorRpTest;
friend class PnorDdTest;
+ friend class SfcIBMTest;
+ friend class SfcAST2400Test;
// allow this function to use constant(s)
friend errlHndl_t PNOR::validateAltMaster( void );
diff --git a/src/usr/pnor/pnorvalid.C b/src/usr/pnor/pnorvalid.C
index b690fd5fc..048078c93 100644
--- a/src/usr/pnor/pnorvalid.C
+++ b/src/usr/pnor/pnorvalid.C
@@ -173,7 +173,7 @@ errlHndl_t validateAltMaster( void )
continue;
}
- pnordd = new PnorDD(PnorDD::MODEL_REAL_MMIO, 0, 0, procList[i]);
+ pnordd = new PnorDD(procList[i]);
// Read Flash
l_err = pnordd->readFlash(tocBuffer, read_size,
diff --git a/src/usr/pnor/sfc_ast2400.C b/src/usr/pnor/sfc_ast2400.C
new file mode 100644
index 000000000..197cd6b1a
--- /dev/null
+++ b/src/usr/pnor/sfc_ast2400.C
@@ -0,0 +1,856 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/pnor/sfc_ast2400.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2014 */
+/* [+] Google Inc. */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+/*****************************************************************************/
+// I n c l u d e s
+/*****************************************************************************/
+#include <sys/mmio.h>
+#include <sys/task.h>
+#include <sys/sync.h>
+#include <string.h>
+#include <devicefw/driverif.H>
+#include <trace/interface.H>
+#include <errl/errlentry.H>
+#include <errl/errlmanager.H>
+#include <errl/errludlogregister.H>
+#include <targeting/common/targetservice.H>
+#include <pnor/pnor_reasoncodes.H>
+#include <sys/time.h>
+#include <errl/hberrltypes.H>
+#include <lpc/lpcif.H>
+#include "sfc_ast2400.H"
+#include "norflash.H"
+
+
+/*****************************************************************************/
+// C o n s t a n t s
+/*****************************************************************************/
+
+
+
+
+/*****************************************************************************/
+// G l o b a l s
+/*****************************************************************************/
+
+// Initialized in pnorrp.C
+extern trace_desc_t* g_trac_pnor;
+
+/*****************************************************************************/
+// M e t h o d s
+/*****************************************************************************/
+
+
+namespace PNOR {
+
+/**
+ * @brief Wrapper for device driver constructor
+ */
+errlHndl_t create_SfcDD( SfcDD*& o_sfc,
+ TARGETING::Target* i_proc )
+{
+ errlHndl_t l_err = NULL;
+ TRACFCOMP( g_trac_pnor, "Creating SfcAST2400 object" );
+ o_sfc = new SfcAST2400( l_err, i_proc );
+ return l_err;
+}
+
+};
+
+/**
+ * @brief Constructor
+ */
+SfcAST2400::SfcAST2400( errlHndl_t& o_err,
+ TARGETING::Target* i_proc )
+: SfcDD(o_err,i_proc)
+{
+}
+
+
+/**
+ * @brief Read data from the flash
+ */
+errlHndl_t SfcAST2400::readFlash( uint32_t i_addr,
+ size_t i_size,
+ void* o_data )
+{
+ errlHndl_t l_err = NULL;
+ TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2400::readFlash> i_addr=0x%.8x, i_size=0x%.8x", i_addr, i_size );
+
+ do{
+ uint32_t* word_ptr = static_cast<uint32_t*>(o_data);
+ uint32_t word_size = i_size/4;
+ for( uint32_t words_read = 0;
+ words_read < word_size;
+ words_read ++ )
+ {
+ //Read directly from MMIO space
+ uint32_t lpc_addr = LPC_SFC_MMIO_OFFSET | (i_addr + words_read*4);
+ size_t reg_size = sizeof(uint32_t);
+
+ l_err = deviceOp( DeviceFW::READ,
+ iv_proc,
+ &(word_ptr[words_read]),
+ reg_size,
+ DEVICE_LPC_ADDRESS(LPC::TRANS_FW,
+ lpc_addr) );
+ if( l_err ) { break; }
+ }
+ if( l_err ) { break; }
+ }while(0);
+
+ TRACDCOMP( g_trac_pnor, EXIT_MRK"SfcAST2400::readFlash> err=%.8X", ERRL_GETEID_SAFE(l_err) );
+ return l_err;
+}
+
+
+/**
+ * @brief Write data into flash
+ */
+errlHndl_t SfcAST2400::writeFlash( uint32_t i_addr,
+ size_t i_size,
+ void* i_data )
+{
+ TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2400::writeFlash> i_addr=0x%.8x, i_size=0x%.8x", i_addr, i_size );
+ errlHndl_t l_err = NULL;
+
+ do {
+ // Enable write mode
+ l_err = enableWriteMode();
+ if( l_err ) { break; }
+
+ // Send in the Page Program command with the data to write
+ uint8_t opcode = PNOR::SPI_JEDEC_PAGE_PROGRAM;
+ l_err = sendSpiCmd( opcode, i_addr,
+ i_size, reinterpret_cast<uint8_t*>(i_data),
+ 0, NULL );
+ if( l_err ) { break; }
+
+ // Wait for idle
+ l_err = pollOpComplete();
+ if( l_err ) { break; }
+
+#ifdef CONFIG_ALLOW_MICRON_PNOR
+ //check for special Micron Flag Status reg
+ if(iv_flashWorkarounds & PNOR::HWWK_MICRON_WRT_ERASE)
+ {
+ l_err = PNOR::micronFlagStatus(this);
+ if(l_err) { break; }
+ }
+#endif
+
+ } while(0);
+
+ TRACDCOMP( g_trac_pnor, EXIT_MRK"SfcAST2400::writeFlash> err=%.8X", ERRL_GETEID_SAFE(l_err) );
+ return l_err;
+}
+
+
+/**
+ * @brief Erase a block of flash
+ */
+errlHndl_t SfcAST2400::eraseFlash( uint32_t i_addr )
+{
+ TRACFCOMP(g_trac_pnor, ">>SfcAST2400::eraseFlash> Block 0x%.8X", i_addr );
+ errlHndl_t l_err = NULL;
+
+ do {
+ // Enable write mode
+ l_err = enableWriteMode();
+ if( l_err ) { break; }
+
+ // Send erase command
+ uint8_t opcode = PNOR::SPI_JEDEC_SECTOR_ERASE;
+ l_err = sendSpiCmd( opcode, i_addr, 0, 0, 0, NULL );
+ if( l_err ) { break; }
+
+ // Wait for idle
+ l_err = pollOpComplete();
+ if( l_err ) { break; }
+
+#ifdef CONFIG_ALLOW_MICRON_PNOR
+ //check for special Micron Flag Status reg
+ if(iv_flashWorkarounds & PNOR::HWWK_MICRON_WRT_ERASE)
+ {
+ l_err = PNOR::micronFlagStatus(this);
+ if(l_err) { break; }
+ }
+#endif
+
+ } while(0);
+
+ TRACDCOMP( g_trac_pnor, EXIT_MRK"SfcAST2400::eraseFlash> err=%.8X", ERRL_GETEID_SAFE(l_err) );
+ return l_err;
+}
+
+/**
+ * @brief Initialize and configure the SFC hardware
+ */
+errlHndl_t SfcAST2400::hwInit( )
+{
+ TRACFCOMP( g_trac_pnor, ENTER_MRK"SfcAST2400::hwInit>" );
+ errlHndl_t l_err = NULL;
+
+ do {
+ size_t reg_size = sizeof(uint8_t);
+
+ //** Initialize the LPC2AHB logic
+
+ // Send SuperIO password - send A5 twice
+ uint8_t data = 0xA5;
+ l_err = deviceOp( DeviceFW::WRITE,
+ iv_proc,
+ &data,
+ reg_size,
+ DEVICE_LPC_ADDRESS(LPC::TRANS_IO,SIO_ADDR_2E) );
+ if( l_err ) { break; }
+
+ l_err = deviceOp( DeviceFW::WRITE,
+ iv_proc,
+ &data,
+ reg_size,
+ DEVICE_LPC_ADDRESS(LPC::TRANS_IO,SIO_ADDR_2E) );
+ if( l_err ) { break; }
+
+
+ // Select logical device D (iLPC2AHB)
+ l_err = writeRegSIO( 0x07, 0x0D );
+ if( l_err ) { break; }
+
+
+ // Enable iLPC->AHB
+ l_err = writeRegSIO( 0x30, 0x01 );
+ if( l_err ) { break; }
+
+
+ //** Setup the SPI Controller
+
+ /* Enable writing to the controller */
+ SpiControlReg04_t ctlreg;
+ l_err = readRegSPIC( CTLREG_04, ctlreg.data32 );
+ if( l_err ) { break; }
+ ctlreg.cmdMode = 0b10; //10:Normal Write (CMD + Address + Write data)
+ l_err = writeRegSPIC( CTLREG_04, ctlreg.data32 );
+ if( l_err ) { break; }
+
+ SpiConfigReg00_t confreg;
+ l_err = readRegSPIC( CONFREG_00, confreg.data32 );
+ if( l_err ) { break; }
+ confreg.inactiveX2mode = 1; //Enable CE# Inactive pulse width X2 mode
+ confreg.enableWrite = 1; //Enable flash memory write
+ l_err = writeRegSPIC( CONFREG_00, confreg.data32 );
+ if( l_err ) { break; }
+
+
+ /*
+ * Setup control reg and for our use, switching
+ * to 1-bit mode, clearing user mode if set, etc...
+ *
+ * Also configure SPI clock to something safe
+ * like HCLK/8 (24Mhz)
+ */
+ ctlreg.fourByteMode = 1;
+ ctlreg.ioMode = 0b00; //single bit or controlled by bit[3]
+ ctlreg.pulseWidth = 0x0; //0000: 16T (1T = 1 HCLK clock)
+ ctlreg.cmdData = 0x00;
+ ctlreg.spiClkFreq = 0x4; //HCLK/8
+ ctlreg.dummyCycleRead1 = 0; //no dummy cycles
+ ctlreg.dummyCycleRead2 = 0b00; //no dummy cycles
+ ctlreg.cmdMode = 0b00; //00:Normal Read (03h + Address + Read data)
+ iv_ctlRegDefault = ctlreg; // Default setup is regular read mode
+
+ // Configure for read
+ l_err = writeRegSPIC( CTLREG_04, ctlreg.data32 );
+ if( l_err ) { break; }
+
+ // Figure out what flash chip we have
+ uint32_t chipid = 0;
+ l_err = getNORChipId( chipid );
+ if( l_err ) { break; }
+
+ // Setup flash-specific settings here, if there are any
+
+ } while(0);
+
+ TRACFCOMP( g_trac_pnor, EXIT_MRK"SfcAST2400::hwInit> err=%.8X", ERRL_GETEID_SAFE(l_err) );
+ return l_err;
+}
+
+/**
+ * @brief Send a SPI command
+ */
+errlHndl_t SfcAST2400::sendSpiCmd( uint8_t i_opCode,
+ uint32_t i_address,
+ size_t i_writeCnt,
+ const uint8_t* i_writeData,
+ size_t i_readCnt,
+ uint8_t* o_readData )
+{
+ errlHndl_t l_err = NULL;
+ size_t opsize = 0;
+ TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2400::sendSpiCmd> i_opCode=%.2X, i_address=%.8X, i_writeCnt=0x%X, i_writeData=%p, i_readCnt=0x%X, o_readData=%p", i_opCode, i_address, i_writeCnt, i_writeData, i_readCnt, o_readData );
+
+ do {
+#ifdef CONFIG_ALLOW_MICRON_PNOR
+ //Do a read of flash address zero to workaround
+ // a micron bug with extended reads
+ if( (PNOR::HWWK_MICRON_EXT_READ & iv_flashWorkarounds)
+ && (i_readCnt > 4) )
+ {
+ uint32_t ignored = 0;
+ l_err = readFlash( 0, 1, &ignored );
+ if(l_err) { break; }
+ }
+#endif
+
+ // Put controller into command mode (instead of read mode)
+ l_err = commandMode( true );
+ if( l_err ) { break; }
+
+ // Write command to the beginning of the flash space
+ opsize = sizeof(i_opCode);
+ l_err = deviceOp( DeviceFW::WRITE,
+ iv_proc,
+ &i_opCode,
+ opsize, //just send opcode
+ DEVICE_LPC_ADDRESS(LPC::TRANS_FW,
+ LPC_SFC_MMIO_OFFSET) );
+ if( l_err ) { break; }
+
+ // Send address if there is one
+ if( i_address != NO_ADDRESS )
+ {
+ // Write address to the beginning of the flash space
+ opsize = sizeof(i_address);
+ l_err = deviceOp( DeviceFW::WRITE,
+ iv_proc,
+ &i_address,
+ opsize, //only supporting 4-byte addresses
+ DEVICE_LPC_ADDRESS(LPC::TRANS_FW,
+ LPC_SFC_MMIO_OFFSET) );
+ if( l_err ) { break; }
+ }
+
+ // Send in the rest of the write data
+ if( i_writeCnt && i_writeData )
+ {
+ size_t bytes_left = i_writeCnt;
+ uint8_t* curptr = const_cast<uint8_t*>(i_writeData);
+ while( bytes_left )
+ {
+ // Write the last partial word if there is one
+ if( bytes_left < 4 )
+ {
+ opsize = bytes_left;
+ l_err = deviceOp( DeviceFW::WRITE,
+ iv_proc,
+ curptr,
+ opsize,
+ DEVICE_LPC_ADDRESS(LPC::TRANS_FW,
+ LPC_SFC_MMIO_OFFSET) );
+ break;
+ }
+
+ // Write data into the beginning of the flash space,
+ // in command mode this doesn't write the flash
+ // but instead is a pass-through to the area we
+ // really want to write
+ opsize = sizeof(uint32_t);
+ l_err = deviceOp( DeviceFW::WRITE,
+ iv_proc,
+ curptr,
+ opsize,
+ DEVICE_LPC_ADDRESS(LPC::TRANS_FW,
+ LPC_SFC_MMIO_OFFSET) );
+ if( l_err ) { break; }
+
+ curptr += 4;
+ bytes_left -= 4;
+ }
+ if( l_err ) { break; }
+ }
+
+ // Read back the results
+ if( i_readCnt && o_readData )
+ {
+ size_t bytes_left = i_readCnt;
+ uint8_t* curptr = o_readData;
+ while( bytes_left )
+ {
+ // Grab the last partial word if there is one
+ if( bytes_left < 4 )
+ {
+ opsize = bytes_left;
+ l_err = deviceOp( DeviceFW::READ,
+ iv_proc,
+ curptr,
+ opsize,
+ DEVICE_LPC_ADDRESS(LPC::TRANS_FW,
+ LPC_SFC_MMIO_OFFSET) );
+ break;
+ }
+
+ // Read data from the beginning of the flash space,
+ // in command mode this doesn't read the flash
+ // but instead is a pass-through to the data we
+ // really want
+ opsize = sizeof(uint32_t);
+ l_err = deviceOp( DeviceFW::READ,
+ iv_proc,
+ curptr,
+ opsize,
+ DEVICE_LPC_ADDRESS(LPC::TRANS_FW,
+ LPC_SFC_MMIO_OFFSET) );
+ if( l_err ) { break; }
+
+ curptr += 4;
+ bytes_left -= 4;
+ }
+ if( l_err ) { break; }
+ }
+ } while(0);
+
+ // No matter what, put the logic back into read mode
+ errlHndl_t tmp_err = commandMode( false );
+ if( tmp_err )
+ {
+ if( l_err )
+ {
+ // Keep the original error, commit this one as info
+ tmp_err->plid(l_err->plid());
+ tmp_err->setSev(ERRORLOG::ERRL_SEV_INFORMATIONAL);
+ ERRORLOG::errlCommit(tmp_err,PNOR_COMP_ID);
+ }
+ else
+ {
+ l_err = tmp_err;
+ }
+ }
+
+ TRACDCOMP( g_trac_pnor, EXIT_MRK"SfcAST2400::sendSpiCmd> o_readData=%.2X, err=%.8X", o_readData == NULL ? 0 : o_readData[0], ERRL_GETEID_SAFE(l_err) );
+ return l_err;
+}
+
+/**
+ * @brief Enter/exit command mode
+ */
+errlHndl_t SfcAST2400::commandMode( bool i_enter )
+{
+ errlHndl_t l_err = NULL;
+ TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2400::commandMode(%d)", i_enter );
+
+ /*
+ * There is only a limited addressable window within LPC space. The AST
+ * has its control register space at too far of a distance from the read
+ * space for them both to fit in a single window. Rather than moving the
+ * window around we will use the iLPC2AHB backdoor inside the SuperIO
+ * controller to do both register accesses and to write into the flash.
+ *
+ * High level flow to write into control space:
+ * Stop active control (SPI04 Control Reg)
+ * Enable command mode (SPI04 Control Reg)
+ * Write actual command into flash base addr (0x0E000000)
+ */
+
+ do {
+ SpiControlReg04_t ctlreg = iv_ctlRegDefault;
+
+ // Switch to user mode, CE# dropped
+ ctlreg.stopActiveCtl = 1;
+ ctlreg.cmdMode = 0b11; //User Mode (Read/Write Data)
+ l_err = writeRegSPIC( CTLREG_04, ctlreg.data32 );
+ if( l_err ) { break; }
+
+ if( i_enter ) //ast_sf_start_cmd
+ {
+ // user mode, CE# active
+ ctlreg.stopActiveCtl = 0;
+ l_err = writeRegSPIC( CTLREG_04, ctlreg.data32 );
+ if( l_err ) { break; }
+ }
+ else //ast_sf_end_cmd
+ {
+ // Switch back to read mode
+ l_err = writeRegSPIC( CTLREG_04, iv_ctlRegDefault.data32 );
+ if( l_err ) { break; }
+ }
+ } while(0);
+
+ TRACDCOMP( g_trac_pnor, EXIT_MRK"SfcAST2400::commandMode> err=%.8X", ERRL_GETEID_SAFE(l_err) );
+ return l_err;
+}
+
+/**
+ * @brief Enable write mode
+ */
+errlHndl_t SfcAST2400::enableWriteMode( void )
+{
+ errlHndl_t l_err = NULL;
+ TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2400::enableWriteMode>" );
+
+ /* Some flashes need it to be hammered */
+ PNOR::NorStatusReg_t status;
+ size_t i = 0;
+ for( i = 0; i < 10; i++ )
+ {
+ // Send the command to enable writes
+ uint8_t opcode = PNOR::SPI_JEDEC_WRITE_ENABLE;
+ l_err = sendSpiCmd( opcode, NO_ADDRESS, 0, NULL, 0, NULL );
+ if( l_err ) { break; }
+
+ // Check to see if it worked
+ opcode = PNOR::SPI_JEDEC_READ_STATUS;
+ l_err = sendSpiCmd( opcode, NO_ADDRESS, 0, NULL, 1, &(status.data8) );
+ if( l_err ) { break; }
+
+ if( status.writeEnable )
+ {
+ break;
+ }
+ }
+
+ if( !l_err && !status.writeEnable )
+ {
+ /*@
+ * @errortype
+ * @moduleid PNOR::MOD_SFCAST2400_ENABLEWRITEMODE
+ * @reasoncode PNOR::RC_CANNOT_ENABLE_WRITES
+ * @userdata1[24:31] Output from RDSR
+ * @userdata1[32:63] NOR chip id
+ * @userdata2 <unused>
+ * @devdesc SfcAST2400::enableWriteMode> Unable to enable
+ * write mode on the PNOR flash
+ * @custdesc Firmware error accessing flash during IPL
+ */
+ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ PNOR::MOD_SFCAST2400_ENABLEWRITEMODE,
+ PNOR::RC_CANNOT_ENABLE_WRITES,
+ TWO_UINT32_TO_UINT64( TO_UINT32(status.data8),
+ iv_norChipId),
+ 0);
+ // Limited in callout: no flash sub-target, so calling out processor
+ l_err->addHwCallout( iv_proc,
+ HWAS::SRCI_PRIORITY_HIGH,
+ HWAS::NO_DECONFIG,
+ HWAS::GARD_NULL );
+ addFFDC(l_err);
+ l_err->collectTrace(PNOR_COMP_NAME);
+ }
+
+ TRACDCOMP( g_trac_pnor, EXIT_MRK"SfcAST2400::enableWriteMode> err=%.8X", ERRL_GETEID_SAFE(l_err) );
+ return l_err;
+}
+
+/**
+ * @brief Write a single byte into the SIO
+ */
+errlHndl_t SfcAST2400::writeRegSIO( uint8_t i_regAddr,
+ uint8_t i_data )
+{ //lpc_sio_outb
+ errlHndl_t l_err = NULL;
+ TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2400::writeRegSIO> i_regAddr=0x%.2X, i_data=0x%.2X", i_regAddr, i_data );
+
+ do {
+ size_t reg_size = sizeof(uint8_t);
+
+ // AST2400 integrates a Super I/O module with
+ // LPC protocol (I/O cycle 0x2E/0x2F)
+
+ // Write out the register address
+ l_err = deviceOp( DeviceFW::WRITE,
+ iv_proc,
+ &i_regAddr,
+ reg_size,
+ DEVICE_LPC_ADDRESS(LPC::TRANS_IO,SIO_ADDR_2E) );
+ if( l_err ) { break; }
+
+ // Write out the register data
+ l_err = deviceOp( DeviceFW::WRITE,
+ iv_proc,
+ &i_data,
+ reg_size,
+ DEVICE_LPC_ADDRESS(LPC::TRANS_IO,SIO_DATA_2F) );
+ if( l_err ) { break; }
+
+ } while(0);
+
+ TRACDCOMP( g_trac_pnor, EXIT_MRK"SfcAST2400::writeRegSIO> err=%.8X", ERRL_GETEID_SAFE(l_err) );
+ return l_err;
+}
+
+/**
+ * @brief Read a single byte from the SIO
+ */
+errlHndl_t SfcAST2400::readRegSIO( uint8_t i_regAddr,
+ uint8_t& o_data )
+{ //lpc_sio_inb
+ errlHndl_t l_err = NULL;
+ TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2400::readRegSIO> i_regAddr=0x%.2X", i_regAddr );
+
+ do {
+ size_t reg_size = sizeof(uint8_t);
+
+ // AST2400 integrates a Super I/O module with
+ // LPC protocol (I/O cycle 0x2E/0x2F)
+
+ // Write out the register address
+ l_err = deviceOp( DeviceFW::WRITE,
+ iv_proc,
+ &i_regAddr,
+ reg_size,
+ DEVICE_LPC_ADDRESS(LPC::TRANS_IO,SIO_ADDR_2E) );
+ if( l_err ) { break; }
+
+ // Read in the register data
+ l_err = deviceOp( DeviceFW::READ,
+ iv_proc,
+ &o_data,
+ reg_size,
+ DEVICE_LPC_ADDRESS(LPC::TRANS_IO,SIO_DATA_2F) );
+ if( l_err ) { break; }
+
+ } while(0);
+
+ TRACDCOMP( g_trac_pnor, EXIT_MRK"SfcAST2400::readRegSIO> o_data=0x%.2X, err-%.8X", o_data, ERRL_GETEID_SAFE(l_err) );
+ return l_err;
+}
+
+/**
+ * @brief Prepare the iLPC2AHB address regs
+ */
+errlHndl_t SfcAST2400::setupAddrLPC2AHB( uint32_t i_addr )
+{ //lpc_ahb_prep
+ errlHndl_t l_err = NULL;
+ TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2400::setupAddrLPC2AHB> i_addr=0x%X", i_addr );
+
+ do {
+ // Select logical device D (iLPC2AHB)
+ l_err = writeRegSIO( 0x07, 0x0D );
+ if( l_err ) { break; }
+
+ // Push 4 address bytes into SIO regs 0xF0-0xF3
+ for( size_t i=sizeof(i_addr); i>0; i-- )
+ {
+ l_err = writeRegSIO( 0xF3-(i-1), //F0,F1,F2,F3
+ static_cast<uint8_t>(i_addr >> ((i-1)*8)) );
+ if( l_err ) { break; }
+ }
+ if( l_err ) { break; }
+
+ // Configure 4 byte length
+ l_err = writeRegSIO( 0xF8, 0x02 );
+ if( l_err ) { break; }
+
+ } while(0);
+
+ TRACDCOMP( g_trac_pnor, EXIT_MRK"SfcAST2400::setupAddrLPC2AHB> err=%.8X", ERRL_GETEID_SAFE(l_err) );
+ return l_err;
+}
+
+/**
+ * @brief Write SPI Controller Register
+ */
+errlHndl_t SfcAST2400::writeRegSPIC( SpicReg_t i_reg,
+ uint32_t i_data )
+{
+ errlHndl_t l_err = NULL;
+ TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2400::writeRegSPIC> i_reg=0x%.2X, i_data=0x%.8X", i_reg, i_data );
+
+ do {
+ // Compute the full LPC address
+ uint32_t lpc_addr = i_reg | SPIC_BASE_ADDR_AHB;
+
+ // Setup the logic for the write
+ l_err = setupAddrLPC2AHB( lpc_addr );
+ if( l_err ) { break; }
+
+ // Push 4 data bytes into SIO regs 0xF4-0xF7
+ uint8_t* ptr8 = reinterpret_cast<uint8_t*>(&i_data);
+ for( size_t i=0; i<sizeof(i_data); i++ )
+ {
+ l_err = writeRegSIO( 0xF4+i, //F4,F5,F6,F7
+ ptr8[i] );
+ if( l_err ) { break; }
+ }
+ if( l_err ) { break; }
+
+ // Trigger the write operation by writing the magic 0xCF value
+ l_err = writeRegSIO( 0xFE, 0xCF );
+ if( l_err ) { break; }
+
+ } while(0);
+
+ TRACDCOMP( g_trac_pnor, EXIT_MRK"SfcAST2400::writeRegSPIC> err=%.8X", ERRL_GETEID_SAFE(l_err) );
+ return l_err;
+}
+
+/**
+ * @brief Read SPI Controller Register
+ */
+errlHndl_t SfcAST2400::readRegSPIC( SpicReg_t i_reg,
+ uint32_t& o_data )
+{
+ TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2400::readRegSPIC> i_reg=0x%.2X", i_reg );
+ errlHndl_t l_err = NULL;
+
+ do {
+ // Compute the full LPC address
+ uint32_t lpc_addr = i_reg | SPIC_BASE_ADDR_AHB;
+
+ // Setup the logic for the write
+ l_err = setupAddrLPC2AHB( lpc_addr );
+ if( l_err ) { break; }
+
+ // Trigger the write operation by reading the magic register
+ uint8_t ignored = 0;
+ l_err = readRegSIO( 0xFE, ignored );
+ if( l_err ) { break; }
+
+ // Read 4 data bytes into SIO regs 0xF4-0xF7
+ uint8_t* ptr8 = reinterpret_cast<uint8_t*>(&o_data);
+ for( size_t i=0; i<sizeof(o_data); i++ )
+ {
+ l_err = readRegSIO( 0xF4+i, //F4,F5,F6,F7
+ ptr8[i] );
+ if( l_err ) { break; }
+ }
+ if( l_err ) { break; }
+
+ } while(0);
+
+ TRACDCOMP( g_trac_pnor, EXIT_MRK"SfcAST2400::readRegSPIC> o_data=0x%.8X, l_err=%.8X", o_data, ERRL_GETEID_SAFE(l_err) );
+ return l_err;
+}
+
+/**
+ * @brief Poll for completion of SPI operation
+ */
+errlHndl_t SfcAST2400::pollOpComplete( void )
+{
+ errlHndl_t l_err = NULL;
+ TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2400::pollOpComplete>" );
+
+ do {
+ // Send RDSR command until write-in-progress clears
+ PNOR::NorStatusReg_t status;
+ uint64_t poll_time = 0;
+ uint64_t loop = 0;
+ while( poll_time < MAX_WRITE_TIME_NS )
+ {
+ uint8_t opcode = PNOR::SPI_JEDEC_READ_STATUS;
+ l_err = sendSpiCmd( opcode,
+ NO_ADDRESS,
+ 0, NULL,
+ 1, &(status.data8) );
+ if( l_err ) { break; }
+
+ // check if any op is still going
+ if( !status.writeInProgress )
+ {
+ break;
+ }
+
+ // 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
+ ++loop;
+ nanosleep( 0, 100*loop );
+ poll_time += 100*loop;
+ }
+ if( l_err ) { break; }
+
+ TRACDCOMP(g_trac_pnor,"SfcAST2400::pollOpComplete> command took %d ns", poll_time);
+
+ // No status regs to check so just look for timeout
+ if( status.writeInProgress )
+ {
+ TRACFCOMP( g_trac_pnor, "SfcAST2400::pollOpComplete> Timeout during write or erase" );
+
+ /*@
+ * @errortype
+ * @moduleid PNOR::MOD_SFCAST2400_POLLOPCOMPLETE
+ * @reasoncode PNOR::RC_SFC_TIMEOUT
+ * @userdata1[0:31] NOR Flash Chip ID
+ * @userdata1[32:63] Total poll time (ns)
+ * @userdata2[56:63] Output of RDSR command
+ * @devdesc SfcAST2400::pollOpComplete> Timeout during
+ * write or erase operation
+ * @custdesc Hardware error accessing flash during IPL
+ */
+ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ PNOR::MOD_SFCAST2400_POLLOPCOMPLETE,
+ PNOR::RC_SFC_TIMEOUT,
+ TWO_UINT32_TO_UINT64(iv_norChipId,
+ poll_time),
+ status.data8);
+
+ // Limited in callout: no PNOR target, so calling out processor
+ l_err->addHwCallout(
+ iv_proc,
+ HWAS::SRCI_PRIORITY_HIGH,
+ HWAS::NO_DECONFIG,
+ HWAS::GARD_NULL );
+
+ addFFDC(l_err);
+ l_err->collectTrace(PNOR_COMP_NAME);
+ break;
+ }
+ } while(0);
+
+ TRACDCOMP( g_trac_pnor, EXIT_MRK"SfcAST2400::pollOpComplete> err=%.8X", ERRL_GETEID_SAFE(l_err) );
+ return l_err;
+}
+
+/**
+ * @brief Add error registers to an existing Error Log
+ */
+void SfcAST2400::addFFDC( errlHndl_t& io_errhdl )
+{
+ TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2400::addFFDC>" );
+ //@fixme-RTC:115212 - Create userdetails that includes chipid and SFDP data
+
+ errlHndl_t l_err = NULL;
+
+ //Read SFDP for FFDC
+ uint32_t outdata[4];
+ l_err = sendSpiCmd( PNOR::SPI_JEDEC_READ_SFDP,
+ 0,
+ 0, NULL,
+ 16, reinterpret_cast<uint8_t*>(outdata) );
+ if( l_err )
+ {
+ delete l_err;
+ }
+ else
+ {
+ //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] );
+ }
+ }
+
+ TRACDCOMP( g_trac_pnor, EXIT_MRK"SfcAST2400::addFFDC>" );
+}
diff --git a/src/usr/pnor/sfc_ast2400.H b/src/usr/pnor/sfc_ast2400.H
new file mode 100644
index 000000000..7b4527c09
--- /dev/null
+++ b/src/usr/pnor/sfc_ast2400.H
@@ -0,0 +1,295 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/pnor/sfc_ast2400.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2014 */
+/* [+] Google Inc. */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __PNOR_SFCAST2400_H
+#define __PNOR_SFCAST2400_H
+
+#include <limits.h>
+#include <targeting/common/targetservice.H>
+#include <errl/errlentry.H>
+#include "sfcdd.H"
+
+/** @file sfc_ast2400.H
+ * @brief Provides the logic to access and configure the
+ * AST2400 BMC in order to access the PNOR
+ */
+
+/**
+ * @brief AST2400 SFC Device Driver Class
+ * Provides the logic to access and configure the
+ * AST2400 BMC in order to access the PNOR
+ */
+class SfcAST2400 : public SfcDD
+{
+
+ public: //SfcDD methods
+ /**
+ * @brief Initialize the SFC Hardware
+ *
+ * @return void
+ */
+ virtual errlHndl_t hwInit();
+
+ /**
+ * @brief Read data from the PNOR flash
+ *
+ * @parm i_addr PNOR flash Address to read
+ * @parm i_size Amount of data to read, in bytes.
+ * @parm o_data Buffer to read data into
+ *
+ * @return Error from operation
+ */
+ virtual errlHndl_t readFlash(uint32_t i_addr,
+ size_t i_size,
+ void* o_data);
+
+ /**
+ * @brief Write data to the PNOR flash
+ *
+ * @parm i_addr PNOR flash Address to write
+ * @parm i_size Amount of data to write, in bytes.
+ * @parm i_data Buffer containing data to write
+ *
+ * @return Error from operation
+ */
+ virtual errlHndl_t writeFlash(uint32_t i_addr,
+ size_t i_size,
+ void* i_data);
+
+ /**
+ * @brief Erase a block of flash
+ *
+ * @parm i_address Offset into flash to erase, aligned to erase block
+ *
+ * @return Error from operation
+ */
+ virtual errlHndl_t eraseFlash(uint32_t i_address);
+
+
+ /**
+ * @brief Send a SPI command
+ *
+ * @parm[in] i_opCode: command to send into controller first
+ * @parm[in] i_address: address for those commands that need it
+ * @parm[in] i_writeCnt: number of bytes to write to device
+ * @parm[in] i_writeData: write data buffer
+ * @parm[in] i_readCnt: number of bytes to read from device
+ * @parm[out] o_readData: read data buffer
+ *
+ * @return Error from operation
+ */
+ virtual errlHndl_t sendSpiCmd( uint8_t i_opCode,
+ uint32_t i_address,
+ size_t i_writeCnt,
+ const uint8_t* i_writeData,
+ size_t i_readCnt,
+ uint8_t* o_readData );
+
+ /**
+ * @brief Add error registers to an existing Error Log
+ *
+ * @param[in] io_errhdl: Error log to add data to
+ */
+ virtual void addFFDC( errlHndl_t& io_errhdl );
+
+ public:
+ /**
+ * @brief Constructor
+ * @param[out] Return any error in constructor
+ * @param[in] Processor target associated with the LPC master
+ */
+ SfcAST2400( errlHndl_t& o_err,
+ TARGETING::Target* i_proc
+ = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL );
+
+ protected:
+ /**
+ * @brief List of registers in the SPI Controller logic
+ */
+ enum SpicReg_t
+ {
+ CONFREG_00 = 0x00,
+ CTLREG_04 = 0x04,
+ MISCCTLREG_10 = 0x10,
+ READTIMEREG_14 = 0x14
+ };
+
+ /**
+ * @brief Write a SPI Controller register
+ *
+ * @param[in] i_reg: Register to write
+ * @param[in] i_data: Data to write
+ *
+ * @return Error from operation
+ */
+ errlHndl_t writeRegSPIC( SpicReg_t i_reg,
+ uint32_t i_data );
+
+ /**
+ * @brief Write a SPI Controller register
+ *
+ * @param[in] i_reg: Register to write
+ * @param[in] o_data: Data that was read
+ *
+ * @return Error from operation
+ */
+ errlHndl_t readRegSPIC( SpicReg_t i_reg,
+ uint32_t& o_data );
+
+ /**
+ * @brief Write a single byte into a SIO register
+ *
+ * @param[in] i_reg: Register to write
+ * @param[in] i_data: Data to write
+ *
+ * @return Error from operation
+ */
+ errlHndl_t writeRegSIO( uint8_t i_regAddr,
+ uint8_t i_data );
+
+ /**
+ * @brief Read a single byte from a SIO register
+ *
+ * @param[in] i_reg: Register to read
+ * @param[in] o_data: Data that was read
+ *
+ * @return Error from operation
+ */
+ errlHndl_t readRegSIO( uint8_t i_regAddr,
+ uint8_t& o_data );
+
+ /**
+ * @brief Enable write mode
+ *
+ * @return Error from operation
+ */
+ errlHndl_t enableWriteMode( void );
+
+ /**
+ * @brief Enter/exit command mode
+ *
+ * @param[in] i_enter: true=enter cmd mode, false=exit cmd mode
+ *
+ * @return Error from operation
+ */
+ errlHndl_t commandMode( bool i_enter );
+
+ /**
+ * @brief Poll for completion of SPI operation
+ *
+ * @return Error from operation
+ */
+ errlHndl_t pollOpComplete( void );
+
+ /**
+ * @brief Prepare the iLPC2AHB address regs
+ *
+ * @param[in] i_addr: LPC address to access
+ *
+ * @return Error from operation
+ */
+ errlHndl_t setupAddrLPC2AHB( uint32_t i_addr );
+
+
+ /**
+ * @brief SPI0 Configuration Register
+ */
+ union SpiConfigReg00_t
+ {
+ uint32_t data32;
+ struct
+ { //Little-endian bit positions
+ uint32_t rsvd : 30; //31:2
+ uint32_t inactiveX2mode : 1; //1
+ uint32_t enableWrite : 1; //0
+ };
+ SpiConfigReg00_t() : data32(0) {};
+ };
+
+ /**
+ * @brief SPI04 Control Register
+ */
+ union SpiControlReg04_t
+ {
+ uint32_t data32;
+ struct
+ { //Little-endian bit positions
+ uint32_t rsvd : 2; //31:30
+ uint32_t ioMode : 2; //29:28
+ uint32_t pulseWidth : 4; //27:24
+ uint32_t cmdData : 8; //23:16
+ uint32_t dummyCycleCmd : 1; //15
+ uint32_t dummyCycleRead1 : 1; //14
+ uint32_t fourByteMode : 1; //13
+ uint32_t disableCmdMerge : 1; //12
+ uint32_t spiClkFreq : 4; //11:8
+ uint32_t dummyCycleRead2 : 2; //7:6
+ uint32_t lsbFirst : 1; //5
+ uint32_t useClkMode3 : 1; //4
+ uint32_t dualInputMode : 1; //3
+ uint32_t stopActiveCtl : 1; //2
+ uint32_t cmdMode : 2; //1:0
+ };
+ SpiControlReg04_t() : data32(0) {};
+ };
+
+ /**
+ * @brief Default value of SPI04 (saves a read)
+ */
+ SpiControlReg04_t iv_ctlRegDefault;
+
+
+ /** @brief General Constants */
+ enum
+ {
+ /**< Offset to direct read space, from FW base */
+ LPC_SFC_MMIO_OFFSET = 0x0E000000,
+
+ /**< Offset to SPI Controller Register Space */
+ LPC_SFC_CTLR_BASE = 0x1E789000,
+
+ /**< AHB address of SPI Flash controller */
+ SPIC_BASE_ADDR_AHB = 0x1E630000,
+
+ /**< AHB address of flash */
+ FLASH_BASE_ADDR_AHB = 0x30000000,
+
+ /**< AHB address of LPC registers */
+ LPC_CTLR_BASE_ADDR_AHB = 0x1E789000,
+
+ /**< Maximum time to wait for a write/erase */
+ MAX_WRITE_TIME_NS = NS_PER_SEC,
+
+ /**< SuperIO Address Cycle */
+ SIO_ADDR_2E = 0x2E,
+
+ /**< SuperIO Data Cycle */
+ SIO_DATA_2F = 0x2F,
+ };
+
+ friend class SfcAST2400Test;
+};
+
+#endif
diff --git a/src/usr/pnor/sfc_fake.C b/src/usr/pnor/sfc_fake.C
new file mode 100644
index 000000000..90cce7843
--- /dev/null
+++ b/src/usr/pnor/sfc_fake.C
@@ -0,0 +1,295 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/pnor/sfc_fake.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2014 */
+/* [+] Google Inc. */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+/*****************************************************************************/
+// I n c l u d e s
+/*****************************************************************************/
+#include <sys/mmio.h>
+#include <sys/task.h>
+#include <sys/sync.h>
+#include <string.h>
+#include <devicefw/driverif.H>
+#include <trace/interface.H>
+#include <errl/errlentry.H>
+#include <errl/errlmanager.H>
+#include <errl/errludlogregister.H>
+#include <targeting/common/targetservice.H>
+#include <pnor/pnor_reasoncodes.H>
+#include <sys/time.h>
+#include <lpc/lpcif.H>
+#include "sfc_fake.H"
+#include "norflash.H"
+
+
+/*****************************************************************************/
+// C o n s t a n t s
+/*****************************************************************************/
+
+// By default we well use the top of the cache 4MB-8MB
+#define FAKE_PNOR_START (4*MEGABYTE)
+#define FAKE_PNOR_END (8*MEGABYTE)
+#define FAKE_PNOR_SIZE (FAKE_PNOR_END-FAKE_PNOR_START)
+
+
+
+
+/*****************************************************************************/
+// G l o b a l s
+/*****************************************************************************/
+
+// Initialized in pnorrp.C
+extern trace_desc_t* g_trac_pnor;
+
+/*****************************************************************************/
+// M e t h o d s
+/*****************************************************************************/
+
+namespace PNOR {
+/**
+ * @brief Wrapper for device driver constructor
+ */
+errlHndl_t create_SfcDD( SfcDD*& o_sfc,
+ TARGETING::Target* i_proc )
+{
+ errlHndl_t l_err = NULL;
+ TRACFCOMP( g_trac_pnor, "Creating SfcFake object" );
+ o_sfc = new SfcFake( l_err, i_proc );
+ return l_err;
+}
+
+};
+
+/**
+ * @brief Constructor
+ */
+SfcFake::SfcFake( errlHndl_t& o_err,
+ TARGETING::Target* i_proc )
+: SfcDD(o_err,i_proc)
+, iv_fakePnor(reinterpret_cast<uint8_t*>(FAKE_PNOR_START))
+, iv_sizeBytes(FAKE_PNOR_SIZE)
+{
+ TRACFCOMP( g_trac_pnor, "Instantiating SfcFake" );
+}
+
+
+/**
+ * @brief Read data from the flash
+ */
+errlHndl_t SfcFake::readFlash( uint32_t i_addr,
+ size_t i_size,
+ void* o_data )
+{
+ TRACDCOMP( g_trac_pnor, "SfcFake::readFlash> i_addr=0x%.8x, i_size=0x%.8x",
+ i_addr, i_size );
+ errlHndl_t errhdl = NULL;
+
+ //create a pointer to the offset start.
+ uint8_t* srcPtr = reinterpret_cast<uint8_t*>(iv_fakePnor+i_addr);
+
+ if( (srcPtr+i_size) > (iv_fakePnor+iv_sizeBytes) )
+ {
+ TRACFCOMP(g_trac_pnor, "SfcFake::readFlash> Read goes past end of fake-PNOR : i_addr=0x%X, i_size=0x%X", i_addr, i_size );
+ /*@
+ * @errortype
+ * @moduleid PNOR::MOD_SFCFAKE_READFLASH
+ * @reasoncode PNOR::RC_INVALID_ADDRESS
+ * @userdata1[0:31] PNOR Address
+ * @userdata1[32:63] Bytes to read
+ * @userdata2[0:31] <unused>
+ * @userdata2[32:63] Size of allocated PNOR space
+ * @devdesc SfcFake::readFlash> Requested access exceeded the
+ * bounds of the allocated PNOR space
+ * @custdesc Firmware error accessing flash during IPL
+ */
+ errhdl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ PNOR::MOD_SFCFAKE_READFLASH,
+ PNOR::RC_INVALID_ADDRESS,
+ TWO_UINT32_TO_UINT64(i_addr,
+ i_size),
+ TWO_UINT32_TO_UINT64(0,
+ iv_sizeBytes),
+ true /*Software error*/);
+ }
+ else
+ {
+ //Read directly from memory
+ memcpy( o_data, srcPtr, i_size );
+ }
+
+ return errhdl;
+}
+
+
+/**
+ * @brief Write data into flash
+ */
+errlHndl_t SfcFake::writeFlash( uint32_t i_addr,
+ size_t i_size,
+ void* i_data )
+{
+ TRACDCOMP( g_trac_pnor, "SfcFake::writeFlash> i_addr=0x%.8x, i_size=0x%.8x",
+ i_addr, i_size );
+ errlHndl_t errhdl = NULL;
+
+ //create a pointer to the offset start.
+ uint8_t* destPtr = reinterpret_cast<uint8_t*>(iv_fakePnor+i_addr);
+
+ if( (destPtr+i_size) > (iv_fakePnor+iv_sizeBytes) )
+ {
+ TRACFCOMP(g_trac_pnor, "SfcFake::writeFlash> Write goes past end of fake-PNOR : i_addr=0x%X, i_size=0x%X", i_addr, i_size );
+ /*@
+ * @errortype
+ * @moduleid PNOR::MOD_SFCFAKE_WRITEFLASH
+ * @reasoncode PNOR::RC_INVALID_ADDRESS
+ * @userdata1[0:31] PNOR Address
+ * @userdata1[32:63] Bytes to write
+ * @userdata2[0:31] <unused>
+ * @userdata2[32:63] Size of allocated PNOR space
+ * @devdesc SfcFake::writeFlash> Requested access exceeded the
+ * bounds of the allocated PNOR space
+ * @custdesc Firmware error accessing flash during IPL
+ */
+ errhdl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ PNOR::MOD_SFCFAKE_WRITEFLASH,
+ PNOR::RC_INVALID_ADDRESS,
+ TWO_UINT32_TO_UINT64(i_addr,
+ i_size),
+ TWO_UINT32_TO_UINT64(0,
+ iv_sizeBytes),
+ true /*Software error*/);
+ }
+ else
+ {
+ //Write directly to memory
+ memcpy( destPtr, i_data, i_size );
+ }
+
+ return errhdl;
+}
+
+
+/**
+ * @brief Erase a block of flash
+ */
+errlHndl_t SfcFake::eraseFlash( uint32_t i_addr )
+{
+ TRACDCOMP( g_trac_pnor, "SfcFake::eraseFlash> i_addr=0x%.8x, i_size=0x%.8x",
+ i_addr );
+ errlHndl_t errhdl = NULL;
+
+ //create a pointer to the offset start.
+ uint8_t* destPtr = reinterpret_cast<uint8_t*>(iv_fakePnor+i_addr);
+
+ if( (destPtr+iv_eraseSizeBytes) > (iv_fakePnor+iv_sizeBytes) )
+ {
+ TRACFCOMP(g_trac_pnor, "SfcFake::writeFlash> Write goes past end of fake-PNOR : i_addr=0x%X, i_size=0x%X", i_addr );
+ /*@
+ * @errortype
+ * @moduleid PNOR::MOD_SFCFAKE_ERASEFLASH
+ * @reasoncode PNOR::RC_INVALID_ADDRESS
+ * @userdata1[0:31] PNOR Address
+ * @userdata1[32:63] <unused>
+ * @userdata2[0:31] Bytes in erase block
+ * @userdata2[32:63] Size of allocated PNOR space
+ * @devdesc SfcFake::writeFlash> Requested access exceeded the
+ * bounds of the allocated PNOR space
+ * @custdesc Firmware error accessing flash during IPL
+ */
+ errhdl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ PNOR::MOD_SFCFAKE_ERASEFLASH,
+ PNOR::RC_INVALID_ADDRESS,
+ TWO_UINT32_TO_UINT64(i_addr,
+ 0),
+ TWO_UINT32_TO_UINT64(iv_eraseSizeBytes,
+ iv_sizeBytes),
+ true /*Software error*/);
+ }
+ else
+ {
+ //A real erase sets every bit so emulate that with a memset
+ memset( destPtr, 0xFF, iv_eraseSizeBytes );
+ }
+
+ return errhdl;
+}
+
+/**
+ * @brief Initialize and configure the SFC hardware
+ */
+errlHndl_t SfcFake::hwInit( )
+{
+ TRACFCOMP( g_trac_pnor, "SfcFake::hwInit> Nothing to do here" );
+ return NULL;
+}
+
+/**
+ * @brief Informs caller if PNORDD is using
+ * L3 Cache for fake PNOR or not.
+ */
+bool SfcFake::usingL3Cache( void )
+{
+ return true;
+}
+
+/**
+ * @brief Send a user-defined SPI command
+ */
+errlHndl_t SfcFake::sendSpiCmd( uint8_t i_opCode,
+ uint32_t i_address,
+ size_t i_writeCnt,
+ const uint8_t* i_writeData,
+ size_t i_readCnt,
+ uint8_t* o_readData )
+{
+ TRACFCOMP( g_trac_pnor, "SfcFake::sendSpiCmd> Nothing to do here : opcode=%.2X", i_opCode );
+ /*@
+ * @errortype
+ * @moduleid PNOR::MOD_SFCFAKE_SENDSPICMD
+ * @reasoncode PNOR::RC_UNSUPPORTED_OPERATION
+ * @userdata1[0:31] Op Code
+ * @userdata1[32:63] Address
+ * @userdata2 <unused>
+ * @devdesc SfcFake::sendSpiCmd> Function is not supported
+ * @custdesc Firmware error accessing flash during IPL
+ */
+ return new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ PNOR::MOD_SFCFAKE_SENDSPICMD,
+ PNOR::RC_UNSUPPORTED_OPERATION,
+ TWO_UINT32_TO_UINT64(i_opCode
+ i_addr),
+ 0,
+ true /*Software error*/);
+}
+
+/**
+ * @brief Return first 3 bytes of NOR chip id
+ */
+errlHndl_t SfcFake::getNORChipId( uint32_t& o_chipId )
+{
+ o_chipId = PNOR::FAKE_NOR_ID;
+ iv_norChipId = PNOR::FAKE_NOR_ID;
+ return NULL;
+}
+
diff --git a/src/usr/pnor/sfc_fake.H b/src/usr/pnor/sfc_fake.H
new file mode 100644
index 000000000..dc55e5e0d
--- /dev/null
+++ b/src/usr/pnor/sfc_fake.H
@@ -0,0 +1,151 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/pnor/sfc_fake.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2014 */
+/* [+] Google Inc. */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __PNOR_SFCFAKE_H
+#define __PNOR_SFCFAKE_H
+
+#include <limits.h>
+#include <targeting/common/targetservice.H>
+#include <errl/errlentry.H>
+#include "sfcdd.H"
+
+/** @file sfc_fake.H
+ * @brief Provides the logic to access an emulated PNOR
+ * model using mainstore as a proxy for flash
+ */
+
+/**
+ * @brief Fake SFC Device Driver Class
+ * Provides the logic to access an emulated PNOR
+ * model using mainstore as a proxy for flash
+ */
+class SfcFake : public SfcDD
+{
+
+ public: //SfcDD methods
+ /**
+ * @brief Initialize the SFC Hardware
+ *
+ * @return void
+ */
+ virtual errlHndl_t hwInit();
+
+ /**
+ * @brief Read data from the PNOR flash
+ *
+ * @parm i_addr PNOR flash Address to read
+ * @parm i_size Amount of data to read, in bytes.
+ * @parm o_data Buffer to read data into
+ *
+ * @return Error from operation
+ */
+ virtual errlHndl_t readFlash(uint32_t i_addr,
+ size_t i_size,
+ void* o_data);
+
+ /**
+ * @brief Write data to the PNOR flash
+ *
+ * @parm i_addr PNOR flash Address to write
+ * @parm i_size Amount of data to write, in bytes.
+ * @parm i_data Buffer containing data to write
+ *
+ * @return Error from operation
+ */
+ virtual errlHndl_t writeFlash(uint32_t i_addr,
+ size_t i_size,
+ void* i_data);
+
+ /**
+ * @brief Erase a block of flash
+ *
+ * @parm i_address Offset into flash to erase, aligned to erase block
+ *
+ * @return Error from operation
+ */
+ virtual errlHndl_t eraseFlash(uint32_t i_address);
+
+ /**
+ * @brief Send a user-defined SPI command
+ *
+ * @parm[in] i_opCode: command to send into controller first
+ * @parm[in] i_address: address for those commands that need it
+ * @parm[in] i_writeCnt: number of bytes to write to device
+ * @parm[in] i_writeData: write data buffer
+ * @parm[in] i_readCnt: number of bytes to read from device
+ * @parm[out] o_readData: read data buffer
+ *
+ * @return Error from operation
+ */
+ virtual errlHndl_t sendSpiCmd( uint8_t i_opCode,
+ uint32_t i_address,
+ size_t i_writeCnt,
+ const uint8_t* i_writeData,
+ size_t i_readCnt,
+ uint8_t* o_readData );
+
+ /**
+ * @brief Informs caller if PNORDD is using
+ * L3 Cache for fake PNOR or not.
+ *
+ * @return Indicate state of fake PNOR
+ * true = using L3 Cache for fake PNOR
+ * false = not using L3 Cache for fake PNOR
+ */
+ virtual bool usingL3Cache( void );
+
+ /**
+ * @brief Return first 3 bytes of NOR chip id
+ *
+ * @parm[out] NOR chip id
+ *
+ * @return Error from operation
+ */
+ virtual errlHndl_t getNORChipId( uint32_t& o_chipId );
+
+ public:
+ /**
+ * @brief Constructor
+ * @param[out] Return any error in constructor
+ * @param[in] Processor target associated with the LPC master
+ */
+ SfcFake( errlHndl_t& o_err,
+ TARGETING::Target* i_proc
+ = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL );
+
+
+ protected:
+ /**
+ * @brief Pointer to fake memory location
+ */
+ uint8_t* iv_fakePnor;
+
+ /**
+ * @brief Size of allocated PNOR space in bytes
+ */
+ size_t iv_sizeBytes;
+};
+
+#endif
diff --git a/src/usr/pnor/sfc_ibm.C b/src/usr/pnor/sfc_ibm.C
new file mode 100644
index 000000000..7574923b6
--- /dev/null
+++ b/src/usr/pnor/sfc_ibm.C
@@ -0,0 +1,1290 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/pnor/sfc_ibm.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2014 */
+/* [+] Google Inc. */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+/*****************************************************************************/
+// I n c l u d e s
+/*****************************************************************************/
+#include <sys/mmio.h>
+#include <sys/task.h>
+#include <sys/sync.h>
+#include <string.h>
+#include <devicefw/driverif.H>
+#include <trace/interface.H>
+#include <errl/errlentry.H>
+#include <errl/errlmanager.H>
+#include <errl/errludlogregister.H>
+#include <targeting/common/targetservice.H>
+#include <pnor/pnor_reasoncodes.H>
+#include <sys/time.h>
+#include <util/align.H>
+#include <lpc/lpcif.H>
+#include "sfc_ibm.H"
+#include "norflash.H"
+using namespace PNOR;
+
+/*****************************************************************************/
+// C o n s t a n t s
+/*****************************************************************************/
+
+
+
+
+/*****************************************************************************/
+// G l o b a l s
+/*****************************************************************************/
+
+// Initialized in pnorrp.C
+extern trace_desc_t* g_trac_pnor;
+
+/*****************************************************************************/
+// M e t h o d s
+/*****************************************************************************/
+
+namespace PNOR {
+/**
+ * @brief Wrapper for device driver constructor
+ */
+errlHndl_t create_SfcDD( SfcDD*& o_sfc,
+ TARGETING::Target* i_proc )
+{
+ errlHndl_t l_err = NULL;
+ TRACFCOMP( g_trac_pnor, "Creating SfcIBM object" );
+ o_sfc = new SfcIBM( l_err, i_proc );
+ return l_err;
+}
+
+};
+
+/**
+ * @brief Constructor
+ */
+SfcIBM::SfcIBM( errlHndl_t& o_err,
+ TARGETING::Target* i_proc )
+: SfcDD(o_err,i_proc)
+,iv_ffdcActive(false)
+,iv_errorHandledCount(0)
+,iv_resetActive(false)
+{
+}
+
+
+/**
+ * @brief Write a SFC Register
+ */
+errlHndl_t SfcIBM::writeReg( SfcRange i_range,
+ uint32_t i_addr,
+ uint32_t i_data )
+{
+ errlHndl_t l_err = NULL;
+ uint32_t lpc_addr = i_addr;
+ LPC::TransType lpc_range = LPC::TRANS_LAST;
+
+ // Find the appropriate LPC parms
+ sfc2lpc( i_range, i_addr, lpc_range, lpc_addr );
+
+ TRACDCOMP( g_trac_pnor, "SfcIBM::writeReg> SFC::%d-%.8X, LPC::%d-%.8X, i_data=0x%.8x", i_range, i_addr, lpc_range, lpc_addr, i_data );
+ size_t reg_size = sizeof(uint32_t);
+ l_err = deviceOp( DeviceFW::WRITE,
+ iv_proc,
+ &i_data,
+ reg_size,
+ DEVICE_LPC_ADDRESS(lpc_range,lpc_addr) );
+
+ return l_err;
+}
+
+
+/**
+ * @brief Read a SFC Register
+ */
+errlHndl_t SfcIBM::readReg( SfcRange i_range,
+ uint32_t i_addr,
+ uint32_t& o_data )
+{
+ errlHndl_t l_err = NULL;
+ uint32_t lpc_addr = i_addr;
+ LPC::TransType lpc_range = LPC::TRANS_LAST;
+
+ // Find the appropriate LPC parms
+ sfc2lpc( i_range, i_addr, lpc_range, lpc_addr );
+
+ size_t reg_size = sizeof(uint32_t);
+ l_err = deviceOp( DeviceFW::READ,
+ iv_proc,
+ &o_data,
+ reg_size,
+ DEVICE_LPC_ADDRESS(lpc_range,lpc_addr) );
+ TRACDCOMP( g_trac_pnor, "SfcIBM::readReg> SFC::%d-%.8X, LPC::%d-%.8X, o_data=0x%.8x", i_range, i_addr, lpc_range, lpc_addr, o_data );
+
+ return l_err;
+}
+
+
+/**
+ * @brief Poll for SFC operation to complete and look for errors
+ */
+errlHndl_t SfcIBM::pollOpComplete( void )
+{
+ TRACDCOMP( g_trac_pnor, "SfcIBM::pollOpComplete>" );
+ errlHndl_t l_err = NULL;
+ ResetLevels l_resetLevel = RESET_CLEAR;
+
+ do {
+ //Poll for complete status
+ SfcStatReg_t sfc_stat;
+ uint64_t poll_time = 0;
+ uint64_t loop = 0;
+ while( poll_time < SFC_POLL_TIME_NS )
+ {
+ l_err = readReg(SFC_CMD_SPACE,
+ SFC_REG_STATUS,
+ sfc_stat.data32);
+ if(l_err) { break; }
+
+ if( ( sfc_stat.done == 1 ) ||
+ ( sfc_stat.timeout == 1 ) ||
+ ( sfc_stat.illegal == 1 ) )
+ {
+ break;
+ }
+
+ // 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
+ ++loop;
+ nanosleep( 0, SFC_POLL_INCR_NS*loop );
+ poll_time += SFC_POLL_INCR_NS*loop;
+ }
+ if( l_err ) { break; }
+
+ // Look for errors, regardless of how we exited the loop
+ l_err = checkForErrors(l_resetLevel);
+ if( l_err ) { break; }
+
+ // If no errors AND done bit not set, call out undefined error
+ if( sfc_stat.done == 0 )
+ {
+ TRACFCOMP(g_trac_pnor, "SfcIBM::pollOpComplete> Error or timeout from SFC Status Register" );
+
+ /*@
+ * @errortype
+ * @moduleid PNOR::MOD_SFCIBM_POLLOPCOMPLETE
+ * @reasoncode PNOR::RC_SFC_TIMEOUT
+ * @userdata1[0:31] NOR Flash Chip ID
+ * @userdata1[32:63] Total poll time (ns)
+ * @userdata2[0:31] SFC Status Register
+ * @devdesc SfcIBM::pollOpComplete> Error or timeout from
+ * SFC Status Register
+ * @custdesc Hardware error accessing flash during IPL
+ */
+ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ PNOR::MOD_SFCIBM_POLLOPCOMPLETE,
+ PNOR::RC_SFC_TIMEOUT,
+ TWO_UINT32_TO_UINT64(iv_norChipId,
+ poll_time),
+ TWO_UINT32_TO_UINT64(sfc_stat.data32,0));
+
+ // Limited in callout: no PNOR target, so calling out processor
+ l_err->addHwCallout(
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ HWAS::SRCI_PRIORITY_HIGH,
+ HWAS::NO_DECONFIG,
+ HWAS::GARD_NULL );
+
+ addFFDC(l_err);
+ l_err->collectTrace(PNOR_COMP_NAME);
+ l_err->collectTrace(XSCOM_COMP_NAME);
+
+ // Reset LPC Slave since it appears to be hung - handled below
+ l_resetLevel = RESET_LPC_SLAVE;
+
+ break;
+ }
+ TRACDCOMP(g_trac_pnor,"SfcIBM::pollOpComplete> command took %d ns", poll_time);
+
+ }while(0);
+
+ // If we have an error that requires a reset, do that here
+ if ( l_err && ( l_resetLevel != RESET_CLEAR ) )
+ {
+ errlHndl_t tmp_err = NULL;
+ tmp_err = hwReset(l_resetLevel);
+
+ if ( tmp_err )
+ {
+ // Commit reset error as informational since we have
+ // original error l_err
+ TRACFCOMP(g_trac_pnor, "SfcIBM::pollOpComplete> Error from resetPnor() after previous error eid=0x%X. Committing resetPnor() error log eid=0x%X.",
+ l_err->eid(), tmp_err->eid());
+ tmp_err->setSev(ERRORLOG::ERRL_SEV_INFORMATIONAL);
+ tmp_err->collectTrace(PNOR_COMP_NAME);
+ tmp_err->plid(l_err->plid());
+ errlCommit(tmp_err, PNOR_COMP_ID);
+ }
+ }
+
+
+ return l_err;
+}
+
+
+/**
+ * @brief Load SFC command buffer with data from PNOR
+ */
+errlHndl_t SfcIBM::loadSfcBuf(uint32_t i_addr,
+ size_t i_size)
+{
+ errlHndl_t l_err = NULL;
+ TRACDCOMP( g_trac_pnor, "SfcIBM::loadSfcBuf> i_addr=0x%.8x, i_size=0x%.8x",
+ i_addr, i_size );
+
+ do {
+ //Write flash address to ADR reg
+ l_err = writeReg(SFC_CMD_SPACE,
+ SFC_REG_ADR,
+ i_addr);
+ if(l_err) { break; }
+
+ //Issue ReadRaw command with size to read
+ SfcCmdReg_t sfc_cmd;
+ sfc_cmd.opcode = SFC_OP_READRAW;
+ sfc_cmd.length = i_size;
+ l_err = writeReg(SFC_CMD_SPACE,
+ SFC_REG_CMD,
+ sfc_cmd.data32);
+ if(l_err) { break; }
+
+ //Poll for complete status
+ l_err = pollOpComplete();
+ if(l_err) { break; }
+
+ }while(0);
+
+ return l_err;
+
+}
+
+
+/**
+ * @brief Flush SFC command buffer data out to PNOR Flash
+ */
+errlHndl_t SfcIBM::flushSfcBuf( uint32_t i_addr,
+ size_t i_size )
+{
+ errlHndl_t l_err = NULL;
+ TRACDCOMP( g_trac_pnor,
+ "SfcIBM::flushSfcBuf> i_addr=0x%.8x, i_size=0x%.8x",
+ i_addr, i_size );
+
+ do {
+ //Write flash address to ADR reg
+ l_err = writeReg(SFC_CMD_SPACE,
+ SFC_REG_ADR,
+ i_addr);
+ if(l_err) { break; }
+
+ //Issue WriteRaw command + size to write
+ SfcCmdReg_t sfc_cmd;
+ sfc_cmd.opcode = SFC_OP_WRITERAW;
+ sfc_cmd.length = i_size;
+ l_err = writeReg(SFC_CMD_SPACE,
+ SFC_REG_CMD,
+ sfc_cmd.data32);
+ if(l_err) { break; }
+
+ //Poll for complete status
+ l_err = pollOpComplete();
+ if(l_err) { break; }
+
+#ifdef CONFIG_ALLOW_MICRON_PNOR
+ //check for special Micron Flag Status reg
+ if(iv_flashWorkarounds & HWWK_MICRON_WRT_ERASE)
+ {
+ l_err = PNOR::micronFlagStatus(this);
+ if(l_err) { break; }
+ }
+#endif
+
+ }while(0);
+
+ return l_err;
+
+}
+
+
+/**
+ * @brief Read data from the flash
+ */
+errlHndl_t SfcIBM::readFlash( uint32_t i_addr,
+ size_t i_size,
+ void* o_data )
+{
+ errlHndl_t l_err = NULL;
+ TRACDCOMP( g_trac_pnor, "SfcIBM::readFlash> i_addr=0x%.8x, i_size=0x%.8x",
+ i_addr, i_size );
+
+ do{
+ //Read directly from MMIO space
+ uint32_t* word_ptr = static_cast<uint32_t*>(o_data);
+ uint32_t word_size = i_size/4;
+ for( uint32_t words_read = 0;
+ words_read < word_size;
+ words_read ++ )
+ {
+ l_err = readReg(SFC_MMIO_SPACE,
+ i_addr+words_read*4, //MMIO Address offset
+ word_ptr[words_read]);
+ if( l_err ) { break; }
+ }
+ if( l_err ) { break; }
+ }while(0);
+
+ return l_err;
+}
+
+
+/**
+ * @brief Write data into flash
+ */
+errlHndl_t SfcIBM::writeFlash( uint32_t i_addr,
+ size_t i_size,
+ void* i_data )
+{
+ TRACDCOMP( g_trac_pnor, "SfcIBM::writeFlash> i_addr=0x%.8x, i_size=0x%.8x",
+ i_addr, i_size );
+
+ errlHndl_t l_err = NULL;
+
+ do{
+ // Command based reads are buffered 256 bytes at a time.
+ uint32_t chunk_size = 0;
+ uint64_t addr = i_addr;
+ uint64_t end_addr = i_addr + i_size;
+
+ while(addr < end_addr)
+ {
+ chunk_size = SFC_CMDBUF_SIZE;
+ if( (addr + SFC_CMDBUF_SIZE) > end_addr)
+ {
+ chunk_size = end_addr - addr;
+ }
+
+ //write data to SFC CMD Buffer via MMIO
+ l_err = writeIntoBuffer(chunk_size,
+ (void*)((uint64_t)i_data + (addr-i_addr)));
+ if(l_err) { break;}
+
+ //Push data from buffer out to flash
+ l_err = flushSfcBuf(addr, chunk_size);
+ if(l_err) { break;}
+
+ addr += chunk_size;
+ }
+ if(l_err) { break;}
+
+ } while(0);
+
+ return l_err;
+}
+
+
+/**
+ * @brief Read data from SFC Command buffer
+ */
+errlHndl_t SfcIBM::readFromBuffer( size_t i_size,
+ void* o_data )
+{
+ errlHndl_t l_err = NULL;
+ TRACDCOMP( g_trac_pnor, "SfcIBM::readFromBuffer> i_size=0x%.8x",
+ 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 = (ALIGN_4(i_size))/4;
+ for( uint32_t words_read = 0;
+ words_read < word_size;
+ words_read ++ )
+ {
+ l_err = readReg(SFC_CMDBUF_SPACE,
+ words_read*4, //Offset into CMD BUFF space in bytes
+ word_ptr[words_read]);
+ TRACDCOMP( g_trac_pnor, "SfcIBM::readFromBuffer: Read offset=0x%.8x, data_read=0x%.8x", words_read*4, word_ptr[words_read] );
+
+ if( l_err ) { break; }
+ }
+
+ return l_err;
+}
+
+/**
+ * @brief Write data into SFC Command buffer
+ */
+errlHndl_t SfcIBM::writeIntoBuffer( size_t i_size,
+ void* i_data )
+{
+ errlHndl_t l_err = NULL;
+ TRACDCOMP( g_trac_pnor, "SfcIBM::writeIntoBuffer> i_size=0x%.8x",
+ i_size );
+
+ // SFC Command Buffer is accessed 32-bits at a time
+ uint32_t* word_ptr = static_cast<uint32_t*>(i_data);
+ uint32_t word_size = i_size/4;
+ for( uint32_t words_read = 0;
+ words_read < word_size;
+ words_read ++ )
+ {
+ l_err = writeReg(SFC_CMDBUF_SPACE,
+ words_read*4, //Offset into CMD BUFF space in bytes
+ word_ptr[words_read]);
+ if( l_err ) { break; }
+ }
+
+ return l_err;
+}
+
+/**
+ * @brief Erase a block of flash
+ */
+errlHndl_t SfcIBM::eraseFlash(uint32_t i_address)
+{
+ errlHndl_t l_err = NULL;
+ TRACFCOMP(g_trac_pnor, ">>SfcIBM::eraseFlash> Block 0x%.8X", i_address );
+
+ do {
+ if( i_address%iv_eraseSizeBytes != 0 )
+ {
+ /*@
+ * @errortype
+ * @moduleid PNOR::MOD_SFCIBM_ERASEFLASH
+ * @reasoncode PNOR::RC_INVALID_ADDRESS
+ * @userdata1 Flash address being erased
+ * @userdata2 Nearest Erase Boundary
+ * @devdesc PnorDD::eraseFlash> Address not on erase boundary
+ * @custdesc Firmware error accessing flash during IPL
+ */
+ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ PNOR::MOD_SFCIBM_ERASEFLASH,
+ PNOR::RC_INVALID_ADDRESS,
+ TWO_UINT32_TO_UINT64(0,i_address),
+ i_address
+ - i_address%iv_eraseSizeBytes,
+ true /*Add HB SW Callout*/ );
+ l_err->collectTrace(PNOR_COMP_NAME);
+ break;
+ }
+
+ //Write erase address to ADR reg
+ l_err = writeReg(SFC_CMD_SPACE,
+ SFC_REG_ADR,
+ i_address);
+ if(l_err) { break; }
+
+ //Issue Erase command
+ SfcCmdReg_t sfc_cmd;
+ sfc_cmd.opcode = SFC_OP_ERASM;
+ sfc_cmd.length = 0; //Not used for erase
+ l_err = writeReg(SFC_CMD_SPACE,
+ SFC_REG_CMD,
+ sfc_cmd.data32);
+ if(l_err) { break; }
+
+ //Poll for complete status
+ l_err = pollOpComplete();
+ if(l_err) { break; }
+
+#ifdef CONFIG_ALLOW_MICRON_PNOR
+ //check for special Micron Flag Status reg
+ if(iv_flashWorkarounds & HWWK_MICRON_WRT_ERASE)
+ {
+ l_err = PNOR::micronFlagStatus(this);
+ if(l_err) { break; }
+ }
+#endif
+ } while(0);
+
+ return l_err;
+}
+
+
+/**
+ * @brief Initialize and configure the SFC hardware
+ */
+errlHndl_t SfcIBM::hwInit( )
+{
+ TRACFCOMP(g_trac_pnor, "SfcIBM::hwInit>" );
+ errlHndl_t l_err = NULL;
+
+ do {
+ //Determine NOR Flash type - triggers vendor specific workarounds
+ //We also use the chipID in some FFDC situations.
+ l_err = getNORChipId(iv_norChipId);
+ if(l_err) { break; }
+ TRACFCOMP(g_trac_pnor,
+ "SfcIBM::hwInit: iv_norChipId=0x%.8x> ",
+ iv_norChipId );
+
+ //Query the configured size of the erase block
+ l_err = readReg(SFC_CMD_SPACE,
+ SFC_REG_ERASMS,
+ iv_eraseSizeBytes);
+ if(l_err) { break; }
+ TRACFCOMP(g_trac_pnor,"iv_eraseSizeBytes=0x%X",iv_eraseSizeBytes);
+
+
+#ifndef CONFIG_BMC_DOES_SFC_INIT
+ TRACFCOMP( g_trac_pnor, INFO_MRK "Initializing SFC registers" );
+
+ static struct
+ {
+ // Chip id to match or UNKNOWN_NOR_ID for all chips.
+ uint32_t chip_id;
+ // SFC register to set.
+ uint8_t reg;
+ // Value which is set in register.
+ uint32_t val;
+ } sfc_init_regs[] = {
+ //*** Direct access window and basic SFC settings.
+ //Set MMIO/Direct window to start at 64MB
+ { PNOR::UNKNOWN_NOR_ID, SFC_REG_OADRNB, 0x0C000000 },
+ //Set the MMIO/Direct window size to 64MB
+ { PNOR::UNKNOWN_NOR_ID, SFC_REG_OADRNS, 0x0000000F },
+ //Set the flash index to 0
+ { PNOR::UNKNOWN_NOR_ID, SFC_REG_ADRCBF, 0x00000000 },
+ //Set the flash size to 64MB
+ { PNOR::UNKNOWN_NOR_ID, SFC_REG_ADRCMF, 0x0000000F },
+ //Enable Direct Access Cache
+ { PNOR::UNKNOWN_NOR_ID, SFC_REG_CONF, 0x00000001 },
+
+#ifdef CONFIG_ALLOW_MICRON_PNOR
+ //*** Micron 512mb chip specific settings.
+ { PNOR::MICRON_NOR_ID, SFC_REG_SPICLK,
+ 0 << SFC_REG_SPICLK_OUTDLY_SHFT |
+ 0 << SFC_REG_SPICLK_INSAMPDLY_SHFT |
+ 1 << SFC_REG_SPICLK_CLKHI_SHFT |
+ 1 << SFC_REG_SPICLK_CLKLO_SHFT
+ },
+ { PNOR::MICRON_NOR_ID, SFC_REG_CONF8,
+ 6 << SFC_REG_CONF8_CSINACTIVEREAD_SHFT |
+ 15 << SFC_REG_CONF8_DUMMY_SHFT |
+ SPI_JEDEC_FAST_READ << SFC_REG_CONF8_READOP_SHFT
+ },
+ { PNOR::MICRON_NOR_ID, SFC_REG_CONF4, SPI_JEDEC_SECTOR_ERASE },
+ { PNOR::MICRON_NOR_ID, SFC_REG_CONF5, 4096 },
+ //*** End Micron
+#endif
+
+#ifdef CONFIG_RHESUS
+ // HACK: Micron N25Q256A13 for use with EM100.
+ { 0x20ba1900, SFC_REG_CONF4, SPI_JEDEC_SECTOR_ERASE },
+ { 0x20ba1900, SFC_REG_CONF5, 4096 },
+#endif
+
+#ifdef CONFIG_ALLOW_MACRONIX_PNOR
+ //*** Macronix 512mb chip specific settings.
+ { PNOR::MACRONIX_NOR_ID, SFC_REG_SPICLK,
+ 0 << SFC_REG_SPICLK_OUTDLY_SHFT |
+ 0 << SFC_REG_SPICLK_INSAMPDLY_SHFT |
+ 0 << SFC_REG_SPICLK_CLKHI_SHFT |
+ 0 << SFC_REG_SPICLK_CLKLO_SHFT
+ },
+ { PNOR::MACRONIX_NOR_ID, SFC_REG_CONF8,
+ 2 << SFC_REG_CONF8_CSINACTIVEREAD_SHFT |
+ 8 << SFC_REG_CONF8_DUMMY_SHFT |
+ SPI_JEDEC_FAST_READ << SFC_REG_CONF8_READOP_SHFT
+ },
+ { PNOR::MACRONIX_NOR_ID, SFC_REG_CONF4, SPI_JEDEC_SECTOR_ERASE },
+ { PNOR::MACRONIX_NOR_ID, SFC_REG_CONF5, 4096 },
+ //*** End Macronix
+#endif
+ };
+
+ for ( size_t i = 0;
+ i < sizeof(sfc_init_regs) / sizeof(sfc_init_regs[0]);
+ ++i )
+ {
+ if( (sfc_init_regs[i].chip_id == PNOR::UNKNOWN_NOR_ID) ||
+ (sfc_init_regs[i].chip_id == iv_norChipId) )
+ {
+ TRACDCOMP( g_trac_pnor, INFO_MRK " SFC reg %02x = %08x",
+ sfc_init_regs[i].reg,
+ sfc_init_regs[i].val );
+ l_err = writeReg( SFC_CMD_SPACE,
+ sfc_init_regs[i].reg,
+ sfc_init_regs[i].val );
+ if( l_err ) { break; }
+ }
+ }
+ if( l_err ) { break; }
+
+#if 0 //@fixme-RTC:109860
+ // Enable 4-byte addressing.
+ l_err = SfcErrlFromRc( iv_sfc.set_4ba( &iv_sfc, 1 ) );
+ if( l_err ) { break; }
+
+ // Re-initialize internal erase size cached value.
+ l_err = SfcErrlFromRc( iv_sfc.get_erase_size(
+ &iv_sfc, &iv_eraseSizeBytes, NULL ) );
+ if( l_err ) { break; }
+#endif
+
+#endif //!CONFIG_BMC_DOES_SFC_INIT
+
+
+#ifdef CONFIG_ALLOW_MICRON_PNOR
+ if( iv_norChipId == PNOR::MICRON_NOR_ID )
+ {
+ l_err = PNOR::micronCheckForWorkarounds( this,
+ iv_flashWorkarounds );
+ if(l_err) { break; }
+ }
+#endif //CONFIG_ALLOW_MICRON_PNOR
+
+ }while(0);
+
+ TRACFCOMP(g_trac_pnor, "< SfcIBM::hwInit :: RC=%.4X", ERRL_GETRC_SAFE(l_err) );
+ return l_err;
+}
+
+/**
+ * @brief Convert a SFC address to a LPC address
+ */
+void SfcIBM::sfc2lpc( SfcRange i_sfcRange,
+ uint32_t i_sfcAddr,
+ LPC::TransType& o_lpcRange,
+ uint32_t& o_lpcAddr )
+{
+ switch(i_sfcRange)
+ {
+ case SFC_MMIO_SPACE:
+ o_lpcRange = LPC::TRANS_FW;
+ o_lpcAddr = i_sfcAddr | SFC_MMIO_OFFSET;
+ break;
+ case SFC_CMD_SPACE:
+ o_lpcRange = LPC::TRANS_FW;
+ o_lpcAddr = i_sfcAddr | SFC_CMDREG_OFFSET;
+ break;
+ case SFC_CMDBUF_SPACE:
+ o_lpcRange = LPC::TRANS_FW;
+ o_lpcAddr = i_sfcAddr | SFC_CMDBUF_OFFSET;
+ break;
+ case SFC_LPC_SPACE:
+ o_lpcRange = LPC::TRANS_FW;
+ o_lpcAddr = i_sfcAddr;
+ break;
+ } //end switch
+}
+
+
+/**
+ * @brief Check For Errors in SFC Status Registers
+ */
+errlHndl_t SfcIBM::checkForErrors( ResetLevels &o_resetLevel )
+{
+ errlHndl_t l_err = NULL;
+ bool errorFound = false;
+
+ // Used to set Reset Levels, if necessary
+ o_resetLevel = RESET_CLEAR;
+
+ // Default status values in case we fail in reading the registers
+ LpcSlaveStatReg_t lpc_slave_stat;
+ lpc_slave_stat.data32 = 0xDEADBEEF;
+ SfcStatReg_t sfc_stat;
+ sfc_stat.data32 = 0xDEADBEEF;
+
+ do {
+
+ // First Read LPC Slave Status Register
+ l_err = readReg( SFC_LPC_SPACE,
+ LPC_SLAVE_REG_STATUS,
+ lpc_slave_stat.data32 );
+
+ // If we can't read status register, exit out
+ if( l_err ) { break; }
+
+ TRACDCOMP( g_trac_pnor, INFO_MRK"SfcIBM::checkForErrors> LPC Slave status reg: 0x%08llx",
+ lpc_slave_stat.data32);
+
+ // Start with lighter reset level
+ if( 1 == lpc_slave_stat.lbusparityerror )
+ {
+ errorFound = true;
+ o_resetLevel = RESET_LPC_SLAVE_ERRS;
+ TRACFCOMP( g_trac_pnor, ERR_MRK"SfcIBM::checkForErrors> LPC Slave Local Bus Parity Error: status reg: 0x%08llx, ResetLevel=%d",
+ lpc_slave_stat.data32, o_resetLevel);
+ }
+
+ // Check for more stronger reset level
+ if( 0 != lpc_slave_stat.lbus2opberr )
+ {
+ errorFound = true;
+ // All of these errors require the SFC Local Bus Reset
+ o_resetLevel = RESET_SFC_LOCAL_BUS;
+
+ if ( LBUS2OPB_ADDR_PARITY_ERR == lpc_slave_stat.lbus2opberr )
+ {
+ // This error also requires LPC Slave Errors to be Cleared
+ o_resetLevel = RESET_SFCBUS_LPCSLAVE_ERRS;
+ TRACFCOMP( g_trac_pnor, ERR_MRK"SfcIBM::checkForErrors> LBUS2OPB Address Parity Error: LPC Slave status reg: 0x%08llx, ResetLevel=%d",
+ lpc_slave_stat.data32, o_resetLevel);
+
+ }
+
+ else if ( LBUS2OPB_INVALID_SELECT_ERR == lpc_slave_stat.lbus2opberr)
+ {
+ TRACFCOMP( g_trac_pnor, ERR_MRK"SfcIBM::checkForErrors> LBUS2OPB Invalid Select Error: LPC Slave status reg: 0x%08llx, ResetLevel=%d",
+ lpc_slave_stat.data32, o_resetLevel);
+
+ }
+ else if ( LBUS2OPB_DATA_PARITY_ERR == lpc_slave_stat.lbus2opberr )
+ {
+ // This error also requires LPC Slave Errors to be Cleared
+ o_resetLevel = RESET_SFCBUS_LPCSLAVE_ERRS;
+ TRACFCOMP( g_trac_pnor, ERR_MRK"SfcIBM::checkForErrors> LBUS2OPB Data Parity Error: LPC Slave status reg: 0x%08llx, ResetLevel=%d",
+ lpc_slave_stat.data32, o_resetLevel);
+
+ }
+ else if ( LBUS2OPB_MONITOR_ERR == lpc_slave_stat.lbus2opberr )
+ {
+ TRACFCOMP( g_trac_pnor, ERR_MRK"SfcIBM::checkForErrors> LBUS2OPB Monitor Error: LPC Slave status reg: 0x%08llx, ResetLevel=%d",
+ lpc_slave_stat.data32, o_resetLevel);
+
+ }
+
+ else if ( LBUS2OPB_TIMEOUT_ERR == lpc_slave_stat.lbus2opberr )
+ {
+ TRACFCOMP( g_trac_pnor, ERR_MRK"SfcIBM::checkForErrors> LBUS2OPB Timeout Error: LPC Slave status reg: 0x%08llx, ResetLevel=%d",
+ lpc_slave_stat.data32, o_resetLevel);
+
+ }
+ else
+ {
+ // Just in case, clear LPC Slave Errors
+ o_resetLevel = RESET_LPC_SLAVE_ERRS;
+ TRACFCOMP( g_trac_pnor, ERR_MRK"SfcIBM::checkForErrors> LBUS2OPB UNKNOWN Error: LPC Slave status reg: 0x%08llx, ResetLevel=%d",
+ lpc_slave_stat.data32, o_resetLevel);
+ }
+
+ }
+
+ // Second Read SFC and check for error bits
+ l_err = readReg(SFC_CMD_SPACE,
+ SFC_REG_STATUS,
+ sfc_stat.data32);
+
+ // If we can't read status register, exit out
+ if( l_err ) { break; }
+
+ TRACDCOMP( g_trac_pnor, INFO_MRK"SfcIBM::checkForErrors> SFC status reg(0x%X): 0x%08llx",
+ SFC_CMD_SPACE|SFC_REG_STATUS,sfc_stat.data32);
+
+ // No resets needed for these errors
+ if( 1 == sfc_stat.eccerrcntr )
+ {
+ errorFound = true;
+ TRACFCOMP( g_trac_pnor, ERR_MRK"SfcIBM::checkForErrors> Threshold of SRAM ECC Errors Reached: SFC status reg: 0x%08llx, ResetLevel=%d",
+ sfc_stat.data32, o_resetLevel);
+ }
+
+ if( 1 == sfc_stat.eccues )
+ {
+ errorFound = true;
+ TRACFCOMP( g_trac_pnor, ERR_MRK"SfcIBM::checkForErrors> SRAM Command Uncorrectable ECC Error: SFC status reg: 0x%08llx, ResetLevel=%d",
+ sfc_stat.data32, o_resetLevel);
+ }
+
+ if( 1 == sfc_stat.illegal )
+ {
+ errorFound = true;
+ TRACFCOMP( g_trac_pnor, ERR_MRK"SfcIBM::checkForErrors> Previous Operation was Illegal: SFC status reg: 0x%08llx, ResetLevel=%d",
+ sfc_stat.data32, o_resetLevel);
+ }
+
+ if( 1 == sfc_stat.eccerrcntn )
+ {
+ errorFound = true;
+ TRACFCOMP( g_trac_pnor, ERR_MRK"SfcIBM::checkForErrors> Threshold for Flash ECC Errors Reached: SFC status reg: 0x%08llx, ResetLevel=%d",
+
+ sfc_stat.data32, o_resetLevel);
+ }
+
+ if( 1 == sfc_stat.eccuen )
+ {
+ errorFound = true;
+ TRACFCOMP( g_trac_pnor, ERR_MRK"SfcIBM::checkForErrors> Flash Command Uncorrectable ECC Error: SFC status reg: 0x%08llx, ResetLevel=%d",
+ sfc_stat.data32, o_resetLevel);
+ }
+
+ if( 1 == sfc_stat.timeout )
+ {
+ errorFound = true;
+ TRACFCOMP( g_trac_pnor, ERR_MRK"SfcIBM::checkForErrors> Timeout: SFC status reg: 0x%08llx, ResetLevel=%d",
+ sfc_stat.data32, o_resetLevel);
+ }
+
+ }while(0);
+
+
+ // If there is any error create an error log
+ if ( errorFound )
+ {
+ // If we failed on a register read above, but still found an error,
+ // delete register read error log and create an original error log
+ // for the found error
+ if ( l_err )
+ {
+ TRACFCOMP( g_trac_pnor, ERR_MRK"SfcIBM::checkForErrors> Deleting register read error. Returning error created for the found error");
+ delete l_err;
+ }
+
+
+ /*@
+ * @errortype
+ * @moduleid PNOR::MOD_SFCIBM_CHECKFORERRORS
+ * @reasoncode PNOR::RC_ERROR_IN_STATUS_REG
+ * @userdata1[0:31] SFC Status Register
+ * @userdata1[32:63] LPC Slave Status Register
+ * @userdata2 Reset Level
+ * @devdesc SfcIBM::checkForErrors> Error(s) found in SFC
+ * and/or LPC Slave Status Registers
+ * @custdesc A problem occurred while accessing the boot flash.
+ */
+ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ PNOR::MOD_SFCIBM_CHECKFORERRORS,
+ PNOR::RC_ERROR_IN_STATUS_REG,
+ TWO_UINT32_TO_UINT64(
+ sfc_stat.data32,
+ lpc_slave_stat.data32),
+ o_resetLevel );
+
+ // Limited in callout: no PNOR target, so calling out processor
+ l_err->addHwCallout(
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ HWAS::SRCI_PRIORITY_HIGH,
+ HWAS::NO_DECONFIG,
+ HWAS::GARD_NULL );
+
+ addFFDC(l_err);
+ l_err->collectTrace(PNOR_COMP_NAME);
+ }
+
+ return l_err;
+
+}
+
+/**
+ * @brief Add FFDC Error Registers to an existing Error Log
+ */
+void SfcIBM::addFFDC(errlHndl_t & io_errl)
+{
+ errlHndl_t tmp_err = NULL;
+ uint32_t data32 = 0;
+ size_t size32 = sizeof(data32);
+
+ // check iv_ffdcActive to avoid infinite loops
+ if ( iv_ffdcActive == false )
+ {
+ iv_ffdcActive = true;
+
+ TRACFCOMP( g_trac_pnor, ENTER_MRK"SfcIBM::addFFDC> adding FFDC to Error Log EID=0x%X, PLID=0x%X", io_errl->eid(), io_errl->plid() );
+
+ ERRORLOG::ErrlUserDetailsLogRegister l_eud(iv_proc);
+
+ // Add LPC Slave Status Register
+ LpcSlaveStatReg_t lpc_slave_stat;
+ tmp_err = readReg(SFC_LPC_SPACE,
+ LPC_SLAVE_REG_STATUS,
+ lpc_slave_stat.data32);
+ if ( tmp_err )
+ {
+ delete tmp_err;
+ TRACFCOMP( g_trac_pnor, "SfcIBM::addFFDC> Fail reading LPC Slave Status Register");
+ }
+ else
+ {
+ LPC::TransType lpc_range;
+ uint32_t lpc_addr;
+ sfc2lpc( SFC_LPC_SPACE, LPC_SLAVE_REG_STATUS,
+ lpc_range, lpc_addr );
+ l_eud.addDataBuffer(&lpc_slave_stat.data32, size32,
+ DEVICE_LPC_ADDRESS( lpc_range,
+ lpc_addr ) );
+ }
+
+ // Add SFC Registers
+ uint32_t sfc_regs[] = {
+ SFC_REG_STATUS,
+ SFC_REG_CONF,
+ SFC_REG_CMD,
+ SFC_REG_ADR,
+ SFC_REG_ERASMS,
+ SFC_REG_ERASLGS,
+ SFC_REG_CONF4,
+ SFC_REG_CONF5,
+ SFC_REG_ADRCBF,
+ SFC_REG_ADRCMF,
+ SFC_REG_OADRNB,
+ SFC_REG_OADRNS,
+ SFC_REG_CHIPIDCONF,
+ SFC_REG_ERRCONF,
+ SFC_REG_ERRTAG,
+ SFC_REG_ERROFF,
+ SFC_REG_ERRSYN,
+ SFC_REG_ERRDATH,
+ SFC_REG_ERRDATL,
+ SFC_REG_ERRCNT,
+ SFC_REG_CLRCNT,
+ SFC_REG_ERRINJ,
+ SFC_REG_PROTA,
+ SFC_REG_PROTM,
+ SFC_REG_ECCADDR,
+ SFC_REG_ECCRNG,
+ SFC_REG_ERRORS,
+ SFC_REG_INTMSK,
+ SFC_REG_INTENM,
+ SFC_REG_CONF2,
+ SFC_REG_CONF3
+ };
+
+
+ for( size_t x=0; x<(sizeof(sfc_regs)/sizeof(sfc_regs[0])); x++ )
+ {
+ tmp_err = readReg( SFC_CMD_SPACE,
+ sfc_regs[x],
+ data32 );
+
+ if( tmp_err )
+ {
+ delete tmp_err;
+ }
+ else
+ {
+ LPC::TransType lpc_range;
+ uint32_t lpc_addr;
+ sfc2lpc( SFC_CMD_SPACE, sfc_regs[x],
+ lpc_range, lpc_addr );
+ l_eud.addDataBuffer(&data32, size32,
+ DEVICE_LPC_ADDRESS(lpc_range,lpc_addr));
+ }
+ }
+
+ l_eud.addToLog(io_errl);
+
+ TRACFCOMP( g_trac_pnor, EXIT_MRK"SfcIBM::addFFDC> Information added to error log");
+
+ // reset FFDC active flag
+ iv_ffdcActive = false;
+ }
+
+ return;
+}
+
+
+/**
+ * @brief Send a user-defined SPI command
+ */
+errlHndl_t SfcIBM::sendSpiCmd( uint8_t i_opCode,
+ uint32_t i_address,
+ size_t i_writeCnt,
+ const uint8_t* i_writeData,
+ size_t i_readCnt,
+ uint8_t* o_readData )
+{
+ errlHndl_t errhdl = NULL;
+
+ do {
+#ifdef CONFIG_ALLOW_MICRON_PNOR
+ //Do a read of flash address zero to workaround
+ // a micron bug with extended reads
+ if( (PNOR::HWWK_MICRON_EXT_READ & iv_flashWorkarounds)
+ && (i_readCnt > 4) )
+ {
+ uint32_t ignored = 0;
+ errhdl = readFlash( 0, 1, &ignored );
+ if(errhdl) { break; }
+ }
+#endif
+
+ //Configure the custom command definition
+ SfcCustomReg_t confreg;
+ confreg.opcode = i_opCode;
+ confreg.length = i_writeCnt;
+ confreg.write = 1;
+ if( i_readCnt > 0 )
+ {
+ confreg.length = i_readCnt;
+ confreg.read = 1;
+ confreg.write = 0;
+ }
+
+ //Setup the address if needed
+ if( i_address != NO_ADDRESS )
+ {
+ confreg.needaddr = 1;
+ errhdl = writeReg(SFC_CMD_SPACE,
+ SFC_REG_ADR,
+ i_address);
+ if( errhdl ) { break; }
+ }
+
+ //@fixme-RTC:109860 - handle write data someday (no current need)
+ assert( i_writeCnt == 0 );
+
+ //Setup the custom command reg
+ errhdl = writeReg(SFC_CMD_SPACE,
+ SFC_REG_CHIPIDCONF,
+ confreg.data32);
+ if( errhdl ) { break; }
+
+ //Issue Get Chip ID command
+ SfcCmdReg_t sfc_cmd;
+ sfc_cmd.opcode = SFC_OP_CHIPID;
+ sfc_cmd.length = 0;
+ errhdl = writeReg(SFC_CMD_SPACE,
+ SFC_REG_CMD,
+ sfc_cmd.data32);
+ if( errhdl ) { break; }
+
+ //Poll for complete status
+ errhdl = pollOpComplete();
+ if( errhdl ) { break; }
+
+ //Return the data if this is a read
+ if( i_readCnt > 0 )
+ {
+ //Read the Status from the Command Buffer
+ errhdl = readFromBuffer( i_readCnt, o_readData );
+ if(errhdl) { break; }
+ }
+ } while(0);
+
+
+ return errhdl;
+}
+
+/**
+ * @brief Return first 3 bytes of NOR chip id
+ * @return Error from operation
+ */
+errlHndl_t SfcIBM::getNORChipId( uint32_t& o_chipId )
+{
+ errlHndl_t l_err = NULL;
+ TRACFCOMP( g_trac_pnor, "SfcIBM::getNORChipId>" );
+
+ do {
+ if( iv_norChipId != PNOR::UNKNOWN_NOR_ID )
+ {
+ o_chipId = iv_norChipId;
+ break;
+ }
+
+ //Configure Get Chip ID opcode
+ uint32_t confData = SPI_JEDEC_CHIPID << 24;
+ confData |= 0x00800003; // 8-> read, 3->3 bytes
+ TRACDCOMP( g_trac_pnor, "SfcIBM::getNORChipId> confData=0x%.8x",
+ confData );
+ l_err = writeReg(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 = writeReg(SFC_CMD_SPACE,
+ SFC_REG_CMD,
+ sfc_cmd.data32);
+ if(l_err) { break; }
+
+ //Poll for complete status
+ l_err = pollOpComplete();
+ if(l_err) { break; }
+
+ //Read the ChipID from the Command Buffer
+ l_err = readReg(SFC_CMDBUF_SPACE,
+ 0, //Offset into CMD BUFF space in bytes
+ o_chipId);
+ if(l_err) { break; }
+
+ // Only look at a portion of the data that is returned
+ o_chipId &= ID_MASK;
+ iv_norChipId = o_chipId;
+ } while(0);
+
+ return l_err;
+
+}
+
+
+/**
+ * @brief Reset hardware to get into clean state
+ */
+errlHndl_t SfcIBM::hwReset( ResetLevels i_resetLevel )
+{
+ errlHndl_t l_err = NULL;
+
+ // @todo RTC 109999 - Skipping because SFC resets can
+ // cause problems on subsequent reads and writes
+ TRACFCOMP(g_trac_pnor, "SfcIBM::hwReset> Skipping reset");
+#if 0
+
+ // check iv_reset_active to avoid infinite loops
+ // and don't reset if in the middle of FFDC collection
+ if ( ( iv_resetActive == false ) &&
+ ( iv_ffdcActive == false ) )
+ {
+ iv_resetActive = true;
+
+ TRACFCOMP(g_trac_pnor, "SfcIBM::hwReset> i_pnorResetLevel=0x%.8X", i_resetLevel);
+
+ do {
+ // 32 bits for address and data for LPC operations
+ uint32_t lpc_data=0;
+ size_t reg_size = sizeof(uint32_t);
+
+ /***************************************/
+ /* Handle the different reset levels */
+ /***************************************/
+ switch(i_resetLevel)
+ {
+ case RESET_CLEAR:
+ {// Nothing to do here, so just break
+ break;
+ }
+
+ case RESET_LPC_SLAVE:
+ {
+ TRACFCOMP(g_trac_pnor, "SfcIBM::hwReset> Writing bit0 of LPC_SLAVE_REG_RESET to reset LPC Slave Logic");
+ lpc_data = 0x80000000;
+ l_err = deviceOp( DeviceFW::WRITE,
+ iv_proc,
+ &lpc_data,
+ reg_size,
+ DEVICE_LPC_ADDRESS(LPC::TRANS_REG,
+ LPC_SLAVE_REG_RESET) );
+ break;
+ }
+
+ case RESET_LPC_SLAVE_ERRS:
+ {
+ TRACFCOMP(g_trac_pnor, "SfcIBM::hwReset> Writing bit1 of LPC_SLAVE_REG_RESET to reset LPC Slave Errors");
+ lpc_data = 0x40000000;
+ l_err = deviceOp( DeviceFW::WRITE,
+ iv_proc,
+ &lpc_data,
+ reg_size,
+ DEVICE_LPC_ADDRESS(LPC::TRANS_REG,
+ LPC_SLAVE_REG_RESET) );
+ break;
+ }
+
+ case RESET_SFC_LOCAL_BUS:
+ {
+ TRACFCOMP(g_trac_pnor, "SfcIBM::hwReset> Writing bit2 of LPC_SLAVE_REG_RESET to reset Local SFC Bus. Requires PNOR reinitialization");
+ lpc_data = 0x20000000;
+ l_err = deviceOp( DeviceFW::WRITE,
+ iv_proc,
+ &lpc_data,
+ reg_size,
+ DEVICE_LPC_ADDRESS(LPC::TRANS_REG,
+ LPC_SLAVE_REG_RESET) );
+ if (l_err) { break; }
+
+ l_err = hwInit();
+ break;
+ }
+
+ case RESET_SFCBUS_LPCSLAVE_ERRS:
+ {
+ // Must handle both errors
+ TRACFCOMP(g_trac_pnor, "SfcIBM::hwReset> Writing bits1,2 of LPC_SLAVE_REG_RESET to reset LPC Slave Errors and Local SFC Bus. Requires PNOR reinitialization");
+ lpc_data = 0x60000000;
+ l_err = deviceOp( DeviceFW::WRITE,
+ iv_proc,
+ &lpc_data,
+ reg_size,
+ DEVICE_LPC_ADDRESS(LPC::TRANS_REG,
+ LPC_SLAVE_REG_RESET) );
+ if (l_err) { break; }
+
+ l_err = hwInit();
+ break;
+ }
+
+ // else - unsupported reset level
+ default:
+ {
+
+ TRACFCOMP( g_trac_pnor, ERR_MRK"SfcIBM::hwReset> Unsupported Reset Level Passed In: 0x%X", i_resetLevel);
+
+ /*@
+ * @errortype
+ * @moduleid PNOR::MOD_SFCIBM_HWRESET
+ * @reasoncode PNOR::RC_UNSUPPORTED_OPERATION
+ * @userdata1 Unsupported Reset Level Parameter
+ * @userdata2 <unused>
+ * @devdesc SfcIBM::hwReset> Unsupported Reset
+ * Level requested
+ */
+ l_err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ PNOR::MOD_SFCIBM_HWRESET,
+ PNOR::RC_UNSUPPORTED_OPERATION,
+ i_resetLevel,
+ 0,
+ true /*SW error*/);
+
+ l_err->collectTrace(PNOR_COMP_NAME);
+ break;
+ }
+ }// end switch
+
+ if ( l_err )
+ {
+ // Indicate that we weren't successful in resetting PNOR
+ TRACFCOMP( g_trac_pnor,ERR_MRK"SfcIBM::hwReset>> Fail doing PNOR reset at level 0x%X (recovery count=%d): eid=0x%X", i_resetLevel, iv_errorHandledCount, l_err->eid());
+ }
+ else
+ {
+ // Successful, so increment recovery count
+ iv_errorHandledCount++;
+
+ TRACFCOMP( g_trac_pnor,INFO_MRK"SfcIBM::hwReset>> Successful PNOR reset at level 0x%X (recovery count=%d)", i_resetLevel, iv_errorHandledCount);
+ }
+
+
+ } while(0);
+
+ // reset RESET active flag
+ iv_resetActive = false;
+ }
+
+#endif
+
+ return l_err;
+}
+
diff --git a/src/usr/pnor/sfc_ibm.H b/src/usr/pnor/sfc_ibm.H
new file mode 100644
index 000000000..03ce0b772
--- /dev/null
+++ b/src/usr/pnor/sfc_ibm.H
@@ -0,0 +1,502 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/pnor/sfc_ibm.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2014 */
+/* [+] Google Inc. */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __PNOR_SFC_IBM_H
+#define __PNOR_SFC_IBM_H
+
+#include <limits.h>
+#include <targeting/common/targetservice.H>
+#include <errl/errlentry.H>
+#include <lpc/lpcif.H>
+#include "sfcdd.H"
+
+/** @file sfc_ibm.H
+ * @brief Provides the logic to access and configure the
+ * IBM Serial Flash Controller which provides access
+ * to the PNOR
+ */
+
+/**
+ * @brief IBM SFC Device Driver Class
+ * Provides the logic to access and configure the
+ * IBM Serial Flash Controller which provides access
+ * to the PNOR
+ */
+class SfcIBM : public SfcDD
+{
+
+ public: //SfcDD methods
+ /**
+ * @brief Initialize the SFC Hardware
+ *
+ * @return void
+ */
+ virtual errlHndl_t hwInit();
+
+ /**
+ * @brief Return first 3 bytes of NOR chip id
+ *
+ * @parm[out] NOR chip id
+ *
+ * @return Error from operation
+ */
+ virtual errlHndl_t getNORChipId( uint32_t& o_chipId );
+
+ /**
+ * @brief Read data from the PNOR flash
+ *
+ * @parm i_addr PNOR flash Address to read
+ * @parm i_size Amount of data to read, in bytes.
+ * @parm o_data Buffer to read data into
+ *
+ * @return Error from operation
+ */
+ virtual errlHndl_t readFlash(uint32_t i_addr,
+ size_t i_size,
+ void* o_data);
+
+ /**
+ * @brief Write data to the PNOR flash
+ *
+ * @parm i_addr PNOR flash Address to write
+ * @parm i_size Amount of data to write, in bytes.
+ * @parm i_data Buffer containing data to write
+ *
+ * @return Error from operation
+ */
+ virtual errlHndl_t writeFlash(uint32_t i_addr,
+ size_t i_size,
+ void* i_data);
+
+ /**
+ * @brief Erase a block of flash
+ *
+ * @parm i_address Offset into flash to erase, aligned to erase block
+ *
+ * @return Error from operation
+ */
+ virtual errlHndl_t eraseFlash(uint32_t i_address);
+
+ /**
+ * @brief Send a user-defined SPI command
+ *
+ * @parm[in] i_opCode: command to send into controller first
+ * @parm[in] i_address: address for those commands that need it
+ * @parm[in] i_writeCnt: number of bytes to write to device
+ * @parm[in] i_writeData: write data buffer
+ * @parm[in] i_readCnt: number of bytes to read from device
+ * @parm[out] o_readData: read data buffer
+ *
+ * @return Error from operation
+ */
+ virtual errlHndl_t sendSpiCmd( uint8_t i_opCode,
+ uint32_t i_address,
+ size_t i_writeCnt,
+ const uint8_t* i_writeData,
+ size_t i_readCnt,
+ uint8_t* o_readData );
+
+ /**
+ * @brief Add error registers to an existing Error Log
+ *
+ * @param[in] io_errhdl: Error log to add data to
+ */
+ virtual void addFFDC( errlHndl_t& io_errhdl );
+
+ public: //SfcIBM methods
+ /**
+ * @brief Constructor
+ * @param[out] Return any error in constructor
+ * @param[in] Processor target associated with the LPC master
+ */
+ SfcIBM( errlHndl_t& o_err,
+ TARGETING::Target* i_proc
+ = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL );
+
+
+ protected: //SfcDD methods
+
+ /**
+ * @brief Reset hardware to get into clean state
+ *
+ * @parm i_resetLevel How much SFC logic to reset
+ *
+ * @return errlHndl_t NULL on success, else error log
+ */
+ virtual errlHndl_t hwReset( ResetLevels i_resetLevel );
+
+
+ protected: //SfcIBM stuff
+
+ /** @brief General constants */
+ enum
+ {
+ /** @brief SFC Command buffer is 0x100/256 bytes/0x40 words */
+ SFC_CMDBUF_SIZE = 256,
+
+ //@todo-RTC:95125 Find out Max time to wait
+ /** @brief Max time to wait for SFC op to complete */
+ SFC_POLL_TIME_NS = 1000000000,
+
+ /** @brief Minimum increment during poll for complete */
+ SFC_POLL_INCR_NS = 10,
+
+ /** @brief Offset to SFC command regs, from FW base */
+ SFC_CMDREG_OFFSET = 0x00000C00,
+
+ /** @brief Offset to SFC buffer space, from FW base */
+ SFC_CMDBUF_OFFSET = 0x00000D00,
+
+ /** @brief Offset to SFC direct read space, from FW base */
+ SFC_MMIO_OFFSET = 0x0C000000,
+ };
+
+ /**
+ * @brief SFC Op Codes
+ * OP Codes for the SFC Command Register
+ */
+ enum SfcOpCodes {
+ SFC_OP_READRAW = 0x03, /**< Read Raw */
+ SFC_OP_WRITERAW = 0x02, /**< Write Raw */
+ SFC_OP_ERASM = 0x32, /**< Erase Small */
+ SFC_OP_ERALG = 0x34, /**< Erase Large */
+ SFC_OP_ENWRITPROT = 0x53, /**< Enable WRite Protect */
+ SFC_OP_CHIPID = 0x1F, /**< Get Chip ID */
+ SFC_OP_STATUS = 0x05, /**< Get Status */
+ SFC_OP_TURNOFF = 0x5E, /**< Turn Off */
+ SFC_OP_TURNON = 0x50, /**< Turn On */
+ SFC_OP_ABORT = 0x6F, /**< Super-Abort */
+ SFC_OP_START4BA = 0x37, /**< Start 4BA */
+ SFC_OP_END4BA = 0x69, /**< End 4BA */
+ SFC_OP_INVALID = 0x00, /**< Invalid - used for testing */
+ };
+
+ //@fixme-RTC:109860 : Create structures for this data
+#define SFC_REG_SPICLK_OUTDLY_SHFT 24
+#define SFC_REG_SPICLK_INSAMPDLY_SHFT 16
+#define SFC_REG_SPICLK_CLKHI_SHFT 8
+#define SFC_REG_SPICLK_CLKLO_SHFT 0
+#define SFC_REG_CONF8_CSINACTIVEREAD_SHFT 18
+#define SFC_REG_CONF8_DUMMY_SHFT 8
+#define SFC_REG_CONF8_READOP_SHFT 0
+
+ /**
+ * @brief Ranges of SFC addresses
+ */
+ enum SfcRange {
+ SFC_CMD_SPACE, /**< Indicate accessing command reg */
+ SFC_CMDBUF_SPACE, /**< Indicate accessing command buffer space */
+ SFC_MMIO_SPACE, /**< Indicate accessing MMIO based Direct Reads */
+ SFC_LPC_SPACE, /**< Indicate LPC Slave Space */
+ };
+
+
+ /**
+ * @brief SFC Registers
+ * These are offsets within the SFC Register Space
+ */
+ enum SfcRegAddr {
+ SFC_REG_CONF = 0x10, /**< CONF: Direct Access Configuration */
+ SFC_REG_STATUS = 0x0C, /**< STATUS : Status Reg */
+ SFC_REG_SPICLK = 0x3C, /**< SPICLK : SPI clock rate config */
+ SFC_REG_CMD = 0x40, /**< CMD : Command */
+ SFC_REG_ADR = 0x44, /**< ADR : Address */
+ SFC_REG_ERASMS = 0x48, /**< ERASMS : Small Erase Block Size */
+ SFC_REG_ERASLGS = 0x4C, /**< ERALGS : Large Erase Block Size */
+ SFC_REG_CONF4 = 0x54, /**< CONF4 : SPI Op Code for Small Erase */
+ SFC_REG_CONF5 = 0x58, /**< CONF5 : Small Erase Size config reg */
+ SFC_REG_CONF8 = 0x64, /**< CONF8 : Read Command */
+ SFC_REG_ADRCBF = 0x80, /**< ADRCBF : First Intf NOR Addr Offset */
+ SFC_REG_ADRCMF = 0x84, /**< ADRCMF : First Intf NOR Allocation */
+ SFC_REG_ADRCBS = 0x88, /**< ADRCBS : Second Intf NOR Addr Offset */
+ SFC_REG_ADRCMS = 0x8C, /**< ADRCMS : Second Intf NOR Allocation */
+ SFC_REG_OADRNB = 0x90, /**< OADRNB : Direct Access OBP Window Base Address */
+ SFC_REG_OADRNS = 0x94, /**< OADRNS : DIrect Access OPB Window Size */
+ SFC_REG_CHIPIDCONF = 0x9C, /**< CHIPIDCONF : config ChipId CMD */
+ SFC_REG_ERRCONF = 0x6C, /**< ERRCONF : Configures error counts that
+ cause interupts */
+ SFC_REG_ERRTAG = 0x1C, /**< ERRTAG : Holds Control Info of Error */
+ SFC_REG_ERROFF = 0x20, /**< ERROFF : Holds Address Info of Error */
+ SFC_REG_ERRSYN = 0x24, /**< ERRSYN : Holds Syndrome That Caused Error*/
+ SFC_REG_ERRDATH = 0x28, /**< ERRDATH : Holds Most Signifcant Word of
+ Double Word That Caused Error */
+ SFC_REG_ERRDATL = 0x2C, /**< ERRDATL : Holds Least Signifcant Word of
+ Double Word That Caused Error */
+ SFC_REG_ERRCNT = 0x30, /**< ERRCNT : Counts The Number Of Errors */
+ SFC_REG_CLRCNT = 0x34, /**< CLRCNT : Which Bits To Clear In ERRCNT */
+ SFC_REG_ERRINJ = 0x38, /**< ERRINJ : Force Errors Into Read Paths */
+ SFC_REG_PROTA = 0x70, /**< PROTA : Write Protect Range Address Base */
+ SFC_REG_PROTM = 0x74, /**< PROTM : Write Protect Range Size */
+ SFC_REG_ECCADDR = 0x78, /**< ECCADDR : ECC Disable Range Base Address */
+ SFC_REG_ECCRNG = 0x7C, /**< ECCRNG : ECC Disable Range Size */
+ SFC_REG_ERRORS = 0x00, /**< ERRORS : Collection of Error Status Bits */
+ SFC_REG_INTMSK = 0x04, /**< INTMSK : Record of Events That Could Lead
+ To Interupt */
+ SFC_REG_INTENM = 0x14, /**< INTENM : Controls Which Events Lead
+ To Interupts */
+ SFC_REG_CONF2 = 0x18, /**< CONF2 : SPI Configuration */
+ SFC_REG_CONF3 = 0x50, /**< CONF3 : SPI Recovery */
+
+ };
+
+ /**
+ * @brief LPC Slave Registers
+ * These are offsets within the LPC Slave Register Space
+ */
+ enum LpcSlaveRegAddr
+ {
+ LPC_SLAVE_REG_STATUS = 0x14, /**< STATUS: read-only */
+ LPC_SLAVE_REG_RESET = 0x14, /**< RESET : write-only */
+ };
+
+ /**
+ * @brief LPC Slave Status Register Layout
+ */
+ union LpcSlaveStatReg_t
+ {
+ uint32_t data32;
+ struct
+ {
+ uint32_t lbusowner : 2; /**< 0:1 = Local Bus Owner */
+ uint32_t lbusparityerror : 1; /**< 2 = Local Bus Parity Error */
+ uint32_t lbus2opberr : 3; /**< 3:5 = Errors From LBUS2OPB */
+ uint32_t unused : 26; /**< 6:21 = Not Currently Used */
+ };
+ LpcSlaveStatReg_t() : data32(0) {};
+ };
+
+ /**
+ * @brief LPC Slave Reset Register Layout
+ */
+ union LpcSlaveResetReg_t
+ {
+ uint32_t data32;
+ struct
+ {
+ uint32_t lpcslave : 1; /**< 0 Reset LPC Slave */
+ uint32_t lpcslaveerrs : 1; /**< 1 Reset LPC Slave Errors */
+ uint32_t localbus : 1; /**< 2 Reset Local Bus */
+ uint32_t unused : 29; /**< 4:31 = Not Currently Used */
+ };
+ LpcSlaveResetReg_t() : data32(0) {};
+ };
+
+
+ /**
+ * @brief LPC Slave LBUS2OPB Errors
+ * Translation of LPC Slave Status Register Bits 3:5
+ */
+ enum LpcSlaveLbus2OpbErrors {
+ LBUS2OPB_ADDR_PARITY_ERR = 0b010, /**< Address Parity Error */
+ LBUS2OPB_INVALID_SELECT_ERR = 0b001, /**< Invalid Select Error */
+ LBUS2OPB_DATA_PARITY_ERR = 0b011, /**< Data Parity Error */
+ LBUS2OPB_MONITOR_ERR = 0b100, /**< Monitor Error */
+ LBUS2OPB_TIMEOUT_ERR = 0b101, /**< Timeout Error */
+ };
+
+
+
+
+ /**
+ * @brief SFC Command Register Layout
+ */
+ union SfcCmdReg_t
+ {
+ uint32_t data32;
+ struct
+ {
+ uint32_t reserved : 16; /**< 0:15 = Reserved */
+ uint32_t opcode : 7; /**< 16:22 = OpCode */
+ uint32_t length : 9; /**< 22:31 = Num bytes for Read/Write Raw */
+ };
+ SfcCmdReg_t() : data32(0) {};
+ };
+
+
+ /**
+ * @brief SFC Status Register Layout
+ */
+ union SfcStatReg_t
+ {
+ uint32_t data32;
+ struct
+ {
+ uint32_t unused : 20; /**< 0:19 = Not Currently Used */
+ uint32_t eccerrcntr : 1; /**< 20 Threshold for SRAM ECC errors */
+ uint32_t eccues : 1; /**< 21 SRAM cmd uncorrectable ECC error*/
+ uint32_t unused_22 : 3; /**< 22:24 = Not Currently Used */
+ uint32_t cmdexe : 1; /**< 25 Previous cmd is in progress */
+ uint32_t cmdwait : 1; /**< 26 Previous cmd waiting to execute */
+ uint32_t illegal : 1; /**< 27 Previous op illegal */
+ uint32_t eccerrcntn : 1; /**< 28 Threshold for Flash ECC errors */
+ uint32_t eccuen : 1; /**< 29 Flash cmd uncorrectable ECC err */
+ uint32_t timeout : 1; /**< 30 Timeout */
+ uint32_t done : 1; /**< 31 Done */
+ };
+ SfcStatReg_t() : data32(0) {};
+ };
+
+
+ /**
+ * @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
+ *
+ * @parm i_range SFC Address Range
+ * @parm i_addr SFC Register to write
+ * @parm i_data Data to write
+ *
+ * @return Error from operation
+ */
+ errlHndl_t writeReg(SfcRange i_range,
+ uint32_t i_addr,
+ uint32_t i_data);
+
+ /**
+ * @brief Read a SFC Register
+ *
+ * @parm i_range SFC Address Range
+ * @parm i_addr SFC Register to read
+ * @parm o_data Data to write
+ *
+ * @return Error from operation
+ */
+ errlHndl_t readReg(SfcRange i_range,
+ uint32_t i_addr,
+ uint32_t& o_data);
+
+ /**
+ * @brief Poll for SFC operation to complete and look for
+ * errors
+ *
+ * @return Error from operation
+ */
+ errlHndl_t pollOpComplete( void );
+
+ /**
+ * @brief Load SFC command buffer with data from PNOR
+ *
+ * @parm i_addr PNOR flash Address to read
+ * @parm i_size Number of bytes to read.to command buffer
+ *
+ * @return Error from operation
+ */
+ errlHndl_t loadSfcBuf(uint32_t i_addr,
+ size_t i_size);
+
+ /**
+ * @brief Flush SFC command buffer contents out to PNOR Flash
+ *
+ * @parm[in] i_addr PNOR flash Address to write
+ * @parm[in] i_size Number of bytes to write.to command buffer
+ *
+ * @return Error from operation
+ */
+ errlHndl_t flushSfcBuf(uint32_t i_addr,
+ size_t i_size);
+
+ /**
+ * @brief Read data in SFC Command buffer and put into buffer
+ *
+ * @parm[in] i_size Amount of data in Cmd Buffer to read, in bytes.
+ * @parm[out] o_data Buffer to read data into
+ *
+ * @return Error from operation
+ */
+ errlHndl_t readFromBuffer(size_t i_size,
+ void* o_data);
+
+ /**
+ * @brief Write data into SFC Command buffer
+ *
+ * @parm[in] i_size Amount of data in Cmd Buffer to write, in bytes.
+ * @parm[out] o_data Buffer to read data from
+ *
+ * @return Error from operation
+ */
+ errlHndl_t writeIntoBuffer(size_t i_size,
+ void* i_data);
+
+ /**
+ * @brief Convert a SFC address to a LPC address
+ *
+ * @parm[in] i_sfcRange SFC Address range
+ * @parm[in] i_sfcAddr SFC Address relative to i_sfcRange
+ * @parm[out] o_lpcRange LPC Address type
+ * @parm[out] o_lpcAddr LPC Address relative to o_lpcRange
+ */
+ void sfc2lpc( SfcRange i_sfcRange,
+ uint32_t i_sfcAddr,
+ LPC::TransType& o_lpcRange,
+ uint32_t& o_lpcAddr );
+
+ /**
+ * @brief Check For Errors in SFC Status Registers
+ *
+ * @parm o_resetLevel if error, reset level to clear error
+ * @return Error log if error found
+ */
+ errlHndl_t checkForErrors( ResetLevels &o_resetLevel );
+
+
+ /**
+ * @brief Indicates if class is currently collecting FFDC data
+ */
+ bool iv_ffdcActive;
+
+ /**
+ * @brief Number of times recovered from an error
+ */
+ uint32_t iv_errorHandledCount;
+
+ /**
+ * @brief Indicates if class is currently doing a RESET procedure
+ */
+ bool iv_resetActive;
+
+
+ // Needed for testcases
+ friend class PnorDdTest;
+};
+
+
+#endif
diff --git a/src/usr/pnor/sfcdd.C b/src/usr/pnor/sfcdd.C
new file mode 100644
index 000000000..0aad547c1
--- /dev/null
+++ b/src/usr/pnor/sfcdd.C
@@ -0,0 +1,120 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/pnor/sfcdd.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2014 */
+/* [+] Google Inc. */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+/*****************************************************************************/
+// I n c l u d e s
+/*****************************************************************************/
+#include <sys/mmio.h>
+#include <sys/task.h>
+#include <sys/sync.h>
+#include <string.h>
+#include <devicefw/driverif.H>
+#include <trace/interface.H>
+#include <errl/errlentry.H>
+#include <errl/errlmanager.H>
+#include <errl/errludlogregister.H>
+#include <targeting/common/targetservice.H>
+#include <pnor/pnor_reasoncodes.H>
+#include <sys/time.h>
+#include <lpc/lpcif.H>
+#include "sfcdd.H"
+#include "norflash.H"
+
+
+/*****************************************************************************/
+// C o n s t a n t s
+/*****************************************************************************/
+
+
+
+
+/*****************************************************************************/
+// G l o b a l s
+/*****************************************************************************/
+
+// Initialized in pnorrp.C
+extern trace_desc_t* g_trac_pnor;
+
+
+/*****************************************************************************/
+// M e t h o d s
+/*****************************************************************************/
+
+/**
+ * @brief Constructor
+ */
+SfcDD::SfcDD( errlHndl_t& o_err,
+ TARGETING::Target* i_proc )
+: iv_proc(i_proc)
+, iv_flashWorkarounds(PNOR::HWWK_NO_WORKAROUNDS)
+, iv_norChipId(PNOR::UNKNOWN_NOR_ID)
+, iv_eraseSizeBytes(4*KILOBYTE) //default to 4KB blocks
+{
+ o_err = NULL;
+}
+
+/**
+ * @brief Destructor
+ */
+SfcDD::~SfcDD()
+{
+ // Nothing to do by default
+}
+
+/**
+ * @brief Read the NOR FLash ChipID
+ */
+errlHndl_t SfcDD::getNORChipId(uint32_t& o_chipId)
+{
+ errlHndl_t l_err = NULL;
+
+ if( iv_norChipId == PNOR::UNKNOWN_NOR_ID )
+ {
+ o_chipId = 0;
+ l_err = sendSpiCmd( PNOR::SPI_JEDEC_CHIPID,
+ SfcDD::NO_ADDRESS,
+ 0, NULL,
+ 4, reinterpret_cast<uint8_t*>(&o_chipId) );
+ if( !l_err )
+ {
+ // Only look at first 3 bytes of chipid
+ iv_norChipId = o_chipId & PNOR::ID_MASK;
+ }
+ }
+
+ o_chipId = iv_norChipId;
+ TRACFCOMP( g_trac_pnor, "SfcDD::getNORChipId> chipid=%.8X", o_chipId );
+ return l_err;
+}
+
+/**
+ * @brief Informs caller if PNORDD is using
+ * L3 Cache for fake PNOR or not.
+ */
+bool SfcDD::usingL3Cache( void )
+{
+ // by default we are not using the L3
+ return false;
+}
diff --git a/src/usr/pnor/sfcdd.H b/src/usr/pnor/sfcdd.H
new file mode 100644
index 000000000..7c27a1e00
--- /dev/null
+++ b/src/usr/pnor/sfcdd.H
@@ -0,0 +1,231 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/pnor/sfcdd.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2014 */
+/* [+] Google Inc. */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __PNOR_SFCDD_H
+#define __PNOR_SFCDD_H
+
+#include <limits.h>
+#include <targeting/common/targetservice.H>
+#include <errl/errlentry.H>
+
+/** @file sfc.H
+ * @brief Provides the logic to access and configure the
+ * Serial Flash Controller which provides access
+ * to the PNOR
+ */
+
+/**
+ * @brief SFC Device Driver Class
+ * Provides the logic to access and configure the
+ * Serial Flash Controller which provides access
+ * to the PNOR
+ */
+class SfcDD
+{
+
+ public:
+ /**
+ * @brief Initialize the SFC Hardware
+ *
+ * @return void
+ */
+ virtual errlHndl_t hwInit() = 0;
+
+ /**
+ * @brief Return first 3 bytes of NOR chip id
+ *
+ * @parm[out] NOR chip id
+ *
+ * @return Error from operation
+ */
+ virtual errlHndl_t getNORChipId( uint32_t& o_chipId );
+
+ /**
+ * @brief Return size of erase block in bytes
+ * @return Size of erase block in bytes
+ */
+ size_t eraseSizeBytes( void )
+ {
+ return iv_eraseSizeBytes;
+ };
+
+ /**
+ * @brief Read data from the PNOR flash
+ *
+ * @parm[in] i_addr PNOR flash Address to read
+ * @parm[in] i_size Amount of data to read, in bytes.
+ * @parm[out] o_data Buffer to read data into
+ *
+ * @return Error from operation
+ */
+ virtual errlHndl_t readFlash(uint32_t i_addr,
+ size_t i_size,
+ void* o_data) = 0;
+
+ /**
+ * @brief Write data to the PNOR flash
+ *
+ * @parm[in] i_addr PNOR flash Address to write
+ * @parm[in] i_size Amount of data to write, in bytes.
+ * @parm[in] i_data Buffer containing data to write
+ *
+ * @return Error from operation
+ */
+ virtual errlHndl_t writeFlash(uint32_t i_addr,
+ size_t i_size,
+ void* i_data) = 0;
+
+ /**
+ * @brief Erase a block of flash
+ *
+ * @parm[in] i_address Offset into flash to erase, aligned to erase block
+ *
+ * @return Error from operation
+ */
+ virtual errlHndl_t eraseFlash(uint32_t i_address) = 0;
+
+ /** @brief Constant for sendSpiCmd parameter */
+ static const uint32_t NO_ADDRESS = UINT32_MAX;
+
+ /**
+ * @brief Send a SPI command
+ *
+ * @parm[in] i_opCode: command to send into controller first
+ * @parm[in] i_address: address for those commands that need it
+ * @parm[in] i_writeCnt: number of bytes to write to device
+ * @parm[in] i_writeData: write data buffer
+ * @parm[in] i_readCnt: number of bytes to read from device
+ * @parm[out] o_readData: read data buffer
+ *
+ * @return Error from operation
+ */
+ virtual errlHndl_t sendSpiCmd( uint8_t i_opCode,
+ uint32_t i_address,
+ size_t i_writeCnt,
+ const uint8_t* i_writeData,
+ size_t i_readCnt,
+ uint8_t* o_readData ) = 0;
+
+ /**
+ * @brief Informs caller if PNORDD is using
+ * L3 Cache for fake PNOR or not.
+ *
+ * @return Indicate state of fake PNOR usage
+ * true = using L3 Cache for fake PNOR
+ * false = not using L3 Cache for fake PNOR
+ */
+ virtual bool usingL3Cache( void );
+
+ /**
+ * @brief Add error registers to an existing Error Log
+ *
+ * @param[in] io_errhdl: Error log to add data to
+ */
+ virtual void addFFDC( errlHndl_t& io_errhdl )
+ {
+ //do nothing by default
+ };
+
+ /**
+ * @brief Destructor
+ */
+ virtual ~SfcDD();
+
+ protected:
+ /**
+ * @brief Constructor
+ * @param[out] Return any error in constructor
+ * @param[in] Processor target associated with the LPC master
+ */
+ SfcDD( errlHndl_t& o_err,
+ TARGETING::Target* i_proc
+ = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL );
+
+
+ /**
+ * @brief Enums for different levels of resetting PNOR communication levels
+ */
+ enum ResetLevels
+ {
+ RESET_CLEAR = 0x00000000, /**< Clear Reset Level */
+ RESET_LPC_SLAVE = 0x00000008, /**< LPC Slave Logic on SFC */
+ RESET_LPC_SLAVE_ERRS = 0x00000010, /**< LPC Slave Errors on SFC */
+ RESET_SFC_LOCAL_BUS = 0x00000020, /**< SFC Local Bus */
+
+ // Known possible combination:
+ RESET_SFCBUS_LPCSLAVE_ERRS = RESET_LPC_SLAVE_ERRS
+ | RESET_SFC_LOCAL_BUS,
+ };
+
+ /**
+ * @brief Reset hardware to get into clean state
+ *
+ * @parm i_resetLevel How much SFC logic to reset
+ *
+ * @return errlHndl_t NULL on success, else error log
+ */
+ virtual errlHndl_t hwReset( ResetLevels i_resetLevel )
+ {
+ //do nothing by default
+ return NULL;
+ };
+
+
+
+ protected:
+
+ /**
+ * @brief Processor target associated with the LPC logic
+ */
+ TARGETING::Target* iv_proc;
+
+ /**
+ * @brief Hardware workarounds
+ */
+ uint32_t iv_flashWorkarounds;
+
+ /**
+ * @brief PNOR Chip Id
+ */
+ uint32_t iv_norChipId;
+
+ /**
+ * @brief describes the erase block size, set based on NOR chip type
+ */
+ uint32_t iv_eraseSizeBytes;
+
+
+};
+
+namespace PNOR {
+/**
+ * @brief Wrapper for SfcDD constructor
+ */
+errlHndl_t create_SfcDD( SfcDD*& o_sfc,
+ TARGETING::Target* i_proc
+ = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL );
+};
+
+#endif
diff --git a/src/usr/pnor/test/makefile b/src/usr/pnor/test/makefile
index d67b232e0..2c13da7b1 100644
--- a/src/usr/pnor/test/makefile
+++ b/src/usr/pnor/test/makefile
@@ -5,7 +5,10 @@
#
# OpenPOWER HostBoot Project
#
-# COPYRIGHT International Business Machines Corp. 2011,2014
+# Contributors Listed Below - COPYRIGHT 2011,2014
+# [+] Google Inc.
+# [+] International Business Machines Corp.
+#
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -23,6 +26,11 @@
ROOTPATH = ../../../..
MODULE = testpnor
-TESTS = *.H
+
+TESTS = pnorddtest.H ecctest.H pnorrptest.H
+
+#SFC Implementations
+TESTS += $(if $(CONFIG_SFC_IS_IBM_DPSS),sfc_ibmtest.H)
+TESTS += $(if $(CONFIG_SFC_IS_AST2400),sfc_ast2400test.H)
include ${ROOTPATH}/config.mk
diff --git a/src/usr/pnor/test/pnorddtest.H b/src/usr/pnor/test/pnorddtest.H
index 97273cc34..3a38e88a6 100644
--- a/src/usr/pnor/test/pnorddtest.H
+++ b/src/usr/pnor/test/pnorddtest.H
@@ -6,6 +6,7 @@
/* OpenPOWER HostBoot Project */
/* */
/* Contributors Listed Below - COPYRIGHT 2011,2014 */
+/* [+] Google Inc. */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -28,7 +29,7 @@
/**
* @file pnorddtest.H
*
- * @brief Test case for PNOR Resource Provider
+ * @brief Test case for PNOR Device Driver
*/
#include <cxxtest/TestSuite.H>
@@ -44,6 +45,10 @@
#include <list>
#include <targeting/common/attributes.H>
+#ifdef CONFIG_SFC_IS_IBM_DPSS
+#include "../sfc_ibm.H"
+#endif
+
extern trace_desc_t* g_trac_pnor;
/*
@@ -67,7 +72,7 @@ class PnorDdTest : public CxxTest::TestSuite
do{
- // Get SPD PNOR section info from PNOR RP
+ // Get TEST PNOR section info from PNOR RP
l_err = PNOR::getSectionInfo( PNOR::TEST,
info );
if(l_err)
@@ -449,659 +454,6 @@ class PnorDdTest : public CxxTest::TestSuite
TRACFCOMP(g_trac_pnor, "PnorDdTest::test_crossblock> %d/%d fails", fails, total );
}
- /**
- * @brief PNOR DD readWriteTest modes
- * Same as test_readwrite but forcing the use of all supported modes
- */
- void test_readwrite_modes(void)
- {
- PnorDD* pnordd = NULL;
- uint8_t* fake_space = NULL;
- size_t l_size = sizeof(uint64_t);
- errlHndl_t l_err = NULL;
- uint64_t fails = 0;
- uint64_t total = 0;
- uint64_t scratch_space = 0;
- uint64_t sect_size = 0;
-
- do{
- TS_TRACE("PnorDdTest::test_readwrite_modes: starting");
-
- // list of all modes to test
- std::list<PnorDD::PnorMode_t> supported_modes;
- supported_modes.push_back(PnorDD::MODEL_MEMCPY);
- supported_modes.push_back(PnorDD::MODEL_LPC_MEM);
-
- if(!TARGETING::is_vpo())
- {
- TRACFCOMP(g_trac_pnor, "PnorDdTest::test_readwrite_modes> Adding REAL_CMD & MODEL_REAL_MMIO modes");
- supported_modes.push_back(PnorDD::MODEL_REAL_CMD);
- supported_modes.push_back(PnorDD::MODEL_REAL_MMIO);
- }
-
- // loop through all of the supported modes
- for( std::list<PnorDD::PnorMode_t>::iterator m
- = supported_modes.begin();
- m != supported_modes.end();
- ++m )
- {
- if( pnordd )
- {
- delete pnordd;
- }
-
- //Fake PNOR
- if( (PnorDD::MODEL_MEMCPY == *m) ||
- (PnorDD::MODEL_LPC_MEM == *m) )
- {
- //malloc some space to use as fake-PNOR
- if( fake_space )
- {
- delete fake_space;
- }
- fake_space = new uint8_t[4 * KILOBYTE];
- pnordd = new PnorDD(*m,
- reinterpret_cast<uint64_t>(fake_space),
- (4 * KILOBYTE));
- //Adjusting the address by an arbitrary multiplier to keep
- //successive tests from always using the same memory space.
- scratch_space = (*m)*0x20;
- }
- //Real PNOR
- else
- {
- pnordd = new PnorDD(*m);
-
- if(!getTestSection(scratch_space, sect_size))
- {
- TRACFCOMP(g_trac_pnor,
- "PnorDdTest::test_readwrite_modes> Skipped due to not finding test section in PNOR" );
- continue;
- }
- //Adjusting the address by an arbitrary multiplier to keep
- //successive tests from always using the same memory space.
- scratch_space += (*m)*0x20;
- }
-
- // Perform PnorDD Write 1
- uint64_t l_address = scratch_space;
-
- uint64_t l_writeData = 0x12345678FEEDB0B0;
- l_size = sizeof(uint64_t);
- l_err = pnordd->writeFlash(&l_writeData,
- l_size,
- l_address);
- total++;
- if (l_err)
- {
- TS_FAIL("PnorDdTest::test_readwrite_modes: PNORDD write 1: writeFlash() failed! Error committed. mode=%d",
- *m);
- errlCommit(l_err,PNOR_COMP_ID);
- fails++;
- }
- total++;
- if(l_size != sizeof(uint64_t))
- {
- TS_FAIL("PnorDdTest::test_readwrite_modes: PNORDD write 1: Write length not expected value. Addr: 0x%llx, Exp: %d, Act: %d, mode=%d",
- l_address, sizeof(uint64_t), l_size, *m);
- fails++;
- }
-
- // Perform PnorDD Write 2
- l_address = scratch_space+0x08;
- l_writeData = 0xFEEDBEEF000ABCDE;
- l_size = sizeof(uint64_t);
- l_err = pnordd->writeFlash(&l_writeData,
- l_size,
- l_address);
- total++;
- if (l_err)
- {
- TS_FAIL("PnorDdTest::test_readwrite_modes: PNORDD write 2: writeFlash() failed! Error committed. mode=%d",
- *m);
- errlCommit(l_err,PNOR_COMP_ID);
- fails++;
- }
- total++;
- if(l_size != sizeof(uint64_t))
- {
- TS_FAIL("PnorDdTest::test_readwrite_modes: PNORDD write 2: Write length not expected value. Addr: 0x%llx, Exp: %d, Act: %d, mode=%d",
- l_address, sizeof(uint64_t), l_size, *m);
- fails++;
- }
-
- // Perform PnorDD read 1
- l_address = scratch_space;
- uint64_t l_readData = 0;
- l_size = sizeof(uint64_t);
- l_err = pnordd->readFlash(&l_readData,
- l_size,
- l_address);
- total++;
- if (l_err)
- {
- TS_FAIL("PnorDdTest::test_readwrite_modes: PNORDD read 1: readFlash() failed! Error committed. mode=%d",
- *m);
- errlCommit(l_err,PNOR_COMP_ID);
- fails++;
- }
- total++;
- if(l_readData != 0x12345678FEEDB0B0)
- {
- TS_FAIL("PnorDdTest::test_readwrite_modes: PNORDD read 1: Read data not expected value. Addr: 0x%llx, ExpData: 0x12345678FEEDB0B0, ActData: 0x%llx, mode=%d",
- l_address, (long long unsigned)l_readData, *m);
- fails++;
- }
- total++;
- if(l_size != sizeof(uint64_t))
- {
- TS_FAIL("PnorDdTest::test_readwrite_modes: PNORDD read 1: Read length not expected value. Addr: 0x%llx, Exp: %d, Act: %d, mode=%d",
- l_address, sizeof(uint64_t), l_size, *m);
- fails++;
- }
-
- // Perform PnorDD read 2
- l_address = scratch_space+0x08;
- l_size = sizeof(uint64_t);
- l_err = pnordd->readFlash(&l_readData,
- l_size,
- l_address);
- total++;
- if (l_err)
- {
- TS_FAIL("PnorDdTest::test_readwrite_modes: PNORDD read 2: readFlash() failed! Error committed. mode=%d",
- *m);
- errlCommit(l_err,PNOR_COMP_ID);
- fails++;
- }
- total++;
- if(l_readData != 0xFEEDBEEF000ABCDE)
- {
- TS_FAIL("PnorDdTest::test_readwrite_modes: PNORDD read 2: Read data not expected value. Addr: 0x%llx, ExpData: 0xFEEDBEEF000ABCDE, ActData: 0x%llx, mode=%d",
- l_address, (long long unsigned)l_readData, *m);
- fails++;
- }
- total++;
- if(l_size != sizeof(uint64_t))
- {
- TS_FAIL("PnorDdTest::test_readwrite_modes: PNORDD read 2: Read length not expected value. Addr: 0x%llx, Exp: %d, Act: %d, mode=%d",
- l_address, sizeof(uint64_t), l_size, *m);
- fails++;
- }
- }
-
- }while(0);
-
- TRACFCOMP(g_trac_pnor, "PnorDdTest::test_readwrite_modes> %d/%d fails", fails, total );
-
- if( pnordd )
- {
- delete pnordd;
- }
- if( fake_space )
- {
- delete fake_space;
- }
-
- }
-
- /**
- * @brief PNOR DD smart write/erase test
- * Same as test_smartwrite but forcing the use of all supported modes
- */
- void test_smartwrite_modes(void)
- {
- PnorDD* pnordd = NULL;
- uint8_t* fake_space = NULL;
- size_t l_size = sizeof(uint64_t);
- errlHndl_t l_err = NULL;
- uint64_t fails = 0;
- uint64_t total = 0;
- uint64_t scratch_space = 0;
- uint64_t sect_size = 0;
-
- do{
- TS_TRACE("PnorDdTest::test_smartwrite_modes: starting");
-
- // list of all modes to test
- std::list<PnorDD::PnorMode_t> supported_modes;
- supported_modes.push_back(PnorDD::MODEL_MEMCPY);
- supported_modes.push_back(PnorDD::MODEL_LPC_MEM);
-
- if(!TARGETING::is_vpo())
- {
- TRACFCOMP(g_trac_pnor, "PnorDdTest::test_smartwrite_modes> Adding REAL_CMD & MODEL_REAL_MMIO modes");
- supported_modes.push_back(PnorDD::MODEL_REAL_CMD);
- supported_modes.push_back(PnorDD::MODEL_REAL_MMIO);
- }
-
- // loop through all of the supported modes
- for( std::list<PnorDD::PnorMode_t>::iterator m
- = supported_modes.begin();
- m != supported_modes.end();
- ++m )
- {
- if( pnordd )
- {
- delete pnordd;
- }
-
- //Fake PNOR
- if( (PnorDD::MODEL_MEMCPY == *m) ||
- (PnorDD::MODEL_LPC_MEM == *m) )
- {
- //malloc some space to use as fake-PNOR
- if( fake_space )
- {
- delete fake_space;
- }
- fake_space = new uint8_t[4 * KILOBYTE];
- pnordd = new PnorDD(*m,
- reinterpret_cast<uint64_t>(fake_space),
- (4 * KILOBYTE));
-
- //Adjusting the address by an arbitrary multiplier to keep
- //successive tests from always using the same memory space.
- scratch_space = (*m)*0x30;
-
- }
- //Real PNOR
- else
- {
- pnordd = new PnorDD(*m);
-
- if(!getTestSection(scratch_space, sect_size))
- {
- TRACFCOMP(g_trac_pnor,
- "PnorDdTest::test_readwrite_modes> Skipped due to not finding test section in PNOR" );
- continue;
- }
- //Adjusting the address by an arbitrary multiplier to keep
- //successive tests from always using the same memory space.
- scratch_space += (*m)*0x30;
- }
-
- // Perform PnorDD Write 1
- uint64_t l_address = scratch_space+0x20;
- uint64_t l_writeData = 0xAAAAAAAA55555555;
- l_size = sizeof(uint64_t);
- l_err = pnordd->writeFlash(&l_writeData,
- l_size,
- l_address);
- total++;
- if (l_err)
- {
- TS_FAIL("PnorDdTest::test_smartwrite_modes: PNORDD write 1: writeFlash() failed! Error committed.");
- errlCommit(l_err,PNOR_COMP_ID);
- fails++;
- }
-
- // Perform PnorDD Write 2 - no erase
- l_writeData = 0xAAAAAAAAFFFFFFFF;
- l_size = sizeof(uint64_t);
- l_err = pnordd->writeFlash(&l_writeData,
- l_size,
- l_address);
- total++;
- if (l_err)
- {
- TS_FAIL("PnorDdTest::test_smartwrite_modes: PNORDD write 2: writeFlash() failed! Error committed.");
- errlCommit(l_err,PNOR_COMP_ID);
- fails++;
- }
-
- // Perform PnorDD Write 3 - put some words after the next write
- l_writeData = 0x1234567887654321;
- l_size = sizeof(uint64_t);
- l_err = pnordd->writeFlash(&l_writeData,
- l_size,
- l_address+sizeof(uint64_t));
- total++;
- if (l_err)
- {
- TS_FAIL("PnorDdTest::test_smartwrite_modes: PNORDD write 3: writeFlash() failed! Error committed.");
- errlCommit(l_err,PNOR_COMP_ID);
- fails++;
- }
-
- // Perform PnorDD Write 4 - requires erase
- l_writeData = 0x8888888811111111;
- l_size = sizeof(uint64_t);
- l_err = pnordd->writeFlash(&l_writeData,
- l_size,
- l_address);
- total++;
- if (l_err)
- {
- TS_FAIL("PnorDdTest::test_smartwrite_modes: PNORDD write 4: writeFlash() failed! Error committed.");
- errlCommit(l_err,PNOR_COMP_ID);
- fails++;
- }
-
- // Perform PnorDD read of the data we just wrote
- uint64_t l_readData = 0;
- l_size = sizeof(uint64_t);
- l_err = pnordd->readFlash(&l_readData,
- l_size,
- l_address);
- total++;
- if (l_err)
- {
- TS_FAIL("PnorDdTest::test_smartwrite_modes: PNORDD read: readFlash() failed! Error committed.");
- errlCommit(l_err,PNOR_COMP_ID);
- fails++;
- }
- total++;
- if(l_readData != l_writeData)
- {
- TS_FAIL("PnorDdTest::test_smartwrite_modes: PNORDD read: Read data not expected value. Addr: 0x%llx, ExpData: 0x%llx, ActData: 0x%llx",
- l_address, l_writeData, l_readData);
- fails++;
- }
-
- // Perform PnorDD read of the data after what we just wrote
- // verifies that we restored the rest of the block
- l_readData = 0;
- l_size = sizeof(uint64_t);
- l_err = pnordd->readFlash(&l_readData,
- l_size,
- l_address+sizeof(uint64_t));
- total++;
- if (l_err)
- {
- TS_FAIL("PnorDdTest::test_smartwrite_modes: PNORDD read: readFlash() failed! Error committed.");
- errlCommit(l_err,PNOR_COMP_ID);
- fails++;
- }
- total++;
- if(l_readData != 0x1234567887654321)
- {
- TS_FAIL("PnorDdTest::test_smartwrite_modes: PNORDD read: Read data not expected value. Addr: 0x%llx, ExpData: 0x%llx, ActData: 0x%llx",
- l_address, 0x1234567887654321, l_readData);
- fails++;
- }
- }
-
- }while(0);
-
- if( pnordd )
- {
- delete pnordd;
- }
- if( fake_space )
- {
- delete fake_space;
- }
-
- TRACFCOMP(g_trac_pnor, "PnorDdTest::test_smartwrite> %d/%d fails", fails, total );
- }
-
- /**
- * @brief PNOR DD Cross-Block testcase
- * Same as test_crossblock but forcing the use of all supported modes
- */
- void test_crossblock_modes(void)
- {
- PnorDD* pnordd = NULL;
- uint8_t* fake_space = NULL;
- size_t l_size = sizeof(uint64_t);
- errlHndl_t l_err = NULL;
- uint64_t fails = 0;
- uint64_t total = 0;
- uint64_t scratch_space = 0;
- uint64_t sect_size = 0;
-
- do{
- TS_TRACE("PnorDdTest::test_crossblock_modes: starting");
-
- // list of all modes to test
- std::list<PnorDD::PnorMode_t> supported_modes;
- supported_modes.push_back(PnorDD::MODEL_MEMCPY);
- supported_modes.push_back(PnorDD::MODEL_LPC_MEM);
-
- if(!TARGETING::is_vpo())
- {
- TRACFCOMP(g_trac_pnor, "PnorDdTest::test_crossblock_modes> Adding REAL_CMD & MODEL_REAL_MMIO mode");
- supported_modes.push_back(PnorDD::MODEL_REAL_CMD);
- supported_modes.push_back(PnorDD::MODEL_REAL_MMIO);
- }
-
- // loop through all of the supported modes
- for( std::list<PnorDD::PnorMode_t>::iterator m
- = supported_modes.begin();
- m != supported_modes.end();
- ++m )
- {
- if( pnordd )
- {
- delete pnordd;
- }
-
-
- //Fake PNOR
- if( (PnorDD::MODEL_MEMCPY == *m) ||
- (PnorDD::MODEL_LPC_MEM == *m) )
- {
- //malloc some space to use as fake-PNOR
- if( fake_space )
- {
- delete fake_space;
- }
- fake_space = new uint8_t[8 * KILOBYTE];
- pnordd = new PnorDD(*m,
- reinterpret_cast<uint64_t>(fake_space),
- (8 * KILOBYTE));
- scratch_space = 0;
- sect_size = 8 * KILOBYTE;
- }
- //Real PNOR
- else
- {
- pnordd = new PnorDD(*m);
-
- if(!getTestSection(scratch_space, sect_size))
- {
- TRACFCOMP(g_trac_pnor,
- "PnorDdTest::test_readwrite_modes> Skipped due to not finding test section in PNOR" );
- continue;
- }
- }
-
- // Find the nearest erase-block (4K) boundary
- uint64_t l_boundary = (scratch_space+4096)
- - (scratch_space%4096);
- uint64_t l_address = 0;
-
- //make sure we don't go past the end of the section
- if(l_boundary+0x4 > scratch_space+sect_size)
- {
- TS_FAIL("PnorDdTest::test_crossblock_modes: Test Case went beyond allocated space in test section.");
- TRACFCOMP(g_trac_pnor,
- "PnorDdTest::test_crossblock_modes: Test Case went beyond allocated space in test section.l_boundary=0x%X, scratch_space=0x%X, sect_size=0x%X",
- l_boundary, scratch_space, sect_size);
- TRACFCOMP(g_trac_pnor,
- "PnorDdTest::test_crossblock_modes: sect_size=0x%X",
- sect_size);
- break;
- }
-
- // Perform PnorDD Write 1 - write through boundary
- l_address = l_boundary - sizeof(uint32_t);
- uint64_t l_writeData = 0x6666666699999999;
- l_size = sizeof(uint64_t);
- l_err = pnordd->writeFlash(&l_writeData,
- l_size,
- l_address);
- total++;
- if (l_err)
- {
- TS_FAIL("PnorDdTest::test_crossblock_modes: PNORDD write 1: writeFlash() failed! Error committed.");
- errlCommit(l_err,PNOR_COMP_ID);
- fails++;
- }
-
- // Perform PnorDD Read 1 - verify previous write
- l_address = l_boundary - sizeof(uint32_t);
- uint64_t l_readData = 0x0;
- l_size = sizeof(uint64_t);
- l_err = pnordd->readFlash(&l_readData,
- l_size,
- l_address);
- total++;
- if (l_err)
- {
- TS_FAIL("PnorDdTest::test_crossblock_modes: PNORDD Read 1: readFlash() failed! Error committed.");
- errlCommit(l_err,PNOR_COMP_ID);
- fails++;
- }
- total++;
- if(l_readData != l_writeData)
- {
- TS_FAIL("PnorDdTest::test_crossblock_modes: PNORDD read: Read data not expected value. Addr: 0x%.llx, ExpData: 0x%.llx, ActData: 0x%llx", l_address, l_writeData, l_readData);
- fails++;
- }
- }
- }while(0);
-
- if( pnordd )
- {
- delete pnordd;
- }
- if( fake_space )
- {
- delete fake_space;
- }
-
- TRACFCOMP(g_trac_pnor, "PnorDdTest::test_crossblock_modes> %d/%d fails", fails, total );
- }
-
-
- /**
- * @brief PNOR DD Force Fails testcase
- */
-/****************************************************************************/
-/* NOTE: TEST DISABLED!!! remove "_" before test name to re-enable */
-/****************************************************************************/
- void _test_forceFails(void)
- {
- errlHndl_t l_err = NULL;
- uint64_t fails = 0;
- uint64_t total = 0;
- PnorDD* pnordd = new PnorDD();
- uint32_t l_poll = 0;
- PnorDD::SfcCmdReg_t sfc_cmd;
-
- do{
- TRACFCOMP(g_trac_pnor, "PnorDdTest::test_forceFails> starting - expect to see errors");
-
- /*******************************/
- /* Send in an invalid OP Code */
- /*******************************/
- sfc_cmd.opcode = PnorDD::SFC_OP_INVALID;
- sfc_cmd.length = 0;
-
- mutex_lock(pnordd->iv_mutex_ptr);
- l_err = pnordd->writeRegSfc(PnorDD::SFC_CMD_SPACE,
- PnorDD::SFC_REG_CMD,
- sfc_cmd.data32);
- total++;
- if (l_err)
- {
- TS_FAIL("PnorDdTest::test_forceFails> Get Chip Id cmd failed! Error committed.");
- fails++;
-
- // Unlock mutex for Error Log to be commited
- mutex_unlock(pnordd->iv_mutex_ptr);
- errlCommit(l_err,PNOR_COMP_ID);
-
- // Lock mutex for next operation
- mutex_lock(pnordd->iv_mutex_ptr);
- }
-
- // Poll for complete status without waiting
- l_err = pnordd->pollSfcOpComplete();
- mutex_unlock(pnordd->iv_mutex_ptr);
-
- total++;
- if ( l_err == NULL )
- {
- TS_FAIL("PnorDdTest::test_forceFails> Failed to create illegal opcode error!");
- fails++;
- }
- else
- {
- // error correctly created - delete it
- delete l_err;
- }
-
- /*******************************************************/
- /* Issue a cmd but poll for completion without waiting */
- /*******************************************************/
- //Issue Get Chip ID command
- sfc_cmd.opcode = PnorDD::SFC_OP_CHIPID;
- sfc_cmd.length = 0;
-
- mutex_lock(pnordd->iv_mutex_ptr);
- l_err = pnordd->writeRegSfc(PnorDD::SFC_CMD_SPACE,
- PnorDD::SFC_REG_CMD,
- sfc_cmd.data32);
-
- total++;
- if (l_err)
- {
- TS_FAIL("PnorDdTest::test_forceFails> Get Chip Id cmd failed! Error committed.");
- fails++;
-
- // Unlock mutex for Error Log to be commited
- mutex_unlock(pnordd->iv_mutex_ptr);
- errlCommit(l_err,PNOR_COMP_ID);
-
- // Lock mutex for next operation
- mutex_lock(pnordd->iv_mutex_ptr);
- }
-
- // Poll for complete status without waiting
- l_err = pnordd->pollSfcOpComplete(l_poll);
-
- total++;
- if ( l_err == NULL )
- {
- TS_FAIL("PnorDdTest::test_forceFails> pollSfcOpCompletel(l_poll=0) Failed to create an error!");
- fails++;
- }
- else
- {
- // error correctly created - delete it
- delete l_err;
- }
-
- /*******************************************************/
- /* Cleanup: poll to make sure last operation completes */
- /* before continuing */
- /*******************************************************/
- l_err = pnordd->pollSfcOpComplete();
- mutex_unlock(pnordd->iv_mutex_ptr);
-
- total++;
- if (l_err)
- {
- TS_FAIL("PnorDdTest::test_forceFails> Cleanup polling failed! Error committed.");
- errlCommit(l_err,PNOR_COMP_ID);
- fails++;
- }
-
-
- }while(0);
-
- if( pnordd )
- {
- delete pnordd;
- }
-
- TRACFCOMP(g_trac_pnor, "PnorDdTest::test_forceFails> %d/%d fails", fails, total );
-
- }
-
};
/*Not really a real test, just using to verify ext image is loading properly.
diff --git a/src/usr/pnor/test/pnorrptest.H b/src/usr/pnor/test/pnorrptest.H
index 6c90f2a99..6c43f9d4a 100644
--- a/src/usr/pnor/test/pnorrptest.H
+++ b/src/usr/pnor/test/pnorrptest.H
@@ -6,6 +6,7 @@
/* OpenPOWER HostBoot Project */
/* */
/* Contributors Listed Below - COPYRIGHT 2011,2014 */
+/* [+] Google Inc. */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -544,12 +545,12 @@ class PnorRpTest : public CxxTest::TestSuite
// Check if cur_TOC failed that other TOC is used
PnorRP::getInstance().readTOC();
TOC_used = PnorRP::getInstance().iv_TOC_used;
- TRACFCOMP(g_trac_pnor, "PnorRpTest::test_TOC : TOC %d Corrupt Header Toc_used = %d", cur_TOC, TOC_used);
+ TRACFCOMP(g_trac_pnor, "PnorRpTest::test_TOC : TOC %d Corrupt Header, Toc_used = %d", cur_TOC, TOC_used);
if (TOC_used == cur_TOC)
{
- TRACFCOMP(g_trac_pnor, "PnorRpTest::test_TOC> ERROR : TOC %d is corrupted, did not use other TOC", cur_TOC);
- TS_FAIL("PnorRpTest::test_TOC> ERROR : TOC %d is corrupted, did not use other TOC");
+ TRACFCOMP(g_trac_pnor, "PnorRpTest::test_TOC> ERROR : TOC %d header is corrupted, did not use other TOC", cur_TOC);
+ TS_FAIL("PnorRpTest::test_TOC> ERROR : TOC %d header is corrupted, did not use other TOC");
}
// Fix cur_TOC header
@@ -571,12 +572,12 @@ class PnorRpTest : public CxxTest::TestSuite
TOC_used = cur_TOC;
PnorRP::getInstance().readTOC();
TOC_used = PnorRP::getInstance().iv_TOC_used;
- TRACFCOMP(g_trac_pnor, "PnorRpTest::test_TOC : TOC %d Corrupt Entry Toc_used = %d", cur_TOC, TOC_used);
+ TRACFCOMP(g_trac_pnor, "PnorRpTest::test_TOC : TOC %d Corrupt Entry, Toc_used = %d", cur_TOC, TOC_used);
if (TOC_used == cur_TOC)
{
- TRACFCOMP(g_trac_pnor, "PnorRpTest::test_TOC> ERROR : TOC %d is corrupted, did not use other TOC ENTRY", cur_TOC);
- TS_FAIL("PnorRpTest::test_TOC> ERROR : TOC %d is corrupted, did not use other TOC", cur_TOC);
+ TRACFCOMP(g_trac_pnor, "PnorRpTest::test_TOC> ERROR : TOC %d entry is corrupted, did not use other TOC ENTRY", cur_TOC);
+ TS_FAIL("PnorRpTest::test_TOC> ERROR : TOC %d entry is corrupted, did not use other TOC", cur_TOC);
}
// Fix cur_TOC first entry
diff --git a/src/usr/pnor/test/sfc_ast2400test.H b/src/usr/pnor/test/sfc_ast2400test.H
new file mode 100644
index 000000000..4dc69e68e
--- /dev/null
+++ b/src/usr/pnor/test/sfc_ast2400test.H
@@ -0,0 +1,305 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/pnor/test/sfc_ast2400test.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2014 */
+/* [+] Google Inc. */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __SFC_AST2400TEST_H
+#define __SFC_AST2400TEST_H
+
+/**
+ * @file sfc_ast2400test.H
+ *
+ * @brief Test case for AST2400 Flash Controller
+*/
+
+#include <cxxtest/TestSuite.H>
+#include <errl/errlmanager.H>
+#include <errl/errlentry.H>
+#include <devicefw/userif.H>
+#include <sys/time.h>
+#include "../pnordd.H"
+#include <list>
+#include <targeting/common/attributes.H>
+#include <lpc/lpcif.H>
+#include "../sfc_ast2400.H"
+
+extern trace_desc_t* g_trac_pnor;
+
+class SfcAST2400Test : public CxxTest::TestSuite
+{
+ public:
+
+ bool getTestSection(uint64_t &o_physAddr, uint64_t &o_size)
+ {
+ errlHndl_t l_err = NULL;
+ PNOR::SectionInfo_t info;
+ uint64_t chip_select = 0xF;
+ bool needs_ecc = false;
+ bool section_found = false;
+
+ do{
+
+ // Get TEST PNOR section info from PNOR RP
+ l_err = PNOR::getSectionInfo( PNOR::TEST,
+ info );
+ if(l_err)
+ {
+ if(l_err->reasonCode() == PNOR::RC_INVALID_SECTION)
+ {
+ //This is expected in some configurations,
+ // so just delete it.
+ delete l_err;
+ }
+ else
+ {
+ //Any other type of error is not expected, so commit it.
+ errlCommit(l_err,PNOR_COMP_ID);
+ }
+ break;
+ }
+
+ l_err = PnorRP::getInstance().computeDeviceAddr((void*)info.vaddr,
+ o_physAddr,
+ chip_select,
+ needs_ecc);
+ if(l_err)
+ {
+ errlCommit(l_err,PNOR_COMP_ID);
+ break;
+ }
+
+ o_size = info.size;
+ section_found = true;
+
+ }while(0);
+
+ return section_found;
+ }
+
+ /**
+ * @brief Test Flash Reads
+ * Verify that reads work in normal mode and then do
+ * not work in command mode
+ */
+ void test_FlashReads( void )
+ {
+ PnorDD& pnordd = Singleton<PnorDD>::instance();
+ SfcAST2400* sfc = reinterpret_cast<SfcAST2400*>(pnordd.iv_sfc );
+ mutex_t* l_mutex = pnordd.iv_mutex_ptr;
+ errlHndl_t l_err = NULL;
+
+ //Find some pnor to read
+ uint64_t base_address;
+ uint64_t sect_size;
+ if(!getTestSection(base_address, sect_size))
+ {
+ TRACFCOMP(g_trac_pnor, "SfcAST2400Test::test_FlashReads> Skipped due to not finding test section in PNOR" );
+ TS_FAIL("SfcAST2400Test::test_FlashReads> Skipped due to not finding test section in PNOR");
+ return;
+ }
+
+ mutex_lock(l_mutex);
+
+ //Prove reads work by default and that they fail in command mode
+ uint64_t l_readData = 0;
+ size_t l_size = sizeof(uint64_t);
+ l_err = pnordd._readFlash(base_address,
+ l_size,
+ &l_readData);
+ if( l_err )
+ {
+ TS_FAIL("SfcAST2400Test::test_FlashReads> Basic read failed");
+ mutex_unlock(l_mutex);//unlock before commit
+ errlCommit(l_err,PNOR_COMP_ID);
+ return; //just give up if basic reads don't work
+ }
+
+ // Put controller into command mode (instead of read mode)
+ l_err = sfc->commandMode( true );
+ if( l_err )
+ {
+ TS_FAIL("SfcAST2400Test::test_FlashReads> Error entering command mode");
+ mutex_unlock(l_mutex);//unlock before commit
+ errlCommit(l_err,PNOR_COMP_ID);
+ mutex_lock(l_mutex);//lock again for next op
+ }
+
+ // Reads should fail
+ l_err = pnordd._readFlash(base_address,
+ l_size,
+ &l_readData);
+ if( !l_err )
+ {
+ TS_FAIL("SfcAST2400Test::test_FlashReads> Read did not fail in command mode");
+ }
+ else
+ {
+ delete l_err;
+ }
+
+ // Put controller back into read mode
+ l_err = sfc->commandMode( false );
+ mutex_unlock(l_mutex);
+ if( l_err )
+ {
+ TS_FAIL("SfcAST2400Test::test_FlashReads> Error exiting command mode");
+ errlCommit(l_err,PNOR_COMP_ID);
+ }
+ }
+
+ /**
+ * @brief Test SIO access
+ * Use a SIO scratch register to verify reads and writes
+ */
+ void test_SIO(void)
+ {
+ SfcAST2400* sfc = reinterpret_cast<SfcAST2400*>(
+ Singleton<PnorDD>::instance().iv_sfc );
+ errlHndl_t l_err = NULL;
+
+ // Read SIO to BMC scratch reg 1,2 and save off values
+ uint8_t scratch1 = 0;
+ l_err = sfc->readRegSIO( 0x21, scratch1 );
+ if( l_err )
+ {
+ TS_FAIL("SfcAST2400Test::test_SIO> readRegSIO failed");
+ errlCommit(l_err,PNOR_COMP_ID);
+ }
+ uint8_t scratch2 = 0;
+ l_err = sfc->readRegSIO( 0x22, scratch2 );
+ if( l_err )
+ {
+ TS_FAIL("SfcAST2400Test::test_SIO> readRegSIO failed");
+ errlCommit(l_err,PNOR_COMP_ID);
+ }
+
+ // Write test patterns into registers
+ uint8_t testdata = 0xA5;
+ l_err = sfc->writeRegSIO( 0x21, testdata );
+ if( l_err )
+ {
+ TS_FAIL("SfcAST2400Test::test_SIO> writeRegSIO failed");
+ errlCommit(l_err,PNOR_COMP_ID);
+ }
+ testdata = 0x12;
+ l_err = sfc->writeRegSIO( 0x22, testdata );
+ if( l_err )
+ {
+ TS_FAIL("SfcAST2400Test::test_SIO> writeRegSIO failed");
+ errlCommit(l_err,PNOR_COMP_ID);
+ }
+
+ // Read the data back and compare to expected results
+ l_err = sfc->readRegSIO( 0x21, testdata );
+ if( l_err )
+ {
+ TS_FAIL("SfcAST2400Test::test_SIO> readRegSIO failed");
+ errlCommit(l_err,PNOR_COMP_ID);
+ }
+ if( testdata != 0xA5 )
+ {
+ TS_FAIL("SfcAST2400Test::test_SIO> Data mismatch on SIO 0x21 : Exp=0xA5, Act=%.2X", testdata);
+ }
+ l_err = sfc->readRegSIO( 0x22, testdata );
+ if( l_err )
+ {
+ TS_FAIL("SfcAST2400Test::test_SIO> readRegSIO failed");
+ errlCommit(l_err,PNOR_COMP_ID);
+ }
+ if( testdata != 0x12 )
+ {
+ TS_FAIL("SfcAST2400Test::test_SIO> Data mismatch on SIO 0x22 : Exp=0x12, Act=%.2X", testdata);
+ }
+
+ // Restore the original data
+ l_err = sfc->writeRegSIO( 0x21, scratch1 );
+ if( l_err )
+ {
+ TS_FAIL("SfcAST2400Test::test_SIO> writeRegSIO failed");
+ errlCommit(l_err,PNOR_COMP_ID);
+ }
+ l_err = sfc->writeRegSIO( 0x22, scratch2 );
+ if( l_err )
+ {
+ TS_FAIL("SfcAST2400Test::test_SIO> writeRegSIO failed");
+ errlCommit(l_err,PNOR_COMP_ID);
+ }
+ }
+
+ /**
+ * @brief Test SPIC access
+ * Read and write data to the SPI Control register
+ */
+ void test_SPIC( void )
+ {
+ SfcAST2400* sfc = reinterpret_cast<SfcAST2400*>(
+ Singleton<PnorDD>::instance().iv_sfc );
+ mutex_t* l_mutex = Singleton<PnorDD>::instance().iv_mutex_ptr;
+ errlHndl_t l_err = NULL;
+
+ mutex_lock(l_mutex);
+
+ uint32_t first = 0;
+ l_err = sfc->readRegSPIC( SfcAST2400::CTLREG_04, first );
+ if( l_err )
+ {
+ TS_FAIL("SfcAST2400Test::test_SPIC> readRegSIO failed");
+ mutex_unlock(l_mutex);//unlock before commit
+ errlCommit(l_err,PNOR_COMP_ID);
+ mutex_lock(l_mutex);//lock again for next op
+ }
+ uint32_t data1 = 0x12345678;
+ l_err = sfc->writeRegSPIC( SfcAST2400::CTLREG_04, data1 );
+ if( l_err )
+ {
+ TS_FAIL("SfcAST2400Test::test_SPIC> readRegSIO failed");
+ mutex_unlock(l_mutex);//unlock before commit
+ errlCommit(l_err,PNOR_COMP_ID);
+ mutex_lock(l_mutex);//lock again for next op
+ }
+ l_err = sfc->readRegSPIC( SfcAST2400::CTLREG_04, data1 );
+ if( l_err )
+ {
+ TS_FAIL("SfcAST2400Test::test_SPIC> readRegSIO failed");
+ mutex_unlock(l_mutex);//unlock before commit
+ errlCommit(l_err,PNOR_COMP_ID);
+ mutex_lock(l_mutex);//lock again for next op
+ }
+ if( data1 != 0x12345678 )
+ {
+ TS_FAIL("SfcAST2400Test::test_SPIC> Unexpected result of %.8X (exp 0x12345678)",data1);
+ }
+ //put back the original
+ l_err = sfc->writeRegSPIC( SfcAST2400::CTLREG_04, first );
+ if( l_err )
+ {
+ TS_FAIL("SfcAST2400Test::test_SPIC> readRegSIO failed");
+ mutex_unlock(l_mutex);//unlock before commit
+ errlCommit(l_err,PNOR_COMP_ID);
+ }
+
+ mutex_unlock(l_mutex);
+ }
+};
+
+#endif
diff --git a/src/usr/pnor/test/sfc_ibmtest.H b/src/usr/pnor/test/sfc_ibmtest.H
new file mode 100644
index 000000000..967045ad0
--- /dev/null
+++ b/src/usr/pnor/test/sfc_ibmtest.H
@@ -0,0 +1,174 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/pnor/test/sfc_ibmtest.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2014 */
+/* [+] Google Inc. */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __SFC_IBMTEST_H
+#define __SFC_IBMTEST_H
+
+/**
+ * @file sfc_ibmtest.H
+ *
+ * @brief Test case for IBM DPSS Flash Controller
+*/
+
+#include <cxxtest/TestSuite.H>
+#include <errl/errlmanager.H>
+#include <errl/errlentry.H>
+#include <devicefw/userif.H>
+#include <sys/time.h>
+#include "../pnordd.H"
+#include <list>
+#include <targeting/common/attributes.H>
+#include "../sfc_ibm.H"
+
+extern trace_desc_t* g_trac_pnor;
+
+class SfcIBMTest : public CxxTest::TestSuite
+{
+ public:
+
+ /*************************************************************************/
+ /* NOTE: TEST DISABLED!!! remove "_" before test name to re-enable */
+ /*************************************************************************/
+ /**
+ * @brief PNOR DD Force Fails testcase
+ */
+ void _test_forceFails(void)
+ {
+ errlHndl_t l_err = NULL;
+ uint64_t fails = 0;
+ uint64_t total = 0;
+ SfcIBM* sfcdd = reinterpret_cast<SfcIBM*>(
+ Singleton<PnorDD>::instance().iv_sfc );
+ mutex_t* l_mutex = Singleton<PnorDD>::instance().iv_mutex_ptr;
+ SfcIBM::SfcCmdReg_t sfc_cmd;
+
+ do{
+ TRACFCOMP(g_trac_pnor, "SfcIBMTest::test_forceFails> starting - expect to see errors");
+
+ /*******************************/
+ /* Send in an invalid OP Code */
+ /*******************************/
+ sfc_cmd.opcode = SfcIBM::SFC_OP_INVALID;
+ sfc_cmd.length = 0;
+
+ mutex_lock(l_mutex);
+ l_err = sfcdd->writeReg(SfcIBM::SFC_CMD_SPACE,
+ SfcIBM::SFC_REG_CMD,
+ sfc_cmd.data32);
+ total++;
+ if (l_err)
+ {
+ TS_FAIL("SfcIBMTest::test_forceFails> writeReg failed! Error committed.");
+ fails++;
+
+ // Unlock mutex for Error Log to be commited
+ mutex_unlock(l_mutex);
+ errlCommit(l_err,PNOR_COMP_ID);
+
+ // Lock mutex for next operation
+ mutex_lock(l_mutex);
+ }
+
+ // Poll for complete status without waiting
+ l_err = sfcdd->pollOpComplete();
+ mutex_unlock(l_mutex);
+
+ total++;
+ if ( l_err == NULL )
+ {
+ TS_FAIL("SfcIBMTest::test_forceFails> Failed to create illegal opcode error!");
+ fails++;
+ }
+ else
+ {
+ // error correctly created - delete it
+ delete l_err;
+ }
+
+ /*******************************************************/
+ /* Issue a cmd but poll for completion without waiting */
+ /*******************************************************/
+ //Issue Get Chip ID command
+ sfc_cmd.opcode = SfcIBM::SFC_OP_CHIPID;
+ sfc_cmd.length = 0;
+
+ mutex_lock(l_mutex);
+ l_err = sfcdd->writeReg(SfcIBM::SFC_CMD_SPACE,
+ SfcIBM::SFC_REG_CMD,
+ sfc_cmd.data32);
+
+ total++;
+ if (l_err)
+ {
+ TS_FAIL("SfcIBMTest::test_forceFails> Get Chip Id cmd failed! Error committed.");
+ fails++;
+
+ // Unlock mutex for Error Log to be commited
+ mutex_unlock(l_mutex);
+ errlCommit(l_err,PNOR_COMP_ID);
+
+ // Lock mutex for next operation
+ mutex_lock(l_mutex);
+ }
+
+ // Poll for complete status without waiting
+ l_err = sfcdd->pollOpComplete();
+
+ total++;
+ if ( l_err == NULL )
+ {
+ TS_FAIL("SfcIBMTest::test_forceFails> pollOpCompletel(l_poll=0) Failed to create an error!");
+ fails++;
+ }
+ else
+ {
+ // error correctly created - delete it
+ delete l_err;
+ }
+
+ /*******************************************************/
+ /* Cleanup: poll to make sure last operation completes */
+ /* before continuing */
+ /*******************************************************/
+ l_err = sfcdd->pollOpComplete();
+ mutex_unlock(l_mutex);
+
+ total++;
+ if (l_err)
+ {
+ TS_FAIL("SfcIBMTest::test_forceFails> Cleanup polling failed! Error committed.");
+ errlCommit(l_err,PNOR_COMP_ID);
+ fails++;
+ }
+
+
+ }while(0);
+
+ TRACFCOMP(g_trac_pnor, "SfcIBMTest::test_forceFails> %d/%d fails", fails, total );
+
+ }
+};
+
+#endif
OpenPOWER on IntegriCloud