1 /*
2  * Copyright (C) 2014      Panasonic Corporation
3  * Copyright (C) 2015-2016 Socionext Inc.
4  *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
5  *
6  * SPDX-License-Identifier:	GPL-2.0+
7  */
8 
9 #include <common.h>
10 #include <linux/io.h>
11 #include <linux/sizes.h>
12 
13 #include "../soc-info.h"
14 #include "ddrphy-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 struct phy_param {
28 	resource_size_t base;
29 	unsigned int nr_dx;
30 };
31 
32 static const struct phy_param uniphier_ld4_phy_param[] = {
33 	{ .base = 0x5bc01000, .nr_dx = 2, },
34 	{ .base = 0x5be01000, .nr_dx = 2, },
35 	{ /* sentinel */ }
36 };
37 
38 static const struct phy_param uniphier_pro4_phy_param[] = {
39 	{ .base = 0x5bc01000, .nr_dx = 2, },
40 	{ .base = 0x5bc02000, .nr_dx = 2, },
41 	{ .base = 0x5be01000, .nr_dx = 2, },
42 	{ .base = 0x5be02000, .nr_dx = 2, },
43 	{ /* sentinel */ }
44 };
45 
46 static const struct phy_param uniphier_sld8_phy_param[] = {
47 	{ .base = 0x5bc01000, .nr_dx = 2, },
48 	{ .base = 0x5be01000, .nr_dx = 2, },
49 	{ /* sentinel */ }
50 };
51 
52 static const struct phy_param uniphier_ld11_phy_param[] = {
53 	{ .base = 0x5bc01000, .nr_dx = 4, },
54 	{ /* sentinel */ }
55 };
56 
57 static void print_bdl(void __iomem *reg, int n)
58 {
59 	u32 val = readl(reg);
60 	int i;
61 
62 	for (i = 0; i < n; i++)
63 		printf(FS PRINTF_FORMAT, (val >> i * 6) & 0x3f);
64 }
65 
66 static void dump_loop(const struct phy_param *phy_param,
67 		      void (*callback)(void __iomem *))
68 {
69 	void __iomem *phy_base, *dx_base;
70 	int p, dx;
71 
72 	for (p = 0; phy_param->base; phy_param++, p++) {
73 		phy_base = ioremap(phy_param->base, SZ_4K);
74 		dx_base = phy_base + PHY_DX_BASE;
75 
76 		for (dx = 0; dx < phy_param->nr_dx; dx++) {
77 			printf("PHY%dDX%d:", p, dx);
78 			(*callback)(dx_base);
79 			dx_base += PHY_DX_STRIDE;
80 			printf("\n");
81 		}
82 
83 		iounmap(phy_base);
84 	}
85 }
86 
87 static void __wbdl_dump(void __iomem *dx_base)
88 {
89 	print_bdl(dx_base + PHY_DX_BDLR0, 5);
90 	print_bdl(dx_base + PHY_DX_BDLR1, 5);
91 
92 	printf(FS "(+" PRINTF_FORMAT ")",
93 	       readl(dx_base + PHY_DX_LCDLR1) & 0xff);
94 }
95 
96 static void wbdl_dump(const struct phy_param *phy_param)
97 {
98 	printf("\n--- Write Bit Delay Line ---\n");
99 	printf("           DQ0  DQ1  DQ2  DQ3  DQ4  DQ5  DQ6  DQ7   DM  DQS  (WDQD)\n");
100 
101 	dump_loop(phy_param, &__wbdl_dump);
102 }
103 
104 static void __rbdl_dump(void __iomem *dx_base)
105 {
106 	print_bdl(dx_base + PHY_DX_BDLR3, 5);
107 	print_bdl(dx_base + PHY_DX_BDLR4, 4);
108 
109 	printf(FS "(+" PRINTF_FORMAT ")",
110 	       (readl(dx_base + PHY_DX_LCDLR1) >> 8) & 0xff);
111 }
112 
113 static void rbdl_dump(const struct phy_param *phy_param)
114 {
115 	printf("\n--- Read Bit Delay Line ---\n");
116 	printf("           DQ0  DQ1  DQ2  DQ3  DQ4  DQ5  DQ6  DQ7   DM  (RDQSD)\n");
117 
118 	dump_loop(phy_param, &__rbdl_dump);
119 }
120 
121 static void __wld_dump(void __iomem *dx_base)
122 {
123 	int rank;
124 	u32 lcdlr0 = readl(dx_base + PHY_DX_LCDLR0);
125 	u32 gtr = readl(dx_base + PHY_DX_GTR);
126 
127 	for (rank = 0; rank < 4; rank++) {
128 		u32 wld = (lcdlr0 >> (8 * rank)) & 0xff; /* Delay */
129 		u32 wlsl = (gtr >> (12 + 2 * rank)) & 0x3; /* System Latency */
130 
131 		printf(FS PRINTF_FORMAT "%sT", wld,
132 		       wlsl == 0 ? "-1" : wlsl == 1 ? "+0" : "+1");
133 	}
134 }
135 
136 static void wld_dump(const struct phy_param *phy_param)
137 {
138 	printf("\n--- Write Leveling Delay ---\n");
139 	printf("            Rank0   Rank1   Rank2   Rank3\n");
140 
141 	dump_loop(phy_param, &__wld_dump);
142 }
143 
144 static void __dqsgd_dump(void __iomem *dx_base)
145 {
146 	int rank;
147 	u32 lcdlr2 = readl(dx_base + PHY_DX_LCDLR2);
148 	u32 gtr = readl(dx_base + PHY_DX_GTR);
149 
150 	for (rank = 0; rank < 4; rank++) {
151 		u32 dqsgd = (lcdlr2 >> (8 * rank)) & 0xff; /* Delay */
152 		u32 dgsl = (gtr >> (3 * rank)) & 0x7; /* System Latency */
153 
154 		printf(FS PRINTF_FORMAT "+%dT", dqsgd, dgsl);
155 	}
156 }
157 
158 static void dqsgd_dump(const struct phy_param *phy_param)
159 {
160 	printf("\n--- DQS Gating Delay ---\n");
161 	printf("            Rank0   Rank1   Rank2   Rank3\n");
162 
163 	dump_loop(phy_param, &__dqsgd_dump);
164 }
165 
166 static void __mdl_dump(void __iomem *dx_base)
167 {
168 	int i;
169 	u32 mdl = readl(dx_base + PHY_DX_MDLR);
170 	for (i = 0; i < 3; i++)
171 		printf(FS PRINTF_FORMAT, (mdl >> (8 * i)) & 0xff);
172 }
173 
174 static void mdl_dump(const struct phy_param *phy_param)
175 {
176 	printf("\n--- Master Delay Line ---\n");
177 	printf("          IPRD TPRD MDLD\n");
178 
179 	dump_loop(phy_param, &__mdl_dump);
180 }
181 
182 #define REG_DUMP(x)							\
183 	{ int ofst = PHY_ ## x; void __iomem *reg = phy_base + ofst;	\
184 		printf("%3d: %-10s: %08x : %08x\n",			\
185 		       ofst >> PHY_REG_SHIFT, #x,			\
186 		       ptr_to_uint(reg), readl(reg)); }
187 
188 #define DX_REG_DUMP(dx, x)						\
189 	{ int ofst = PHY_DX_BASE + PHY_DX_STRIDE * (dx) +		\
190 			PHY_DX_## x;					\
191 		void __iomem *reg = phy_base + ofst;			\
192 		printf("%3d: DX%d%-7s: %08x : %08x\n",			\
193 		       ofst >> PHY_REG_SHIFT, (dx), #x,			\
194 		       ptr_to_uint(reg), readl(reg)); }
195 
196 static void reg_dump(const struct phy_param *phy_param)
197 {
198 	void __iomem *phy_base;
199 	int p, dx;
200 
201 	printf("\n--- DDR PHY registers ---\n");
202 
203 	for (p = 0; phy_param->base; phy_param++, p++) {
204 		phy_base = ioremap(phy_param->base, SZ_4K);
205 
206 		printf("== PHY%d (base: %08x) ==\n", p, ptr_to_uint(phy_base));
207 		printf(" No: Name      : Address  : Data\n");
208 
209 		REG_DUMP(RIDR);
210 		REG_DUMP(PIR);
211 		REG_DUMP(PGCR0);
212 		REG_DUMP(PGCR1);
213 		REG_DUMP(PGSR0);
214 		REG_DUMP(PGSR1);
215 		REG_DUMP(PLLCR);
216 		REG_DUMP(PTR0);
217 		REG_DUMP(PTR1);
218 		REG_DUMP(PTR2);
219 		REG_DUMP(PTR3);
220 		REG_DUMP(PTR4);
221 		REG_DUMP(ACMDLR);
222 		REG_DUMP(ACBDLR);
223 		REG_DUMP(DXCCR);
224 		REG_DUMP(DSGCR);
225 		REG_DUMP(DCR);
226 		REG_DUMP(DTPR0);
227 		REG_DUMP(DTPR1);
228 		REG_DUMP(DTPR2);
229 		REG_DUMP(MR0);
230 		REG_DUMP(MR1);
231 		REG_DUMP(MR2);
232 		REG_DUMP(MR3);
233 
234 		for (dx = 0; dx < phy_param->nr_dx; dx++) {
235 			DX_REG_DUMP(dx, GCR);
236 			DX_REG_DUMP(dx, GTR);
237 		}
238 
239 		iounmap(phy_base);
240 	}
241 }
242 
243 static int do_ddr(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
244 {
245 	char *cmd = argv[1];
246 	const struct phy_param *phy_param;
247 
248 	switch (uniphier_get_soc_type()) {
249 	case SOC_UNIPHIER_LD4:
250 		phy_param = uniphier_ld4_phy_param;
251 		break;
252 	case SOC_UNIPHIER_PRO4:
253 		phy_param = uniphier_pro4_phy_param;
254 		break;
255 	case SOC_UNIPHIER_SLD8:
256 		phy_param = uniphier_sld8_phy_param;
257 		break;
258 	case SOC_UNIPHIER_LD11:
259 		phy_param = uniphier_ld11_phy_param;
260 		break;
261 	default:
262 		printf("unsupported SoC\n");
263 		return CMD_RET_FAILURE;
264 	}
265 
266 	if (argc == 1)
267 		cmd = "all";
268 
269 	if (!strcmp(cmd, "wbdl") || !strcmp(cmd, "all"))
270 		wbdl_dump(phy_param);
271 
272 	if (!strcmp(cmd, "rbdl") || !strcmp(cmd, "all"))
273 		rbdl_dump(phy_param);
274 
275 	if (!strcmp(cmd, "wld") || !strcmp(cmd, "all"))
276 		wld_dump(phy_param);
277 
278 	if (!strcmp(cmd, "dqsgd") || !strcmp(cmd, "all"))
279 		dqsgd_dump(phy_param);
280 
281 	if (!strcmp(cmd, "mdl") || !strcmp(cmd, "all"))
282 		mdl_dump(phy_param);
283 
284 	if (!strcmp(cmd, "reg") || !strcmp(cmd, "all"))
285 		reg_dump(phy_param);
286 
287 	return CMD_RET_SUCCESS;
288 }
289 
290 U_BOOT_CMD(
291 	ddr,	2,	1,	do_ddr,
292 	"UniPhier DDR PHY parameters dumper",
293 	"- dump all of the following\n"
294 	"ddr wbdl - dump Write Bit Delay\n"
295 	"ddr rbdl - dump Read Bit Delay\n"
296 	"ddr wld - dump Write Leveling\n"
297 	"ddr dqsgd - dump DQS Gating Delay\n"
298 	"ddr mdl - dump Master Delay Line\n"
299 	"ddr reg - dump registers\n"
300 );
301