xref: /aosp_15_r20/external/coreboot/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-address.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
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 "libbdk-arch/bdk-csrs-l2c.h"
41 
42 #define EXTRACT(v, lsb, width) (((v) >> (lsb)) & ((1ull << (width)) - 1))
43 #define INSERT(a, v, lsb, width) a|=(((v) & ((1ull << (width)) - 1)) << (lsb))
44 
45 /**
46  * Given a physical DRAM address, extract information about the node, LMC, DIMM,
47  * prank, lrank, bank, row, and column that was accessed.
48  *
49  * @param address Physical address to decode
50  * @param node    Node the address was for
51  * @param lmc     LMC controller the address was for
52  * @param dimm    DIMM the address was for
53  * @param prank   Physical RANK on the DIMM
54  * @param lrank   Logical RANK on the DIMM
55  * @param bank    BANK on the DIMM
56  * @param row     Row on the DIMM
57  * @param col     Column on the DIMM
58  */
59 void
bdk_dram_address_extract_info(uint64_t address,int * node,int * lmc,int * dimm,int * prank,int * lrank,int * bank,int * row,int * col)60 bdk_dram_address_extract_info(uint64_t address, int *node, int *lmc, int *dimm,
61                               int *prank, int *lrank, int *bank, int *row, int *col)
62 {
63     int bitno = CAVIUM_IS_MODEL(CAVIUM_CN83XX) ? 19 : 20;
64     *node = EXTRACT(address, 40, 2); /* Address bits [41:40] */
65     /* Determine the LMC controller */
66     BDK_CSR_INIT(l2c_ctl, *node, BDK_L2C_CTL);
67     int bank_lsb, xbits;
68 
69     /* xbits depends on number of LMCs */
70     xbits = __bdk_dram_get_num_lmc(*node) >> 1; // 4->2; 2->1; 1->0
71     bank_lsb = 7 + xbits;
72 
73     /* LMC number is probably aliased */
74     if (l2c_ctl.s.disidxalias)
75         *lmc = EXTRACT(address, 7, xbits);
76     else
77         *lmc = EXTRACT(address, 7, xbits) ^ EXTRACT(address, bitno, xbits) ^ EXTRACT(address, 12, xbits);
78 
79     /* Figure out the bank field width */
80     BDK_CSR_INIT(lmcx_config, *node, BDK_LMCX_CONFIG(*lmc));
81     int bank_width = __bdk_dram_get_num_bank_bits(*node, *lmc);
82 
83     /* Extract additional info from the LMC_CONFIG CSR */
84     BDK_CSR_INIT(ext_config, *node, BDK_LMCX_EXT_CONFIG(*lmc));
85     int dimm_lsb    = 28 + lmcx_config.s.pbank_lsb + xbits;
86     int dimm_width  = 40 - dimm_lsb;
87     int prank_lsb    = dimm_lsb - lmcx_config.s.rank_ena;
88     int prank_width  = dimm_lsb - prank_lsb;
89     int lrank_lsb    = prank_lsb - ext_config.s.dimm0_cid;
90     int lrank_width  = prank_lsb - lrank_lsb;
91     int row_lsb     = 14 + lmcx_config.s.row_lsb + xbits;
92     int row_width   = lrank_lsb - row_lsb;
93     int col_hi_lsb  = bank_lsb + bank_width;
94     int col_hi_width= row_lsb - col_hi_lsb;
95 
96     /* Extract the parts of the address */
97     *dimm =  EXTRACT(address, dimm_lsb, dimm_width);
98     *prank = EXTRACT(address, prank_lsb, prank_width);
99     *lrank = EXTRACT(address, lrank_lsb, lrank_width);
100     *row =   EXTRACT(address, row_lsb, row_width);
101 
102     /* bank calculation may be aliased... */
103     BDK_CSR_INIT(lmcx_control, *node, BDK_LMCX_CONTROL(*lmc));
104     if (lmcx_control.s.xor_bank)
105         *bank = EXTRACT(address, bank_lsb, bank_width) ^ EXTRACT(address, 12 + xbits, bank_width);
106     else
107         *bank = EXTRACT(address, bank_lsb, bank_width);
108 
109     /* LMC number already extracted */
110     int col_hi = EXTRACT(address, col_hi_lsb, col_hi_width);
111     *col = EXTRACT(address, 3, 4) | (col_hi << 4);
112     /* Bus byte is address bits [2:0]. Unused here */
113 }
114 
115 /**
116  * Construct a physical address given the node, LMC, DIMM, prank, lrank, bank, row, and column.
117  *
118  * @param node    Node the address was for
119  * @param lmc     LMC controller the address was for
120  * @param dimm    DIMM the address was for
121  * @param prank   Physical RANK on the DIMM
122  * @param lrank   Logical RANK on the DIMM
123  * @param bank    BANK on the DIMM
124  * @param row     Row on the DIMM
125  * @param col     Column on the DIMM
126  */
127 uint64_t
bdk_dram_address_construct_info(bdk_node_t node,int lmc,int dimm,int prank,int lrank,int bank,int row,int col)128 bdk_dram_address_construct_info(bdk_node_t node, int lmc, int dimm,
129                                 int prank, int lrank, int bank, int row, int col)
130 
131 {
132     uint64_t address = 0;
133     int bitno = CAVIUM_IS_MODEL(CAVIUM_CN83XX) ? 19 : 20;
134 
135     // insert node bits
136     INSERT(address, node, 40, 2); /* Address bits [41:40] */
137 
138     /* xbits depends on number of LMCs */
139     int xbits = __bdk_dram_get_num_lmc(node) >> 1; // 4->2; 2->1; 1->0
140     int bank_lsb = 7 + xbits;
141 
142     /* Figure out the bank field width */
143     int bank_width = __bdk_dram_get_num_bank_bits(node, lmc);
144 
145     /* Extract additional info from the LMC_CONFIG CSR */
146     BDK_CSR_INIT(lmcx_config, node, BDK_LMCX_CONFIG(lmc));
147     BDK_CSR_INIT(ext_config, node, BDK_LMCX_EXT_CONFIG(lmc));
148     int dimm_lsb     = 28 + lmcx_config.s.pbank_lsb + xbits;
149     int dimm_width   = 40 - dimm_lsb;
150     int prank_lsb    = dimm_lsb - lmcx_config.s.rank_ena;
151     int prank_width  = dimm_lsb - prank_lsb;
152     int lrank_lsb    = prank_lsb - ext_config.s.dimm0_cid;
153     int lrank_width  = prank_lsb - lrank_lsb;
154     int row_lsb      = 14 + lmcx_config.s.row_lsb + xbits;
155     int row_width    = lrank_lsb - row_lsb;
156     int col_hi_lsb   = bank_lsb + bank_width;
157     int col_hi_width = row_lsb - col_hi_lsb;
158 
159     /* Insert some other parts of the address */
160     INSERT(address, dimm, dimm_lsb, dimm_width);
161     INSERT(address, prank, prank_lsb, prank_width);
162     INSERT(address, lrank, lrank_lsb, lrank_width);
163     INSERT(address, row,  row_lsb,  row_width);
164     INSERT(address, col >> 4, col_hi_lsb, col_hi_width);
165     INSERT(address, col, 3, 4);
166 
167     /* bank calculation may be aliased... */
168     BDK_CSR_INIT(lmcx_control, node, BDK_LMCX_CONTROL(lmc));
169     int new_bank = bank;
170     if (lmcx_control.s.xor_bank)
171         new_bank ^= EXTRACT(address, 12 + xbits, bank_width);
172     INSERT(address, new_bank, bank_lsb, bank_width);
173 
174     /* Determine the actual C bits from the input LMC controller arg */
175     /* The input LMC number was probably aliased with other fields */
176     BDK_CSR_INIT(l2c_ctl, node, BDK_L2C_CTL);
177     int new_lmc = lmc;
178     if (!l2c_ctl.s.disidxalias)
179         new_lmc ^= EXTRACT(address, bitno, xbits) ^ EXTRACT(address, 12, xbits);
180     INSERT(address, new_lmc, 7, xbits);
181 
182     return address;
183 }
184