uboot/cmd/ti/ddr3.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * EMIF: DDR3 test commands
   4 *
   5 * Copyright (C) 2012-2017 Texas Instruments Incorporated, <www.ti.com>
   6 */
   7
   8#include <asm/arch/hardware.h>
   9#include <asm/cache.h>
  10#include <asm/emif.h>
  11#include <common.h>
  12#include <command.h>
  13
  14DECLARE_GLOBAL_DATA_PTR;
  15
  16#ifdef CONFIG_ARCH_KEYSTONE
  17#include <asm/arch/ddr3.h>
  18#define DDR_MIN_ADDR            CONFIG_SYS_SDRAM_BASE
  19#define STACKSIZE               (512 << 10)     /* 512 KiB */
  20
  21#define DDR_REMAP_ADDR          0x80000000
  22#define ECC_START_ADDR1         ((DDR_MIN_ADDR - DDR_REMAP_ADDR) >> 17)
  23
  24#define ECC_END_ADDR1           (((gd->start_addr_sp - DDR_REMAP_ADDR - \
  25                                 STACKSIZE) >> 17) - 2)
  26#endif
  27
  28#define DDR_TEST_BURST_SIZE     1024
  29
  30static int ddr_memory_test(u32 start_address, u32 end_address, int quick)
  31{
  32        u32 index_start, value, index;
  33
  34        index_start = start_address;
  35
  36        while (1) {
  37                /* Write a pattern */
  38                for (index = index_start;
  39                                index < index_start + DDR_TEST_BURST_SIZE;
  40                                index += 4)
  41                        __raw_writel(index, index);
  42
  43                /* Read and check the pattern */
  44                for (index = index_start;
  45                                index < index_start + DDR_TEST_BURST_SIZE;
  46                                index += 4) {
  47                        value = __raw_readl(index);
  48                        if (value != index) {
  49                                printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
  50                                       index, value, __raw_readl(index));
  51
  52                                return -1;
  53                        }
  54                }
  55
  56                index_start += DDR_TEST_BURST_SIZE;
  57                if (index_start >= end_address)
  58                        break;
  59
  60                if (quick)
  61                        continue;
  62
  63                /* Write a pattern for complementary values */
  64                for (index = index_start;
  65                     index < index_start + DDR_TEST_BURST_SIZE;
  66                     index += 4)
  67                        __raw_writel((u32)~index, index);
  68
  69                /* Read and check the pattern */
  70                for (index = index_start;
  71                     index < index_start + DDR_TEST_BURST_SIZE;
  72                     index += 4) {
  73                        value = __raw_readl(index);
  74                        if (value != ~index) {
  75                                printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
  76                                       index, value, __raw_readl(index));
  77
  78                                return -1;
  79                        }
  80                }
  81
  82                index_start += DDR_TEST_BURST_SIZE;
  83                if (index_start >= end_address)
  84                        break;
  85
  86                /* Write a pattern */
  87                for (index = index_start;
  88                     index < index_start + DDR_TEST_BURST_SIZE;
  89                     index += 2)
  90                        __raw_writew((u16)index, index);
  91
  92                /* Read and check the pattern */
  93                for (index = index_start;
  94                     index < index_start + DDR_TEST_BURST_SIZE;
  95                     index += 2) {
  96                        value = __raw_readw(index);
  97                        if (value != (u16)index) {
  98                                printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
  99                                       index, value, __raw_readw(index));
 100
 101                                return -1;
 102                        }
 103                }
 104
 105                index_start += DDR_TEST_BURST_SIZE;
 106                if (index_start >= end_address)
 107                        break;
 108
 109                /* Write a pattern */
 110                for (index = index_start;
 111                     index < index_start + DDR_TEST_BURST_SIZE;
 112                     index += 1)
 113                        __raw_writeb((u8)index, index);
 114
 115                /* Read and check the pattern */
 116                for (index = index_start;
 117                     index < index_start + DDR_TEST_BURST_SIZE;
 118                     index += 1) {
 119                        value = __raw_readb(index);
 120                        if (value != (u8)index) {
 121                                printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n",
 122                                       index, value, __raw_readb(index));
 123
 124                                return -1;
 125                        }
 126                }
 127
 128                index_start += DDR_TEST_BURST_SIZE;
 129                if (index_start >= end_address)
 130                        break;
 131        }
 132
 133        puts("ddr memory test PASSED!\n");
 134        return 0;
 135}
 136
 137static int ddr_memory_compare(u32 address1, u32 address2, u32 size)
 138{
 139        u32 index, value, index2, value2;
 140
 141        for (index = address1, index2 = address2;
 142             index < address1 + size;
 143             index += 4, index2 += 4) {
 144                value = __raw_readl(index);
 145                value2 = __raw_readl(index2);
 146
 147                if (value != value2) {
 148                        printf("ddr_memory_test: Compare failed at address = 0x%x value = 0x%x, address2 = 0x%x value2 = 0x%x\n",
 149                               index, value, index2, value2);
 150
 151                        return -1;
 152                }
 153        }
 154
 155        puts("ddr memory compare PASSED!\n");
 156        return 0;
 157}
 158
 159static void ddr_check_ecc_status(void)
 160{
 161        struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
 162        u32 err_1b = readl(&emif->emif_1b_ecc_err_cnt);
 163        u32 int_status = readl(&emif->emif_irqstatus_raw_sys);
 164        int ecc_test = 0;
 165        char *env;
 166
 167        env = env_get("ecc_test");
 168        if (env)
 169                ecc_test = simple_strtol(env, NULL, 0);
 170
 171        puts("ECC test Status:\n");
 172        if (int_status & EMIF_INT_WR_ECC_ERR_SYS_MASK)
 173                puts("\tECC test: DDR ECC write error interrupted\n");
 174
 175        if (int_status & EMIF_INT_TWOBIT_ECC_ERR_SYS_MASK)
 176                if (!ecc_test)
 177                        panic("\tECC test: DDR ECC 2-bit error interrupted");
 178
 179        if (int_status & EMIF_INT_ONEBIT_ECC_ERR_SYS_MASK)
 180                puts("\tECC test: DDR ECC 1-bit error interrupted\n");
 181
 182        if (err_1b)
 183                printf("\tECC test: 1-bit ECC err count: 0x%x\n", err_1b);
 184}
 185
 186static int ddr_memory_ecc_err(u32 addr, u32 ecc_err)
 187{
 188        struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
 189        u32 ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg);
 190        u32 val1, val2, val3;
 191
 192        debug("Disabling D-Cache before ECC test\n");
 193        dcache_disable();
 194        invalidate_dcache_all();
 195
 196        puts("Testing DDR ECC:\n");
 197        puts("\tECC test: Disabling DDR ECC ...\n");
 198        writel(0, &emif->emif_ecc_ctrl_reg);
 199
 200        val1 = readl(addr);
 201        val2 = val1 ^ ecc_err;
 202        writel(val2, addr);
 203
 204        val3 = readl(addr);
 205        printf("\tECC test: addr 0x%x, read data 0x%x, written data 0x%x, err pattern: 0x%x, read after write data 0x%x\n",
 206               addr, val1, val2, ecc_err, val3);
 207
 208        puts("\tECC test: Enabling DDR ECC ...\n");
 209#ifdef CONFIG_ARCH_KEYSTONE
 210        ecc_ctrl = ECC_START_ADDR1 | (ECC_END_ADDR1 << 16);
 211        writel(ecc_ctrl, EMIF1_BASE + KS2_DDR3_ECC_ADDR_RANGE1_OFFSET);
 212        ddr3_enable_ecc(EMIF1_BASE, 1);
 213#else
 214        writel(ecc_ctrl, &emif->emif_ecc_ctrl_reg);
 215#endif
 216
 217        val1 = readl(addr);
 218        printf("\tECC test: addr 0x%x, read data 0x%x\n", addr, val1);
 219
 220        ddr_check_ecc_status();
 221
 222        debug("Enabling D-cache back after ECC test\n");
 223        enable_caches();
 224
 225        return 0;
 226}
 227
 228static int is_addr_valid(u32 addr)
 229{
 230        struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
 231        u32 start_addr, end_addr, range, ecc_ctrl;
 232
 233#ifdef CONFIG_ARCH_KEYSTONE
 234        ecc_ctrl = EMIF_ECC_REG_ECC_ADDR_RGN_1_EN_MASK;
 235        range = ECC_START_ADDR1 | (ECC_END_ADDR1 << 16);
 236#else
 237        ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg);
 238        range = readl(&emif->emif_ecc_address_range_1);
 239#endif
 240
 241        /* Check in ecc address range 1 */
 242        if (ecc_ctrl & EMIF_ECC_REG_ECC_ADDR_RGN_1_EN_MASK) {
 243                start_addr = ((range & EMIF_ECC_REG_ECC_START_ADDR_MASK) << 16)
 244                                + CONFIG_SYS_SDRAM_BASE;
 245                end_addr = start_addr + (range & EMIF_ECC_REG_ECC_END_ADDR_MASK)
 246                                + 0xFFFF;
 247                if ((addr >= start_addr) && (addr <= end_addr))
 248                        /* addr within ecc address range 1 */
 249                        return 1;
 250        }
 251
 252        /* Check in ecc address range 2 */
 253        if (ecc_ctrl & EMIF_ECC_REG_ECC_ADDR_RGN_2_EN_MASK) {
 254                range = readl(&emif->emif_ecc_address_range_2);
 255                start_addr = ((range & EMIF_ECC_REG_ECC_START_ADDR_MASK) << 16)
 256                                + CONFIG_SYS_SDRAM_BASE;
 257                end_addr = start_addr + (range & EMIF_ECC_REG_ECC_END_ADDR_MASK)
 258                                + 0xFFFF;
 259                if ((addr >= start_addr) && (addr <= end_addr))
 260                        /* addr within ecc address range 2 */
 261                        return 1;
 262        }
 263
 264        return 0;
 265}
 266
 267static int is_ecc_enabled(void)
 268{
 269        struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
 270        u32 ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg);
 271
 272        return (ecc_ctrl & EMIF_ECC_CTRL_REG_ECC_EN_MASK) &&
 273                (ecc_ctrl & EMIF_ECC_REG_RMW_EN_MASK);
 274}
 275
 276static int do_ddr_test(cmd_tbl_t *cmdtp,
 277                       int flag, int argc, char * const argv[])
 278{
 279        u32 start_addr, end_addr, size, ecc_err;
 280
 281        if ((argc == 4) && (strncmp(argv[1], "ecc_err", 8) == 0)) {
 282                if (!is_ecc_enabled()) {
 283                        puts("ECC not enabled. Please Enable ECC any try again\n");
 284                        return CMD_RET_FAILURE;
 285                }
 286
 287                start_addr = simple_strtoul(argv[2], NULL, 16);
 288                ecc_err = simple_strtoul(argv[3], NULL, 16);
 289
 290                if (!is_addr_valid(start_addr)) {
 291                        puts("Invalid address. Please enter ECC supported address!\n");
 292                        return CMD_RET_FAILURE;
 293                }
 294
 295                ddr_memory_ecc_err(start_addr, ecc_err);
 296                return 0;
 297        }
 298
 299        if (!(((argc == 4) && (strncmp(argv[1], "test", 5) == 0)) ||
 300              ((argc == 5) && (strncmp(argv[1], "compare", 8) == 0))))
 301                return cmd_usage(cmdtp);
 302
 303        start_addr = simple_strtoul(argv[2], NULL, 16);
 304        end_addr = simple_strtoul(argv[3], NULL, 16);
 305
 306        if ((start_addr < CONFIG_SYS_SDRAM_BASE) ||
 307            (start_addr > (CONFIG_SYS_SDRAM_BASE +
 308             get_effective_memsize() - 1)) ||
 309            (end_addr < CONFIG_SYS_SDRAM_BASE) ||
 310            (end_addr > (CONFIG_SYS_SDRAM_BASE +
 311             get_effective_memsize() - 1)) || (start_addr >= end_addr)) {
 312                puts("Invalid start or end address!\n");
 313                return cmd_usage(cmdtp);
 314        }
 315
 316        puts("Please wait ...\n");
 317        if (argc == 5) {
 318                size = simple_strtoul(argv[4], NULL, 16);
 319                ddr_memory_compare(start_addr, end_addr, size);
 320        } else {
 321                ddr_memory_test(start_addr, end_addr, 0);
 322        }
 323
 324        return 0;
 325}
 326
 327U_BOOT_CMD(ddr, 5, 1, do_ddr_test,
 328           "DDR3 test",
 329           "test <start_addr in hex> <end_addr in hex> - test DDR from start\n"
 330           "    address to end address\n"
 331           "ddr compare <start_addr in hex> <end_addr in hex> <size in hex> -\n"
 332           "    compare DDR data of (size) bytes from start address to end\n"
 333           "    address\n"
 334           "ddr ecc_err <addr in hex> <bit_err in hex> - generate bit errors\n"
 335           "    in DDR data at <addr>, the command will read a 32-bit data\n"
 336           "    from <addr>, and write (data ^ bit_err) back to <addr>\n"
 337);
 338