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