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