blob: 1f8be79938139c17f4190c7b222a0b974b4fdace [file] [log] [blame]
Patrick Georgiac959032020-05-05 22:49:26 +02001/* SPDX-License-Identifier: GPL-2.0-or-later */
Arthur Heymans6d7a8c12017-03-07 20:48:14 +01002
Kyösti Mälkki13f66502019-03-03 08:01:05 +02003#include <device/mmio.h>
Arthur Heymans6d7a8c12017-03-07 20:48:14 +01004#include <console/console.h>
5#include <delay.h>
Arthur Heymans2aeb2a12021-07-02 10:05:09 +02006#include <stdint.h>
Angel Pons41e66ac2020-09-15 13:17:23 +02007#include "raminit.h"
Arthur Heymans6d7a8c12017-03-07 20:48:14 +01008#include "x4x.h"
9
10#define MAX_COARSE 15
11#define DQS_HIGH 1
12#define DQS_LOW 0
13
Angel Ponsd0591122021-05-26 14:24:06 +020014#define RESET_CNTL(channel) (0x5d8 + (channel) * 0x400)
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010015
16struct rec_timing {
17 u8 medium;
18 u8 coarse;
19 u8 pi;
20 u8 tap;
21};
22
Angel Pons879c4de2020-07-24 16:15:04 +020023static inline void mfence(void)
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010024{
25 asm volatile("mfence":::);
26}
27
28static u8 sampledqs(u32 addr, u8 lane, u8 channel)
29{
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010030 u32 sample_offset = 0x400 * channel + 0x561 + lane * 4;
31
Angel Ponsbc15e012021-01-12 23:38:44 +010032 /* Reset the DQS probe, on both channels? */
33 for (u8 i = 0; i < TOTAL_CHANNELS; i++) {
Angel Ponsa5146f32021-03-27 09:35:57 +010034 mchbar_clrbits8(RESET_CNTL(i), 1 << 1);
Angel Ponsbc15e012021-01-12 23:38:44 +010035 udelay(1);
Angel Ponsa5146f32021-03-27 09:35:57 +010036 mchbar_setbits8(RESET_CNTL(i), 1 << 1);
Angel Ponsbc15e012021-01-12 23:38:44 +010037 udelay(1);
38 }
Angel Pons879c4de2020-07-24 16:15:04 +020039 mfence();
Elyes HAOUAS2dbc0952019-05-22 21:44:48 +020040 /* Read strobe */
Arthur Heymans4d06ff02021-07-02 10:05:09 +020041 read32p(addr);
Angel Pons879c4de2020-07-24 16:15:04 +020042 mfence();
Angel Ponsa5146f32021-03-27 09:35:57 +010043 return mchbar_read8(sample_offset) >> 6 & 1;
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010044}
45
Angel Ponsdd7ce4e2021-03-26 23:21:02 +010046static void program_timing(const struct rec_timing *timing, u8 channel, u8 lane)
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010047{
48 u32 reg32;
49 u16 reg16;
50 u8 reg8;
51
Angel Ponsdd7ce4e2021-03-26 23:21:02 +010052 printk(RAM_SPEW, " Programming timings:Coarse: %d, Medium: %d, TAP: %d, PI: %d\n",
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010053 timing->coarse, timing->medium, timing->tap, timing->pi);
54
Angel Ponsa5146f32021-03-27 09:35:57 +010055 reg32 = mchbar_read32(0x400 * channel + 0x248);
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010056 reg32 &= ~0xf0000;
57 reg32 |= timing->coarse << 16;
Angel Ponsa5146f32021-03-27 09:35:57 +010058 mchbar_write32(0x400 * channel + 0x248, reg32);
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010059
Angel Ponsa5146f32021-03-27 09:35:57 +010060 reg16 = mchbar_read16(0x400 * channel + 0x58c);
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010061 reg16 &= ~(3 << (lane * 2));
62 reg16 |= timing->medium << (lane * 2);
Angel Ponsa5146f32021-03-27 09:35:57 +010063 mchbar_write16(0x400 * channel + 0x58c, reg16);
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010064
Angel Ponsa5146f32021-03-27 09:35:57 +010065 reg8 = mchbar_read8(0x400 * channel + 0x560 + lane * 4);
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010066 reg8 &= ~0x7f;
67 reg8 |= timing->tap;
68 reg8 |= timing->pi << 4;
Angel Ponsa5146f32021-03-27 09:35:57 +010069 mchbar_write8(0x400 * channel + 0x560 + lane * 4, reg8);
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010070}
71
72static int increase_medium(struct rec_timing *timing)
73{
74 if (timing->medium < 3) {
75 timing->medium++;
76 } else if (timing->coarse < MAX_COARSE) {
77 timing->medium = 0;
78 timing->coarse++;
79 } else {
80 printk(BIOS_ERR, "Cannot increase medium any further.\n");
81 return -1;
82 }
83 return 0;
84}
85
86static int decrease_medium(struct rec_timing *timing)
87{
88 if (timing->medium > 0) {
89 timing->medium--;
90 } else if (timing->coarse > 0) {
91 timing->medium = 3;
92 timing->coarse--;
93 } else {
94 printk(BIOS_ERR, "Cannot lower medium any further.\n");
95 return -1;
96 }
97 return 0;
98}
99
100static int increase_tap(struct rec_timing *timing)
101{
102 if (timing->tap == 14) {
103 if (increase_medium(timing))
104 return -1;
105 timing->tap = 0;
106 } else {
107 timing->tap++;
108 }
109 return 0;
110}
111
112static int decrease_tap(struct rec_timing *timing)
113{
114 if (timing->tap > 0) {
115 timing->tap--;
116 } else {
117 if (decrease_medium(timing))
118 return -1;
119 timing->tap = 14;
120 }
121 return 0;
122}
123
Angel Ponsdd7ce4e2021-03-26 23:21:02 +0100124static int decr_coarse_low(u8 channel, u8 lane, u32 addr, struct rec_timing *timing)
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100125{
Angel Ponsdd7ce4e2021-03-26 23:21:02 +0100126 printk(RAM_DEBUG, " Decreasing coarse until high to low transition is found\n");
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100127 while (sampledqs(addr, lane, channel) != DQS_LOW) {
128 if (timing->coarse == 0) {
Angel Ponsdd7ce4e2021-03-26 23:21:02 +0100129 printk(BIOS_CRIT, "Couldn't find DQS-high 0 indicator, halt\n");
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100130 return -1;
131 }
132 timing->coarse--;
133 program_timing(timing, channel, lane);
134 }
Arthur Heymansa4e8f67b2017-12-16 21:04:46 +0100135 printk(RAM_DEBUG, " DQS low at coarse=%d medium=%d\n",
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100136 timing->coarse, timing->medium);
137 return 0;
138}
139
Angel Ponsdd7ce4e2021-03-26 23:21:02 +0100140static int fine_search_dqs_high(u8 channel, u8 lane, u32 addr, struct rec_timing *timing)
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100141{
Angel Ponsdd7ce4e2021-03-26 23:21:02 +0100142 printk(RAM_DEBUG, " Increasing TAP until low to high transition is found\n");
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100143 /*
144 * We use a do while loop since it happens that the strobe read
145 * is inconsistent, with the strobe already high. The current
146 * code flow results in failure later when finding the preamble,
147 * at which DQS needs to be high is often not the case if TAP was
148 * not increased at least once here. Work around this by incrementing
149 * TAP at least once to guarantee searching for preamble start at
150 * DQS high.
151 * This seems to be the result of hysteresis on some settings, where
152 * the DQS probe is influenced by its previous value.
153 */
154 if (sampledqs(addr, lane, channel) == DQS_HIGH) {
155 printk(BIOS_WARNING,
156 "DQS already HIGH... DQS probe is inconsistent!\n"
157 "Continuing....\n");
158 }
159 do {
160 if (increase_tap(timing)) {
Angel Ponsdd7ce4e2021-03-26 23:21:02 +0100161 printk(BIOS_CRIT, "Could not find DQS-high on fine search.\n");
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100162 return -1;
163 }
164 program_timing(timing, channel, lane);
165 } while (sampledqs(addr, lane, channel) != DQS_HIGH);
166
Arthur Heymansa4e8f67b2017-12-16 21:04:46 +0100167 printk(RAM_DEBUG, " DQS high at coarse=%d medium=%d tap:%d\n",
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100168 timing->coarse, timing->medium, timing->tap);
169 return 0;
170}
171
Angel Ponsdd7ce4e2021-03-26 23:21:02 +0100172static int find_dqs_low(u8 channel, u8 lane, u32 addr, struct rec_timing *timing)
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100173{
174 /* Look for DQS low, using quarter steps. */
Arthur Heymansa4e8f67b2017-12-16 21:04:46 +0100175 printk(RAM_DEBUG, " Increasing medium until DQS LOW is found\n");
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100176 while (sampledqs(addr, lane, channel) != DQS_LOW) {
177 if (increase_medium(timing)) {
Angel Ponsdd7ce4e2021-03-26 23:21:02 +0100178 printk(BIOS_CRIT, "Coarse > 15: DQS tuning failed, halt\n");
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100179 return -1;
180 }
181 program_timing(timing, channel, lane);
182 }
Arthur Heymansa4e8f67b2017-12-16 21:04:46 +0100183 printk(RAM_DEBUG, " DQS low at coarse=%d medium=%d\n",
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100184 timing->coarse, timing->medium);
185 return 0;
186}
187static int find_dqs_high(u8 channel, u8 lane, u32 addr,
188 struct rec_timing *timing)
189{
190 /* Look for DQS high, using quarter steps. */
Arthur Heymansa4e8f67b2017-12-16 21:04:46 +0100191 printk(RAM_DEBUG, " Increasing medium until DQS HIGH is found\n");
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100192 while (sampledqs(addr, lane, channel) != DQS_HIGH) {
193 if (increase_medium(timing)) {
Angel Ponsdd7ce4e2021-03-26 23:21:02 +0100194 printk(BIOS_CRIT, "Coarse > 16: DQS tuning failed, halt\n");
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100195 return -1;
196 }
197 program_timing(timing, channel, lane);
198 }
Arthur Heymansa4e8f67b2017-12-16 21:04:46 +0100199 printk(RAM_DEBUG, " DQS high at coarse=%d medium=%d\n",
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100200 timing->coarse, timing->medium);
201 return 0;
202}
203
204static int find_dqs_edge_lowhigh(u8 channel, u8 lane,
205 u32 addr, struct rec_timing *timing)
206{
207 /* Medium search for DQS high. */
208 if (find_dqs_high(channel, lane, addr, timing))
209 return -1;
210
211 /* Go back and perform finer search. */
212 if (decrease_medium(timing))
213 return -1;
214 program_timing(timing, channel, lane);
215 if (fine_search_dqs_high(channel, lane, addr, timing) < 0)
216 return -1;
217
218 return 0;
219}
220
221static int find_preamble(u8 channel, u8 lane, u32 addr,
222 struct rec_timing *timing)
223{
224 /* Add a quarter step */
225 if (increase_medium(timing))
226 return -1;
227 program_timing(timing, channel, lane);
228 /* Verify we are at high */
229 if (sampledqs(addr, lane, channel) != DQS_HIGH) {
230 printk(BIOS_CRIT, "Not at DQS high, d'oh\n");
231 return -1;
232 }
233
234 /* Decrease coarse until LOW is found */
235 if (decr_coarse_low(channel, lane, addr, timing))
236 return -1;
237 return 0;
238}
239
240static int calibrate_receive_enable(u8 channel, u8 lane,
241 u32 addr, struct rec_timing *timing)
242{
243 program_timing(timing, channel, lane);
244 /* Set receive enable bit */
Angel Ponsa5146f32021-03-27 09:35:57 +0100245 mchbar_clrsetbits16(0x400 * channel + 0x588, 3 << (lane * 2), 1 << (lane * 2));
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100246
247 if (find_dqs_low(channel, lane, addr, timing))
248 return -1;
249
250 /* Advance a little further. */
251 if (increase_medium(timing)) {
252 /* A finer search could be implemented */
253 printk(BIOS_WARNING, "Cannot increase medium further");
254 return -1;
255 }
256 program_timing(timing, channel, lane);
257
258 if (find_dqs_edge_lowhigh(channel, lane, addr, timing))
259 return -1;
260
261 /* Go back on fine search */
262 if (decrease_tap(timing))
263 return -1;
264 timing->pi = 3;
265 program_timing(timing, channel, lane);
266
267 if (find_preamble(channel, lane, addr, timing))
268 return -1;
269
270 if (find_dqs_edge_lowhigh(channel, lane, addr, timing))
271 return -1;
272 if (decrease_tap(timing))
273 return -1;
274 timing->pi = 7;
275 program_timing(timing, channel, lane);
276
277 /* Unset receive enable bit */
Angel Ponsa5146f32021-03-27 09:35:57 +0100278 mchbar_clrbits16(0x400 * channel + 0x588, 3 << (lane * 2));
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100279 return 0;
280}
281
Arthur Heymansadc571a2017-09-25 09:40:54 +0200282void rcven(struct sysinfo *s)
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100283{
Arthur Heymans1994e4482017-11-04 07:52:23 +0100284 int rank;
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100285 u8 channel, lane, reg8;
Arthur Heymans1994e4482017-11-04 07:52:23 +0100286 /*
287 * Using the macros below the compiler warns about this possibly being
288 * unitialised.
289 */
290 u32 addr = 0;
Arthur Heymans276049f2017-11-05 05:56:34 +0100291 struct rec_timing timing[TOTAL_BYTELANES];
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100292 u8 mincoarse;
293
Arthur Heymansa4e8f67b2017-12-16 21:04:46 +0100294 printk(BIOS_DEBUG, "Starting DQS receiver enable calibration\n");
295
Angel Ponsa5146f32021-03-27 09:35:57 +0100296 mchbar_clrbits8(0x5d8, 3 << 2);
297 mchbar_clrbits8(0x9d8, 3 << 2);
298 mchbar_clrbits8(0x5dc, 1 << 7);
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100299 FOR_EACH_POPULATED_CHANNEL(s->dimms, channel) {
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100300 mincoarse = 0xff;
Arthur Heymans1994e4482017-11-04 07:52:23 +0100301 /*
302 * Receive enable calibration happens on the first populated
303 * rank on each channel.
304 */
305 FOR_EACH_POPULATED_RANK_IN_CHANNEL(s->dimms, channel, rank) {
306 addr = test_address(channel, rank);
307 break;
308 }
Arthur Heymans276049f2017-11-05 05:56:34 +0100309 FOR_EACH_BYTELANE(lane) {
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100310 printk(BIOS_DEBUG, "Channel %d, Lane %d addr=0x%08x\n",
311 channel, lane, addr);
312 timing[lane].coarse = (s->selected_timings.CAS + 1);
313 switch (lane) {
314 default:
315 case 0:
316 case 1:
317 timing[lane].medium = 0;
318 break;
319 case 2:
320 case 3:
321 timing[lane].medium = 1;
322 break;
323 case 4:
324 case 5:
325 timing[lane].medium = 2;
326 break;
327 case 6:
328 case 7:
329 timing[lane].medium = 3;
330 break;
331 }
332 timing[lane].tap = 0;
333 timing[lane].pi = 0;
334
Angel Ponsdd7ce4e2021-03-26 23:21:02 +0100335 if (calibrate_receive_enable(channel, lane, addr, &timing[lane]))
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100336 die("Receive enable calibration failed\n");
337 if (mincoarse > timing[lane].coarse)
338 mincoarse = timing[lane].coarse;
339 }
340 printk(BIOS_DEBUG, "Found min coarse value = %d\n", mincoarse);
Arthur Heymansadc571a2017-09-25 09:40:54 +0200341 s->rcven_t[channel].min_common_coarse = mincoarse;
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100342 printk(BIOS_DEBUG, "Receive enable, final timings:\n");
343 /* Normalise coarse */
Arthur Heymans276049f2017-11-05 05:56:34 +0100344 FOR_EACH_BYTELANE(lane) {
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100345 if (timing[lane].coarse == 0)
346 reg8 = 0;
347 else
348 reg8 = timing[lane].coarse - mincoarse;
Angel Ponsdd7ce4e2021-03-26 23:21:02 +0100349 printk(BIOS_DEBUG,
350 "ch %d lane %d: coarse offset: %d;medium: %d; tap: %d\n",
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100351 channel, lane, reg8, timing[lane].medium,
352 timing[lane].tap);
Arthur Heymansadc571a2017-09-25 09:40:54 +0200353 s->rcven_t[channel].coarse_offset[lane] = reg8;
354 s->rcven_t[channel].medium[lane] = timing[lane].medium;
355 s->rcven_t[channel].tap[lane] = timing[lane].tap;
356 s->rcven_t[channel].pi[lane] = timing[lane].pi;
Angel Ponsa5146f32021-03-27 09:35:57 +0100357 mchbar_clrsetbits16(0x400 * channel + 0x5fa, 3 << (lane * 2),
358 reg8 << (lane * 2));
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100359 }
360 /* simply use timing[0] to program mincoarse */
361 timing[0].coarse = mincoarse;
362 program_timing(&timing[0], channel, 0);
363 }
364}