1 /***********************license start***********************************
2 * Copyright (c) 2003-2017 Cavium Inc. ([email protected]). All rights
3 * reserved.
4 *
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * * Neither the name of Cavium Inc. nor the names of
19 * its contributors may be used to endorse or promote products
20 * derived from this software without specific prior written
21 * permission.
22 *
23 * This Software, including technical data, may be subject to U.S. export
24 * control laws, including the U.S. Export Administration Act and its
25 * associated regulations, and may be subject to export or import
26 * regulations in other countries.
27 *
28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29 * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT
31 * TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
32 * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
33 * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
34 * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
35 * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT,
36 * QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK
37 * ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38 ***********************license end**************************************/
39 #include <bdk.h>
40 #include <bdk-coreboot.h>
41 #include <libbdk-hal/bdk-utils.h>
42
43
44 /**
45 * Return the number of LMC controllers in use
46 *
47 * @param node Node to probe
48 *
49 * @return 2 or 4 depending on the mode
50 */
__bdk_dram_get_num_lmc(bdk_node_t node)51 int __bdk_dram_get_num_lmc(bdk_node_t node)
52 {
53 if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
54 {
55 BDK_CSR_INIT(lmcx_dll_ctl2, node, BDK_LMCX_DLL_CTL2(2)); // sample LMC2
56 return (lmcx_dll_ctl2.s.intf_en) ? 4 : 2;
57 }
58 else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
59 {
60 BDK_CSR_INIT(lmcx_dll_ctl1, node, BDK_LMCX_DLL_CTL2(1)); // sample LMC1
61 return (lmcx_dll_ctl1.s.intf_en) ? 2 : 1;
62 }
63 else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
64 {
65 return 1;
66 }
67 else if (CAVIUM_IS_MODEL(CAVIUM_CN93XX))
68 {
69 BDK_CSR_INIT(lmcx_dll_ctl1, node, BDK_LMCX_DLL_CTL2(2));
70 if (lmcx_dll_ctl1.s.intf_en)
71 return 3;
72 lmcx_dll_ctl1.u = BDK_CSR_READ(node, BDK_LMCX_DLL_CTL2(1));
73 return (lmcx_dll_ctl1.s.intf_en) ? 2 : 1;
74 }
75 bdk_error("__bdk_dram_get_num_lmc() needs update for this chip\n");
76 return 1;
77 }
78
79 /**
80 * Return whether the node/LMC is in DRESET
81 *
82 * @param node Node to probe
83 * @param node LMC to probe
84 *
85 * @return 1 or 0
86 */
__bdk_dram_is_lmc_in_dreset(bdk_node_t node,int lmc)87 static int __bdk_dram_is_lmc_in_dreset(bdk_node_t node, int lmc)
88 {
89 BDK_CSR_INIT(lmcx_dll_ctl2, node, BDK_LMCX_DLL_CTL2(lmc)); // can always read this
90 return (lmcx_dll_ctl2.s.dreset != 0) ? 1 : 0;
91 }
92
93 /**
94 * Return a mask of the number of row bits in use
95 *
96 * @param node Node to probe
97 *
98 */
__bdk_dram_get_row_mask(bdk_node_t node,int lmc)99 uint32_t __bdk_dram_get_row_mask(bdk_node_t node, int lmc)
100 {
101 // PROTECT!!!
102 if (__bdk_dram_is_lmc_in_dreset(node, lmc)) // check LMCn
103 return 0;
104 BDK_CSR_INIT(lmcx_config, node, BDK_LMCX_CONFIG(lmc)); // sample LMCn
105 int numbits = 14 + lmcx_config.s.pbank_lsb - lmcx_config.s.row_lsb - lmcx_config.s.rank_ena;
106 return ((1ul << numbits) - 1);
107 }
108
109 /**
110 * Return a mask of the number of column bits in use
111 *
112 * @param node Node to probe
113 *
114 */
__bdk_dram_get_col_mask(bdk_node_t node,int lmc)115 uint32_t __bdk_dram_get_col_mask(bdk_node_t node, int lmc)
116 {
117 // PROTECT!!!
118 if (__bdk_dram_is_lmc_in_dreset(node, lmc)) // check LMCn
119 return 0;
120 BDK_CSR_INIT(lmcx_config, node, BDK_LMCX_CONFIG(lmc)); // sample LMCn
121 int numbits = 11 + lmcx_config.s.row_lsb - __bdk_dram_get_num_bank_bits(node, lmc);
122 return ((1ul << numbits) - 1);
123 }
124
125 /**
126 * Return the number of bank bits in use
127 *
128 * @param node Node to probe
129 *
130 */
131 // all DDR3, and DDR4 x16 today, use only 3 bank bits; DDR4 x4 and x8 always have 4 bank bits
132 // NOTE: this will change in the future, when DDR4 x16 devices can come with 16 banks!! FIXME!!
__bdk_dram_get_num_bank_bits(bdk_node_t node,int lmc)133 int __bdk_dram_get_num_bank_bits(bdk_node_t node, int lmc)
134 {
135 // PROTECT!!!
136 if (__bdk_dram_is_lmc_in_dreset(node, lmc)) // check LMCn
137 return 0;
138 BDK_CSR_INIT(lmcx_config, node, BDK_LMCX_CONFIG(lmc)); // sample LMCn
139 int bank_width = (__bdk_dram_is_ddr4(node, lmc) && (lmcx_config.s.bg2_enable)) ? 4 : 3;
140 return bank_width;
141 }
142
143 /**
144 * Return whether the node has DDR3 or DDR4 DRAM
145 *
146 * @param node Node to probe
147 *
148 * @return 0 (DDR3) or 1 (DDR4)
149 */
__bdk_dram_is_ddr4(bdk_node_t node,int lmc)150 int __bdk_dram_is_ddr4(bdk_node_t node, int lmc)
151 {
152 // PROTECT!!!
153 if (__bdk_dram_is_lmc_in_dreset(node, lmc)) // check LMCn
154 return 0;
155 if (CAVIUM_IS_MODEL(CAVIUM_CN9XXX))
156 return 1;
157 BDK_CSR_INIT(lmcx_ddr_pll_ctl, node, BDK_LMCX_DDR_PLL_CTL(lmc)); // sample LMCn
158 return (lmcx_ddr_pll_ctl.cn83xx.ddr4_mode != 0);
159 }
160
161 /**
162 * Return whether the node has Registered DIMMs or Unbuffered DIMMs
163 *
164 * @param node Node to probe
165 *
166 * @return 0 (Unbuffered) or 1 (Registered)
167 */
__bdk_dram_is_rdimm(bdk_node_t node,int lmc)168 int __bdk_dram_is_rdimm(bdk_node_t node, int lmc)
169 {
170 // PROTECT!!!
171 if (__bdk_dram_is_lmc_in_dreset(node, lmc)) // check LMCn
172 return 0;
173 BDK_CSR_INIT(lmcx_control, node, BDK_LMCX_CONTROL(lmc)); // sample LMCn
174 return (lmcx_control.s.rdimm_ena != 0);
175 }
176
177 /**
178 * Get the amount of DRAM configured for a node. This is read from the LMC
179 * controller after DRAM is setup.
180 *
181 * @param node Node to query
182 *
183 * @return Size in megabytes
184 */
bdk_dram_get_size_mbytes(int node)185 uint64_t bdk_dram_get_size_mbytes(int node)
186 {
187 /* Return zero if dram isn't enabled */
188 if (!__bdk_is_dram_enabled(node))
189 return 0;
190
191 uint64_t memsize = 0;
192 const int num_dram_controllers = __bdk_dram_get_num_lmc(node);
193 for (int lmc = 0; lmc < num_dram_controllers; lmc++)
194 {
195 // PROTECT!!!
196 if (__bdk_dram_is_lmc_in_dreset(node, lmc)) // check LMCn
197 return 0;
198 BDK_CSR_INIT(lmcx_config, node, BDK_LMCX_CONFIG(lmc));
199 int num_ranks = bdk_pop(lmcx_config.s.init_status);
200 uint64_t rank_size = 1ull << (28 + lmcx_config.s.pbank_lsb - lmcx_config.s.rank_ena);
201 memsize += rank_size * num_ranks;
202 }
203 return memsize >> 20;
204 }
205
206