From patchwork Mon Dec 31 11:13:48 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jagan Teki X-Patchwork-Id: 208839 X-Patchwork-Delegate: jagannadh.teki@gmail.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 C92BC2C00A7 for ; Mon, 31 Dec 2012 22:17:24 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id DE8954A167; Mon, 31 Dec 2012 12:17:21 +0100 (CET) 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 gP+8Tk-hNm9y; Mon, 31 Dec 2012 12:17:21 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id A4A7E4A187; Mon, 31 Dec 2012 12:15:54 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id B53C04A01E for ; Mon, 31 Dec 2012 12:15:18 +0100 (CET) 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 U8iRN03103Tg for ; Mon, 31 Dec 2012 12:15:15 +0100 (CET) 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-da0-f53.google.com (mail-da0-f53.google.com [209.85.210.53]) by theia.denx.de (Postfix) with ESMTPS id 6F4244A02E for ; Mon, 31 Dec 2012 12:14:29 +0100 (CET) Received: by mail-da0-f53.google.com with SMTP id x6so5698622dac.12 for ; Mon, 31 Dec 2012 03:14:28 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; bh=N+8zvUv4dNgRW7mnzT7AurksdddJoZulAdjQ0e/Q2NE=; b=KtpkPpvEvDXCA/73jmmValQszteuq3ImUE59KsT+IJ7F9boYTZ/pRM+N7dlvcEudDj 9c1V5aZl2i/pps1+Sjd1pqcbvFfWV7VzBSTDlNwmN1+tiGpdRh0wsFTagzQ7KWwLZxDj gk0LTarFZbZ4YXq68YWxNJL55nTZtpV2+57pPYPN8eLT+lBh5zaxS0WLE7GDehPFH7IN wxFl5uGqghgzgbvaZAYpgN6nbAdybwiOi+JxlHCHw0WXZRr4U2Fp0okGFirofVnm+gQM ybSzUa5eriHcwQewHdAVcISzbCL/ZExQHaiNxE7m9MeRfi1Eu64/4qLgM/fllMVf/dp9 r3Pw== X-Received: by 10.66.87.133 with SMTP id ay5mr120002017pab.59.1356952468117; Mon, 31 Dec 2012 03:14:28 -0800 (PST) Received: from localhost.localdomain ([49.204.11.250]) by mx.google.com with ESMTPS id nw9sm24715215pbb.42.2012.12.31.03.14.26 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 31 Dec 2012 03:14:27 -0800 (PST) From: Jagannadha Sutradharudu Teki To: u-boot@lists.denx.de Date: Mon, 31 Dec 2012 16:43:48 +0530 Message-Id: <1356952428-19824-10-git-send-email-jagannadh.teki@gmail.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1356952428-19824-1-git-send-email-jagannadh.teki@gmail.com> References: <1356952428-19824-1-git-send-email-jagannadh.teki@gmail.com> Subject: [U-Boot] [PATCH 09/12] cmd_sf: Add QOFR(Quad Output Fast Read) read instruction support 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 This patch provides a support to read a flash using 'qofr' read instruction(rd_inst) for 'sf read' and 'sf update' commands. 'qofr' will effectively increases the data transfer rate by up to four times, as compared to the afr(Array Fast Read). Example: read 0x2000 length bytes starting at offset 0x0 to memory at 0x10000 using qofr read instruction. u-boot> sf read qofr 0x10000 0x0 0x2000 erase and write 0x2000 length bytes from memory at 0x10000 address to flash offset at 0x0 using pp write instruction and qofr read instruction. u-boot> sf update pp qofr 0x10000 0x0 0x2000 Signed-off-by: Jagannadha Sutradharudu Teki --- common/cmd_sf.c | 43 ++++++++++++++++++++++------------ drivers/mtd/spi/spi_flash.c | 18 +++++++++++--- drivers/mtd/spi/spi_flash_internal.h | 6 ++-- include/spi_flash.h | 7 +++-- include/spi_flash_inst.h | 1 + 5 files changed, 50 insertions(+), 25 deletions(-) diff --git a/common/cmd_sf.c b/common/cmd_sf.c index b971d2a..a07effd 100644 --- a/common/cmd_sf.c +++ b/common/cmd_sf.c @@ -144,6 +144,7 @@ static int do_spi_flash_probe(int argc, char * const argv[]) * @param wr_inst write instruction * @param rd_inst read instruction * @param wr_qeb_req quad enable bit is required for this write operation? + * @param rd_qeb_req quad enable bit is required for this read operation? * @param offset flash offset to write * @param len number of bytes to write * @param buf buffer to write from @@ -152,12 +153,12 @@ static int do_spi_flash_probe(int argc, char * const argv[]) * @return NULL if OK, else a string containing the stage which failed */ static const char *spi_flash_update_block(struct spi_flash *flash, u8 wr_inst, - u8 rd_inst, u8 wr_qeb_req, u32 offset, size_t len, - const char *buf, char *cmp_buf, size_t *skipped) + u8 rd_inst, u8 wr_qeb_req, u8 rd_qeb_req, u32 offset, + size_t len, const char *buf, char *cmp_buf, size_t *skipped) { debug("offset=%#x, sector_size=%#x, len=%#zx\n", offset, flash->sector_size, len); - if (spi_flash_read(flash, rd_inst, offset, len, cmp_buf)) + if (spi_flash_read(flash, rd_inst, rd_qeb_req, offset, len, cmp_buf)) return "read"; if (memcmp(cmp_buf, buf, len) == 0) { debug("Skip region %x size %zx: no change\n", @@ -180,13 +181,15 @@ static const char *spi_flash_update_block(struct spi_flash *flash, u8 wr_inst, * @param wr_inst write instruction * @param rd_inst read instruction * @param wr_qeb_req quad enable bit is required for this write operation? + * @param rd_qeb_req quad enable bit is required for this read operation? * @param offset flash offset to write * @param len number of bytes to write * @param buf buffer to write from * @return 0 if ok, 1 on error */ static int spi_flash_update(struct spi_flash *flash, u8 wr_inst, u8 rd_inst, - u8 wr_qeb_req, u32 offset, size_t len, const char *buf) + u8 wr_qeb_req, u8 rd_qeb_req, u32 offset, + size_t len, const char *buf) { const char *err_oper = NULL; char *cmp_buf; @@ -214,7 +217,7 @@ static int spi_flash_update(struct spi_flash *flash, u8 wr_inst, u8 rd_inst, last_update = get_timer(0); } err_oper = spi_flash_update_block(flash, wr_inst, - rd_inst, wr_qeb_req, + rd_inst, wr_qeb_req, rd_qeb_req, offset, todo, buf, cmp_buf, &skipped); } @@ -271,19 +274,26 @@ static int sf_parse_wr_inst_arg(char *arg, u8 *wr_inst, u8 *wr_qeb_req) * arg: specified read instruction from user * Output: * rd_inst: parsed read instruction for write operation + * rd_qeb_req: assign to 1 if this instruction require quad enable bit + * need to set prior to actual read operation * Return: * 1: for Unknown rd_inst from user * 0: Success */ -static int sf_parse_rd_inst_arg(char *arg, u8 *rd_inst) +static int sf_parse_rd_inst_arg(char *arg, u8 *rd_inst, u8 *rd_qeb_req) { + *rd_qeb_req = 0; + if (strcmp(arg, "afr") == 0) *rd_inst = CMD_READ_ARRAY_FAST; else if (strcmp(arg, "asr") == 0) *rd_inst = CMD_READ_ARRAY_SLOW; else if (strcmp(arg, "dofr") == 0) *rd_inst = CMD_READ_DUAL_OUTPUT_FAST; - else + else if (strcmp(arg, "qofr") == 0) { + *rd_inst = CMD_READ_QUAD_OUTPUT_FAST; + *rd_qeb_req = 1; + } else return 1; return 0; @@ -297,7 +307,7 @@ static int do_spi_flash_read_write(int argc, char * const argv[]) void *buf; char *endp; u8 wr_inst, rd_inst; - u8 wr_qeb_req; + u8 wr_qeb_req, rd_qeb_req; int update_rd_inst; int ret; @@ -344,7 +354,7 @@ static int do_spi_flash_read_write(int argc, char * const argv[]) return ret; } - ret = sf_parse_rd_inst_arg(argv[2], &rd_inst); + ret = sf_parse_rd_inst_arg(argv[2], &rd_inst, &rd_qeb_req); if (ret) { printf("SF: Unknown %s rd_inst on 'sf update'\n", argv[2]); @@ -352,16 +362,17 @@ static int do_spi_flash_read_write(int argc, char * const argv[]) } ret = spi_flash_update(flash, wr_inst, rd_inst, - wr_qeb_req, offset, len, buf); + wr_qeb_req, rd_qeb_req, offset, len, buf); } else if (strcmp(argv[0], "read") == 0) { - ret = sf_parse_rd_inst_arg(argv[1], &rd_inst); + ret = sf_parse_rd_inst_arg(argv[1], &rd_inst, &rd_qeb_req); if (ret) { printf("SF: Unknown %s rd_inst on 'sf read'\n", argv[1]); return ret; } - ret = spi_flash_read(flash, rd_inst, offset, len, buf); + ret = spi_flash_read(flash, rd_inst, rd_qeb_req, + offset, len, buf); } else { ret = sf_parse_wr_inst_arg(argv[1], &wr_inst, &wr_qeb_req); if (ret) { @@ -632,10 +643,11 @@ U_BOOT_CMD( "sf read rd_inst addr offset len\n" " - read `len' bytes starting at\n" " `offset' to memory at `addr' using\n" - " afr | asr | dofr `rd_inst' read instructions\n" + " afr | asr | dofr | qofr `rd_inst' read instructions\n" " afr (Array Fast Read, 0bh)\n" " asr (Array Slow Read, 02b)\n" " dofr (Dual Output Fast Read, 3bh)\n" + " qofr (Quad Output Fast Read, 6bh)\n" "sf write wr_inst addr offset len\n" " - write `len' bytes from memory\n" " at `addr' to flash at `offset' using\n" @@ -650,9 +662,10 @@ U_BOOT_CMD( " pp | qpp `wr_inst' write instructions and\n" " pp (Page Program, 02h)\n" " qpp (Quad Page Program, 32h)\n" - " afr | asr | dofr `rd_inst' read instructions\n" + " afr | asr | dofr | qofr `rd_inst' read instructions\n" " afr (Array Fast Read, 0bh)\n" " asr (Array Slow Read, 02b)\n" - " dofr (Dual Output Fast Read, 3bh)" + " dofr (Dual Output Fast Read, 3bh)\n" + " qofr (Quad Output Fast Read, 6bh)" SF_TEST_HELP ); diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 3d57863..15ad05c 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -130,21 +130,30 @@ int spi_flash_cmd_write_multi(struct spi_flash *flash, u8 wr_inst, return ret; } -int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, +int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, u8 rd_qeb_req, size_t cmd_len, void *data, size_t data_len) { struct spi_slave *spi = flash->spi; int ret; spi_claim_bus(spi); + + if (rd_qeb_req) { + ret = spi_flash_set_quad_enable_bit(flash); + if (ret) { + debug("SF: set quad enable bit failed\n"); + return ret; + } + } + ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); spi_release_bus(spi); return ret; } -int spi_flash_cmd_read_fast(struct spi_flash *flash, u8 rd_inst, u32 offset, - size_t len, void *data) +int spi_flash_cmd_read_fast(struct spi_flash *flash, u8 rd_inst, + u8 rd_qeb_req, u32 offset, size_t len, void *data) { u8 cmd[5]; @@ -152,7 +161,8 @@ int spi_flash_cmd_read_fast(struct spi_flash *flash, u8 rd_inst, u32 offset, spi_flash_addr(offset, cmd); cmd[4] = 0x00; - return spi_flash_read_common(flash, cmd, sizeof(cmd), data, len); + return spi_flash_read_common(flash, cmd, rd_qeb_req, + sizeof(cmd), data, len); } int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h index e36f216..feefdee 100644 --- a/drivers/mtd/spi/spi_flash_internal.h +++ b/drivers/mtd/spi/spi_flash_internal.h @@ -43,8 +43,8 @@ int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len); int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, void *data, size_t data_len); -int spi_flash_cmd_read_fast(struct spi_flash *flash, u8 rd_inst, u32 offset, - size_t len, void *data); +int spi_flash_cmd_read_fast(struct spi_flash *flash, u8 rd_inst, u8 rd_qeb_req, + u32 offset, size_t len, void *data); /* * Send a multi-byte command to the device followed by (optional) @@ -96,7 +96,7 @@ int spi_flash_set_quad_enable_bit(struct spi_flash *flash); * bus. Used as common part of the ->read() operation. */ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, - size_t cmd_len, void *data, size_t data_len); + u8 rd_qeb_req, size_t cmd_len, void *data, size_t data_len); /* Send a command to the device and wait for some bit to clear itself. */ int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, diff --git a/include/spi_flash.h b/include/spi_flash.h index 31e7d9e..d3e6ca5 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -40,7 +40,8 @@ struct spi_flash { u32 sector_size; int (*read)(struct spi_flash *flash, u8 rd_inst, - u32 offset, size_t len, void *buf); + u8 rd_qeb_req, u32 offset, size_t len, + void *buf); int (*write)(struct spi_flash *flash, u8 wr_inst, u8 wr_qeb_req, u32 offset, size_t len, const void *buf); @@ -53,9 +54,9 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, void spi_flash_free(struct spi_flash *flash); static inline int spi_flash_read(struct spi_flash *flash, u8 rd_inst, - u32 offset, size_t len, void *buf) + u8 rd_qeb_req, u32 offset, size_t len, void *buf) { - return flash->read(flash, rd_inst, offset, len, buf); + return flash->read(flash, rd_inst, rd_qeb_req, offset, len, buf); } static inline int spi_flash_write(struct spi_flash *flash, u8 wr_inst, diff --git a/include/spi_flash_inst.h b/include/spi_flash_inst.h index f8fcf5e..67b22c8 100644 --- a/include/spi_flash_inst.h +++ b/include/spi_flash_inst.h @@ -32,5 +32,6 @@ #define CMD_READ_ARRAY_FAST 0x0b #define CMD_READ_ARRAY_SLOW 0x03 #define CMD_READ_DUAL_OUTPUT_FAST 0x3b +#define CMD_READ_QUAD_OUTPUT_FAST 0x6b #endif /* _SPI_FLASH_INST_H_ */