/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* $Source: src/import/chips/p9/procedures/hwp/memory/p9_mss_draminit.C $ */ /* */ /* OpenPOWER HostBoot Project */ /* */ /* Contributors Listed Below - COPYRIGHT 2015,2019 */ /* [+] 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 */ /// /// @file p9_mss_draminit.C /// @brief Initialize dram /// // *HWP HWP Owner: Jacob L Harvey // *HWP HWP Backup: Andre Marin // *HWP Team: Memory // *HWP Level: 3 // *HWP Consumed by: FSP:HB #include #include #include #include #include #include #include #include #include using fapi2::TARGET_TYPE_MCBIST; using fapi2::TARGET_TYPE_MCA; using fapi2::TARGET_TYPE_DIMM; using fapi2::FAPI2_RC_SUCCESS; extern "C" { /// /// @brief Initialize dram /// @param[in] i_target, the McBIST of the ports of the dram you're initializing /// @return FAPI2_RC_SUCCESS iff ok /// fapi2::ReturnCode p9_mss_draminit( const fapi2::Target& i_target ) { fapi2::buffer l_data; // Up, down P down, up N. Somewhat magic numbers - came from Centaur and proven to be the // same on Nimbus. Why these are what they are might be lost to time ... constexpr uint64_t PCLK_INITIAL_VALUE = 0b10; constexpr uint64_t NCLK_INITIAL_VALUE = 0b01; const auto l_mcas = mss::find_targets(i_target); FAPI_INF("Start draminit: %s", mss::c_str(i_target)); // If we don't have any ports, lets go. if (l_mcas.size() == 0) { FAPI_INF("++++ No ports? %s ++++", mss::c_str(i_target)); return fapi2::FAPI2_RC_SUCCESS; } // If we don't have any DIMM, lets go. if (mss::count_dimm(i_target) == 0) { FAPI_INF("++++ NO DIMM on %s ++++", mss::c_str(i_target)); return fapi2::FAPI2_RC_SUCCESS; } // Configure the CCS engine. Since this is a chunk of MCBIST logic, we don't want // to do it for every port. If we ever break this code out so f/w can call draminit // per-port (separate threads) we'll need to provide them a way to set this up before // sapwning per-port threads. { fapi2::buffer l_ccs_config; FAPI_TRY( mss::ccs::read_mode(i_target, l_ccs_config), "%s Failed ccs read_mode in p9_mss_draminit", mss::c_str(i_target) ); // It's unclear if we want to run with this true or false. Right now (10/15) this // has to be false. Shelton was unclear if this should be on or off in general BRS mss::ccs::stop_on_err(i_target, l_ccs_config, mss::LOW); mss::ccs::ue_disable(i_target, l_ccs_config, mss::LOW); mss::ccs::copy_cke_to_spare_cke(i_target, l_ccs_config, mss::HIGH); mss::ccs::parity_after_cmd(i_target, l_ccs_config, mss::HIGH); FAPI_TRY( mss::ccs::write_mode(i_target, l_ccs_config), "%s Failed ccs write_mode in p9_mss_draminit", mss::c_str(i_target) ); } // We initialize dram by iterating over the (ungarded) ports. We could allow the caller // to initialize each port's dram on a separate thread if we could synchronize access // to the MCBIST (CCS engine.) Right now we can't, so we'll do it this way. // // We expect to come in to draminit with the following setup: // 1. ENABLE_RESET_N (FARB5Q(6)) 0 // 2. RESET_N (FARB5Q(4)) 0 - driving reset // 3. CCS_ADDR_MUX_SEL (FARB5Q(5)) - 1 // 4. CKE out of high impedence // for (const auto& p : l_mcas) { FAPI_TRY( mss::draminit_entry_invariant(p), "%s Failed mss::draminit_entry_invariant in p9_mss_draminit", mss::c_str(i_target) ); // Begin driving mem clks, and wait 10ns (we'll do this outside the loop) // From the RCD Spec, before the DRST_n (resetn) input is pulled HIGH the // clock input signal must be stable. FAPI_TRY( mss::drive_mem_clks(p, PCLK_INITIAL_VALUE, NCLK_INITIAL_VALUE), "%s Failed mss::drive_mem_clks in p9_mss_draminit", mss::c_str(i_target) ); // After RESET_n is de-asserted, wait for another 500us until CKE becomes active. // During this time, the DRAM will start internal initialization; this will be done // independently of external clocks. FAPI_TRY( mss::ddr_resetn(p, mss::HIGH), "%s Failed mss::resetn in p9_mss_draminit", mss::c_str(i_target) ); } // From the DDR4 JEDEC Spec (79-A): Power-up Initialization Sequence { // Clocks (CK_t,CK_c) need to be started and stable for 10ns or 5tCK // (whichever is greater) before CKE goes active. // Doing this once here than twice in drive_mem_clks constexpr uint64_t DELAY_5TCK = 5; const uint64_t l_delay_in_ns = std::max( static_cast(mss::DELAY_10NS), mss::cycles_to_ns(i_target, DELAY_5TCK) ); const uint64_t l_delay_in_cycles = mss::ns_to_cycles(i_target, l_delay_in_ns); // Set our delay (for HW and SIM) FAPI_TRY( fapi2::delay(l_delay_in_ns, mss::cycles_to_simcycles(l_delay_in_cycles)), "%s Failed delay in p9_mss_draminit", mss::c_str(i_target) ); } // Holds our CKE high for 400 cycles - required by the JEDEC spec FAPI_TRY( mss::draminit_cke_helper(l_mcas[0]), "%s Failed to hold CKE high in p9_mss_draminit", mss::c_str(i_target)); // Per conversation with Shelton and Steve 10/9/15, turn off addr_mux_sel after the CKE CCS but // before the RCD/MRS CCSs for (const auto& p : l_mcas) { FAPI_TRY( change_addr_mux_sel(p, mss::LOW), "%s Failed change_addr_mux_sel in p9_mss_draminit", mss::c_str(i_target) ); } // Load RCD control words FAPI_TRY( mss::rcd_load(i_target), "%s Failed rcd_load in p9_mss_draminit", mss::c_str(i_target) ); // Load data buffer control words (BCW) FAPI_TRY( mss::bcw_load(i_target), "%s Failed bcw_load in p9_mss_draminit", mss::c_str(i_target) ); // Load MRS FAPI_TRY( mss::mrs_load(i_target), "%s Failed mrs_load in p9_mss_draminit", mss::c_str(i_target) ); fapi_try_exit: FAPI_INF("End draminit: %s (0x%lx)", mss::c_str(i_target), uint64_t(fapi2::current_err)); return fapi2::current_err; } }