199d14b01SJoseph Chen /* 299d14b01SJoseph Chen * (C) Copyright 2019 Rockchip Electronics Co., Ltd 399d14b01SJoseph Chen * 499d14b01SJoseph Chen * SPDX-License-Identifier: GPL-2.0+ 599d14b01SJoseph Chen */ 699d14b01SJoseph Chen 799d14b01SJoseph Chen #include <common.h> 899d14b01SJoseph Chen #include <boot_rkimg.h> 999d14b01SJoseph Chen #include <cli.h> 1099d14b01SJoseph Chen #include <dm.h> 1199d14b01SJoseph Chen #include <environment.h> 1299d14b01SJoseph Chen #include <malloc.h> 1399d14b01SJoseph Chen #include <misc.h> 1499d14b01SJoseph Chen #include <sysmem.h> 1599d14b01SJoseph Chen #include <linux/ctype.h> 1699d14b01SJoseph Chen #include <asm/arch/vendor.h> 1799d14b01SJoseph Chen #include "test-rockchip.h" 1899d14b01SJoseph Chen 1999d14b01SJoseph Chen #define DEFAULT_STORAGE_RW_PART "userdata" 2099d14b01SJoseph Chen 2199d14b01SJoseph Chen #if defined(CONFIG_MMC) || defined(CONFIG_RKNAND) || defined(CONFIG_BLK) 2299d14b01SJoseph Chen static int do_test_storage(cmd_tbl_t *cmdtp, int flag, 2399d14b01SJoseph Chen int argc, char *const argv[], 2499d14b01SJoseph Chen const char *devtype, 2599d14b01SJoseph Chen const char *devnum, 2699d14b01SJoseph Chen const char *label) 2799d14b01SJoseph Chen { 2899d14b01SJoseph Chen struct blk_desc *dev_desc; 29*474718ffSJoseph Chen disk_partition_t part; 3099d14b01SJoseph Chen u32 blocks, round, sector; 3199d14b01SJoseph Chen char *w_buf, *r_buf; 3299d14b01SJoseph Chen char cmd[64]; 3399d14b01SJoseph Chen int i, ret; 3499d14b01SJoseph Chen ulong ts; 3599d14b01SJoseph Chen 36*474718ffSJoseph Chen /* 1. Get test partition */ 3799d14b01SJoseph Chen dev_desc = rockchip_get_bootdev(); 3899d14b01SJoseph Chen if (!dev_desc) { 3999d14b01SJoseph Chen printf("%s: Can't find dev_desc\n", __func__); 4099d14b01SJoseph Chen return -ENODEV; 4199d14b01SJoseph Chen } 4299d14b01SJoseph Chen 4399d14b01SJoseph Chen if (part_get_info_by_name(dev_desc, 4499d14b01SJoseph Chen DEFAULT_STORAGE_RW_PART, &part) < 0) { 4599d14b01SJoseph Chen printf("%s: Can't find %s part\n", 4699d14b01SJoseph Chen __func__, DEFAULT_STORAGE_RW_PART); 4799d14b01SJoseph Chen return -EINVAL; 4899d14b01SJoseph Chen } 4999d14b01SJoseph Chen 5099d14b01SJoseph Chen /* 32MB */ 5199d14b01SJoseph Chen sector = part.start; 5299d14b01SJoseph Chen blocks = part.size > 0x10000 ? 0x10000 : part.size; 5399d14b01SJoseph Chen round = 4; 5499d14b01SJoseph Chen 5599d14b01SJoseph Chen /* Round up */ 5699d14b01SJoseph Chen if (blocks % 2) 5799d14b01SJoseph Chen blocks += 1; 5899d14b01SJoseph Chen 5999d14b01SJoseph Chen printf("%s RW sectors on %s 0x%08x - 0x%08x(size: %ld MiB) for %d round\n\n", 60*474718ffSJoseph Chen label, DEFAULT_STORAGE_RW_PART, 6199d14b01SJoseph Chen sector, sector + blocks, 6299d14b01SJoseph Chen (blocks * dev_desc->blksz) >> 20, round); 6399d14b01SJoseph Chen 6499d14b01SJoseph Chen /* 2. Switch to devnum */ 6599d14b01SJoseph Chen if (devtype) { 6699d14b01SJoseph Chen snprintf(cmd, sizeof(cmd), "%s dev %s", devtype, devnum); 6799d14b01SJoseph Chen if (run_command(cmd, 0)) { 6899d14b01SJoseph Chen printf("Switch to %s%s failed\n", devtype, devnum); 6999d14b01SJoseph Chen ret = -ENODEV; 7099d14b01SJoseph Chen goto err1; 7199d14b01SJoseph Chen } 7299d14b01SJoseph Chen } 7399d14b01SJoseph Chen 7499d14b01SJoseph Chen /* 3. Prepare memory */ 7599d14b01SJoseph Chen w_buf = sysmem_alloc_by_name("storage_w", blocks * dev_desc->blksz); 7699d14b01SJoseph Chen if (!w_buf) { 7799d14b01SJoseph Chen printf("No sysmem for w_buf!\n"); 7899d14b01SJoseph Chen ret = -ENOMEM; 7999d14b01SJoseph Chen goto err1; 8099d14b01SJoseph Chen } 8199d14b01SJoseph Chen 8299d14b01SJoseph Chen r_buf = sysmem_alloc_by_name("storage_r", blocks * dev_desc->blksz); 8399d14b01SJoseph Chen if (!r_buf) { 8499d14b01SJoseph Chen printf("No sysmem for r_buf!\n"); 8599d14b01SJoseph Chen ret = -ENOMEM; 8699d14b01SJoseph Chen goto err2; 8799d14b01SJoseph Chen } 8899d14b01SJoseph Chen 8999d14b01SJoseph Chen for (i = 0; i < blocks * dev_desc->blksz; i++) { 9099d14b01SJoseph Chen w_buf[i] = i; 9199d14b01SJoseph Chen r_buf[i] = 0; 9299d14b01SJoseph Chen } 9399d14b01SJoseph Chen 9499d14b01SJoseph Chen /* 4. Write test */ 9599d14b01SJoseph Chen ts = get_timer(0); 9699d14b01SJoseph Chen if (devtype) { 9799d14b01SJoseph Chen snprintf(cmd, sizeof(cmd), "%s write 0x%x 0x%x 0x%x", 9899d14b01SJoseph Chen devtype, (u32)(ulong)w_buf, sector, blocks); 9999d14b01SJoseph Chen for (i = 0; i < round; i++) { 10099d14b01SJoseph Chen if (run_command(cmd, 0)) { 10199d14b01SJoseph Chen ret = -EIO; 10299d14b01SJoseph Chen goto err3; 10399d14b01SJoseph Chen } 10499d14b01SJoseph Chen } 10599d14b01SJoseph Chen } else { 10699d14b01SJoseph Chen for (i = 0; i < round; i++) { 10799d14b01SJoseph Chen ret = blk_dwrite(dev_desc, sector, blocks, w_buf); 10899d14b01SJoseph Chen if (ret != blocks) { 10999d14b01SJoseph Chen ret = -EIO; 11099d14b01SJoseph Chen goto err3; 11199d14b01SJoseph Chen } 11299d14b01SJoseph Chen } 11399d14b01SJoseph Chen } 11499d14b01SJoseph Chen 11599d14b01SJoseph Chen ts = get_timer(0) - ts; 11699d14b01SJoseph Chen printf("\n%s write: size %dMB, used %ldms, speed %ldMB/s\n", 11799d14b01SJoseph Chen label, blocks * round / 2048, ts, (blocks * round >> 1) / ts); 11899d14b01SJoseph Chen 11999d14b01SJoseph Chen /* 5. Read test */ 12099d14b01SJoseph Chen ts = get_timer(0); 12199d14b01SJoseph Chen if (devtype) { 12299d14b01SJoseph Chen snprintf(cmd, sizeof(cmd), "%s read 0x%x 0x%x 0x%x", 12399d14b01SJoseph Chen devtype, (u32)(ulong)r_buf, sector, blocks); 12499d14b01SJoseph Chen 12599d14b01SJoseph Chen for (i = 0; i < round; i++) { 12699d14b01SJoseph Chen if (run_command(cmd, 0)) { 12799d14b01SJoseph Chen ret = -EIO; 12899d14b01SJoseph Chen goto err3; 12999d14b01SJoseph Chen } 13099d14b01SJoseph Chen } 13199d14b01SJoseph Chen } else { 13299d14b01SJoseph Chen for (i = 0; i < round; i++) { 13399d14b01SJoseph Chen ret = blk_dread(dev_desc, sector, blocks, r_buf); 13499d14b01SJoseph Chen if (ret != blocks) { 13599d14b01SJoseph Chen ret = -EIO; 13699d14b01SJoseph Chen goto err3; 13799d14b01SJoseph Chen } 13899d14b01SJoseph Chen } 13999d14b01SJoseph Chen } 14099d14b01SJoseph Chen 14199d14b01SJoseph Chen ts = get_timer(0) - ts; 14299d14b01SJoseph Chen printf("\n%s read: size %dMB, used %ldms, speed %ldMB/s\n", 14399d14b01SJoseph Chen label, blocks * round / 2048, ts, (blocks * round >> 1) / ts); 14499d14b01SJoseph Chen 14599d14b01SJoseph Chen /* 6. Verify the context */ 14699d14b01SJoseph Chen for (i = 0; i < blocks * dev_desc->blksz; i++) { 14799d14b01SJoseph Chen if (w_buf[i] != r_buf[i]) { 14899d14b01SJoseph Chen printf("%s context compare error!\n", label); 14999d14b01SJoseph Chen ret = -EINVAL; 15099d14b01SJoseph Chen goto err3; 15199d14b01SJoseph Chen } 15299d14b01SJoseph Chen } 15399d14b01SJoseph Chen 15499d14b01SJoseph Chen /* 7. Switch back to default system devnum */ 15599d14b01SJoseph Chen if (devtype && !strcmp(devtype, "mmc") && 15699d14b01SJoseph Chen strcmp(devnum, env_get("devnum"))) { 15799d14b01SJoseph Chen ret = run_command(cmd, 0); 15899d14b01SJoseph Chen if (ret) { 15999d14b01SJoseph Chen printf("Switch to mmc1 failed\n"); 16099d14b01SJoseph Chen ret = -ENODEV; 16199d14b01SJoseph Chen goto err3; 16299d14b01SJoseph Chen } 16399d14b01SJoseph Chen } 16499d14b01SJoseph Chen 16599d14b01SJoseph Chen ret = 0; 16699d14b01SJoseph Chen err3: 16799d14b01SJoseph Chen sysmem_free((phys_addr_t)r_buf); 16899d14b01SJoseph Chen err2: 16999d14b01SJoseph Chen sysmem_free((phys_addr_t)w_buf); 17099d14b01SJoseph Chen err1: 17199d14b01SJoseph Chen 17299d14b01SJoseph Chen return ret; 17399d14b01SJoseph Chen } 17499d14b01SJoseph Chen 17599d14b01SJoseph Chen #ifdef CONFIG_MMC 17699d14b01SJoseph Chen static int do_test_emmc(cmd_tbl_t *cmdtp, int flag, 17799d14b01SJoseph Chen int argc, char *const argv[]) 17899d14b01SJoseph Chen { 17999d14b01SJoseph Chen return do_test_storage(cmdtp, flag, argc, argv, "mmc", "0", "MMC0"); 18099d14b01SJoseph Chen } 18199d14b01SJoseph Chen 18299d14b01SJoseph Chen static int do_test_sdmmc(cmd_tbl_t *cmdtp, int flag, 18399d14b01SJoseph Chen int argc, char *const argv[]) 18499d14b01SJoseph Chen { 18599d14b01SJoseph Chen return do_test_storage(cmdtp, flag, argc, argv, "mmc", "1", "MMC1"); 18699d14b01SJoseph Chen } 18799d14b01SJoseph Chen #endif 18899d14b01SJoseph Chen 18999d14b01SJoseph Chen #ifdef CONFIG_RKNAND 19099d14b01SJoseph Chen static int do_test_rknand(cmd_tbl_t *cmdtp, int flag, 19199d14b01SJoseph Chen int argc, char *const argv[]) 19299d14b01SJoseph Chen { 19399d14b01SJoseph Chen return do_test_storage(cmdtp, flag, argc, argv, "rknand", "0", "RKNAND0"); 19499d14b01SJoseph Chen } 19599d14b01SJoseph Chen #endif 19699d14b01SJoseph Chen 19799d14b01SJoseph Chen static int do_test_blk(cmd_tbl_t *cmdtp, int flag, 19899d14b01SJoseph Chen int argc, char *const argv[]) 19999d14b01SJoseph Chen { 20099d14b01SJoseph Chen return do_test_storage(cmdtp, flag, argc, argv, NULL, NULL, "BLK"); 20199d14b01SJoseph Chen } 20299d14b01SJoseph Chen #endif/* defined(CONFIG_MMC) || defined(CONFIG_RKNAND) || defined(CONFIG_BLK) */ 20399d14b01SJoseph Chen 20499d14b01SJoseph Chen #if defined(CONFIG_OPTEE_CLIENT) && defined(CONFIG_MMC) 20599d14b01SJoseph Chen static int do_test_secure_storage(cmd_tbl_t *cmdtp, int flag, 20699d14b01SJoseph Chen int argc, char *const argv[]) 20799d14b01SJoseph Chen { 20899d14b01SJoseph Chen return run_command("mmc testsecurestorage", 0); 20999d14b01SJoseph Chen } 21099d14b01SJoseph Chen #endif 21199d14b01SJoseph Chen 21299d14b01SJoseph Chen #if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE) && \ 21399d14b01SJoseph Chen !defined(CONFIG_SPL_BUILD) 21499d14b01SJoseph Chen static int do_test_env(cmd_tbl_t *cmdtp, int flag, 21599d14b01SJoseph Chen int argc, char *const argv[]) 21699d14b01SJoseph Chen { 21799d14b01SJoseph Chen int ret; 21899d14b01SJoseph Chen 21999d14b01SJoseph Chen ret = env_save(); 22099d14b01SJoseph Chen if (ret) 22199d14b01SJoseph Chen return ret; 22299d14b01SJoseph Chen 22399d14b01SJoseph Chen return env_load(); 22499d14b01SJoseph Chen } 22599d14b01SJoseph Chen #endif 22699d14b01SJoseph Chen 22799d14b01SJoseph Chen #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION 22899d14b01SJoseph Chen static int do_test_vendor(cmd_tbl_t *cmdtp, int flag, 22999d14b01SJoseph Chen int argc, char *const argv[]) 23099d14b01SJoseph Chen { 23199d14b01SJoseph Chen return vendor_storage_test(); 23299d14b01SJoseph Chen } 23399d14b01SJoseph Chen #endif 23499d14b01SJoseph Chen 23599d14b01SJoseph Chen #ifdef CONFIG_ROCKCHIP_EFUSE 23699d14b01SJoseph Chen static int do_test_efuse(cmd_tbl_t *cmdtp, int flag, 23799d14b01SJoseph Chen int argc, char *const argv[]) 23899d14b01SJoseph Chen { 23999d14b01SJoseph Chen struct udevice *dev; 24099d14b01SJoseph Chen u8 fuses[128] = {0}; 24199d14b01SJoseph Chen int ret; 24299d14b01SJoseph Chen 24399d14b01SJoseph Chen ret = uclass_get_device(UCLASS_MISC, 0, &dev); 24499d14b01SJoseph Chen if (ret) { 24599d14b01SJoseph Chen printf("Can't find efuse device\n"); 24699d14b01SJoseph Chen return 0; 24799d14b01SJoseph Chen } 24899d14b01SJoseph Chen 24999d14b01SJoseph Chen ret = misc_read(dev, 0, &fuses, sizeof(fuses)); 25099d14b01SJoseph Chen if (ret) { 25199d14b01SJoseph Chen printf("Efuse read failed\n"); 25299d14b01SJoseph Chen return 0; 25399d14b01SJoseph Chen } 25499d14b01SJoseph Chen 25599d14b01SJoseph Chen printf("Efuse-content:\n"); 25699d14b01SJoseph Chen print_buffer(0, fuses, 1, 128, 16); 25799d14b01SJoseph Chen 25899d14b01SJoseph Chen return 0; 25999d14b01SJoseph Chen } 26099d14b01SJoseph Chen #endif 26199d14b01SJoseph Chen 26299d14b01SJoseph Chen #ifdef CONFIG_ROCKCHIP_OTP 26399d14b01SJoseph Chen static int do_test_otp(cmd_tbl_t *cmdtp, int flag, 26499d14b01SJoseph Chen int argc, char *const argv[]) 26599d14b01SJoseph Chen { 26699d14b01SJoseph Chen struct udevice *dev; 26799d14b01SJoseph Chen u8 otps[64] = {0}; 26899d14b01SJoseph Chen int ret; 26999d14b01SJoseph Chen 27099d14b01SJoseph Chen /* retrieve the device */ 27199d14b01SJoseph Chen ret = uclass_get_device_by_driver(UCLASS_MISC, 0, &dev); 27299d14b01SJoseph Chen if (ret) { 27399d14b01SJoseph Chen printf("Can't find otp device\n"); 27499d14b01SJoseph Chen return 0; 27599d14b01SJoseph Chen } 27699d14b01SJoseph Chen 27799d14b01SJoseph Chen ret = misc_read(dev, 0, &otps, sizeof(otps)); 27899d14b01SJoseph Chen if (ret) { 27999d14b01SJoseph Chen printf("OTP read failed\n"); 28099d14b01SJoseph Chen return 0; 28199d14b01SJoseph Chen } 28299d14b01SJoseph Chen 28399d14b01SJoseph Chen printf("Otp-content:\n"); 28499d14b01SJoseph Chen print_buffer(0, otps, 1, 64, 16); 28599d14b01SJoseph Chen 28699d14b01SJoseph Chen return 0; 28799d14b01SJoseph Chen } 28899d14b01SJoseph Chen #endif 28999d14b01SJoseph Chen 29099d14b01SJoseph Chen #ifdef CONFIG_PARTITIONS 29199d14b01SJoseph Chen static int do_test_part(cmd_tbl_t *cmdtp, int flag, 29299d14b01SJoseph Chen int argc, char *const argv[]) 29399d14b01SJoseph Chen { 29499d14b01SJoseph Chen return run_command("part list ${devtype} ${devnum}", 0); 29599d14b01SJoseph Chen } 29699d14b01SJoseph Chen #endif 29799d14b01SJoseph Chen 29899d14b01SJoseph Chen static cmd_tbl_t sub_cmd[] = { 29999d14b01SJoseph Chen #ifdef CONFIG_BLK 30099d14b01SJoseph Chen UNIT_CMD_DEFINE(blk, 0), 30199d14b01SJoseph Chen #endif 30299d14b01SJoseph Chen #ifdef CONFIG_MMC 30399d14b01SJoseph Chen UNIT_CMD_DEFINE(emmc, 0), 30499d14b01SJoseph Chen #endif 30599d14b01SJoseph Chen #ifdef CONFIG_ROCKCHIP_EFUSE 30699d14b01SJoseph Chen UNIT_CMD_DEFINE(efuse, 0), 30799d14b01SJoseph Chen #endif 30899d14b01SJoseph Chen #if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE) && \ 30999d14b01SJoseph Chen !defined(CONFIG_SPL_BUILD) 31099d14b01SJoseph Chen UNIT_CMD_DEFINE(env, 0), 31199d14b01SJoseph Chen #endif 31299d14b01SJoseph Chen #ifdef CONFIG_ROCKCHIP_OTP 31399d14b01SJoseph Chen UNIT_CMD_DEFINE(otp, 0), 31499d14b01SJoseph Chen #endif 31599d14b01SJoseph Chen #ifdef CONFIG_RKNAND 31699d14b01SJoseph Chen UNIT_CMD_DEFINE(rknand, 0), 31799d14b01SJoseph Chen #endif 31899d14b01SJoseph Chen #if defined(CONFIG_OPTEE_CLIENT) && defined(CONFIG_MMC) 31999d14b01SJoseph Chen UNIT_CMD_DEFINE(secure_storage, 0), 32099d14b01SJoseph Chen #endif 32199d14b01SJoseph Chen #ifdef CONFIG_PARTITIONS 32299d14b01SJoseph Chen UNIT_CMD_DEFINE(part, 0), 32399d14b01SJoseph Chen #endif 32499d14b01SJoseph Chen #ifdef CONFIG_MMC 32599d14b01SJoseph Chen UNIT_CMD_DEFINE(sdmmc, 0), 32699d14b01SJoseph Chen #endif 32799d14b01SJoseph Chen #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION 32899d14b01SJoseph Chen UNIT_CMD_DEFINE(vendor, 0), 32999d14b01SJoseph Chen #endif 33099d14b01SJoseph Chen }; 33199d14b01SJoseph Chen 33299d14b01SJoseph Chen static char sub_cmd_help[] = 33399d14b01SJoseph Chen #ifdef CONFIG_BLK 33499d14b01SJoseph Chen " [.] rktest blk - test blk layer read/write\n" 33599d14b01SJoseph Chen #endif 33699d14b01SJoseph Chen #ifdef CONFIG_MMC 337*474718ffSJoseph Chen " [.] rktest emmc - test emmc read/write speed\n" 33899d14b01SJoseph Chen " [.] rktest sdmmc - test sd card and fat fs read/write\n" 33999d14b01SJoseph Chen #endif 34099d14b01SJoseph Chen #ifdef CONFIG_RKNAND 341*474718ffSJoseph Chen " [.] rktest rknand - test rknand read/write speed\n" 34299d14b01SJoseph Chen #endif 34399d14b01SJoseph Chen #if defined(CONFIG_OPTEE_CLIENT) && defined(CONFIG_MMC) 34499d14b01SJoseph Chen " [.] rktest secure_storage - test secure storage\n" 34599d14b01SJoseph Chen #endif 34699d14b01SJoseph Chen #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION 34799d14b01SJoseph Chen " [.] rktest vendor - test vendor storage read/write\n" 34899d14b01SJoseph Chen #endif 34999d14b01SJoseph Chen #ifdef CONFIG_ROCKCHIP_EFUSE 35099d14b01SJoseph Chen " [.] rktest efuse - test efuse, dump content\n" 35199d14b01SJoseph Chen #endif 35299d14b01SJoseph Chen #ifdef CONFIG_ROCKCHIP_OTP 35399d14b01SJoseph Chen " [.] rktest otp - test otp, dump content\n" 35499d14b01SJoseph Chen #endif 35599d14b01SJoseph Chen #if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE) && \ 35699d14b01SJoseph Chen !defined(CONFIG_SPL_BUILD) 35799d14b01SJoseph Chen " [.] rktest env - test save env to storage\n" 35899d14b01SJoseph Chen #endif 35999d14b01SJoseph Chen #ifdef CONFIG_PARTITIONS 36099d14b01SJoseph Chen " [.] rktest part - test part list\n" 36199d14b01SJoseph Chen #endif 36299d14b01SJoseph Chen ; 36399d14b01SJoseph Chen 36499d14b01SJoseph Chen const struct cmd_group cmd_grp_storage = { 36599d14b01SJoseph Chen .id = TEST_ID_STORAGE, 36699d14b01SJoseph Chen .help = sub_cmd_help, 36799d14b01SJoseph Chen .cmd = sub_cmd, 36899d14b01SJoseph Chen .cmd_n = ARRAY_SIZE(sub_cmd), 36999d14b01SJoseph Chen }; 370