xref: /openbmc/u-boot/arch/arm/mach-uniphier/dram/cmd_ddrmphy.c (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
1  // SPDX-License-Identifier: GPL-2.0+
2  /*
3   * Copyright (C) 2015-2017 Socionext Inc.
4   *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
5   */
6  
7  #include <common.h>
8  #include <stdio.h>
9  #include <linux/io.h>
10  #include <linux/printk.h>
11  #include <linux/sizes.h>
12  
13  #include "../soc-info.h"
14  #include "ddrmphy-regs.h"
15  
16  /* Select either decimal or hexadecimal */
17  #if 1
18  #define PRINTF_FORMAT "%2d"
19  #else
20  #define PRINTF_FORMAT "%02x"
21  #endif
22  /* field separator */
23  #define FS "   "
24  
25  #define ptr_to_uint(p)	((unsigned int)(unsigned long)(p))
26  
27  #define UNIPHIER_MAX_NR_DDRMPHY		3
28  
29  struct uniphier_ddrmphy_param {
30  	unsigned int soc_id;
31  	unsigned int nr_phy;
32  	struct {
33  		resource_size_t base;
34  		unsigned int nr_zq;
35  		unsigned int nr_dx;
36  	} phy[UNIPHIER_MAX_NR_DDRMPHY];
37  };
38  
39  static const struct uniphier_ddrmphy_param uniphier_ddrmphy_param[] = {
40  	{
41  		.soc_id = UNIPHIER_PXS2_ID,
42  		.nr_phy = 3,
43  		.phy = {
44  			{ .base = 0x5b830000, .nr_zq = 3, .nr_dx = 4, },
45  			{ .base = 0x5ba30000, .nr_zq = 3, .nr_dx = 4, },
46  			{ .base = 0x5bc30000, .nr_zq = 2, .nr_dx = 2, },
47  		},
48  	},
49  	{
50  		.soc_id = UNIPHIER_LD6B_ID,
51  		.nr_phy = 3,
52  		.phy = {
53  			{ .base = 0x5b830000, .nr_zq = 3, .nr_dx = 4, },
54  			{ .base = 0x5ba30000, .nr_zq = 3, .nr_dx = 4, },
55  			{ .base = 0x5bc30000, .nr_zq = 2, .nr_dx = 2, },
56  		},
57  	},
58  };
UNIPHIER_DEFINE_SOCDATA_FUNC(uniphier_get_ddrmphy_param,uniphier_ddrmphy_param)59  UNIPHIER_DEFINE_SOCDATA_FUNC(uniphier_get_ddrmphy_param, uniphier_ddrmphy_param)
60  
61  static void print_bdl(void __iomem *reg, int n)
62  {
63  	u32 val = readl(reg);
64  	int i;
65  
66  	for (i = 0; i < n; i++)
67  		printf(FS PRINTF_FORMAT, (val >> i * 8) & 0x1f);
68  }
69  
dump_loop(const struct uniphier_ddrmphy_param * param,void (* callback)(void __iomem *))70  static void dump_loop(const struct uniphier_ddrmphy_param *param,
71  		      void (*callback)(void __iomem *))
72  {
73  	void __iomem *phy_base, *dx_base;
74  	int phy, dx;
75  
76  	for (phy = 0; phy < param->nr_phy; phy++) {
77  		phy_base = ioremap(param->phy[phy].base, SZ_4K);
78  		dx_base = phy_base + MPHY_DX_BASE;
79  
80  		for (dx = 0; dx < param->phy[phy].nr_dx; dx++) {
81  			printf("PHY%dDX%d:", phy, dx);
82  			(*callback)(dx_base);
83  			dx_base += MPHY_DX_STRIDE;
84  			printf("\n");
85  		}
86  
87  		iounmap(phy_base);
88  	}
89  }
90  
zq_dump(const struct uniphier_ddrmphy_param * param)91  static void zq_dump(const struct uniphier_ddrmphy_param *param)
92  {
93  	void __iomem *phy_base, *zq_base;
94  	u32 val;
95  	int phy, zq, i;
96  
97  	printf("\n--- Impedance Data ---\n");
98  	printf("           ZPD  ZPU  OPD  OPU  ZDV  ODV\n");
99  
100  	for (phy = 0; phy < param->nr_phy; phy++) {
101  		phy_base = ioremap(param->phy[phy].base, SZ_4K);
102  		zq_base = phy_base + MPHY_ZQ_BASE;
103  
104  		for (zq = 0; zq < param->phy[phy].nr_zq; zq++) {
105  			printf("PHY%dZQ%d:", phy, zq);
106  
107  			val = readl(zq_base + MPHY_ZQ_DR);
108  			for (i = 0; i < 4; i++) {
109  				printf(FS PRINTF_FORMAT, val & 0x7f);
110  				val >>= 7;
111  			}
112  
113  			val = readl(zq_base + MPHY_ZQ_PR);
114  			for (i = 0; i < 2; i++) {
115  				printf(FS PRINTF_FORMAT, val & 0xf);
116  				val >>= 4;
117  			}
118  
119  			zq_base += MPHY_ZQ_STRIDE;
120  			printf("\n");
121  		}
122  
123  		iounmap(phy_base);
124  	}
125  }
126  
__wbdl_dump(void __iomem * dx_base)127  static void __wbdl_dump(void __iomem *dx_base)
128  {
129  	print_bdl(dx_base + MPHY_DX_BDLR0, 4);
130  	print_bdl(dx_base + MPHY_DX_BDLR1, 4);
131  	print_bdl(dx_base + MPHY_DX_BDLR2, 2);
132  
133  	printf(FS "(+" PRINTF_FORMAT ")",
134  	       readl(dx_base + MPHY_DX_LCDLR1) & 0xff);
135  }
136  
wbdl_dump(const struct uniphier_ddrmphy_param * param)137  static void wbdl_dump(const struct uniphier_ddrmphy_param *param)
138  {
139  	printf("\n--- Write Bit Delay Line ---\n");
140  	printf("           DQ0  DQ1  DQ2  DQ3  DQ4  DQ5  DQ6  DQ7   DM  DQS  (WDQD)\n");
141  
142  	dump_loop(param, &__wbdl_dump);
143  }
144  
__rbdl_dump(void __iomem * dx_base)145  static void __rbdl_dump(void __iomem *dx_base)
146  {
147  	print_bdl(dx_base + MPHY_DX_BDLR3, 4);
148  	print_bdl(dx_base + MPHY_DX_BDLR4, 4);
149  	print_bdl(dx_base + MPHY_DX_BDLR5, 1);
150  
151  	printf(FS "(+" PRINTF_FORMAT ")",
152  	       (readl(dx_base + MPHY_DX_LCDLR1) >> 8) & 0xff);
153  
154  	printf(FS "(+" PRINTF_FORMAT ")",
155  	       (readl(dx_base + MPHY_DX_LCDLR1) >> 16) & 0xff);
156  }
157  
rbdl_dump(const struct uniphier_ddrmphy_param * param)158  static void rbdl_dump(const struct uniphier_ddrmphy_param *param)
159  {
160  	printf("\n--- Read Bit Delay Line ---\n");
161  	printf("           DQ0  DQ1  DQ2  DQ3  DQ4  DQ5  DQ6  DQ7   DM  (RDQSD) (RDQSND)\n");
162  
163  	dump_loop(param, &__rbdl_dump);
164  }
165  
__wld_dump(void __iomem * dx_base)166  static void __wld_dump(void __iomem *dx_base)
167  {
168  	int rank;
169  	u32 lcdlr0 = readl(dx_base + MPHY_DX_LCDLR0);
170  	u32 gtr = readl(dx_base + MPHY_DX_GTR);
171  
172  	for (rank = 0; rank < 4; rank++) {
173  		u32 wld = (lcdlr0 >> (8 * rank)) & 0xff; /* Delay */
174  		u32 wlsl = (gtr >> (12 + 2 * rank)) & 0x3; /* System Latency */
175  
176  		printf(FS PRINTF_FORMAT "%sT", wld,
177  		       wlsl == 0 ? "-1" : wlsl == 1 ? "+0" : "+1");
178  	}
179  }
180  
wld_dump(const struct uniphier_ddrmphy_param * param)181  static void wld_dump(const struct uniphier_ddrmphy_param *param)
182  {
183  	printf("\n--- Write Leveling Delay ---\n");
184  	printf("           Rank0   Rank1   Rank2   Rank3\n");
185  
186  	dump_loop(param, &__wld_dump);
187  }
188  
__dqsgd_dump(void __iomem * dx_base)189  static void __dqsgd_dump(void __iomem *dx_base)
190  {
191  	int rank;
192  	u32 lcdlr2 = readl(dx_base + MPHY_DX_LCDLR2);
193  	u32 gtr = readl(dx_base + MPHY_DX_GTR);
194  
195  	for (rank = 0; rank < 4; rank++) {
196  		u32 dqsgd = (lcdlr2 >> (8 * rank)) & 0xff; /* Delay */
197  		u32 dgsl = (gtr >> (3 * rank)) & 0x7; /* System Latency */
198  
199  		printf(FS PRINTF_FORMAT "+%dT", dqsgd, dgsl);
200  	}
201  }
202  
dqsgd_dump(const struct uniphier_ddrmphy_param * param)203  static void dqsgd_dump(const struct uniphier_ddrmphy_param *param)
204  {
205  	printf("\n--- DQS Gating Delay ---\n");
206  	printf("           Rank0   Rank1   Rank2   Rank3\n");
207  
208  	dump_loop(param, &__dqsgd_dump);
209  }
210  
__mdl_dump(void __iomem * dx_base)211  static void __mdl_dump(void __iomem *dx_base)
212  {
213  	int i;
214  	u32 mdl = readl(dx_base + MPHY_DX_MDLR);
215  
216  	for (i = 0; i < 3; i++)
217  		printf(FS PRINTF_FORMAT, (mdl >> (8 * i)) & 0xff);
218  }
219  
mdl_dump(const struct uniphier_ddrmphy_param * param)220  static void mdl_dump(const struct uniphier_ddrmphy_param *param)
221  {
222  	printf("\n--- Master Delay Line ---\n");
223  	printf("          IPRD TPRD MDLD\n");
224  
225  	dump_loop(param, &__mdl_dump);
226  }
227  
228  #define REG_DUMP(x)							\
229  	{ int ofst = MPHY_ ## x; void __iomem *reg = phy_base + ofst;	\
230  		printf("%3d: %-10s: %p : %08x\n",			\
231  		       ofst >> MPHY_SHIFT, #x, reg, readl(reg)); }
232  
233  #define DX_REG_DUMP(dx, x)						\
234  	{ int ofst = MPHY_DX_BASE + MPHY_DX_STRIDE * (dx) +		\
235  			MPHY_DX_## x;					\
236  		void __iomem *reg = phy_base + ofst;			\
237  		printf("%3d: DX%d%-7s: %p : %08x\n",			\
238  		       ofst >> MPHY_SHIFT, (dx), #x, reg, readl(reg)); }
239  
reg_dump(const struct uniphier_ddrmphy_param * param)240  static void reg_dump(const struct uniphier_ddrmphy_param *param)
241  {
242  	void __iomem *phy_base;
243  	int phy, dx;
244  
245  	printf("\n--- DDR Multi PHY registers ---\n");
246  
247  	for (phy = 0; phy < param->nr_phy; phy++) {
248  		phy_base = ioremap(param->phy[phy].base, SZ_4K);
249  
250  		printf("== PHY%d (base: %08x) ==\n", phy,
251  		       ptr_to_uint(phy_base));
252  		printf(" No: Name      : Address  : Data\n");
253  
254  		REG_DUMP(RIDR);
255  		REG_DUMP(PIR);
256  		REG_DUMP(PGCR0);
257  		REG_DUMP(PGCR1);
258  		REG_DUMP(PGCR2);
259  		REG_DUMP(PGCR3);
260  		REG_DUMP(PGSR0);
261  		REG_DUMP(PGSR1);
262  		REG_DUMP(PLLCR);
263  		REG_DUMP(PTR0);
264  		REG_DUMP(PTR1);
265  		REG_DUMP(PTR2);
266  		REG_DUMP(PTR3);
267  		REG_DUMP(PTR4);
268  		REG_DUMP(ACMDLR);
269  		REG_DUMP(ACBDLR0);
270  		REG_DUMP(DXCCR);
271  		REG_DUMP(DSGCR);
272  		REG_DUMP(DCR);
273  		REG_DUMP(DTPR0);
274  		REG_DUMP(DTPR1);
275  		REG_DUMP(DTPR2);
276  		REG_DUMP(DTPR3);
277  		REG_DUMP(MR0);
278  		REG_DUMP(MR1);
279  		REG_DUMP(MR2);
280  		REG_DUMP(MR3);
281  
282  		for (dx = 0; dx < param->phy[phy].nr_dx; dx++) {
283  			DX_REG_DUMP(dx, GCR0);
284  			DX_REG_DUMP(dx, GCR1);
285  			DX_REG_DUMP(dx, GCR2);
286  			DX_REG_DUMP(dx, GCR3);
287  			DX_REG_DUMP(dx, GTR);
288  		}
289  
290  		iounmap(phy_base);
291  	}
292  }
293  
do_ddrm(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])294  static int do_ddrm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
295  {
296  	const struct uniphier_ddrmphy_param *param;
297  	char *cmd;
298  
299  	param = uniphier_get_ddrmphy_param();
300  	if (!param) {
301  		pr_err("unsupported SoC\n");
302  		return CMD_RET_FAILURE;
303  	}
304  
305  	if (argc == 1)
306  		cmd = "all";
307  	else
308  		cmd = argv[1];
309  
310  	if (!strcmp(cmd, "zq") || !strcmp(cmd, "all"))
311  		zq_dump(param);
312  
313  	if (!strcmp(cmd, "wbdl") || !strcmp(cmd, "all"))
314  		wbdl_dump(param);
315  
316  	if (!strcmp(cmd, "rbdl") || !strcmp(cmd, "all"))
317  		rbdl_dump(param);
318  
319  	if (!strcmp(cmd, "wld") || !strcmp(cmd, "all"))
320  		wld_dump(param);
321  
322  	if (!strcmp(cmd, "dqsgd") || !strcmp(cmd, "all"))
323  		dqsgd_dump(param);
324  
325  	if (!strcmp(cmd, "mdl") || !strcmp(cmd, "all"))
326  		mdl_dump(param);
327  
328  	if (!strcmp(cmd, "reg") || !strcmp(cmd, "all"))
329  		reg_dump(param);
330  
331  	return CMD_RET_SUCCESS;
332  }
333  
334  U_BOOT_CMD(
335  	ddrm,	2,	1,	do_ddrm,
336  	"UniPhier DDR Multi PHY parameters dumper",
337  	"- dump all of the following\n"
338  	"ddrm zq - dump Impedance Data\n"
339  	"ddrm wbdl - dump Write Bit Delay\n"
340  	"ddrm rbdl - dump Read Bit Delay\n"
341  	"ddrm wld - dump Write Leveling\n"
342  	"ddrm dqsgd - dump DQS Gating Delay\n"
343  	"ddrm mdl - dump Master Delay Line\n"
344  	"ddrm reg - dump registers\n"
345  );
346