summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/procedures/hwp/memory/p9_mss_draminit.C
blob: 62a9e31142f9bfc1f29129aa29ce968acb704ff2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/* 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 <jlharvey@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: FSP:HB

#include <lib/shared/nimbus_defaults.H>
#include <fapi2.H>
#include <mss.H>

#include <p9_mss_draminit.H>
#include <generic/memory/lib/utils/count_dimm.H>
#include <lib/utils/mss_nimbus_conversions.H>
#include <lib/dimm/bcw_load.H>
#include <lib/workarounds/dqs_align_workarounds.H>
#include <lib/mc/port.H>

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<TARGET_TYPE_MCBIST>& i_target )
    {
        fapi2::buffer<uint64_t> 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<TARGET_TYPE_MCA>(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<uint64_t> 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<uint64_t>(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;
    }
}
OpenPOWER on IntegriCloud