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