diff options
Diffstat (limited to 'cmd/ti')
-rw-r--r-- | cmd/ti/Kconfig | 19 | ||||
-rw-r--r-- | cmd/ti/Makefile | 5 | ||||
-rw-r--r-- | cmd/ti/ddr3.c | 342 | ||||
-rw-r--r-- | cmd/ti/pd.c | 184 |
4 files changed, 550 insertions, 0 deletions
diff --git a/cmd/ti/Kconfig b/cmd/ti/Kconfig new file mode 100644 index 00000000000..9442c9993c1 --- /dev/null +++ b/cmd/ti/Kconfig @@ -0,0 +1,19 @@ +menu "TI specific command line interface" + +config CMD_DDR3 + bool "command for verifying DDR features" + depends on ARCH_KEYSTONE || DRA7XX + help + Support for testing ddr3 on TI platforms. This command + supports memory verification, memory comapre and ecc + verification if supported. + +config CMD_PD + bool "command for verifying power domains" + depends on TI_POWER_DOMAIN + help + Debug command for K3 power domains. For this to work, the + K3 power domain driver must be enabled for the u-boot; by + default it is only enabled for SPL. + +endmenu diff --git a/cmd/ti/Makefile b/cmd/ti/Makefile new file mode 100644 index 00000000000..5f9c64f598a --- /dev/null +++ b/cmd/ti/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/ + +obj-$(CONFIG_CMD_DDR3) += ddr3.o +obj-$(CONFIG_CMD_PD) += pd.o diff --git a/cmd/ti/ddr3.c b/cmd/ti/ddr3.c new file mode 100644 index 00000000000..70ce53d01e8 --- /dev/null +++ b/cmd/ti/ddr3.c @@ -0,0 +1,342 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * EMIF: DDR3 test commands + * + * Copyright (C) 2012-2017 Texas Instruments Incorporated, <www.ti.com> + */ + +#include <cpu_func.h> +#include <env.h> +#include <init.h> +#include <log.h> +#include <asm/arch/hardware.h> +#include <asm/cache.h> +#include <asm/emif.h> +#include <command.h> +#include <asm/global_data.h> + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_ARCH_KEYSTONE +#include <asm/arch/ddr3.h> +#define DDR_MIN_ADDR CFG_SYS_SDRAM_BASE +#define STACKSIZE (512 << 10) /* 512 KiB */ + +#define DDR_REMAP_ADDR 0x80000000 +#define ECC_START_ADDR1 ((DDR_MIN_ADDR - DDR_REMAP_ADDR) >> 17) + +#define ECC_END_ADDR1 (((gd->start_addr_sp - DDR_REMAP_ADDR - \ + STACKSIZE) >> 17) - 2) +#endif + +#define DDR_TEST_BURST_SIZE 1024 + +static int ddr_memory_test(u32 start_address, u32 end_address, int quick) +{ + u32 index_start, value, index; + + index_start = start_address; + + while (1) { + /* Write a pattern */ + for (index = index_start; + index < index_start + DDR_TEST_BURST_SIZE; + index += 4) + __raw_writel(index, index); + + /* Read and check the pattern */ + for (index = index_start; + index < index_start + DDR_TEST_BURST_SIZE; + index += 4) { + value = __raw_readl(index); + if (value != index) { + printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n", + index, value, __raw_readl(index)); + + return -1; + } + } + + index_start += DDR_TEST_BURST_SIZE; + if (index_start >= end_address) + break; + + if (quick) + continue; + + /* Write a pattern for complementary values */ + for (index = index_start; + index < index_start + DDR_TEST_BURST_SIZE; + index += 4) + __raw_writel((u32)~index, index); + + /* Read and check the pattern */ + for (index = index_start; + index < index_start + DDR_TEST_BURST_SIZE; + index += 4) { + value = __raw_readl(index); + if (value != ~index) { + printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n", + index, value, __raw_readl(index)); + + return -1; + } + } + + index_start += DDR_TEST_BURST_SIZE; + if (index_start >= end_address) + break; + + /* Write a pattern */ + for (index = index_start; + index < index_start + DDR_TEST_BURST_SIZE; + index += 2) + __raw_writew((u16)index, index); + + /* Read and check the pattern */ + for (index = index_start; + index < index_start + DDR_TEST_BURST_SIZE; + index += 2) { + value = __raw_readw(index); + if (value != (u16)index) { + printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n", + index, value, __raw_readw(index)); + + return -1; + } + } + + index_start += DDR_TEST_BURST_SIZE; + if (index_start >= end_address) + break; + + /* Write a pattern */ + for (index = index_start; + index < index_start + DDR_TEST_BURST_SIZE; + index += 1) + __raw_writeb((u8)index, index); + + /* Read and check the pattern */ + for (index = index_start; + index < index_start + DDR_TEST_BURST_SIZE; + index += 1) { + value = __raw_readb(index); + if (value != (u8)index) { + printf("ddr_memory_test: Failed at address index = 0x%x value = 0x%x *(index) = 0x%x\n", + index, value, __raw_readb(index)); + + return -1; + } + } + + index_start += DDR_TEST_BURST_SIZE; + if (index_start >= end_address) + break; + } + + puts("ddr memory test PASSED!\n"); + return 0; +} + +static int ddr_memory_compare(u32 address1, u32 address2, u32 size) +{ + u32 index, value, index2, value2; + + for (index = address1, index2 = address2; + index < address1 + size; + index += 4, index2 += 4) { + value = __raw_readl(index); + value2 = __raw_readl(index2); + + if (value != value2) { + printf("ddr_memory_test: Compare failed at address = 0x%x value = 0x%x, address2 = 0x%x value2 = 0x%x\n", + index, value, index2, value2); + + return -1; + } + } + + puts("ddr memory compare PASSED!\n"); + return 0; +} + +static void ddr_check_ecc_status(void) +{ + struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE; + u32 err_1b = readl(&emif->emif_1b_ecc_err_cnt); + u32 int_status = readl(&emif->emif_irqstatus_raw_sys); + int ecc_test = 0; + char *env; + + env = env_get("ecc_test"); + if (env) + ecc_test = simple_strtol(env, NULL, 0); + + puts("ECC test Status:\n"); + if (int_status & EMIF_INT_WR_ECC_ERR_SYS_MASK) + puts("\tECC test: DDR ECC write error interrupted\n"); + + if (int_status & EMIF_INT_TWOBIT_ECC_ERR_SYS_MASK) + if (!ecc_test) + panic("\tECC test: DDR ECC 2-bit error interrupted"); + + if (int_status & EMIF_INT_ONEBIT_ECC_ERR_SYS_MASK) + puts("\tECC test: DDR ECC 1-bit error interrupted\n"); + + if (err_1b) + printf("\tECC test: 1-bit ECC err count: 0x%x\n", err_1b); +} + +static int ddr_memory_ecc_err(u32 addr, u32 ecc_err) +{ + struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE; + u32 ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg); + u32 val1, val2, val3; + + debug("Disabling D-Cache before ECC test\n"); + dcache_disable(); + invalidate_dcache_all(); + + puts("Testing DDR ECC:\n"); + puts("\tECC test: Disabling DDR ECC ...\n"); + writel(0, &emif->emif_ecc_ctrl_reg); + + val1 = readl(addr); + val2 = val1 ^ ecc_err; + writel(val2, addr); + + val3 = readl(addr); +#ifdef CONFIG_ARCH_KEYSTONE + ecc_ctrl = ECC_START_ADDR1 | (ECC_END_ADDR1 << 16); + writel(ecc_ctrl, EMIF1_BASE + KS2_DDR3_ECC_ADDR_RANGE1_OFFSET); + ddr3_enable_ecc(EMIF1_BASE, 1); +#else + writel(ecc_ctrl, &emif->emif_ecc_ctrl_reg); +#endif + + 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", + addr, val1, val2, ecc_err, val3); + + puts("\tECC test: Enabled DDR ECC ...\n"); + + val1 = readl(addr); + printf("\tECC test: addr 0x%x, read data 0x%x\n", addr, val1); + + ddr_check_ecc_status(); + + debug("Enabling D-cache back after ECC test\n"); + enable_caches(); + + return 0; +} + +static int is_addr_valid(u32 addr) +{ + struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE; + u32 start_addr, end_addr, range, ecc_ctrl; + +#ifdef CONFIG_ARCH_KEYSTONE + ecc_ctrl = EMIF_ECC_REG_ECC_ADDR_RGN_1_EN_MASK; + range = ECC_START_ADDR1 | (ECC_END_ADDR1 << 16); +#else + ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg); + range = readl(&emif->emif_ecc_address_range_1); +#endif + + /* Check in ecc address range 1 */ + if (ecc_ctrl & EMIF_ECC_REG_ECC_ADDR_RGN_1_EN_MASK) { + start_addr = ((range & EMIF_ECC_REG_ECC_START_ADDR_MASK) << 16) + + CFG_SYS_SDRAM_BASE; + end_addr = (range & EMIF_ECC_REG_ECC_END_ADDR_MASK) + 0xFFFF + + CFG_SYS_SDRAM_BASE; + if ((addr >= start_addr) && (addr <= end_addr)) + /* addr within ecc address range 1 */ + return 1; + } + + /* Check in ecc address range 2 */ + if (ecc_ctrl & EMIF_ECC_REG_ECC_ADDR_RGN_2_EN_MASK) { + range = readl(&emif->emif_ecc_address_range_2); + start_addr = ((range & EMIF_ECC_REG_ECC_START_ADDR_MASK) << 16) + + CFG_SYS_SDRAM_BASE; + end_addr = (range & EMIF_ECC_REG_ECC_END_ADDR_MASK) + 0xFFFF + + CFG_SYS_SDRAM_BASE; + if ((addr >= start_addr) && (addr <= end_addr)) + /* addr within ecc address range 2 */ + return 1; + } + + return 0; +} + +static int is_ecc_enabled(void) +{ + struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE; + u32 ecc_ctrl = readl(&emif->emif_ecc_ctrl_reg); + + return (ecc_ctrl & EMIF_ECC_CTRL_REG_ECC_EN_MASK) && + (ecc_ctrl & EMIF_ECC_REG_RMW_EN_MASK); +} + +static int do_ddr_test(struct cmd_tbl *cmdtp, + int flag, int argc, char *const argv[]) +{ + u32 start_addr, end_addr, size, ecc_err; + + if ((argc == 4) && (strncmp(argv[1], "ecc_err", 8) == 0)) { + if (!is_ecc_enabled()) { + puts("ECC not enabled. Please Enable ECC and try again\n"); + return CMD_RET_FAILURE; + } + + start_addr = hextoul(argv[2], NULL); + ecc_err = hextoul(argv[3], NULL); + + if (!is_addr_valid(start_addr)) { + puts("Invalid address. Please enter ECC supported address!\n"); + return CMD_RET_FAILURE; + } + + ddr_memory_ecc_err(start_addr, ecc_err); + return 0; + } + + if (!(((argc == 4) && (strncmp(argv[1], "test", 5) == 0)) || + ((argc == 5) && (strncmp(argv[1], "compare", 8) == 0)))) + return cmd_usage(cmdtp); + + start_addr = hextoul(argv[2], NULL); + end_addr = hextoul(argv[3], NULL); + + if ((start_addr < CFG_SYS_SDRAM_BASE) || + (start_addr > (CFG_SYS_SDRAM_BASE + + get_effective_memsize() - 1)) || + (end_addr < CFG_SYS_SDRAM_BASE) || + (end_addr > (CFG_SYS_SDRAM_BASE + + get_effective_memsize() - 1)) || (start_addr >= end_addr)) { + puts("Invalid start or end address!\n"); + return cmd_usage(cmdtp); + } + + puts("Please wait ...\n"); + if (argc == 5) { + size = hextoul(argv[4], NULL); + ddr_memory_compare(start_addr, end_addr, size); + } else { + ddr_memory_test(start_addr, end_addr, 0); + } + + return 0; +} + +U_BOOT_CMD(ddr, 5, 1, do_ddr_test, + "DDR3 test", + "test <start_addr in hex> <end_addr in hex> - test DDR from start\n" + " address to end address\n" + "ddr compare <start_addr in hex> <end_addr in hex> <size in hex> -\n" + " compare DDR data of (size) bytes from start address to end\n" + " address\n" + "ddr ecc_err <addr in hex> <bit_err in hex> - generate bit errors\n" + " in DDR data at <addr>, the command will read a 32-bit data\n" + " from <addr>, and write (data ^ bit_err) back to <addr>\n" +); diff --git a/cmd/ti/pd.c b/cmd/ti/pd.c new file mode 100644 index 00000000000..305023af1e7 --- /dev/null +++ b/cmd/ti/pd.c @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Power Domain test commands + * + * Copyright (C) 2020 Texas Instruments Incorporated, <www.ti.com> + */ + +#include <command.h> +#include <dm.h> +#include <k3-dev.h> + +static const struct udevice_id ti_pd_of_match[] = { + { .compatible = "ti,sci-pm-domain" }, + { /* sentinel */ } +}; + +static struct ti_k3_pd_platdata *ti_pd_find_data(void) +{ + struct udevice *dev; + int i = 0; + + while (1) { + uclass_get_device(UCLASS_POWER_DOMAIN, i++, &dev); + if (!dev) + return NULL; + + if (device_is_compatible(dev, + ti_pd_of_match[0].compatible)) + return dev_get_priv(dev); + } + + return NULL; +} + +static void dump_lpsc(struct ti_k3_pd_platdata *data, struct ti_pd *pd) +{ + int i; + struct ti_lpsc *lpsc; + u8 state; + static const char * const lpsc_states[] = { + "swrstdis", "syncrst", "disable", "enable", "autosleep", + "autowake", "unknown", + }; + + for (i = 0; i < data->num_lpsc; i++) { + lpsc = &data->lpsc[i]; + if (lpsc->pd != pd) + continue; + state = lpsc_get_state(lpsc); + if (state > ARRAY_SIZE(lpsc_states)) + state = ARRAY_SIZE(lpsc_states) - 1; + printf(" LPSC%d: state=%s, usecount=%d\n", + lpsc->id, lpsc_states[state], lpsc->usecount); + } +} + +static void dump_pd(struct ti_k3_pd_platdata *data, struct ti_psc *psc) +{ + int i; + struct ti_pd *pd; + u8 state; + static const char * const pd_states[] = { + "off", "on", "unknown" + }; + + for (i = 0; i < data->num_pd; i++) { + pd = &data->pd[i]; + if (pd->psc != psc) + continue; + state = ti_pd_state(pd); + if (state > ARRAY_SIZE(pd_states)) + state = ARRAY_SIZE(pd_states) - 1; + printf(" PD%d: state=%s, usecount=%d:\n", + pd->id, pd_states[state], pd->usecount); + dump_lpsc(data, pd); + } +} + +static void dump_psc(struct ti_k3_pd_platdata *data) +{ + int i; + struct ti_psc *psc; + + for (i = 0; i < data->num_psc; i++) { + psc = &data->psc[i]; + printf("PSC%d [%p]:\n", psc->id, psc->base); + dump_pd(data, psc); + } +} + +static int do_pd_dump(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct ti_k3_pd_platdata *data; + + data = ti_pd_find_data(); + if (!data) + return CMD_RET_FAILURE; + + dump_psc(data); + + return 0; +} + +static int do_pd_endis(int argc, char *const argv[], u8 state) +{ + u32 psc_id; + u32 lpsc_id; + int i; + struct ti_k3_pd_platdata *data; + struct ti_lpsc *lpsc; + int ret; + + if (argc < 3) + return CMD_RET_FAILURE; + + data = ti_pd_find_data(); + if (!data) + return CMD_RET_FAILURE; + + psc_id = dectoul(argv[1], NULL); + lpsc_id = dectoul(argv[2], NULL); + + for (i = 0; i < data->num_lpsc; i++) { + lpsc = &data->lpsc[i]; + if (lpsc->pd->psc->id != psc_id) + continue; + if (lpsc->id != lpsc_id) + continue; + printf("%s pd [PSC:%d,LPSC:%d]...\n", + state == MDSTAT_STATE_ENABLE ? "Enabling" : "Disabling", + psc_id, lpsc_id); + ret = ti_lpsc_transition(lpsc, state); + if (ret) + return CMD_RET_FAILURE; + else + return 0; + } + + printf("No matching psc/lpsc found.\n"); + + return CMD_RET_FAILURE; +} + +static int do_pd_enable(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + return do_pd_endis(argc, argv, MDSTAT_STATE_ENABLE); +} + +static int do_pd_disable(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + return do_pd_endis(argc, argv, MDSTAT_STATE_SWRSTDISABLE); +} + +static struct cmd_tbl cmd_pd[] = { + U_BOOT_CMD_MKENT(dump, 1, 0, do_pd_dump, "", ""), + U_BOOT_CMD_MKENT(enable, 3, 0, do_pd_enable, "", ""), + U_BOOT_CMD_MKENT(disable, 3, 0, do_pd_disable, "", ""), +}; + +static int ti_do_pd(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) +{ + struct cmd_tbl *c; + + argc--; + argv++; + + c = find_cmd_tbl(argv[0], cmd_pd, ARRAY_SIZE(cmd_pd)); + if (c) + return c->cmd(cmdtp, flag, argc, argv); + else + return CMD_RET_USAGE; +} + +U_BOOT_LONGHELP(pd, + "dump - show power domain status\n" + "enable [psc] [lpsc] - enable power domain\n" + "disable [psc] [lpsc] - disable power domain\n"); + +U_BOOT_CMD(pd, 4, 1, ti_do_pd, + "TI power domain control", pd_help_text +); |