xref: /rk3399_rockchip-uboot/cmd/ddr_tool/ddr_dq_eye/ddr_dq_eye.c (revision f9a1c31d51021ad79fb5d72e074600eeeeee80f8)
1*f9a1c31dSWesley Yao // SPDX-License-Identifier: GPL-2.0+
2*f9a1c31dSWesley Yao /*
3*f9a1c31dSWesley Yao  * Copyright (C) 2021 Rockchip Electronics Co., Ltd.
4*f9a1c31dSWesley Yao  */
5*f9a1c31dSWesley Yao 
6*f9a1c31dSWesley Yao #if defined(CONFIG_ROCKCHIP_RV1126) || defined(CONFIG_ROCKCHIP_RK3568)
7*f9a1c31dSWesley Yao 
8*f9a1c31dSWesley Yao #include <common.h>
9*f9a1c31dSWesley Yao #include <console.h>
10*f9a1c31dSWesley Yao #include <asm/io.h>
11*f9a1c31dSWesley Yao #include <asm/arch-rockchip/sdram_common.h>
12*f9a1c31dSWesley Yao #if defined(CONFIG_ROCKCHIP_RV1126)
13*f9a1c31dSWesley Yao #include <asm/arch/sdram_rv1126.h>
14*f9a1c31dSWesley Yao #elif defined(CONFIG_ROCKCHIP_RK3568)
15*f9a1c31dSWesley Yao #include <asm/arch/sdram_rk3568.h>
16*f9a1c31dSWesley Yao #endif
17*f9a1c31dSWesley Yao 
18*f9a1c31dSWesley Yao #define __version__	"0.0.6"
19*f9a1c31dSWesley Yao 
20*f9a1c31dSWesley Yao #define PRINT_LENGTH	64
21*f9a1c31dSWesley Yao #ifndef PRINT_STEP
22*f9a1c31dSWesley Yao #define PRINT_STEP	1
23*f9a1c31dSWesley Yao #endif
24*f9a1c31dSWesley Yao #define PRINT_RANGE	((PRINT_LENGTH) * (PRINT_STEP))
25*f9a1c31dSWesley Yao 
26*f9a1c31dSWesley Yao struct print_border {
27*f9a1c31dSWesley Yao 	u16 far_left;
28*f9a1c31dSWesley Yao 	u16 far_right;
29*f9a1c31dSWesley Yao };
30*f9a1c31dSWesley Yao 
31*f9a1c31dSWesley Yao struct rw_trn_result result;
32*f9a1c31dSWesley Yao 
calc_print_border(struct cs_rw_trn_result * result,u8 byte_en,u16 deskew_num,struct print_border * print_border)33*f9a1c31dSWesley Yao static void calc_print_border(struct cs_rw_trn_result *result, u8 byte_en,
34*f9a1c31dSWesley Yao 			      u16 deskew_num, struct print_border *print_border)
35*f9a1c31dSWesley Yao {
36*f9a1c31dSWesley Yao 	u16 far_left = deskew_num;
37*f9a1c31dSWesley Yao 	u16 far_right = 0;
38*f9a1c31dSWesley Yao 	u16 mid;
39*f9a1c31dSWesley Yao 	u8 dqs;
40*f9a1c31dSWesley Yao 	u8 dq;
41*f9a1c31dSWesley Yao 
42*f9a1c31dSWesley Yao 	if (deskew_num <= PRINT_RANGE) {
43*f9a1c31dSWesley Yao 		print_border->far_left = 0;
44*f9a1c31dSWesley Yao 		print_border->far_right = deskew_num - 1;
45*f9a1c31dSWesley Yao 
46*f9a1c31dSWesley Yao 		return;
47*f9a1c31dSWesley Yao 	}
48*f9a1c31dSWesley Yao 
49*f9a1c31dSWesley Yao 	for (dqs = 0; dqs < BYTE_NUM; dqs++) {
50*f9a1c31dSWesley Yao 		if ((byte_en & BIT(dqs)) == 0)
51*f9a1c31dSWesley Yao 			continue;
52*f9a1c31dSWesley Yao 
53*f9a1c31dSWesley Yao 		for (dq = 0; dq < 8; dq++) {
54*f9a1c31dSWesley Yao 			if (result->dqs[dqs].dq_min[dq] < far_left)
55*f9a1c31dSWesley Yao 				far_left = result->dqs[dqs].dq_min[dq];
56*f9a1c31dSWesley Yao 			if (result->dqs[dqs].dq_max[dq] > far_right)
57*f9a1c31dSWesley Yao 				far_right = result->dqs[dqs].dq_max[dq];
58*f9a1c31dSWesley Yao 		}
59*f9a1c31dSWesley Yao 	}
60*f9a1c31dSWesley Yao 
61*f9a1c31dSWesley Yao 	if (far_right - far_left + 1 > PRINT_RANGE) {
62*f9a1c31dSWesley Yao 		print_border->far_left = far_left & ~((u16)(PRINT_STEP * 4 - 1));
63*f9a1c31dSWesley Yao 		print_border->far_right = far_right | (PRINT_STEP * 4 - 1);
64*f9a1c31dSWesley Yao 	} else {
65*f9a1c31dSWesley Yao 		mid = (far_left + far_right) / 2;
66*f9a1c31dSWesley Yao 		if (mid < PRINT_RANGE / 2) {
67*f9a1c31dSWesley Yao 			print_border->far_left = 0;
68*f9a1c31dSWesley Yao 			print_border->far_right = PRINT_RANGE - 1;
69*f9a1c31dSWesley Yao 		} else if (mid > deskew_num - PRINT_RANGE / 2) {
70*f9a1c31dSWesley Yao 			print_border->far_left = deskew_num - PRINT_RANGE;
71*f9a1c31dSWesley Yao 			print_border->far_right = deskew_num - 1;
72*f9a1c31dSWesley Yao 		} else {
73*f9a1c31dSWesley Yao 			print_border->far_left = mid - PRINT_RANGE / 2;
74*f9a1c31dSWesley Yao 			print_border->far_right = mid + PRINT_RANGE / 2 - 1;
75*f9a1c31dSWesley Yao 		}
76*f9a1c31dSWesley Yao 	}
77*f9a1c31dSWesley Yao }
78*f9a1c31dSWesley Yao 
print_title_bar(struct print_border * print_border)79*f9a1c31dSWesley Yao static void print_title_bar(struct print_border *print_border)
80*f9a1c31dSWesley Yao {
81*f9a1c31dSWesley Yao 	int i;
82*f9a1c31dSWesley Yao 
83*f9a1c31dSWesley Yao 	printf("     ");
84*f9a1c31dSWesley Yao 	for (i = print_border->far_left; i < print_border->far_right;
85*f9a1c31dSWesley Yao 	     i += PRINT_STEP * 4)
86*f9a1c31dSWesley Yao 		printf("%-4d", i);
87*f9a1c31dSWesley Yao 	printf("	Margin_L Sample Margin_R Width    DQS\n");
88*f9a1c31dSWesley Yao }
89*f9a1c31dSWesley Yao 
print_ddr_dq_eye(struct fsp_rw_trn_result * fsp_result,u8 cs,u8 byte_en,u16 width_ref,struct print_border * print_border)90*f9a1c31dSWesley Yao static void print_ddr_dq_eye(struct fsp_rw_trn_result *fsp_result, u8 cs,
91*f9a1c31dSWesley Yao 			     u8 byte_en, u16 width_ref,
92*f9a1c31dSWesley Yao 			     struct print_border *print_border)
93*f9a1c31dSWesley Yao {
94*f9a1c31dSWesley Yao 	u16 sample;
95*f9a1c31dSWesley Yao 	u16 min;
96*f9a1c31dSWesley Yao 	u16 max;
97*f9a1c31dSWesley Yao 	u16 dq_eye_width;
98*f9a1c31dSWesley Yao 	u8 dqs;
99*f9a1c31dSWesley Yao 	u8 dq;
100*f9a1c31dSWesley Yao 	int i;
101*f9a1c31dSWesley Yao 	struct cs_rw_trn_result *result = &fsp_result->cs[cs];
102*f9a1c31dSWesley Yao 
103*f9a1c31dSWesley Yao 	for (dqs = 0; dqs < BYTE_NUM; dqs++) {
104*f9a1c31dSWesley Yao 		if ((byte_en & BIT(dqs)) == 0)
105*f9a1c31dSWesley Yao 			continue;
106*f9a1c31dSWesley Yao 
107*f9a1c31dSWesley Yao 		for (dq = 0; dq < 8; dq++) {
108*f9a1c31dSWesley Yao 			sample = fsp_result->min_val +
109*f9a1c31dSWesley Yao 				 result->dqs[dqs].dq_deskew[dq];
110*f9a1c31dSWesley Yao 			min = result->dqs[dqs].dq_min[dq];
111*f9a1c31dSWesley Yao 			max = result->dqs[dqs].dq_max[dq];
112*f9a1c31dSWesley Yao 			dq_eye_width = max >= min ? max - min + 1 : 0;
113*f9a1c31dSWesley Yao 
114*f9a1c31dSWesley Yao 			printf("DQ%-2d ", dqs * 8 + dq);
115*f9a1c31dSWesley Yao 			for (i = print_border->far_left;
116*f9a1c31dSWesley Yao 			     i <= print_border->far_right; i += PRINT_STEP) {
117*f9a1c31dSWesley Yao 				if (i / PRINT_STEP == sample / PRINT_STEP)
118*f9a1c31dSWesley Yao 					printf("|");
119*f9a1c31dSWesley Yao 				else if (i / PRINT_STEP >= min / PRINT_STEP &&
120*f9a1c31dSWesley Yao 					 i / PRINT_STEP <= max / PRINT_STEP)
121*f9a1c31dSWesley Yao 					printf("*");
122*f9a1c31dSWesley Yao 				else
123*f9a1c31dSWesley Yao 					printf("-");
124*f9a1c31dSWesley Yao 			}
125*f9a1c31dSWesley Yao 
126*f9a1c31dSWesley Yao 			printf("	%5d%8d%8d",
127*f9a1c31dSWesley Yao 			       sample > min ? sample - min : 0, sample,
128*f9a1c31dSWesley Yao 			       max > sample ? max - sample : 0);
129*f9a1c31dSWesley Yao 			if (dq_eye_width >= width_ref)
130*f9a1c31dSWesley Yao 				printf("%8d%8d\n", dq_eye_width,
131*f9a1c31dSWesley Yao 				       fsp_result->min_val +
132*f9a1c31dSWesley Yao 				       result->dqs[dqs].dqs_deskew);
133*f9a1c31dSWesley Yao 			else
134*f9a1c31dSWesley Yao 				printf("    [%3d]%7d\n", dq_eye_width,
135*f9a1c31dSWesley Yao 				       fsp_result->min_val +
136*f9a1c31dSWesley Yao 				       result->dqs[dqs].dqs_deskew);
137*f9a1c31dSWesley Yao 		}
138*f9a1c31dSWesley Yao 	}
139*f9a1c31dSWesley Yao 	printf("\n");
140*f9a1c31dSWesley Yao }
141*f9a1c31dSWesley Yao 
cs_eye_width_min(struct cs_rw_trn_result * result,u8 byte_en,u16 deskew_num)142*f9a1c31dSWesley Yao static u16 cs_eye_width_min(struct cs_rw_trn_result *result, u8 byte_en,
143*f9a1c31dSWesley Yao 			    u16 deskew_num)
144*f9a1c31dSWesley Yao {
145*f9a1c31dSWesley Yao 	u16 min;
146*f9a1c31dSWesley Yao 	u16 max;
147*f9a1c31dSWesley Yao 	u16 dq_eye_width;
148*f9a1c31dSWesley Yao 	u16 cs_eye_width = deskew_num;
149*f9a1c31dSWesley Yao 	u8 dqs;
150*f9a1c31dSWesley Yao 	u8 dq;
151*f9a1c31dSWesley Yao 
152*f9a1c31dSWesley Yao 	for (dqs = 0; dqs < BYTE_NUM; dqs++) {
153*f9a1c31dSWesley Yao 		if ((byte_en & BIT(dqs)) == 0)
154*f9a1c31dSWesley Yao 			continue;
155*f9a1c31dSWesley Yao 
156*f9a1c31dSWesley Yao 		for (dq = 0; dq < 8; dq++) {
157*f9a1c31dSWesley Yao 			min = result->dqs[dqs].dq_min[dq];
158*f9a1c31dSWesley Yao 			max = result->dqs[dqs].dq_max[dq];
159*f9a1c31dSWesley Yao 			dq_eye_width = max >= min ? max - min + 1 : 0;
160*f9a1c31dSWesley Yao 			if (cs_eye_width > dq_eye_width)
161*f9a1c31dSWesley Yao 				cs_eye_width = dq_eye_width;
162*f9a1c31dSWesley Yao 		}
163*f9a1c31dSWesley Yao 	}
164*f9a1c31dSWesley Yao 
165*f9a1c31dSWesley Yao 	return cs_eye_width;
166*f9a1c31dSWesley Yao }
167*f9a1c31dSWesley Yao 
do_ddr_dq_eye(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])168*f9a1c31dSWesley Yao static int do_ddr_dq_eye(cmd_tbl_t *cmdtp, int flag, int argc,
169*f9a1c31dSWesley Yao 			 char * const argv[])
170*f9a1c31dSWesley Yao {
171*f9a1c31dSWesley Yao 	unsigned long freq_mhz;
172*f9a1c31dSWesley Yao 
173*f9a1c31dSWesley Yao 	u32 ddr_type;
174*f9a1c31dSWesley Yao 	u16 rd_width = RD_DESKEW_NUM;
175*f9a1c31dSWesley Yao 	u16 wr_width = WR_DESKEW_NUM;
176*f9a1c31dSWesley Yao 	u16 cs_eye_width;
177*f9a1c31dSWesley Yao 	u16 rd_width_ref;
178*f9a1c31dSWesley Yao 	u16 wr_width_ref;
179*f9a1c31dSWesley Yao 	u16 width_ref_mhz;
180*f9a1c31dSWesley Yao 	u8 fsp = 0;
181*f9a1c31dSWesley Yao 	u8 cs;
182*f9a1c31dSWesley Yao 	int i;
183*f9a1c31dSWesley Yao 	struct print_border print_border;
184*f9a1c31dSWesley Yao 
185*f9a1c31dSWesley Yao 	printf("Rockchip DDR DQ Eye Tool v" __version__ "\n");
186*f9a1c31dSWesley Yao 
187*f9a1c31dSWesley Yao #if defined(CONFIG_ROCKCHIP_RV1126)
188*f9a1c31dSWesley Yao 	ddr_type = (readl(0xfe020208) >> 13) & 0x7;
189*f9a1c31dSWesley Yao #elif defined(CONFIG_ROCKCHIP_RK3568)
190*f9a1c31dSWesley Yao 	ddr_type = ((readl(0xfdc2020c)  & (0x3 << 12)) >> 9) |
191*f9a1c31dSWesley Yao 		   ((readl(0xfdc20208) >> 13) & 0x7);
192*f9a1c31dSWesley Yao #else
193*f9a1c31dSWesley Yao 	printf("Rockchip DDR DQ Eye Tool only support RK3568/RK3566 and RV1126 now.\n");
194*f9a1c31dSWesley Yao 	return CMD_RET_FAILURE;
195*f9a1c31dSWesley Yao #endif
196*f9a1c31dSWesley Yao 
197*f9a1c31dSWesley Yao 	if (readl(RW_TRN_RESULT_ADDR) == DDR_DQ_EYE_FLAG) {
198*f9a1c31dSWesley Yao 		memcpy(&result, (void *)(RW_TRN_RESULT_ADDR), sizeof(result));
199*f9a1c31dSWesley Yao 	} else {
200*f9a1c31dSWesley Yao 		printf("Fail to get data of DDR DQ eye.\n");
201*f9a1c31dSWesley Yao 		printf("Please update the Loader.\n");
202*f9a1c31dSWesley Yao 		return CMD_RET_FAILURE;
203*f9a1c31dSWesley Yao 	}
204*f9a1c31dSWesley Yao 
205*f9a1c31dSWesley Yao 	if (argc == 1) {
206*f9a1c31dSWesley Yao 		/* use the max freq if no arg */
207*f9a1c31dSWesley Yao 		for (i = 0; i < FSP_NUM; i++) {
208*f9a1c31dSWesley Yao 			if (result.fsp_mhz[i] > result.fsp_mhz[fsp])
209*f9a1c31dSWesley Yao 				fsp = i;
210*f9a1c31dSWesley Yao 		}
211*f9a1c31dSWesley Yao 	} else if (argc > 1) {
212*f9a1c31dSWesley Yao 		if (strict_strtoul(argv[1], 0, &freq_mhz) < 0)
213*f9a1c31dSWesley Yao 			return CMD_RET_USAGE;
214*f9a1c31dSWesley Yao 
215*f9a1c31dSWesley Yao 		if (freq_mhz >= 0 && freq_mhz < FSP_NUM) {
216*f9a1c31dSWesley Yao 			/* when user enter the fsp rather than the freq_mhz */
217*f9a1c31dSWesley Yao 			fsp = (u8)freq_mhz;
218*f9a1c31dSWesley Yao 		} else {
219*f9a1c31dSWesley Yao 			for (fsp = 0; fsp < FSP_NUM; fsp++)
220*f9a1c31dSWesley Yao 				if (result.fsp_mhz[fsp] == freq_mhz ||
221*f9a1c31dSWesley Yao 				    result.fsp_mhz[fsp] == (u16)(freq_mhz / MHZ))
222*f9a1c31dSWesley Yao 					break;
223*f9a1c31dSWesley Yao 
224*f9a1c31dSWesley Yao 			if (fsp >= FSP_NUM)
225*f9a1c31dSWesley Yao 				return CMD_RET_USAGE;
226*f9a1c31dSWesley Yao 		}
227*f9a1c31dSWesley Yao 	} else {
228*f9a1c31dSWesley Yao 		return CMD_RET_FAILURE;
229*f9a1c31dSWesley Yao 	}
230*f9a1c31dSWesley Yao 
231*f9a1c31dSWesley Yao 	printf("DDR type: ");
232*f9a1c31dSWesley Yao 	switch (ddr_type) {
233*f9a1c31dSWesley Yao 	case LPDDR4X:
234*f9a1c31dSWesley Yao 		if (result.fsp_mhz[fsp] <
235*f9a1c31dSWesley Yao 			(LP4_WIDTH_REF_MHZ_L + LP4_WIDTH_REF_MHZ_H) / 2) {
236*f9a1c31dSWesley Yao 			rd_width_ref = LP4_RD_WIDTH_REF_L;
237*f9a1c31dSWesley Yao 			wr_width_ref = LP4_WR_WIDTH_REF_L;
238*f9a1c31dSWesley Yao 			width_ref_mhz = LP4_WIDTH_REF_MHZ_L;
239*f9a1c31dSWesley Yao 		} else {
240*f9a1c31dSWesley Yao 			rd_width_ref = LP4_RD_WIDTH_REF_H;
241*f9a1c31dSWesley Yao 			wr_width_ref = LP4_WR_WIDTH_REF_H;
242*f9a1c31dSWesley Yao 			width_ref_mhz = LP4_WIDTH_REF_MHZ_H;
243*f9a1c31dSWesley Yao 		}
244*f9a1c31dSWesley Yao 		printf("LPDDR4X");
245*f9a1c31dSWesley Yao 		break;
246*f9a1c31dSWesley Yao 	case LPDDR4:
247*f9a1c31dSWesley Yao 		if (result.fsp_mhz[fsp] <
248*f9a1c31dSWesley Yao 			(LP4_WIDTH_REF_MHZ_L + LP4_WIDTH_REF_MHZ_H) / 2) {
249*f9a1c31dSWesley Yao 			rd_width_ref = LP4_RD_WIDTH_REF_L;
250*f9a1c31dSWesley Yao 			wr_width_ref = LP4_WR_WIDTH_REF_L;
251*f9a1c31dSWesley Yao 			width_ref_mhz = LP4_WIDTH_REF_MHZ_L;
252*f9a1c31dSWesley Yao 		} else {
253*f9a1c31dSWesley Yao 			rd_width_ref = LP4_RD_WIDTH_REF_H;
254*f9a1c31dSWesley Yao 			wr_width_ref = LP4_WR_WIDTH_REF_H;
255*f9a1c31dSWesley Yao 			width_ref_mhz = LP4_WIDTH_REF_MHZ_H;
256*f9a1c31dSWesley Yao 		}
257*f9a1c31dSWesley Yao 		printf("LPDDR4");
258*f9a1c31dSWesley Yao 		break;
259*f9a1c31dSWesley Yao 	case LPDDR3:
260*f9a1c31dSWesley Yao 		if (result.fsp_mhz[fsp] <
261*f9a1c31dSWesley Yao 			(LP4_WIDTH_REF_MHZ_L + LP4_WIDTH_REF_MHZ_H) / 2) {
262*f9a1c31dSWesley Yao 			rd_width_ref = LP3_RD_WIDTH_REF_L;
263*f9a1c31dSWesley Yao 			wr_width_ref = LP3_WR_WIDTH_REF_L;
264*f9a1c31dSWesley Yao 			width_ref_mhz = LP3_WIDTH_REF_MHZ_L;
265*f9a1c31dSWesley Yao 		} else {
266*f9a1c31dSWesley Yao 			rd_width_ref = LP3_RD_WIDTH_REF_H;
267*f9a1c31dSWesley Yao 			wr_width_ref = LP3_WR_WIDTH_REF_H;
268*f9a1c31dSWesley Yao 			width_ref_mhz = LP3_WIDTH_REF_MHZ_H;
269*f9a1c31dSWesley Yao 		}
270*f9a1c31dSWesley Yao 		printf("LPDDR3");
271*f9a1c31dSWesley Yao 		break;
272*f9a1c31dSWesley Yao 	case DDR4:
273*f9a1c31dSWesley Yao 		if (result.fsp_mhz[fsp] <
274*f9a1c31dSWesley Yao 			(DDR4_WIDTH_REF_MHZ_L + DDR4_WIDTH_REF_MHZ_H) / 2) {
275*f9a1c31dSWesley Yao 			rd_width_ref = DDR4_RD_WIDTH_REF_L;
276*f9a1c31dSWesley Yao 			wr_width_ref = DDR4_WR_WIDTH_REF_L;
277*f9a1c31dSWesley Yao 			width_ref_mhz = DDR4_WIDTH_REF_MHZ_L;
278*f9a1c31dSWesley Yao 		} else {
279*f9a1c31dSWesley Yao 			rd_width_ref = DDR4_RD_WIDTH_REF_H;
280*f9a1c31dSWesley Yao 			wr_width_ref = DDR4_WR_WIDTH_REF_H;
281*f9a1c31dSWesley Yao 			width_ref_mhz = DDR4_WIDTH_REF_MHZ_H;
282*f9a1c31dSWesley Yao 		}
283*f9a1c31dSWesley Yao 		printf("DDR4");
284*f9a1c31dSWesley Yao 		break;
285*f9a1c31dSWesley Yao 	case DDR3:
286*f9a1c31dSWesley Yao 	default:
287*f9a1c31dSWesley Yao 		if (result.fsp_mhz[fsp] <
288*f9a1c31dSWesley Yao 			(DDR3_WIDTH_REF_MHZ_L + DDR3_WIDTH_REF_MHZ_H) / 2) {
289*f9a1c31dSWesley Yao 			rd_width_ref = DDR3_RD_WIDTH_REF_L;
290*f9a1c31dSWesley Yao 			wr_width_ref = DDR3_WR_WIDTH_REF_L;
291*f9a1c31dSWesley Yao 			width_ref_mhz = DDR3_WIDTH_REF_MHZ_L;
292*f9a1c31dSWesley Yao 		} else {
293*f9a1c31dSWesley Yao 			rd_width_ref = DDR3_RD_WIDTH_REF_H;
294*f9a1c31dSWesley Yao 			wr_width_ref = DDR3_WR_WIDTH_REF_H;
295*f9a1c31dSWesley Yao 			width_ref_mhz = DDR3_WIDTH_REF_MHZ_H;
296*f9a1c31dSWesley Yao 		}
297*f9a1c31dSWesley Yao 		printf("DDR3");
298*f9a1c31dSWesley Yao 		break;
299*f9a1c31dSWesley Yao 	} /* switch (ddr_type) */
300*f9a1c31dSWesley Yao 	printf("\n");
301*f9a1c31dSWesley Yao 
302*f9a1c31dSWesley Yao 	for (cs = 0; cs < result.cs_num; cs++) {
303*f9a1c31dSWesley Yao 		calc_print_border(&result.rd_fsp[fsp].cs[cs], result.byte_en,
304*f9a1c31dSWesley Yao 				  RD_DESKEW_NUM, &print_border);
305*f9a1c31dSWesley Yao 		printf("CS%d %dMHz read DQ eye:\n", cs, result.fsp_mhz[fsp]);
306*f9a1c31dSWesley Yao 		print_title_bar(&print_border);
307*f9a1c31dSWesley Yao 		print_ddr_dq_eye(&result.rd_fsp[fsp], cs, result.byte_en,
308*f9a1c31dSWesley Yao 				 rd_width_ref, &print_border);
309*f9a1c31dSWesley Yao 		cs_eye_width = cs_eye_width_min(&result.rd_fsp[fsp].cs[cs],
310*f9a1c31dSWesley Yao 						result.byte_en, RD_DESKEW_NUM);
311*f9a1c31dSWesley Yao 		if (rd_width > cs_eye_width)
312*f9a1c31dSWesley Yao 			rd_width = cs_eye_width;
313*f9a1c31dSWesley Yao 
314*f9a1c31dSWesley Yao 		printf("CS%d %dMHz write DQ eye:\n", cs, result.fsp_mhz[fsp]);
315*f9a1c31dSWesley Yao 		calc_print_border(&result.wr_fsp[fsp].cs[cs], result.byte_en,
316*f9a1c31dSWesley Yao 				  WR_DESKEW_NUM, &print_border);
317*f9a1c31dSWesley Yao 		print_title_bar(&print_border);
318*f9a1c31dSWesley Yao 		print_ddr_dq_eye(&result.wr_fsp[fsp], cs, result.byte_en,
319*f9a1c31dSWesley Yao 				 wr_width_ref, &print_border);
320*f9a1c31dSWesley Yao 		cs_eye_width = cs_eye_width_min(&result.wr_fsp[fsp].cs[cs],
321*f9a1c31dSWesley Yao 						result.byte_en, WR_DESKEW_NUM);
322*f9a1c31dSWesley Yao 		if (wr_width > cs_eye_width)
323*f9a1c31dSWesley Yao 			wr_width = cs_eye_width;
324*f9a1c31dSWesley Yao 	}
325*f9a1c31dSWesley Yao 	printf("DQ eye width min: %d(read), %d(write)\n", rd_width, wr_width);
326*f9a1c31dSWesley Yao 	printf("DQ eye width reference: %d(read), %d(write) in %dMHz\n",
327*f9a1c31dSWesley Yao 	       rd_width_ref, wr_width_ref, width_ref_mhz);
328*f9a1c31dSWesley Yao 	if (rd_width < rd_width_ref || wr_width < wr_width_ref)
329*f9a1c31dSWesley Yao 		printf("ERROR: DQ eye width may be unreliable, please check!\n");
330*f9a1c31dSWesley Yao 
331*f9a1c31dSWesley Yao 	return CMD_RET_SUCCESS;
332*f9a1c31dSWesley Yao }
333*f9a1c31dSWesley Yao 
334*f9a1c31dSWesley Yao U_BOOT_CMD(ddr_dq_eye,	2,	1,	do_ddr_dq_eye,
335*f9a1c31dSWesley Yao 	   "Rockchip DDR DQ Eye Tool\n",
336*f9a1c31dSWesley Yao 	   "arg1: DDR freq in MHz, null for the max freq.\n"
337*f9a1c31dSWesley Yao 	   "example:\n"
338*f9a1c31dSWesley Yao 	   "	ddr_dq_eye 1056: show the DDR DQ eye in 1056MHz."
339*f9a1c31dSWesley Yao );
340*f9a1c31dSWesley Yao 
341*f9a1c31dSWesley Yao #endif /* if defined(CONFIG_ROCKCHIP_RV1126) || defined(CONFIG_ROCKCHIP_RK3568) */
342