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