xref: /aosp_15_r20/external/coreboot/src/vendorcode/cavium/bdk/libbdk-dram/bdk-dram-test-databus.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 
41 #include <libbdk-hal/bdk-utils.h>
42 
43 /* Used for all memory reads/writes related to the test */
44 #define READ64(address) __bdk_dram_read64(address)
45 #define WRITE64(address, data) __bdk_dram_write64(address, data)
46 
47 /* Build a 64bit mask out of a single hex digit */
48 #define REPEAT2(v) ((((uint64_t)v) << 4) | ((uint64_t)v))
49 #define REPEAT4(v) ((REPEAT2(v) << 8) | REPEAT2(v))
50 #define REPEAT8(v) ((REPEAT4(v) << 16) | REPEAT4(v))
51 #define REPEAT16(v) ((REPEAT8(v) << 32) | REPEAT8(v))
52 
53 /**
54  * Read memory and check that the data bus pattern is present. The pattern is a
55  * sequence if 16 dwords created from the 16 hex digits repeated in each word.
56  *
57  * @param address Physical address to read. This must be cache line aligned.
58  * @param bursts  Number of time to repeat the read test to verify stability
59  *
60  * @return Number of errors, zero means success
61  */
read_data_bus_burst(uint64_t address,int bursts)62 static int read_data_bus_burst(uint64_t address, int bursts)
63 {
64     int failures = 0;
65 
66     /* Loop over the burst so people using a scope have time to capture
67        traces */
68     for (int burst = 0; burst < bursts; burst++)
69     {
70         /* Invalidate all caches so we must read from DRAM */
71         __bdk_dram_flush_to_mem(address);
72         BDK_DCACHE_INVALIDATE;
73 
74         for (uint64_t digit = 0; digit < 16; digit++)
75         {
76             uint64_t a = address + digit * 8;
77             uint64_t data = READ64(a);
78             uint64_t correct = REPEAT16(digit);
79             if (data != correct)
80             {
81                 failures++;
82                 __bdk_dram_report_error(a, data, correct, burst, -1);
83             }
84         }
85     }
86     return failures;
87 }
88 
89 /**
90  * Write memory with a data bus pattern and check that it can be read correctly.
91  * The pattern is a sequence if 16 dwords created from the 16 hex digits repeated
92  * in each word.
93  *
94  * @param address Physical address to write. This must be cache line aligned. 128 bytes will be
95  *                written starting at this address.
96  * @param bursts  Number of time to repeat the write+read test to verify stability
97  *
98  * @return Number of errors, zero means success
99  */
write_data_bus_burst(uint64_t address,int bursts)100 static int write_data_bus_burst(uint64_t address, int bursts)
101 {
102     BDK_TRACE(DRAM_TEST, "[0x%016llx:0x%016llx] Writing incrementing digits\n",
103         address, address + 127);
104     /* Loop over the burst so people using a scope have time to capture
105        traces */
106     for (int burst = 0; burst < bursts; burst++)
107     {
108         /* Fill a cache line with an incrementing pattern. Each nibble
109            in the 64bit word increments from 0 to 0xf */
110         for (uint64_t digit = 0; digit < 16; digit++)
111             WRITE64(address + digit * 8, REPEAT16(digit));
112         /* Force the cache line out to memory */
113         __bdk_dram_flush_to_mem(address);
114     }
115     return read_data_bus_burst(address, bursts);
116 }
117 
118 /**
119  * Read back the pattern written by write_data_bus_walk() nad
120  * make sure it was stored properly.
121  *
122  * @param address Physical address to read. This must be cache line aligned.
123  * @param bursts  Number of time to repeat the read test to verify stability
124  * @param pattern Pattern basis for writes. See
125  *                write_data_bus_walk()
126  *
127  * @return Number of errors, zero means success
128  */
read_data_bus_walk(uint64_t address,int burst,uint64_t pattern)129 static int read_data_bus_walk(uint64_t address, int burst, uint64_t pattern)
130 {
131     int failures = 0;
132 
133     /* Invalidate all caches so we must readfrom DRAM */
134     __bdk_dram_flush_to_mem(address);
135     BDK_DCACHE_INVALIDATE;
136 
137     uint64_t correct = pattern;
138     for (uint64_t word = 0; word < 16; word++)
139     {
140         uint64_t a = address + word * 8;
141         uint64_t data = READ64(a);
142         if (data != correct)
143         {
144             failures++;
145             __bdk_dram_report_error(a, data, correct, burst, -1);
146         }
147         uint64_t tmp = correct >> 63; /* Save top bit */
148         correct <<= 1; /* Shift left one bit */
149         correct |= tmp; /* Restore the top bit as bit 0 */
150     }
151 
152     return failures;
153 }
154 
155 /**
156  * Write a pattern to a cache line, rotating it one bit for each DWORD. Read back
157  * the pattern and make sure it was stored properly. The input pattern is rotated
158  * left by one bit for each DWORD written.
159  *
160  * @param address Physical address to write. This must be cache line aligned. 128 bytes will be
161  *                written starting at this address.
162  * @param bursts  Number of time to repeat the write+read test to verify stability
163  * @param pattern Pattern basis
164  *
165  * @return Number of errors, zero means success
166  */
write_data_bus_walk(uint64_t address,int burst,uint64_t pattern)167 static void write_data_bus_walk(uint64_t address, int burst, uint64_t pattern)
168 {
169     BDK_TRACE(DRAM_TEST, "[0x%016llx:0x%016llx] Writing walking pattern 0x%016llx\n",
170         address, address + 127, pattern);
171 
172     uint64_t a = address;
173     uint64_t d = pattern;
174 
175     /* Fill a cache line with pattern. Each 64bit work will have the
176        pattern rotated left one bit */
177     for (uint64_t word = 0; word < 16; word++)
178     {
179         WRITE64(a, d);
180         a += 8;
181         uint64_t tmp = d >> 63; /* Save top bit */
182         d <<= 1; /* Shift left one bit */
183         d |= tmp; /* Restore the top bit as bit 0 */
184     }
185     /* Force the cache line out to memory */
186     __bdk_dram_flush_to_mem(address);
187 }
188 
189 /**
190  * The goal of these tests are to toggle every DDR data pin, one at a time or in
191  * related groups, to isolate any short circuits between the data pins or open
192  * circuits where the pin is not connected to the DDR memory. A board which fails
193  * one of these tests has severe problems and will not be able to run any of the
194  * later test patterns.
195  *
196  * @param start_address
197  *               Physical address of a cache line to
198  *               use for the test. Only this cache line is
199  *               written.
200  * @param end_address
201  *               Top end of the address range. Currently unused
202  * @param bursts Number of time to repeats writes+reads to insure stability
203  *
204  * @return Number of errors, zero means success
205  */
__bdk_dram_test_mem_data_bus(uint64_t start_address,uint64_t end_address,int bursts)206 int __bdk_dram_test_mem_data_bus(uint64_t start_address, uint64_t end_address, int bursts)
207 {
208     int failures = 0;
209 
210     /* Incrementing pattern: 0x0 - 0xf in each nibble */
211     failures += write_data_bus_burst(start_address, bursts);
212 
213     /* Walking ones. Run with 1, 2, and 3 bits walking */
214     for (int bits = 1; bits <= 3; bits++)
215     {
216         for (int burst = 0; burst < bursts; burst++)
217         {
218             /* Each write_data_bus_walk() call write 16 dword, so step by 16 */
219             for (int i = 0; i < 64; i += 16)
220             {
221                 uint64_t pattern = bdk_build_mask(bits) << i;
222                 write_data_bus_walk(start_address + i*8, burst, pattern);
223             }
224             /* Each read_data_bus_walk() call write 16 dword, so step by 16 */
225             for (int i = 0; i < 64; i += 16)
226             {
227                 uint64_t pattern = bdk_build_mask(bits) << i;
228                 failures += read_data_bus_walk(start_address + i*8, burst, pattern);
229             }
230         }
231     }
232 
233     /* Walking zeros. Run with 1, 2, and 3 bits walking */
234     for (int bits = 1; bits <= 3; bits++)
235     {
236         for (int burst = 0; burst < bursts; burst++)
237         {
238             /* Each write_data_bus_walk() call write 16 dword, so step by 16 */
239             for (int i = 0; i < 64; i += 16)
240             {
241                 uint64_t pattern = ~(bdk_build_mask(bits) << i);
242                 write_data_bus_walk(start_address + i*8, burst, pattern);
243             }
244             /* Each read_data_bus_walk() call write 16 dword, so step by 16 */
245             for (int i = 0; i < 64; i += 16)
246             {
247                 uint64_t pattern = ~(bdk_build_mask(bits) << i);
248                 failures += read_data_bus_walk(start_address + i*8, burst, pattern);
249             }
250         }
251     }
252     return failures;
253 }
254 
255