summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/control_word_ddr4.H
blob: 06d8b68c763a83a4a7f5ccdef067659adadf804a (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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/control_word_ddr4.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2017                        */
/* [+] 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 control_word_ddr4.C
/// @brief Run and manage the DDR4 control words for the RCD and data buffers
///
// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
// *HWP HWP Backup: Brian Silver <bsilver@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 1
// *HWP Consumed by: FSP:HB


#ifndef _MSS_CONTROL_WORD_H_
#define _MSS_CONTROL_WORD_H_

#include <fapi2.H>

#include <p9_mc_scom_addresses.H>

#include <c_str.H>
#include <lib/ccs/ccs.H>

namespace mss
{

enum control_word
{
    // buffer control words
    BCW_4BIT,
    BCW_8BIT,

    // register control words
    RCW_4BIT,
    RCW_8BIT,

};

///
/// @class cw_data
/// @brief class that represents (register/buffer) control word data
///
struct cw_data
{
    // function space #
    fapi2::buffer<uint8_t> iv_func_space;

    // Which control word# this is (rcw or bcw)
    fapi2::buffer<uint8_t> iv_number;

    // The attribute getter
    fapi2::ReturnCode (*iv_attr_get)(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&, uint8_t&);

    // The cw value
    fapi2::buffer<uint8_t> iv_data;

    // The delay needed after this CW word is written
    uint64_t iv_delay;

    ///
    /// @brief NO-OP function to avoid a function nullptr
    /// @param[in] i_target a DIMM target
    /// @param[out] o_output output remains unchanged
    /// @return FAPI2_RC_SUCCESS iff okay
    ///
    static fapi2::ReturnCode no_op_func(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, uint8_t& o_output)
    {
        return fapi2::FAPI2_RC_SUCCESS;
    }

    ///
    /// @brief ctor for attribute driven data
    ///
    cw_data( const uint64_t i_func_space,
             const uint64_t i_number,
             fapi2::ReturnCode (*i_func)(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&, uint8_t&),
             const  uint64_t i_delay ):
        iv_func_space(i_func_space),
        iv_number(i_number),
        iv_attr_get(i_func),
        iv_data(0),
        iv_delay(i_delay)
    {}

    ///
    /// @brief ctor for custom data
    ///
    cw_data( const uint64_t i_func_space,
             const uint64_t i_number,
             const uint64_t i_data,
             const uint64_t i_delay):
        iv_func_space(i_func_space),
        iv_number(i_number),
        iv_data(i_data),
        iv_delay(i_delay)
    {
        // Setting the attribute accessor function pointer to NO-OP
        // when we call the ctor that doesn't use it to avoid cases
        // when iv_attr_get can be nullptr and potentially cause a seg fault
        iv_attr_get = &no_op_func;
    }

};

///
/// @class cwTraits
/// @brief a collection of traits associated with the control word engine
///
template< control_word T >
class cwTraits;

///
/// @class cwTraits
/// @brief a collection of traits associated with the 8-bit buffer control words
///
template< >
class cwTraits< BCW_8BIT >
{
    public:
        static constexpr uint64_t DATA_LEN = 8;
        static constexpr uint64_t WORD_LEN = 4;
        static constexpr uint64_t SWIZZLE_START = 7;
};

///
/// @class cwTraits
/// @brief a collection of traits associated with the 4-bit buffer control words
///
template< >
class cwTraits< BCW_4BIT >
{
    public:
        static constexpr uint64_t DATA_LEN = 4;
        static constexpr uint64_t WORD_LEN = 4;
        static constexpr uint64_t SWIZZLE_START = 7;
};

///
/// @class cwTraits
/// @brief a collection of traits associated with the 8-bit register control words
///
template< >
class cwTraits< RCW_8BIT >
{
    public:
        static constexpr uint64_t DATA_LEN = 8;
        static constexpr uint64_t WORD_LEN = 5;
        static constexpr uint64_t SWIZZLE_START = 7;
};

///
/// @class cwTraits
/// @brief a collection of traits associated with the 4-bit register control words
///
template< >
class cwTraits< RCW_4BIT >
{
    public:
        static constexpr uint64_t DATA_LEN = 4;
        static constexpr uint64_t WORD_LEN = 4;
        static constexpr uint64_t SWIZZLE_START = 7;
};

///
/// @brief Helper function to set an RCD or data buffer command to the CCS instruction
/// @tparam T the buffer control word type (4 bit or 8 bit)
/// @tparam TT traits type defaults to cwTraits<T>
/// @tparam OT the TargetType of the CCS instruction
/// @param[in] i_target a DIMM target
/// @param[in,out] io_inst a vector of CCS instructions we should add to
/// @return FAPI2_RC_SUCCESS if and only if ok
///
template< control_word T, typename TT = cwTraits<T>, fapi2::TargetType OT >
static void  set_cw_command( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
                             ccs::instruction_t<OT>& o_inst);

///
/// @brief Helper function to set an RCD or data buffer command to the CCS instruction
/// @param[in] i_target a DIMM target
/// @param[in,out] io_inst a vector of CCS instructions we should add to
/// @return FAPI2_RC_SUCCESS if and only if ok
/// @note BCW_4BIT specialization
///
template< >
inline void set_cw_command<BCW_4BIT>( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
                                      ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST>& o_inst)
{
    // Address bit 12 must be 1 for accesses to Data Buffer (DB) Control Words.
    constexpr uint64_t DDR_ADDRESS_12 = 12;

    o_inst = ccs::rcd_command<fapi2::TARGET_TYPE_MCBIST>(i_target);
    o_inst.arr0.setBit<DDR_ADDRESS_12>();
}

///
/// @brief Helper function to set an RCD or data buffer command to the CCS instruction
/// @param[in] i_target a DIMM target
/// @param[in,out] io_inst a vector of CCS instructions we should add to
/// @return FAPI2_RC_SUCCESS if and only if ok
/// @note BCW_8BIT specialization
///
template< >
inline void set_cw_command<BCW_8BIT> ( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
                                       ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST>& o_inst)
{
    set_cw_command<BCW_4BIT>(i_target, o_inst);
}

///
/// @brief Helper function to set an RCD or data buffer command to the CCS instruction
/// @param[in] i_target a DIMM target
/// @param[in,out] io_inst a vector of CCS instructions we should add to
/// @return FAPI2_RC_SUCCESS if and only if ok
/// @note RCW_4BIT specialization
///
template< >
inline void set_cw_command<RCW_4BIT>( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
                                      ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST>& o_inst)
{
    o_inst = ccs::rcd_command<fapi2::TARGET_TYPE_MCBIST>(i_target);
}

///
/// @brief Helper function to set an RCD or data buffer command to the CCS instruction
/// @param[in] i_target a DIMM target
/// @param[in,out] io_inst a vector of CCS instructions we should add to
/// @return FAPI2_RC_SUCCESS if and only if ok
/// @note RCW_8BIT specialization
///
template< >
inline void set_cw_command<RCW_8BIT>( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
                                      ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST>& o_inst)
{
    set_cw_command<RCW_4BIT>(i_target, o_inst);
}

///
/// @brief Control word engine that sets the CCS instruction
/// @tparam T the buffer control word type (4 bit or 8 bit)
/// @tparam TT traits type defaults to cwTraits<T>
/// @tparam OT the TargetType of the CCS instruction
/// @param[in] i_target a DIMM target
/// @param[in] i_data control word data to send
/// @param[in,out] io_inst a vector of CCS instructions we should add to
/// @return FAPI2_RC_SUCCESS if and only if ok
///
template< control_word T, typename TT = cwTraits<T>, fapi2::TargetType OT >
fapi2::ReturnCode control_word_engine(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
                                      const cw_data& i_data,
                                      std::vector< ccs::instruction_t<OT> >& io_inst)
{
    ccs::instruction_t<OT> l_inst;
    set_cw_command<T>(i_target, l_inst);

    // For user defined data, iv_data is user defined and iv_attr_get is a NO-OP
    // For attribute defined data, iv_attr_get will define datna and l_value initialization is overwritten
    // I need l_value integral because the attribute accessor template deduction doesn't let me use buffers
    // and since I'm passing in bcw data as const I can't pass in iv_data to the attribute accessor
    // which would break const correctness
    uint8_t l_value = i_data.iv_data;
    FAPI_TRY( i_data.iv_attr_get(i_target, l_value) );

    // Data to be written into the configuration registers
    // 4-bit control are containned in bits DA0 thorugh DA3
    // 8-bit control are contained in bits DA0 thorugh DA7
    mss::swizzle< MCBIST_CCS_INST_ARR0_00_DDR_ADDRESS_0_13,
        TT::DATA_LEN, TT::SWIZZLE_START >(fapi2::buffer<uint8_t>(l_value), l_inst.arr0);

    // Selection of each word of control bits
    // 4-bit control words are selected by bits on DA4 through DA11
    // 8-bit control words are selected by bits on DA8 through DA11
    mss::swizzle < MCBIST_CCS_INST_ARR0_00_DDR_ADDRESS_0_13 + TT::DATA_LEN,
        TT::WORD_LEN, TT::SWIZZLE_START > (i_data.iv_number, l_inst.arr0);

    // For changes to the control word setting [...] the controller needs to wait tMRC[tDLLK] after
    // the last control word access, before further access to the DRAM can take place.
    l_inst.arr1.template insertFromRight<MCBIST_CCS_INST_ARR1_00_IDLES,
                         MCBIST_CCS_INST_ARR1_00_IDLES_LEN>(i_data.iv_delay);

    FAPI_INF("F%d%s%02d%s value 0x%x (%d cycles) 0x%016llx:0x%016llx %s",
             uint8_t(i_data.iv_func_space),
             (T == BCW_4BIT || T == BCW_8BIT ? "BC" : "RC"),
             uint8_t(i_data.iv_number),
             (T == BCW_4BIT || T == RCW_4BIT ? "" : "X"),
             l_value,
             i_data.iv_delay,
             uint64_t(l_inst.arr0), uint64_t(l_inst.arr1),
             mss::c_str(i_target));

    io_inst.push_back(l_inst);

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Control word engine that sets the CCS instruction
/// @tparam T the buffer control word type (4 bit or 8 bit)
/// @tparam TT traits type defaults to cwTraits<T>
/// @tparam OT the TargetType of the CCS instruction
/// @param[in] i_target a DIMM target
/// @param[in] i_data_list a vector of control word data to send
/// @param[in,out] io_inst a vector of CCS instructions we should add to
/// @return FAPI2_RC_SUCCESS if and only if ok
///
template< control_word T, typename TT = cwTraits<T>, fapi2::TargetType OT >
fapi2::ReturnCode control_word_engine(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
                                      const std::vector<cw_data>& i_data_list,
                                      std::vector< ccs::instruction_t<OT> >& io_inst)
{
    for (const auto& data : i_data_list)
    {
        FAPI_TRY( control_word_engine<T>(i_target, data, io_inst) );
    }

fapi_try_exit:
    return fapi2::current_err;
}

}// mss

#endif
OpenPOWER on IntegriCloud