diff options
author | Dean Sanner <dsanner@us.ibm.com> | 2015-11-10 07:33:39 -0600 |
---|---|---|
committer | Patrick Williams <iawillia@us.ibm.com> | 2015-12-11 13:56:27 -0600 |
commit | 1d7b38ba816f52b12e0c131ec5daf86b00886c63 (patch) | |
tree | f2ad0a1036582ac20abc1d6c931f78a135acd4ea /src/usr/lpc | |
parent | 90245203585d4212f507770094183aca1f73c4e6 (diff) | |
download | talos-hostboot-1d7b38ba816f52b12e0c131ec5daf86b00886c63.tar.gz talos-hostboot-1d7b38ba816f52b12e0c131ec5daf86b00886c63.zip |
Establish a working P9 Hostboot and Simics base
Includes changes for nimbus.por
Making recent Simics usable by Hostboot
Removing portions of code not yet ready
Basic LPC read/write
Change-Id: Ic40a9613934fab7bb6a28a8100685496246bb5ea
RTC:132170
Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/21931
Tested-by: Jenkins Server
Reviewed-by: WILLIAM G. HOFFA <wghoffa@us.ibm.com>
Reviewed-by: Christian Geddes <crgeddes@us.ibm.com>
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src/usr/lpc')
-rw-r--r-- | src/usr/lpc/lpcdd.C | 275 | ||||
-rw-r--r-- | src/usr/lpc/lpcdd.H | 126 |
2 files changed, 79 insertions, 322 deletions
diff --git a/src/usr/lpc/lpcdd.C b/src/usr/lpc/lpcdd.C index db217bda4..1e421bbe8 100644 --- a/src/usr/lpc/lpcdd.C +++ b/src/usr/lpc/lpcdd.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2014 */ +/* Contributors Listed Below - COPYRIGHT 2014,2015 */ /* [+] Google Inc. */ /* [+] International Business Machines Corp. */ /* */ @@ -378,8 +378,13 @@ LpcDD::LpcDD( TARGETING::Target* i_proc ) ,iv_resetActive(false) { TRACFCOMP(g_trac_lpc, "LpcDD::LpcDD> " ); - mutex_init( &iv_mutex ); + LPCBase_t baseAddr = LPC_PHYS_BASE + LPC_ADDR_START; + + + setLPCBaseAddr( static_cast<uint64_t *>( + mmio_dev_map(reinterpret_cast<void *>(baseAddr), + LPC_SPACE_SIZE ))); if( i_proc == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL ) { @@ -397,13 +402,14 @@ LpcDD::LpcDD( TARGETING::Target* i_proc ) ivp_mutex = &iv_mutex; } + //@todo RTC:126644 // Initialize the hardware - errlHndl_t l_errl = hwReset(LpcDD::RESET_INIT); - if( l_errl ) - { - TRACFCOMP( g_trac_lpc, "Errors initializing LPC logic... Beware! PLID=%.8X", l_errl->plid() ); - errlCommit(l_errl, LPC_COMP_ID); - } +// errlHndl_t l_errl = hwReset(LpcDD::RESET_INIT); +// if( l_errl ) +// { +// TRACFCOMP( g_trac_lpc, "Errors initializing LPC logic... Beware! PLID=%.8X", l_errl->plid() ); +// errlCommit(l_errl, LPC_COMP_ID); +// } } LpcDD::~LpcDD() @@ -411,13 +417,17 @@ LpcDD::~LpcDD() mutex_destroy( &iv_mutex ); } + /** * @brief Reset hardware to get into clean state */ errlHndl_t LpcDD::hwReset( ResetLevels i_resetLevel ) { + errlHndl_t l_err = NULL; +// @todo RTC:133649 Support P9 LPC controller - error detection +#if 0 TRACFCOMP( g_trac_lpc, ENTER_MRK"LpcDD::hwReset(i_resetLevel=%d)>", i_resetLevel ); - errlHndl_t l_err = NULL; + // check iv_resetActive to avoid infinite loops // and don't reset if in the middle of FFDC collection @@ -442,7 +452,6 @@ errlHndl_t LpcDD::hwReset( ResetLevels i_resetLevel ) {// Nothing to do here, so just break break; } - case RESET_INIT: { // Set OPB LPCM FIR Mask @@ -509,7 +518,6 @@ errlHndl_t LpcDD::hwReset( ResetLevels i_resetLevel ) opsize ); if (l_err) { break; } - // Clear FIR register scom_data_64 = ~(OPB_LPCM_FIR_ERROR_MASK); l_err = deviceOp( @@ -606,6 +614,7 @@ errlHndl_t LpcDD::hwReset( ResetLevels i_resetLevel ) } TRACFCOMP( g_trac_lpc, EXIT_MRK"LpcDD::hwReset()=%.8X:%.4X", ERRL_GETEID_SAFE(l_err), ERRL_GETRC_SAFE(l_err) ); +#endif return l_err; } @@ -615,7 +624,7 @@ errlHndl_t LpcDD::hwReset( ResetLevels i_resetLevel ) */ errlHndl_t LpcDD::checkAddr(LPC::TransType i_type, uint32_t i_addr, - uint32_t *o_addr) + uint64_t *o_addr) { bool invalid_address = false; switch ( i_type ) @@ -626,7 +635,7 @@ errlHndl_t LpcDD::checkAddr(LPC::TransType i_type, invalid_address = true; break; } - *o_addr = i_addr + LPCHC_IO_SPACE; + *o_addr = getLPCBaseAddr()+ i_addr+ LPCHC_IO_SPACE- LPC_ADDR_START; break; case LPC::TRANS_MEM: if( i_addr >= 0x10000000 ) @@ -634,17 +643,28 @@ errlHndl_t LpcDD::checkAddr(LPC::TransType i_type, invalid_address = true; break; } - *o_addr = i_addr + LPCHC_MEM_SPACE; + + *o_addr = getLPCBaseAddr()+ i_addr+ LPCHC_MEM_SPACE- LPC_ADDR_START; break; case LPC::TRANS_FW: - *o_addr = i_addr + LPCHC_FW_SPACE; + if( i_addr >= 0x10000000 ) + { + invalid_address = true; + break; + } + *o_addr = getLPCBaseAddr()+ i_addr + LPCHC_FW_SPACE- LPC_ADDR_START; break; case LPC::TRANS_REG: - *o_addr = i_addr + LPCHC_REG_SPACE; + if( i_addr >= 0x100 ) + { + invalid_address = true; + break; + } + *o_addr =getLPCBaseAddr()+ i_addr + LPCHC_REG_SPACE- LPC_ADDR_START; break; case LPC::TRANS_ABS: //Just use the address as given - *o_addr = i_addr; + *o_addr = getLPCBaseAddr() + i_addr; break; default: invalid_address = true; @@ -683,37 +703,18 @@ errlHndl_t LpcDD::_readLPC(LPC::TransType i_type, size_t& io_buflen) { errlHndl_t l_err = NULL; - uint32_t l_addr = 0; + uint64_t l_addr = 0; do { // Generate the full absolute LPC address l_err = checkAddr( i_type, i_addr, &l_addr ); if( l_err ) { break; } - // Execute command. - ControlReg_t eccb_cmd; - eccb_cmd.data_len = io_buflen; - eccb_cmd.read_op = 1; - eccb_cmd.addr_len = sizeof(l_addr); - eccb_cmd.address = l_addr; - size_t scom_size = sizeof(uint64_t); - l_err = deviceOp( DeviceFW::WRITE, - iv_proc, - &(eccb_cmd.data64), - scom_size, - DEVICE_SCOM_ADDRESS(ECCB_CTL_REG) ); - if( l_err ) { break; } - - // Poll for completion - StatusReg_t eccb_stat; - l_err = pollComplete( eccb_cmd, eccb_stat ); - if( l_err ) { break; } // Copy data out to caller's buffer. if( io_buflen <= sizeof(uint32_t) ) { - uint32_t tmpbuf = eccb_stat.read_data; - memcpy( o_buffer, &tmpbuf, io_buflen ); + memcpy( o_buffer, reinterpret_cast<void*>(l_addr), io_buflen ); } else { @@ -755,210 +756,21 @@ errlHndl_t LpcDD::_writeLPC(LPC::TransType i_type, size_t& io_buflen) { errlHndl_t l_err = NULL; - uint32_t l_addr = 0; + uint64_t l_addr = 0; do { // Generate the full absolute LPC address l_err = checkAddr( i_type, i_addr, &l_addr ); if( l_err ) { break; } - uint64_t eccb_data = 0; - // Left-justify user data into data register. - switch ( io_buflen ) - { - case 1: - eccb_data = static_cast<uint64_t>( - *reinterpret_cast<const uint8_t*>( i_buffer ) ) << 56; - break; - case 2: - eccb_data = static_cast<uint64_t>( - *reinterpret_cast<const uint16_t*>( i_buffer ) ) << 48; - break; - case 4: - eccb_data = static_cast<uint64_t>( - *reinterpret_cast<const uint32_t*>( i_buffer ) ) << 32; - break; - default: - TRACFCOMP( g_trac_lpc, "writeLPC> Unsupported buffer size : %d", io_buflen ); - assert( false ); - break; - } - - // Write data out - size_t scom_size = sizeof(uint64_t); - l_err = deviceOp( DeviceFW::WRITE, - iv_proc, - &eccb_data, - scom_size, - DEVICE_SCOM_ADDRESS(ECCB_DATA_REG) ); - if( l_err ) { break; } - - // Execute command. - ControlReg_t eccb_cmd; - eccb_cmd.data_len = io_buflen; - eccb_cmd.read_op = 0; - eccb_cmd.addr_len = sizeof(l_addr); - eccb_cmd.address = l_addr; - l_err = deviceOp( DeviceFW::WRITE, - iv_proc, - &(eccb_cmd.data64), - scom_size, - DEVICE_SCOM_ADDRESS(ECCB_CTL_REG) ); - if( l_err ) { break; } - - // Poll for completion - StatusReg_t eccb_stat; - l_err = pollComplete( eccb_cmd, eccb_stat ); - if( l_err ) { break; } + memcpy(reinterpret_cast<void*>(l_addr), i_buffer, io_buflen); } while(0); return l_err; } -/** - * @brief Poll for completion of LPC operation - */ -errlHndl_t LpcDD::pollComplete(const ControlReg_t &i_ctrl, - StatusReg_t& o_stat) -{ - // Note: Caller must lock mutex before calling this function - errlHndl_t l_err = NULL; - ResetLevels l_resetLevel = RESET_CLEAR; - do { - uint64_t poll_time = 0; - uint64_t loop = 0; - do - { - size_t scom_size = sizeof(uint64_t); - l_err = deviceOp( DeviceFW::READ, - iv_proc, - &(o_stat.data64), - scom_size, - DEVICE_SCOM_ADDRESS(ECCB_STAT_REG) ); - LPC_TRACFCOMP( g_trac_lpc, "writeLPC> Poll on ECCB Status, " - "poll_time=0x%.16x, stat=0x%.16x", - poll_time, - o_stat.data64 ); - if( l_err ) - { - break; - } - - if( o_stat.op_done ) - { - 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 - nanosleep( 0, ECCB_POLL_INCR_NS*(++loop) ); - poll_time += ECCB_POLL_INCR_NS * loop; - } while ( poll_time < ECCB_POLL_TIME_NS ); - - // Check for hw errors or timeout if no previous logs - if( (l_err == NULL) && - ((o_stat.data64 & ECCB_STAT_REG_ERROR_MASK) - || (!o_stat.op_done)) ) - { - TRACFCOMP( g_trac_lpc, "LpcDD::pollComplete> LPC error or timeout: " - "addr=0x%.8X, status=0x%.16X", - i_ctrl.address, o_stat.data64 ); - - if( i_ctrl.read_op ) - { - /*@ - * @errortype - * @moduleid LPC::MOD_LPCDD_READLPC - * @reasoncode LPC::RC_ECCB_ERROR - * @userdata1[0:31] LPC Address - * @userdata1[32:63] Total poll time (ns) - * @userdata2 ECCB Status Register - * @devdesc LpcDD::pollComplete> LPC error or timeout - * @custdesc Hardware error accessing internal - * bus during IPL - */ - l_err = new ERRORLOG::ErrlEntry( - ERRORLOG::ERRL_SEV_UNRECOVERABLE, - LPC::MOD_LPCDD_READLPC, - LPC::RC_ECCB_ERROR, - TWO_UINT32_TO_UINT64( - i_ctrl.address, poll_time), - o_stat.data64 ); - } - else - { - /*@ - * @errortype - * @moduleid LPC::MOD_LPCDD_WRITELPC - * @reasoncode LPC::RC_ECCB_ERROR - * @userdata1[0:31] LPC Address - * @userdata1[32:63] Total poll time (ns) - * @userdata2 ECCB Status Register - * @devdesc LpcDD::pollComplete> LPC error or timeout - * @custdesc Hardware error accessing internal - * bus during IPL - */ - l_err = new ERRORLOG::ErrlEntry( - ERRORLOG::ERRL_SEV_UNRECOVERABLE, - LPC::MOD_LPCDD_WRITELPC, - LPC::RC_ECCB_ERROR, - TWO_UINT32_TO_UINT64( - i_ctrl.address, poll_time), - o_stat.data64 ); - } - // Limited in callout: no LPC sub-target, so calling out processor - l_err->addHwCallout( iv_proc, - HWAS::SRCI_PRIORITY_HIGH, - HWAS::NO_DECONFIG, - HWAS::GARD_NULL ); - - addFFDC(l_err); - l_err->collectTrace(LPC_COMP_NAME); - l_err->collectTrace(XSCOM_COMP_NAME); - - // Reset ECCB - handled below - l_resetLevel = RESET_ECCB; - - break; - } - - // check for errors at OPB level - l_err = checkForOpbErrors( l_resetLevel ); - if( l_err ) { break; } - - } while(0); - - // If we have an error that requires a reset, do that here - if ( l_err && ( l_resetLevel != RESET_CLEAR ) ) - { - errlHndl_t tmp_err = hwReset(l_resetLevel); - if ( tmp_err ) - { - // Commit reset error since we have original error l_err - TRACFCOMP(g_trac_lpc, "LpcDD::pollComplete> Error from reset() after previous error eid=0x%X. Committing reset() error log eid=0x%X.", l_err->eid(), tmp_err->eid()); - - tmp_err->setSev(ERRORLOG::ERRL_SEV_INFORMATIONAL); - tmp_err->collectTrace(LPC_COMP_NAME); - tmp_err->plid(l_err->plid()); - errlCommit(tmp_err, LPC_COMP_ID); - } - - // Limited in callout: no LPC sub-target, so calling out processor - l_err->addHwCallout( iv_proc, - HWAS::SRCI_PRIORITY_HIGH, - HWAS::NO_DECONFIG, - HWAS::GARD_NULL ); - - addFFDC(l_err); - l_err->collectTrace(LPC_COMP_NAME); - l_err->collectTrace(XSCOM_COMP_NAME); - } - - return l_err; -} /** * @brief Add Error Registers to an existing Error Log @@ -975,11 +787,12 @@ void LpcDD::addFFDC(errlHndl_t & io_errl) ERRORLOG::ErrlUserDetailsLogRegister l_eud(iv_proc); + // @todo RTC:133649 Support P9 LPC controller - error detection // Add ECCB Status Register - l_eud.addData(DEVICE_SCOM_ADDRESS(ECCB_STAT_REG)); + //l_eud.addData(DEVICE_SCOM_ADDRESS(ECCB_STAT_REG)); // Add OPB LPC Master FIR - l_eud.addData(DEVICE_SCOM_ADDRESS(OPB_LPCM_FIR_REG)); + //l_eud.addData(DEVICE_SCOM_ADDRESS(OPB_LPCM_FIR_REG)); //@todo - add more LPC regs RTC:37744 //LPCIRQ_STATUS = 0x38 diff --git a/src/usr/lpc/lpcdd.H b/src/usr/lpc/lpcdd.H index 460a031d7..48fefa64c 100644 --- a/src/usr/lpc/lpcdd.H +++ b/src/usr/lpc/lpcdd.H @@ -32,6 +32,8 @@ #include <errl/errlentry.H> #include <lpc/lpcif.H> +typedef uint64_t LPCBase_t; + /** @file lpcdd.H * @brief Provides the interfaces to the LPC Device Driver */ @@ -40,6 +42,7 @@ * @brief LPC Device Driver Class * Provides access to the LPC bus for a specific Processor */ + class LpcDD { public: @@ -109,6 +112,26 @@ class LpcDD }; /** + * @brief Get the base address of the LPC space + * + * @return Pointer to base address + */ + uint64_t getLPCBaseAddr(void) + { + return iv_lpcBaseAddr; + }; + + /** + * @brief Set the base address of the LPC space + * + * @return Void + */ + void setLPCBaseAddr(uint64_t * i_baseLPCAddr) + { + iv_lpcBaseAddr = reinterpret_cast<uint64_t>(i_baseLPCAddr); + }; + + /** * @brief Constructor * @param[in] Processor target associated with the ECCB logic */ @@ -122,17 +145,6 @@ class LpcDD ~LpcDD(); protected: - /** - * @brief LPC HC Registers - * These are offsets within the LPC Host Controller Register Space - */ - enum LpcRegAddr { - LPC_REG_BAR0 = 0x00, /**< BAR0 : OPB register */ - LPC_REG_BAR1 = 0x04, /**< BAR1 : LPC I/O space */ - LPC_REG_BAR2 = 0x08, /**< BAR2 : LPC Memory space */ - LPC_REG_BAR3 = 0x0C, /**< BAR3 : LPC Firmware space */ - LPC_REG_ABRTCNT = 0x2C, /**< ABORT COUNT */ - }; /** @@ -145,19 +157,15 @@ class LpcDD LPCHC_IO_SPACE = 0xD0010000, /**< LPC Host Controller I/O Space */ LPCHC_REG_SPACE = 0xC0012000, /**< LPC Host Ctlr Register Space */ - ECCB_NON_FW_RESET_REG = 0x000B0001, /**< ECCB Reset Reg (non-FW) */ + /** Start of LPC Addr within the memory mapped space*/ + LPC_ADDR_START = 0xC0000000, + /** Size that LPC takes up (0xC0000000 to 0xFFFFFFFF)*/ + LPC_SPACE_SIZE = 0x40000000, + /** Physical addr of the start of LPC address space*/ + LPC_PHYS_BASE = 0x6030000000000, - ECCB_CTL_REG = 0x000B0020, /**< ECCB Control Reg (FW) */ - ECCB_RESET_REG = 0x000B0021, /**< ECCB Reset Reg (FW) */ - ECCB_STAT_REG = 0x000B0022, /**< ECCB Status Reg (FW) */ - ECCB_DATA_REG = 0x000B0023, /**< ECCB Data Reg (FW) */ - // Default Values to set for all operations - // 1101.0100.0000.000x.0000.0001.0000.0000.<address> - ECCB_CTL_REG_DEFAULT = 0xD400010000000000, - // Error bits: 41-43, 56 (52=cmd complete) (not 57: only non-fw use) - ECCB_STAT_REG_ERROR_MASK = 0x0000000000700080, /**< Error Bits */ /**< OPB LPCM Sync FIR Reg - used to read the FIR*/ OPB_LPCM_FIR_REG = 0x01010C00, @@ -174,68 +182,10 @@ class LpcDD OPB_MASTER_LS_CONTROL_REG = 0x008, /**<OPBM LS Control Reg */ LPCHC_RESET_REG = 0x0FC, /**<LPC HC Reset Register */ - ECCB_RESET_LPC_FAST_RESET = 1ULL << 62, /**< bit 1 = Fast reset */ - - #ifndef CONFIG_SFC_IS_IBM_DPSS - // Intel spec requires no LPC timeout during boot, however that guidance - // presumes the system can still boot without the LPC, which is not true - // for systems that require PNOR access. Therefore we'll allow plenty - // of time for delays to work themselves out, but still flag an error - // ahead of the watchdog timer expiring, so that it's easier to debug - // any problems. - ECCB_POLL_TIME_NS = 90000000, /**< max time should be 90s */ - #else - ECCB_POLL_TIME_NS = 400000, /**< max time should be 400ms */ - #endif - ECCB_POLL_INCR_NS = 10, /**< minimum increment during poll */ LPCHC_SYNC_CYCLE_COUNTER_INFINITE = 0xFF000000 }; - /** - * @brief ECCB Control Register Layout - */ - union ControlReg_t - { - uint64_t data64; - struct - { - // unused sections should be set to zero - uint64_t magic1 : 4; /**< 0:3 = b1101 per spec */ - uint64_t data_len : 4; /**< 4:7 = b0100 means 4 byte */ - uint64_t unused1 : 7; /**< 8:14 */ - uint64_t read_op : 1; /**< 15 = set for read operation */ - uint64_t unused2 : 7; /**< 16:22 */ - uint64_t addr_len : 3; /**< 23:25 = b100 means 4 byte */ - uint64_t unused3 : 6; /**< 26:31 */ - uint64_t address : 32; /**< 32:63 = LPC Address */ - }; - - ControlReg_t() : data64(ECCB_CTL_REG_DEFAULT) {}; - }; - - /** - * @brief ECCB Status Register Layout - */ - union StatusReg_t - { - uint64_t data64; - struct - { - uint64_t unused : 6; /**< 0:5 */ - uint64_t read_data : 32; /**< 6:37 */ - uint64_t unused1 : 3; /**< 38:40 */ - uint64_t eccb_err : 3; /**< 41:43 = ECCB_Error_Info */ - uint64_t busy : 1; /**< 44 = Operation Busy */ - uint64_t unused2 : 7; /**< 45:51 */ - uint64_t op_done : 1; /**< 52 = Command Complete */ - uint64_t unused3 : 3; /**< 53:55 */ - uint64_t addr_parity_err : 1; /**< 56 = ECC Address Register - Parity Error */ - uint64_t unused4 : 7; /**< 57:63 */ - }; - StatusReg_t() : data64(0) {}; - }; /** * @brief OPB-LPCM FIR Register Layout @@ -279,18 +229,7 @@ class LpcDD */ errlHndl_t checkAddr( LPC::TransType i_type, uint32_t i_addr, - uint32_t* o_addr ); - - /** - * @brief Poll for completion of LPC operation - * - * @param[in] i_ctrl Control register describing operation - * @param[out] o_stat Status register for failures - * - * @return errlHndl_t NULL on success, else error log - */ - errlHndl_t pollComplete( const ControlReg_t& i_ctrl, - StatusReg_t& o_stat ); + uint64_t* o_addr ); /** * @brief Add Error Registers to an existing Error Log @@ -373,6 +312,11 @@ class LpcDD */ bool iv_resetActive; + /** + * @brief Virtual Address of the begining of LPC address space + */ + uint64_t iv_lpcBaseAddr; + }; |