summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBill Hoffa <wghoffa@us.ibm.com>2016-09-16 15:09:28 -0500
committerMatthew A. Ploetz <maploetz@us.ibm.com>2016-10-31 15:49:47 -0400
commitfde2240fafb48866ef3324f57ae7f4417625ad18 (patch)
tree418a4b243625c08b0bded4675e8a174d3ffcbd20
parent0cb19a22319130ec4ebeb64ee87a47328297486e (diff)
downloadtalos-hostboot-fde2240fafb48866ef3324f57ae7f4417625ad18.tar.gz
talos-hostboot-fde2240fafb48866ef3324f57ae7f4417625ad18.zip
Pnor DD Changes for AST2500
- Created Common sfc_ast2X000 class for common functions - Modified sfc_ast2400 class to use common class - Added sfc_ast2500 class Change-Id: I27c7674b58e006801ae03aabd60fdcfa21f49e9c RTC: 161664 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/30919 Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com> Reviewed-by: Elizabeth K. Liner <eliner@us.ibm.com> Reviewed-by: Matthew A. Ploetz <maploetz@us.ibm.com>
-rw-r--r--src/include/usr/pnor/pnor_reasoncodes.H12
-rw-r--r--src/makefile2
-rw-r--r--src/usr/lpc/lpcdd.C6
-rw-r--r--src/usr/pnor/HBconfig12
-rw-r--r--src/usr/pnor/makefile4
-rw-r--r--src/usr/pnor/sfc_ast2400.C492
-rw-r--r--src/usr/pnor/sfc_ast2400.H124
-rw-r--r--src/usr/pnor/sfc_ast2500.C267
-rw-r--r--src/usr/pnor/sfc_ast2500.H192
-rw-r--r--src/usr/pnor/sfc_ast2X00.C573
-rw-r--r--src/usr/pnor/sfc_ast2X00.H218
-rw-r--r--src/usr/pnor/test/pnorddtest.H4
-rw-r--r--src/usr/pnor/test/sfc_ast2500test.H186
13 files changed, 1471 insertions, 621 deletions
diff --git a/src/include/usr/pnor/pnor_reasoncodes.H b/src/include/usr/pnor/pnor_reasoncodes.H
index d10cd44c6..4235339bd 100644
--- a/src/include/usr/pnor/pnor_reasoncodes.H
+++ b/src/include/usr/pnor/pnor_reasoncodes.H
@@ -77,12 +77,12 @@ namespace PNOR
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 */
+ // sfc_ast2X00.C
+ MOD_SFCAST2X00_ENABLEWRITEMODE = 0x80, /**< SfcAST2X00::verifyAddressRange */
+ MOD_SFCAST2X00_READFLASH = 0x81, /**< SfcAST2X00::readFlash */
+ MOD_SFCAST2X00_WRITEFLASH = 0x82, /**< SfcAST2X00::writeFlash */
+ MOD_SFCAST2X00_POLLOPCOMPLETE = 0x83, /**< SfcAST2X00::pollSfcOpComplete */
+ MOD_SFCAST2X00_ERASEFLASH = 0x84, /**< SfcAST2X00::eraseFlash */
// nor_micron.C
MOD_NORMICRON_MICRONFLAGSTATUS = 0xA0, /**< micronFlagStatus */
diff --git a/src/makefile b/src/makefile
index f7d5e68e1..55b4fdb78 100644
--- a/src/makefile
+++ b/src/makefile
@@ -129,7 +129,7 @@ BASE_MODULES += secureboot_base
BASE_MODULES += lpc
BASE_MODULES += pnor
BASE_MODULES += vfs
-BASE_MODULES += $(if $(CONFIG_AST2400), sio)
+BASE_MODULES += $(if $(CONFIG_AST2400) || $(CONFIG_AST2500), sio)
EXTENDED_MODULES += istep06
EXTENDED_MODULES += istep07
diff --git a/src/usr/lpc/lpcdd.C b/src/usr/lpc/lpcdd.C
index 3b8a2cd5a..a8a23fde1 100644
--- a/src/usr/lpc/lpcdd.C
+++ b/src/usr/lpc/lpcdd.C
@@ -714,7 +714,8 @@ errlHndl_t LpcDD::_readLPC(LPC::TransType i_type,
l_err = checkAddr( i_type, i_addr, &l_addr );
if( l_err ) { break; }
-#if CONFIG_SFC_IS_AST2400 //TODO CQ:SW328950 to work around Simics AST2400 bug
+//TODO CQ:SW328950 to work around Simics AST2400 bug
+#if CONFIG_SFC_IS_AST2400 || CONFIG_SFC_IS_AST2500
if( io_buflen <= sizeof(uint32_t) )
{
memcpy( o_buffer, reinterpret_cast<void*>(l_addr), io_buflen );
@@ -790,7 +791,8 @@ errlHndl_t LpcDD::_writeLPC(LPC::TransType i_type,
l_err = checkAddr( i_type, i_addr, &l_addr );
if( l_err ) { break; }
-#if CONFIG_SFC_IS_AST2400 //TODO CQ:SW328950 to work around Simics AST2400 bug
+//TODO CQ:SW328950 to work around Simics AST2400 bug
+#if CONFIG_SFC_IS_AST2400 || CONFIG_SFC_IS_AST2500
memcpy(reinterpret_cast<void*>(l_addr), i_buffer, io_buflen);
#else
if( io_buflen == sizeof(uint8_t) )
diff --git a/src/usr/pnor/HBconfig b/src/usr/pnor/HBconfig
index 0157eb2c8..c0dfde89a 100644
--- a/src/usr/pnor/HBconfig
+++ b/src/usr/pnor/HBconfig
@@ -1,18 +1,24 @@
config SFC_IS_IBM_DPSS
default n
- depends on !SFC_IS_AST2400 && !SFC_IS_FAKE
+ depends on !SFC_IS_AST2400 && !SFC_IS_FAKE && !SFC_IS_AST2500
help
The Serial Flash Controller is the IBM DPSS FPGA.
config SFC_IS_AST2400
default y
- depends on !SFC_IS_IBM_DPSS && !SFC_IS_FAKE
+ depends on !SFC_IS_IBM_DPSS && !SFC_IS_FAKE && !SFC_IS_AST2500
help
The Serial Flash Controller is the AST2400 BMC.
+config SFC_IS_AST2500
+ default n
+ depends on !SFC_IS_IBM_DPSS && !SFC_IS_FAKE && !SFC_IS_AST2400
+ help
+ The Serial Flash Controller is the AST2500 BMC.
+
config SFC_IS_FAKE
default n
- depends on !SFC_IS_IBM_DPSS && !SFC_IS_AST2400
+ depends on !SFC_IS_IBM_DPSS && !SFC_IS_AST2400 && !SFC_IS_AST2500
help
The Serial Flash Controller is emulated using memory.
diff --git a/src/usr/pnor/makefile b/src/usr/pnor/makefile
index fc6a34b7e..c1ebe38f0 100644
--- a/src/usr/pnor/makefile
+++ b/src/usr/pnor/makefile
@@ -37,13 +37,15 @@ OBJS += sfcdd.o
#SFC Implementations
OBJS += $(if $(CONFIG_SFC_IS_IBM_DPSS),sfc_ibm.o)
+OBJS += $(if $(CONFIG_SFC_IS_AST2400),sfc_ast2X00.o)
+OBJS += $(if $(CONFIG_SFC_IS_AST2500),sfc_ast2X00.o)
OBJS += $(if $(CONFIG_SFC_IS_AST2400),sfc_ast2400.o)
+OBJS += $(if $(CONFIG_SFC_IS_AST2500),sfc_ast2500.o)
OBJS += $(if $(CONFIG_SFC_IS_FAKE),sfc_fake.o)
#NOR Implementations
OBJS += $(if $(CONFIG_ALLOW_MICRON_PNOR),nor_micron.o)
-
SUBDIRS += test.d
SUBDIRS += runtime.d
diff --git a/src/usr/pnor/sfc_ast2400.C b/src/usr/pnor/sfc_ast2400.C
index 14d01bfba..e8e612efa 100644
--- a/src/usr/pnor/sfc_ast2400.C
+++ b/src/usr/pnor/sfc_ast2400.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2014,2015 */
+/* Contributors Listed Below - COPYRIGHT 2014,2016 */
/* [+] Google Inc. */
/* [+] International Business Machines Corp. */
/* */
@@ -43,6 +43,7 @@
#include <lpc/lpcif.H>
#include "sfc_ast2400.H"
#include "norflash.H"
+#include "sfc_ast2X00.H"
#include <util/align.H>
#include "pnor_common.H"
@@ -80,171 +81,11 @@ errlHndl_t create_SfcDD( SfcDD*& o_sfc,
*/
SfcAST2400::SfcAST2400( errlHndl_t& o_err,
TARGETING::Target* i_proc )
-: SfcDD(o_err,i_proc)
+: SfcAST2X00(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 = (ALIGN_4(i_size))/4;
- for( uint32_t words_read = 0;
- words_read < word_size;
- words_read ++ )
- {
- //Read directly from MMIO space
- uint32_t lpc_addr = PNOR::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;
- size_t l_bytes_left = i_size;
- size_t l_bytes_to_write = 0;
- uint32_t l_addr_to_write = i_addr;
- uint8_t* l_dataptr = reinterpret_cast<uint8_t*>(i_data);
-
- do {
- // Enable write mode
- l_err = enableWriteMode();
- if( l_err ) { break; }
-
- // Page Program (PP) command only supports 256 bytes at a time
- if( l_bytes_left <= PNOR::PAGE_PROGRAM_BYTES )
- {
- l_bytes_to_write = l_bytes_left;
- l_bytes_left = 0;
- }
- else
- {
- l_bytes_to_write = PNOR::PAGE_PROGRAM_BYTES;
- l_bytes_left -= PNOR::PAGE_PROGRAM_BYTES;
- }
-
- // Send in the Page Program command with the data to write
- uint8_t opcode = PNOR::SPI_JEDEC_PAGE_PROGRAM;
- l_err = sendSpiCmd( opcode, l_addr_to_write,
- l_bytes_to_write,
- l_dataptr,
- 0, NULL );
- if( l_err ) { break; }
-
- // Move to the next chunk
- l_addr_to_write += l_bytes_to_write;
- l_dataptr += l_bytes_to_write;
-
- // 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(l_bytes_left);
-
- 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 )
-{
- TRACDCOMP(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;
-}
-
-//function to call SIO dd for ahb sio read
-errlHndl_t ahbSioReadWrapper(uint32_t i_ahb_sio_data, uint32_t i_lpc_addr)
-{
- size_t l_ahb_sio_len = sizeof(i_ahb_sio_data);
- return deviceOp( DeviceFW::READ,
- TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
- &(i_ahb_sio_data),
- l_ahb_sio_len,
- DEVICE_AHB_SIO_ADDRESS(i_lpc_addr));
-}
-
-//function to call SIO dd for ahb sio write
-errlHndl_t ahbSioWriteWrapper(uint32_t i_ahb_sio_data, uint32_t i_lpc_addr)
-{
- size_t l_ahb_sio_len = sizeof(i_ahb_sio_data);
- return deviceOp( DeviceFW::WRITE,
- TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
- &(i_ahb_sio_data),
- l_ahb_sio_len,
- DEVICE_AHB_SIO_ADDRESS(i_lpc_addr));
-}
-
-/**
* @brief Initialize and configure the SFC hardware
*/
errlHndl_t SfcAST2400::hwInit( )
@@ -322,161 +163,6 @@ errlHndl_t SfcAST2400::hwInit( )
}
/**
- * @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,
- PNOR::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,
- PNOR::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,
- PNOR::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,
- PNOR::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,
- PNOR::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,
- PNOR::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 )
@@ -526,175 +212,3 @@ errlHndl_t SfcAST2400::commandMode( bool i_enter )
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 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
index 28719425e..c83db94c0 100644
--- a/src/usr/pnor/sfc_ast2400.H
+++ b/src/usr/pnor/sfc_ast2400.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2014,2015 */
+/* Contributors Listed Below - COPYRIGHT 2014,2016 */
/* [+] Google Inc. */
/* [+] International Business Machines Corp. */
/* */
@@ -30,6 +30,7 @@
#include <targeting/common/targetservice.H>
#include <errl/errlentry.H>
#include "sfcdd.H"
+#include "sfc_ast2X00.H"
#include <config.h>
/** @file sfc_ast2400.H
@@ -42,10 +43,11 @@
* Provides the logic to access and configure the
* AST2400 BMC in order to access the PNOR
*/
-class SfcAST2400 : public SfcDD
+class SfcAST2400 : public SfcAST2X00
{
public: //SfcDD methods
+
/**
* @brief Initialize the SFC Hardware
*
@@ -54,66 +56,13 @@ class SfcAST2400 : public SfcDD
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
+ * @brief Enter/exit command mode
*
- * @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
+ * @param[in] i_enter: true=enter cmd mode, false=exit cmd mode
*
* @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 );
+ virtual errlHndl_t commandMode( bool i_enter );
public:
/**
@@ -138,39 +87,6 @@ class SfcAST2400 : public SfcDD
};
/**
- * @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
@@ -217,32 +133,6 @@ class SfcAST2400 : public SfcDD
*/
SpiControlReg04_t iv_ctlRegDefault;
-
- /** @brief General Constants */
- enum
- {
- /**< 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;
};
diff --git a/src/usr/pnor/sfc_ast2500.C b/src/usr/pnor/sfc_ast2500.C
new file mode 100644
index 000000000..39465f9b2
--- /dev/null
+++ b/src/usr/pnor/sfc_ast2500.C
@@ -0,0 +1,267 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/pnor/sfc_ast2500.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2016 */
+/* [+] 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 <sio/sio.H>
+#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_ast2500.H"
+#include "norflash.H"
+#include "sfc_ast2X00.H"
+#include <util/align.H>
+#include "pnor_common.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 SfcAST2500 object" );
+ o_sfc = new SfcAST2500( l_err, i_proc );
+ return l_err;
+}
+
+};
+
+/**
+ * @brief Constructor
+ */
+SfcAST2500::SfcAST2500( errlHndl_t& o_err,
+ TARGETING::Target* i_proc )
+: SfcAST2X00(o_err,i_proc)
+{
+}
+
+/**
+ * @brief Initialize and configure the SFC hardware
+ */
+errlHndl_t SfcAST2500::hwInit( )
+{
+ TRACFCOMP( g_trac_pnor, ENTER_MRK"SfcAST2500::hwInit>" );
+ errlHndl_t l_err = NULL;
+ uint32_t l_lpc_addr;
+ do
+ {
+ /* Enable device 0x0D*/
+ uint8_t l_data = SIO::ENABLE_DEVICE;
+ size_t l_len = sizeof(l_data);
+ l_err = deviceOp( DeviceFW::WRITE,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ (&l_data),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::iLPC2AHB,0x30));
+ if(l_err) { break; }
+
+ /* ----- Setup the SPI Controller ----- */
+
+ /* Enable write command mode to CE0 */
+ SpiCE0ControlReg10_t l_ctlregCE0;
+ l_lpc_addr = CE0_CTRLREG_10 | SPIC_BASE_ADDR_AHB;
+ l_err = ahbSioReadWrapper(l_ctlregCE0.data32, l_lpc_addr);
+ if( l_err ) { break; }
+
+ l_ctlregCE0.cmdMode=0b10; //10:Normal Write (CMD + Address + Write data)
+ l_err = ahbSioWriteWrapper(l_ctlregCE0.data32, l_lpc_addr);
+ if( l_err ) { break; }
+
+/* @TODO RTC:162680
+ // Enable write command mode to CE1
+ SpiCE1ControlReg14_t l_ctlregCE1;
+ l_lpc_addr = CE1_CTRLREG_14 | SPIC_BASE_ADDR_AHB;
+ l_err = ahbSioReadWrapper(l_ctlregCE1.data32, l_lpc_addr);
+ if( l_err ) { break; }
+
+ l_ctlregCE1.cmdMode=0b10; //10:Normal Write (CMD + Address + Write data)
+ l_err = ahbSioWriteWrapper(l_ctlregCE1.data32, l_lpc_addr);
+ if( l_err ) { break; }
+**/
+
+ /* Enable writing to CE0 and CE1 */
+ SpiConfigReg00_t confreg;
+ l_lpc_addr = CONFREG_00 | SPIC_BASE_ADDR_AHB;
+ l_err = ahbSioReadWrapper(confreg.data32, l_lpc_addr);
+ if( l_err ) { break; }
+
+ confreg.enableCE0Write = 1; //Enable flash memory write for CE0
+ //@TODO RTC:162680 - confreg.enableCE1Write = 1;
+ l_err = ahbSioWriteWrapper(confreg.data32, l_lpc_addr);
+ if( l_err ) { break; }
+
+ /*
+ * Setup base CE Control reg for our use, four byte mode for address
+ * selection and setting 2x clock cycles
+ */
+ SpiCEControlReg04_t l_ceCtrlReg;
+ l_lpc_addr = CE_CTLREG_04 | SPIC_BASE_ADDR_AHB;
+ l_err = ahbSioReadWrapper(confreg.data32, l_lpc_addr);
+ if( l_err ) { break; }
+
+ l_ceCtrlReg.enableCE0Div2 = 1; //Enable 2x clock cycles for CE0
+ l_ceCtrlReg.fourByteModeCE0 = 1;
+ /* @TODO RTC:162680
+ * l_ceCtrlReg.enableCE1Div2 = 1; //Enable 2x clock cycles for CE1
+ * l_ceCtrlReg.fourByteModeCE1 = 1;
+ */
+ l_err = ahbSioWriteWrapper(l_ceCtrlReg.data32, l_lpc_addr);
+ if( l_err ) { break; }
+
+ /*
+ * Setup control regs for CE0 + CE1 for our use, switching
+ * to 1-bit mode (ioMode == 0b00), clearing user mode if
+ * set (cmdMode == 0b00)
+ * etc...
+ *
+ * Also configure SPI clock to something safe
+ * like HCLK/8 (24Mhz)
+ */
+ l_ctlregCE0.ioMode = 0b00; //single bit or controlled by bit[3]
+ l_ctlregCE0.pulseWidth = 0x0; //0000: 16T (1T = 1 HCLK clock)
+ l_ctlregCE0.cmdData = 0x00;
+ l_ctlregCE0.spiClkFreq = 0x4; //HCLK/8
+ l_ctlregCE0.dummyCycleRead1 = 0; //no dummy cycles
+ l_ctlregCE0.dummyCycleRead2 = 0b00; //no dummy cycles
+ l_ctlregCE0.cmdMode = 0b00; //00:Normal Read (03h + Address + Read data)
+
+ /* @TODO RTC:162680
+ l_ctlregCE1.ioMode = 0b00; //single bit or controlled by bit[3]
+ l_ctlregCE1.pulseWidth = 0x0; //0000: 16T (1T = 1 HCLK clock)
+ l_ctlregCE1.cmdData = 0x00;
+ l_ctlregCE1.spiClkFreq = 0x4; //HCLK/8
+ l_ctlregCE1.dummyCycleRead1 = 0; //no dummy cycles
+ l_ctlregCE1.dummyCycleRead2 = 0b00; //no dummy cycles
+ l_ctlregCE1.cmdMode = 0b00; //00:Normal Read (03h + Address + Read data)
+ **/
+
+ iv_ctlRegCE0Default = l_ctlregCE0; // Default setup is regular read mode
+ // @TODO RTC:162680 iv_ctlRegCE1Default = l_ctlregCE1;
+
+ // Configure CE0 for read
+ l_lpc_addr = CE0_CTRLREG_10 | SPIC_BASE_ADDR_AHB;
+ l_err = ahbSioWriteWrapper(l_ctlregCE0.data32, l_lpc_addr);
+ if( l_err ) { break; }
+
+ /* @TODO RTC:162680
+ // Configure CE1 for read
+ l_lpc_addr = CE1_CTRLREG_14 | SPIC_BASE_ADDR_AHB;
+ l_err = ahbSioWriteWrapper(l_ctlregCE1.data32, l_lpc_addr);
+ 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"SfcAST2500::hwInit> err=%.8X", ERRL_GETEID_SAFE(l_err) );
+ return l_err;
+}
+
+/**
+ * @brief Enter/exit command mode
+ */
+errlHndl_t SfcAST2500::commandMode( bool i_enter )
+{
+ errlHndl_t l_err = NULL;
+ uint32_t l_lpc_addr;
+ TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2500::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 {
+ //@TODO RTC:162680 - Does this path also need to enable
+ // the CE1 control reg (0x14)
+ SpiCE0ControlReg10_t ctlreg = iv_ctlRegCE0Default;
+
+ // Switch to user mode, CE# dropped
+ ctlreg.stopActiveCtl = 1;
+ ctlreg.cmdMode = 0b11; //User Mode (Read/Write Data)
+ l_lpc_addr = CE0_CTRLREG_10 | SPIC_BASE_ADDR_AHB;
+ l_err = ahbSioWriteWrapper(ctlreg.data32, l_lpc_addr);
+ if( l_err ) { break; }
+
+ if( i_enter ) //ast_sf_start_cmd
+ {
+ // user mode, CE# active
+ ctlreg.stopActiveCtl = 0;
+ l_err = ahbSioWriteWrapper(ctlreg.data32, l_lpc_addr);
+ if( l_err ) { break; }
+ }
+ else //ast_sf_end_cmd
+ {
+ // Switch back to read mode
+ l_err = ahbSioWriteWrapper(iv_ctlRegCE0Default.data32, l_lpc_addr);
+ if( l_err ) { break; }
+ }
+
+ } while(0);
+
+ TRACDCOMP( g_trac_pnor, EXIT_MRK"SfcAST2500::commandMode> err=%.8X", ERRL_GETEID_SAFE(l_err) );
+ return l_err;
+}
diff --git a/src/usr/pnor/sfc_ast2500.H b/src/usr/pnor/sfc_ast2500.H
new file mode 100644
index 000000000..73f07c58a
--- /dev/null
+++ b/src/usr/pnor/sfc_ast2500.H
@@ -0,0 +1,192 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/pnor/sfc_ast2500.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2016 */
+/* [+] 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_SFCAST2500_H
+#define __PNOR_SFCAST2500_H
+
+#include <limits.h>
+#include <targeting/common/targetservice.H>
+#include <errl/errlentry.H>
+#include "sfcdd.H"
+#include "sfc_ast2X00.H"
+#include <config.h>
+
+/** @file sfc_ast2500.H
+ * @brief Provides the logic to access and configure the
+ * AST2500 BMC in order to access the PNOR
+ */
+
+/**
+ * @brief AST2500 SFC Device Driver Class
+ * Provides the logic to access and configure the
+ * AST2500 BMC in order to access the PNOR
+ */
+class SfcAST2500 : public SfcAST2X00
+{
+
+ public: //SfcDD methods
+ /**
+ * @brief Initialize the SFC Hardware
+ *
+ * @return void
+ */
+ virtual errlHndl_t hwInit();
+
+ /**
+ * @brief Enter/exit command mode
+ *
+ * @param[in] i_enter: true=enter cmd mode, false=exit cmd mode
+ *
+ * @return Error from operation
+ */
+ virtual errlHndl_t commandMode( bool i_enter );
+
+ public:
+ /**
+ * @brief Constructor
+ * @param[out] Return any error in constructor
+ * @param[in] Processor target associated with the LPC master
+ */
+ SfcAST2500( 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, //SPIR00
+ CE_CTLREG_04 = 0x04, //SPIR04
+ INTRPCTLSTATUSREG_08 = 0x08, //SPIR08
+ COMMANDCTRLREG_0C = 0x0C, //SPIR0C
+ CE0_CTRLREG_10 = 0x10, //SPIR10
+ CE1_CTRLREG_14 = 0x14, //SPIR14
+ READTIMEREG_94 = 0x94, //SPIR94
+ };
+
+ /**
+ * @brief SPI0 Configuration Register
+ */
+ union SpiConfigReg00_t
+ {
+ uint32_t data32;
+ struct
+ { //Little-endian bit positions
+ uint32_t rsvd : 14; //31:18
+ uint32_t enableCE1Write : 1; //17
+ uint32_t enableCE0Write : 1; //16
+ uint32_t rsvd2 : 16; //15:0
+ };
+ SpiConfigReg00_t() : data32(0) {};
+ };
+
+ /**
+ * @brief SPI04 CE Control Register
+ */
+ union SpiCEControlReg04_t
+ {
+ uint32_t data32;
+ struct
+ { //Little-endian bit positions
+ uint32_t ceSwapControl : 1; //31
+ uint32_t rsvd : 21; //30:10
+ uint32_t enableCE1Div2 : 1; //9
+ uint32_t enableCE0Div2 : 1; //8
+ uint32_t rsvd2 : 6; //7:2
+ uint32_t fourByteModeCE1 : 1; //1
+ uint32_t fourByteModeCE0 : 1; //0
+ };
+ SpiCEControlReg04_t() : data32(0) {};
+ };
+
+ /**
+ * @brief SPI10 CE0 Control Register
+ */
+ union SpiCE0ControlReg10_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 spiClkDivide4Mode : 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
+ };
+ SpiCE0ControlReg10_t() : data32(0) {};
+ };
+
+ /**
+ * @brief Default value of SPI10 (saves a read)
+ */
+ SpiCE0ControlReg10_t iv_ctlRegCE0Default;
+
+ /**
+ * @brief SPI14 CE1 Control Register
+ */
+ union SpiCE1ControlReg14_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 spiClkDivide4Mode : 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
+ };
+ SpiCE1ControlReg14_t() : data32(0) {};
+ };
+
+ /**
+ * @brief Default value of SPI14 (saves a read)
+ */
+ SpiCE1ControlReg14_t iv_ctlRegCE1Default;
+
+ friend class SfcAST2500Test;
+};
+
+#endif
diff --git a/src/usr/pnor/sfc_ast2X00.C b/src/usr/pnor/sfc_ast2X00.C
new file mode 100644
index 000000000..4efededb4
--- /dev/null
+++ b/src/usr/pnor/sfc_ast2X00.C
@@ -0,0 +1,573 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/pnor/sfc_ast2X00.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2016 */
+/* [+] 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 <sio/sio.H>
+#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_ast2X00.H"
+#include "norflash.H"
+#include <util/align.H>
+#include "pnor_common.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 SfcAST2X00 object" );
+ o_sfc = new SfcAST2X00( l_err, i_proc );
+ return l_err;
+}
+**/
+};
+
+/**
+ * @brief Constructor
+ */
+SfcAST2X00::SfcAST2X00( errlHndl_t& o_err,
+ TARGETING::Target* i_proc )
+: SfcDD(o_err,i_proc)
+{
+}
+
+/**
+ * @brief Read data from the flash
+ */
+errlHndl_t SfcAST2X00::readFlash( uint32_t i_addr,
+ size_t i_size,
+ void* o_data )
+{
+ errlHndl_t l_err = NULL;
+ TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2X00::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 = (ALIGN_4(i_size))/4;
+ for( uint32_t words_read = 0;
+ words_read < word_size;
+ words_read ++ )
+ {
+ //Read directly from MMIO space
+ uint32_t lpc_addr = PNOR::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"SfcAST2X00::readFlash> err=%.8X", ERRL_GETEID_SAFE(l_err) );
+ return l_err;
+}
+
+
+/**
+ * @brief Write data into flash
+ */
+errlHndl_t SfcAST2X00::writeFlash( uint32_t i_addr,
+ size_t i_size,
+ void* i_data )
+{
+ TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2X00::writeFlash> i_addr=0x%.8x, i_size=0x%.8x", i_addr, i_size );
+ errlHndl_t l_err = NULL;
+ size_t l_bytes_left = i_size;
+ size_t l_bytes_to_write = 0;
+ uint32_t l_addr_to_write = i_addr;
+ uint8_t* l_dataptr = reinterpret_cast<uint8_t*>(i_data);
+
+ do {
+ // Enable write mode
+ l_err = enableWriteMode();
+ if( l_err ) { break; }
+
+ // Page Program (PP) command only supports 256 bytes at a time
+ if( l_bytes_left <= PNOR::PAGE_PROGRAM_BYTES )
+ {
+ l_bytes_to_write = l_bytes_left;
+ l_bytes_left = 0;
+ }
+ else
+ {
+ l_bytes_to_write = PNOR::PAGE_PROGRAM_BYTES;
+ l_bytes_left -= PNOR::PAGE_PROGRAM_BYTES;
+ }
+
+ // Send in the Page Program command with the data to write
+ uint8_t opcode = PNOR::SPI_JEDEC_PAGE_PROGRAM;
+ l_err = sendSpiCmd( opcode, l_addr_to_write,
+ l_bytes_to_write,
+ l_dataptr,
+ 0, NULL );
+ if( l_err ) { break; }
+
+ // Move to the next chunk
+ l_addr_to_write += l_bytes_to_write;
+ l_dataptr += l_bytes_to_write;
+
+ // 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(l_bytes_left);
+
+ TRACDCOMP( g_trac_pnor, EXIT_MRK"SfcAST2X00::writeFlash> err=%.8X", ERRL_GETEID_SAFE(l_err) );
+ return l_err;
+}
+
+
+/**
+ * @brief Erase a block of flash
+ */
+errlHndl_t SfcAST2X00::eraseFlash( uint32_t i_addr )
+{
+ TRACDCOMP(g_trac_pnor, ">>SfcAST2X00::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"SfcAST2X00::eraseFlash> err=%.8X", ERRL_GETEID_SAFE(l_err) );
+ return l_err;
+}
+
+//function to call SIO dd for ahb sio read
+errlHndl_t SfcAST2X00::ahbSioReadWrapper(uint32_t i_ahb_sio_data,
+ uint32_t i_lpc_addr)
+{
+ size_t l_ahb_sio_len = sizeof(i_ahb_sio_data);
+ return deviceOp( DeviceFW::READ,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(i_ahb_sio_data),
+ l_ahb_sio_len,
+ DEVICE_AHB_SIO_ADDRESS(i_lpc_addr));
+}
+
+//function to call SIO dd for ahb sio write
+errlHndl_t SfcAST2X00::ahbSioWriteWrapper(uint32_t i_ahb_sio_data,
+ uint32_t i_lpc_addr)
+{
+ size_t l_ahb_sio_len = sizeof(i_ahb_sio_data);
+ return deviceOp( DeviceFW::WRITE,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(i_ahb_sio_data),
+ l_ahb_sio_len,
+ DEVICE_AHB_SIO_ADDRESS(i_lpc_addr));
+}
+
+/**
+ * @brief Send a SPI command
+ */
+errlHndl_t SfcAST2X00::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"SfcAST2X00::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,
+ PNOR::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,
+ PNOR::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,
+ PNOR::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,
+ PNOR::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,
+ PNOR::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,
+ PNOR::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"SfcAST2X00::sendSpiCmd> o_readData=%.2X, err=%.8X", o_readData == NULL ? 0 : o_readData[0], ERRL_GETEID_SAFE(l_err) );
+ return l_err;
+}
+
+/**
+ * @brief Enable write mode
+ */
+errlHndl_t SfcAST2X00::enableWriteMode( void )
+{
+ errlHndl_t l_err = NULL;
+ TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2X00::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_SFCAST2X00_ENABLEWRITEMODE
+ * @reasoncode PNOR::RC_CANNOT_ENABLE_WRITES
+ * @userdata1[24:31] Output from RDSR
+ * @userdata1[32:63] NOR chip id
+ * @userdata2 <unused>
+ * @devdesc SfcAST2X00::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_SFCAST2X00_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"SfcAST2X00::enableWriteMode> err=%.8X", ERRL_GETEID_SAFE(l_err) );
+ return l_err;
+}
+
+/**
+ * @brief Poll for completion of SPI operation
+ */
+errlHndl_t SfcAST2X00::pollOpComplete( void )
+{
+ errlHndl_t l_err = NULL;
+ TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2X00::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,"SfcAST2X00::pollOpComplete> command took %d ns", poll_time);
+
+ // No status regs to check so just look for timeout
+ if( status.writeInProgress )
+ {
+ TRACFCOMP( g_trac_pnor, "SfcAST2X00::pollOpComplete> Timeout during write or erase" );
+
+ /*@
+ * @errortype
+ * @moduleid PNOR::MOD_SFCAST2X00_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 SfcAST2X00::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_SFCAST2X00_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"SfcAST2X00::pollOpComplete> err=%.8X", ERRL_GETEID_SAFE(l_err) );
+ return l_err;
+}
+
+/**
+ * @brief Add error registers to an existing Error Log
+ */
+void SfcAST2X00::addFFDC( errlHndl_t& io_errhdl )
+{
+ TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2X00::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"SfcAST2X00::addFFDC>" );
+}
diff --git a/src/usr/pnor/sfc_ast2X00.H b/src/usr/pnor/sfc_ast2X00.H
new file mode 100644
index 000000000..2847b75d3
--- /dev/null
+++ b/src/usr/pnor/sfc_ast2X00.H
@@ -0,0 +1,218 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/pnor/sfc_ast2X00.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2016 */
+/* [+] 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_SFCAST2X00_H
+#define __PNOR_SFCAST2X00_H
+
+#include <limits.h>
+#include <targeting/common/targetservice.H>
+#include <errl/errlentry.H>
+#include "sfcdd.H"
+#include <config.h>
+
+/** @file sfc_ast2X00.H
+ * @brief Provides the base logic to access and configure the
+ * AST2400 and AST2500 BMC in order to access the PNOR.
+ * Note: Where the controllers diverge, the child
+ * classes will implement the necessary functions.
+ *
+ *
+ */
+
+/**
+ * @brief AST2X00 SFC Device Driver Class
+ */
+class SfcAST2X00 : public SfcDD
+{
+
+ public: //SfcDD methods
+ /**
+ * @brief Initialize the SFC Hardware
+ *
+ * @return void
+ */
+ virtual errlHndl_t hwInit() = 0;
+
+ /**
+ * @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 );
+
+ /**
+ *
+ * @brief Function to call SIO dd for abh sio read
+ *
+ * @param[in] i_ahb_sio_data - Register to read data into
+ * @param[in] i_lpc_addr - Address to read from
+ * @param[out] errlHndl_t - Errorlog handle if an error occurred
+ */
+ virtual errlHndl_t ahbSioReadWrapper(uint32_t i_ahb_sio_data,
+ uint32_t i_lpc_addr);
+
+ /**
+ *
+ * @brief Function to call SIO dd for abh sio write
+ *
+ * @param[in] i_ahb_sio_data - Register containing data to write
+ * @param[in] i_lpc_addr - Address to read from
+ * @param[out] errlHndl_t - Errorlog handle if an error occurred
+ */
+ virtual errlHndl_t ahbSioWriteWrapper(uint32_t i_ahb_sio_data,
+ uint32_t i_lpc_addr);
+
+ /**
+ * @brief Enter/exit command mode
+ *
+ * @param[in] i_enter: true=enter cmd mode, false=exit cmd mode
+ *
+ * @return Error from operation
+ */
+ virtual errlHndl_t commandMode( bool i_enter ) = 0;
+
+ public:
+ /**
+ * @brief Constructor
+ * @param[out] Return any error in constructor
+ * @param[in] Processor target associated with the LPC master
+ */
+ SfcAST2X00( errlHndl_t& o_err,
+ TARGETING::Target* i_proc
+ = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL );
+
+ protected:
+ /**
+ * @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
+ */
+
+ /**
+ * @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 General Constants */
+ enum
+ {
+ /**< 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,
+ };
+};
+
+#endif
diff --git a/src/usr/pnor/test/pnorddtest.H b/src/usr/pnor/test/pnorddtest.H
index 3cf3ef350..eb1fa793e 100644
--- a/src/usr/pnor/test/pnorddtest.H
+++ b/src/usr/pnor/test/pnorddtest.H
@@ -133,8 +133,8 @@ class PnorDdTest : public CxxTest::TestSuite
break;
}
- // Perform PnorDD read 1
- uint64_t l_address =
+ // Perform PnorDD read 1
+ uint64_t l_address =
base_address + PNOR::pnorTestSec_readwrite_offset;
uint64_t l_readData = 0;
l_size = sizeof(uint64_t);
diff --git a/src/usr/pnor/test/sfc_ast2500test.H b/src/usr/pnor/test/sfc_ast2500test.H
new file mode 100644
index 000000000..536293ab9
--- /dev/null
+++ b/src/usr/pnor/test/sfc_ast2500test.H
@@ -0,0 +1,186 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/pnor/test/sfc_ast2500test.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2016 */
+/* [+] 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_AST2500TEST_H
+#define __SFC_AST2500TEST_H
+
+/**
+ * @file sfc_ast2500test.H
+ *
+ * @brief Test case for AST2500 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_ast2500.H"
+#include <sio/sio.H>
+
+extern trace_desc_t* g_trac_pnor;
+
+class SfcAST2500Test : 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);
+ TS_FAIL("SfcAST2500Test::getTestSection> Error encountered"
+ " trying to find PNOR::TEST section");
+ }
+ break;
+ }
+
+ l_err = PnorRP::getInstance().computeDeviceAddr((void*)info.vaddr,
+ o_physAddr,
+ chip_select,
+ needs_ecc);
+ if(l_err)
+ {
+ errlCommit(l_err,PNOR_COMP_ID);
+ TS_FAIL("SfcAST2500Test::getTestSection> Error encountered"
+ " computing device address");
+ 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();
+
+ //todo RTC:133649 -- enable once LPC error handling is in place
+ // SfcAST2500* sfc = reinterpret_cast<SfcAST2500*>(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, "SfcAST2500Test::test_FlashReads> Skipped due to not finding test section in PNOR" );
+ TS_FAIL("SfcAST2500Test::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("SfcAST2500Test::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
+ }
+
+ mutex_unlock(l_mutex);
+// *****************************************************
+// Skipping test where we try to read in command mode
+// We know this will fail, currently no solution in place
+// to relay error from BMC to HB
+// todo RTC:133649 -- enable once LPC error handling is in place
+// ********************************
+// // Put controller into command mode (instead of read mode)
+// l_err = sfc->commandMode( true );
+// if( l_err )
+// {
+// TS_FAIL("SfcAST2500Test::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("SfcAST2500Test::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("SfcAST2500Test::test_FlashReads> Error exiting command mode");
+// errlCommit(l_err,PNOR_COMP_ID);
+// }
+ }
+
+};
+
+#endif
OpenPOWER on IntegriCloud