diff options
author | Bill Hoffa <wghoffa@us.ibm.com> | 2016-09-16 15:09:28 -0500 |
---|---|---|
committer | Matthew A. Ploetz <maploetz@us.ibm.com> | 2016-10-31 15:49:47 -0400 |
commit | fde2240fafb48866ef3324f57ae7f4417625ad18 (patch) | |
tree | 418a4b243625c08b0bded4675e8a174d3ffcbd20 | |
parent | 0cb19a22319130ec4ebeb64ee87a47328297486e (diff) | |
download | talos-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.H | 12 | ||||
-rw-r--r-- | src/makefile | 2 | ||||
-rw-r--r-- | src/usr/lpc/lpcdd.C | 6 | ||||
-rw-r--r-- | src/usr/pnor/HBconfig | 12 | ||||
-rw-r--r-- | src/usr/pnor/makefile | 4 | ||||
-rw-r--r-- | src/usr/pnor/sfc_ast2400.C | 492 | ||||
-rw-r--r-- | src/usr/pnor/sfc_ast2400.H | 124 | ||||
-rw-r--r-- | src/usr/pnor/sfc_ast2500.C | 267 | ||||
-rw-r--r-- | src/usr/pnor/sfc_ast2500.H | 192 | ||||
-rw-r--r-- | src/usr/pnor/sfc_ast2X00.C | 573 | ||||
-rw-r--r-- | src/usr/pnor/sfc_ast2X00.H | 218 | ||||
-rw-r--r-- | src/usr/pnor/test/pnorddtest.H | 4 | ||||
-rw-r--r-- | src/usr/pnor/test/sfc_ast2500test.H | 186 |
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 |