From patchwork Mon Oct 8 23:16:02 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 190164 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 84E262C0094 for ; Tue, 9 Oct 2012 10:16:23 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 1320028184; Tue, 9 Oct 2012 01:16:20 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 0WhCEkkJBQUb; Tue, 9 Oct 2012 01:16:19 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id E715428185; Tue, 9 Oct 2012 01:16:17 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 764F328185 for ; Tue, 9 Oct 2012 01:16:15 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id rkx24DFxTFga for ; Tue, 9 Oct 2012 01:16:13 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-vc0-f202.google.com (mail-vc0-f202.google.com [209.85.220.202]) by theia.denx.de (Postfix) with ESMTPS id 3C9AF28184 for ; Tue, 9 Oct 2012 01:16:11 +0200 (CEST) Received: by mail-vc0-f202.google.com with SMTP id fy27so535229vcb.3 for ; Mon, 08 Oct 2012 16:16:10 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:x-gm-message-state; bh=FJWMEv2GSCwefFn8++joGqp54uOoPFTtprRjsKLT62Q=; b=kaZWjaaPb0zu43ys1FAHh1MvL0tuI16jdocrzbAMbED9FLlb769CC4PH8KPUgA4ASL 1JCFadpw2nQSmi642U+gM6/kHMgJNht3kl3kpOkv6ItJCvmRXjxMInz59uqSAkJmA3UD KsR7xA3kvKHu8gTlzE7KEm0VorbJ+SpL/RjgmA/XcTO46R3pCFV6BqTetZgo+ja0fMqM aVz7MpWtYLrvkqZLN6DxeH/C90eZs5Q9EfLb8tK5ct3AQ/uhqWnprJMf4yn+YIqg1c0e nPUlXa7ioQ+OljHN297s7sq/FGfi+jXvzZwttECbdQ3UXO1KYuO7tBJvdBSwsAEKg/uW MQHQ== Received: by 10.236.123.43 with SMTP id u31mr9853210yhh.43.1349738169966; Mon, 08 Oct 2012 16:16:09 -0700 (PDT) Received: from wpzn3.hot.corp.google.com (216-239-44-65.google.com [216.239.44.65]) by gmr-mx.google.com with ESMTPS id i27si4454965yhe.4.2012.10.08.16.16.09 (version=TLSv1/SSLv3 cipher=AES128-SHA); Mon, 08 Oct 2012 16:16:09 -0700 (PDT) Received: from kaka.mtv.corp.google.com (kaka.mtv.corp.google.com [172.22.73.79]) by wpzn3.hot.corp.google.com (Postfix) with ESMTP id B6659100047; Mon, 8 Oct 2012 16:16:09 -0700 (PDT) Received: by kaka.mtv.corp.google.com (Postfix, from userid 121222) id 5BE27160D02; Mon, 8 Oct 2012 16:16:09 -0700 (PDT) From: Simon Glass To: U-Boot Mailing List Date: Mon, 8 Oct 2012 16:16:02 -0700 Message-Id: <1349738163-18983-2-git-send-email-sjg@chromium.org> X-Mailer: git-send-email 1.7.7.3 X-Gm-Message-State: ALoCoQlPglLsZ4wSmRYdRjoxGmUB7K4Clw7QMwglOJD8AwLWSDI7q92P7+lCZUlrT0mq/JD1j+2qu90uOl/w6n1hnlhb05mM1jCCSzqSbkhDMiFmigSFdllbYgkgz8jBjc+K7XOrcamhH/cEhYPUpdpqx2X1LaYQbS+CspCbmggU4fcba3QPUUiNcWTQUOPMDPbJJP3Cf93a Cc: Tom Rini Subject: [U-Boot] [PATCH v2 2/2] spi: Add SPI flash test X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de It is useful to have a basic SPI flash test, which tests that the SPI chip, the SPI bus and the driver are behaving. This test erases part of the flash, writes data and reads it back as a sanity check that all is well. Use CONFIG_SF_TEST to enable it. Signed-off-by: Simon Glass --- Changes in v2: - Add arguments to 'sf test' (may as well do this TODO now) README | 5 ++ common/cmd_sf.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+), 0 deletions(-) diff --git a/README b/README index 0d17e7d..193986e 100644 --- a/README +++ b/README @@ -2315,6 +2315,11 @@ The following options need to be configured: CONFIG_SF_DEFAULT_MODE (see include/spi.h) CONFIG_SF_DEFAULT_SPEED in Hz + CONFIG_CMD_SF_TEST + + Define this option to include a destructive SPI flash + test ('sf test'). + - SystemACE Support: CONFIG_SYSTEMACE diff --git a/common/cmd_sf.c b/common/cmd_sf.c index e22a45e..269afcc 100644 --- a/common/cmd_sf.c +++ b/common/cmd_sf.c @@ -5,6 +5,7 @@ * Licensed under the GPL-2 or later. */ +#include #include #include #include @@ -312,6 +313,161 @@ static int do_spi_flash_erase(int argc, char * const argv[]) return 0; } +#ifdef CONFIG_CMD_SF_TEST +enum { + STAGE_ERASE, + STAGE_CHECK, + STAGE_WRITE, + STAGE_READ, + + STAGE_COUNT, +}; + +static char *stage_name[STAGE_COUNT] = { + "erase", + "check", + "write", + "read", +}; + +struct test_info { + int stage; + int bytes; + unsigned base_ms; + unsigned time_ms[STAGE_COUNT]; +}; + +static void show_time(struct test_info *test, int stage) +{ + uint64_t speed; /* KiB/s */ + int bps; /* Bits per second */ + + speed = (long long)test->bytes * 1000; + do_div(speed, test->time_ms[stage] * 1024); + bps = speed * 8; + + printf("%d %s: %d ticks, %d KiB/s %d.%03d Mbps\n", stage, + stage_name[stage], test->time_ms[stage], + (int)speed, bps / 1000, bps % 1000); +} + +static void spi_test_next_stage(struct test_info *test) +{ + test->time_ms[test->stage] = get_timer(test->base_ms); + show_time(test, test->stage); + test->base_ms = get_timer(0); + test->stage++; +} + +/** + * Run a test on the SPI flash + * + * @param flash SPI flash to use + * @param buf Source buffer for data to write + * @param len Size of data to read/write + * @param offset Offset within flash to check + * @param vbuf Verification buffer + * @return 0 if ok, -1 on error + */ +static int spi_flash_test(struct spi_flash *flash, char *buf, ulong len, + ulong offset, char *vbuf) +{ + struct test_info test; + int i; + + printf("SPI flash test:\n"); + memset(&test, '\0', sizeof(test)); + test.base_ms = get_timer(0); + test.bytes = len; + if (spi_flash_erase(flash, offset, len)) { + printf("Erase failed\n"); + return -1; + } + spi_test_next_stage(&test); + + if (spi_flash_read(flash, offset, len, vbuf)) { + printf("Check read failed\n"); + return -1; + } + for (i = 0; i < len; i++) { + if (vbuf[i] != 0xff) { + printf("Check failed at %d\n", i); + print_buffer(i, vbuf + i, 1, min(len - i, 0x40), 0); + return -1; + } + } + spi_test_next_stage(&test); + + if (spi_flash_write(flash, offset, len, buf)) { + printf("Write failed\n"); + return -1; + } + memset(vbuf, '\0', len); + spi_test_next_stage(&test); + + if (spi_flash_read(flash, offset, len, vbuf)) { + printf("Read failed\n"); + return -1; + } + spi_test_next_stage(&test); + + for (i = 0; i < len; i++) { + if (buf[i] != vbuf[i]) { + printf("Verify failed at %d, good data:\n", i); + print_buffer(i, buf + i, 1, min(len - i, 0x40), 0); + printf("Bad data:\n"); + print_buffer(i, vbuf + i, 1, min(len - i, 0x40), 0); + return -1; + } + } + printf("Test passed\n"); + for (i = 0; i < STAGE_COUNT; i++) + show_time(&test, i); + + return 0; +} + +static int do_spi_flash_test(int argc, char * const argv[]) +{ + unsigned long offset; + unsigned long len; + char *buf = (char *)CONFIG_SYS_TEXT_BASE; + char *endp; + char *vbuf; + int ret; + + offset = simple_strtoul(argv[1], &endp, 16); + if (*argv[1] == 0 || *endp != 0) + return -1; + len = simple_strtoul(argv[2], &endp, 16); + if (*argv[2] == 0 || *endp != 0) + return -1; + + vbuf = malloc(len); + if (!vbuf) { + printf("Cannot allocate memory\n"); + return 1; + } + buf = malloc(len); + if (!buf) { + free(vbuf); + printf("Cannot allocate memory\n"); + return 1; + } + + memcpy(buf, (char *)CONFIG_SYS_TEXT_BASE, len); + ret = spi_flash_test(flash, buf, len, offset, vbuf); + free(vbuf); + free(buf); + if (ret) { + printf("Test failed\n"); + return 1; + } + + return 0; +} +#endif /* CONFIG_CMD_SF_TEST */ + static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { const char *cmd; @@ -341,6 +497,10 @@ static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[ ret = do_spi_flash_read_write(argc, argv); else if (strcmp(cmd, "erase") == 0) ret = do_spi_flash_erase(argc, argv); +#ifdef CONFIG_CMD_SF_TEST + else if (!strcmp(cmd, "test")) + ret = do_spi_flash_test(argc, argv); +#endif else ret = -1; @@ -352,6 +512,13 @@ usage: return CMD_RET_USAGE; } +#ifdef CONFIG_CMD_SF_TEST +#define SF_TEST_HELP "\nsf test offset len " \ + "- run a very basic destructive test" +#else +#define SF_TEST_HELP +#endif + U_BOOT_CMD( sf, 5, 1, do_spi_flash, "SPI flash sub-system", @@ -365,4 +532,5 @@ U_BOOT_CMD( " `+len' round up `len' to block size\n" "sf update addr offset len - erase and write `len' bytes from memory\n" " at `addr' to flash at `offset'" + SF_TEST_HELP );