From patchwork Thu Dec 4 10:21:42 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lee Jones X-Patchwork-Id: 41925 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-wi0-f197.google.com (mail-wi0-f197.google.com [209.85.212.197]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id F1EEA25E8C for ; Thu, 4 Dec 2014 10:25:08 +0000 (UTC) Received: by mail-wi0-f197.google.com with SMTP id l15sf10865568wiw.4 for ; Thu, 04 Dec 2014 02:25:08 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:subject:date:message-id :in-reply-to:references:cc:precedence:list-id:list-unsubscribe :list-archive:list-post:list-help:list-subscribe:mime-version :content-type:content-transfer-encoding:sender:errors-to :x-original-sender:x-original-authentication-results:mailing-list; bh=qtce0BTtPq0yaUZceEXP6vLf69DKBmuWrbH9joqm8Ww=; b=F88MV/6sy1DKrh+q3JWnCh8KrcUxlVg8PqCQZOq6gdjockTn80Q3NzY0dlyzuy5Tgs fgaoCY7y2MAWmCwZG6oevdaJF50sY74jm58I5/2UzMpDKoNR/4RFAUvL2gSuUfzMe1tf XOc3Np2woCrTHq8ASK44cQvM4msLD/a0lJTliRWRO5brWowb8pfhmksbWC7JezPdauA0 XO0BAgk2TDTxSNmJAhUCaypkgLHaIRoClTUI5AXvkNUL5QB8uFxJq6VX8a5UbEs+toWE etwEGWJYfzelcUl739QKKVQf4VcRRf8J49y0G4fuj16VIw6YAfRwYAdqVrgZjCfd4oO9 s0/w== X-Gm-Message-State: ALoCoQnTzuOJeN1hNYKp3xojgqZEjUD3TKo7TihoYvqH5nCuQmiySly/LYxqgY5t/OzlBYeMu5PE X-Received: by 10.112.188.199 with SMTP id gc7mr2084782lbc.6.1417688708207; Thu, 04 Dec 2014 02:25:08 -0800 (PST) X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.206.102 with SMTP id ln6ls241521lac.95.gmail; Thu, 04 Dec 2014 02:25:08 -0800 (PST) X-Received: by 10.112.139.196 with SMTP id ra4mr8648677lbb.95.1417688707977; Thu, 04 Dec 2014 02:25:07 -0800 (PST) Received: from mail-la0-f50.google.com (mail-la0-f50.google.com. [209.85.215.50]) by mx.google.com with ESMTPS id h7si25413664lae.93.2014.12.04.02.25.07 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 04 Dec 2014 02:25:07 -0800 (PST) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.50 as permitted sender) client-ip=209.85.215.50; Received: by mail-la0-f50.google.com with SMTP id pn19so13471090lab.9 for ; Thu, 04 Dec 2014 02:25:07 -0800 (PST) X-Received: by 10.152.3.67 with SMTP id a3mr8654854laa.56.1417688707844; Thu, 04 Dec 2014 02:25:07 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.112.184.201 with SMTP id ew9csp10421lbc; Thu, 4 Dec 2014 02:25:06 -0800 (PST) X-Received: by 10.68.132.225 with SMTP id ox1mr24170562pbb.85.1417688705820; Thu, 04 Dec 2014 02:25:05 -0800 (PST) Received: from bombadil.infradead.org (bombadil.infradead.org. [2001:1868:205::9]) by mx.google.com with ESMTPS id xd4si13639507pbb.102.2014.12.04.02.25.05 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 04 Dec 2014 02:25:05 -0800 (PST) Received-SPF: none (google.com: linux-mtd-bounces+patch=linaro.org@lists.infradead.org does not designate permitted sender hosts) client-ip=2001:1868:205::9; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1XwTZ3-0004fk-Jk; Thu, 04 Dec 2014 10:23:13 +0000 Received: from mail-yh0-f50.google.com ([209.85.213.50]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1XwTYI-0003vo-IM for linux-mtd@lists.infradead.org; Thu, 04 Dec 2014 10:22:28 +0000 Received: by mail-yh0-f50.google.com with SMTP id 29so8672857yhl.37 for ; Thu, 04 Dec 2014 02:22:04 -0800 (PST) X-Received: by 10.170.95.7 with SMTP id m7mr13201342yka.67.1417688524308; Thu, 04 Dec 2014 02:22:04 -0800 (PST) Received: from localhost.localdomain (host109-148-232-11.range109-148.btcentralplus.com. [109.148.232.11]) by mx.google.com with ESMTPSA id y67sm16089929yhc.11.2014.12.04.02.22.01 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 04 Dec 2014 02:22:03 -0800 (PST) From: Lee Jones To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 RESEND 01/11] mtd: st_spi_fsm: Extend fsm_clear_fifo to handle unwanted bytes Date: Thu, 4 Dec 2014 10:21:42 +0000 Message-Id: <1417688512-7644-2-git-send-email-lee.jones@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1417688512-7644-1-git-send-email-lee.jones@linaro.org> References: <1417688512-7644-1-git-send-email-lee.jones@linaro.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20141204_022226_827124_B76FEE01 X-CRM114-Status: GOOD ( 25.25 ) X-Spam-Score: -0.7 (/) X-Spam-Report: SpamAssassin version 3.4.0 on bombadil.infradead.org summary: Content analysis details: (-0.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [209.85.213.50 listed in list.dnswl.org] -0.0 RCVD_IN_MSPIKE_H3 RBL: Good reputation (+3) [209.85.213.50 listed in wl.mailspike.net] -0.0 SPF_PASS SPF: sender matches SPF record -0.0 RCVD_IN_MSPIKE_WL Mailspike good senders Cc: linux-mtd@lists.infradead.org, computersforpeace@gmail.com, lee.jones@linaro.org, kernel@stlinux.com, Angus Clark X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: , List-Help: , List-Subscribe: , MIME-Version: 1.0 Sender: "linux-mtd" Errors-To: linux-mtd-bounces+patch=linaro.org@lists.infradead.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: lee.jones@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.50 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 Under certain conditions, the SPI-FSM Controller can be left in a state where the data FIFO is not entirely empty. This can lead to problems where subsequent data transfers appear to have been shifted by a number of unidentified bytes. One simple example would be an errant FSM sequence which loaded more data to the FIFO than was read by the host. Another more interesting case results from an obscure artefact in the FSM Controller. When switching from data transfers in x4 or x2 mode to data transfers in x1 mode, extraneous bytes will appear in the FIFO, unless the previous data transfer was a multiple of 32 cycles (i.e. 8 bytes for x2, and 16 bytes for x4). This applies equally whether FSM is being operated directly by a S/W driver, or by the SPI boot-controller in FSM-Boot mode. Furthermore, data in the FIFO not only survive a transition between FSM-Boot and FSM, but also a S/W reset of IP block [1]. By taking certain precautions, it is possible to prevent the driver from causing this type of problem (e.g. ensuring that the host and programmed sequence agree on the transfer size, and restricting transfer sizes to multiples of 32-cycles [2]). However, at the point the driver is loaded, no assumptions can be made regarding the state of the FIFO. Even if previous S/W drivers have behaved correctly, it is impossible to control the number of transactions serviced by the controller operating in FSM-Boot. To address this problem, we ensure the FIFO is cleared during initialisation, before performing any FSM operations. Previously, the fsm_clear_fifo() code was capable of detecting and clearing any unwanted 32-bit words from the FIFO. This patch extends the capability to handle an arbitrary number of bytes present in the FIFO [3]. Now that the issue is better understood, we also remove the calls to fsm_clear_fifo() following the fsm_read() and fsm_write() operations. The process of actually clearing the FIFO deserves a mention. While the FIFO may contain any number of bytes, the SPI_FAST_SEQ_STA register only reports the number of complete 32-bit words present. Furthermore, data can only be drained from the FIFO by reading complete 32-bit words. With this in mind, a two stage process is used to the clear the FIFO: 1. Read any complete 32-bit words from the FIFO, as reported by the SPI_FAST_SEQ_STA register. 2. Mop up any remaining bytes. At this point, it is not known if there are 0, 1, 2, or 3 bytes in the FIFO. To handle all cases, a dummy FSM sequence is used to load one byte at a time, until a complete 32-bit word is formed; at most, 4 bytes will need to be loaded. [1] Although this issue has existed since early versions of the SPI-FSM controller, its full extent only emerged recently as a consequence of the targetpacks starting to use FSM-Boot(x4) as the default configuration. [2] The requirement to restrict transfers to multiples of 32 cycles was found empirically back when DUAL and QUAD mode support was added. The current analysis now gives a satisfactory explanation for this requirement. [3] Theoretically, it is possible for the FIFO to contain an arbitrary number of bits. However, since there are no known use-cases that leave incomplete bytes in the FIFO, only words and bytes are considered here. Signed-off-by: Angus Clark Signed-off-by: Lee Jones --- drivers/mtd/devices/st_spi_fsm.c | 95 +++++++++++++++++++++++++++++++++------- 1 file changed, 79 insertions(+), 16 deletions(-) diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c index d252514..6e4d3bfe 100644 --- a/drivers/mtd/devices/st_spi_fsm.c +++ b/drivers/mtd/devices/st_spi_fsm.c @@ -663,6 +663,23 @@ static struct stfsm_seq stfsm_seq_write_status = { SEQ_CFG_STARTSEQ), }; +/* Dummy sequence to read one byte of data from flash into the FIFO */ +static const struct stfsm_seq stfsm_seq_load_fifo_byte = { + .data_size = TRANSFER_SIZE(1), + .seq_opc[0] = (SEQ_OPC_PADS_1 | + SEQ_OPC_CYCLES(8) | + SEQ_OPC_OPCODE(SPINOR_OP_RDID)), + .seq = { + STFSM_INST_CMD1, + STFSM_INST_DATA_READ, + STFSM_INST_STOP, + }, + .seq_cfg = (SEQ_CFG_PADS_1 | + SEQ_CFG_READNOTWRITE | + SEQ_CFG_CSDEASSERT | + SEQ_CFG_STARTSEQ), +}; + static int stfsm_n25q_en_32bit_addr_seq(struct stfsm_seq *seq) { seq->seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | @@ -695,22 +712,6 @@ static inline uint32_t stfsm_fifo_available(struct stfsm *fsm) return (readl(fsm->base + SPI_FAST_SEQ_STA) >> 5) & 0x7f; } -static void stfsm_clear_fifo(struct stfsm *fsm) -{ - uint32_t avail; - - for (;;) { - avail = stfsm_fifo_available(fsm); - if (!avail) - break; - - while (avail) { - readl(fsm->base + SPI_FAST_SEQ_DATA_REG); - avail--; - } - } -} - static inline void stfsm_load_seq(struct stfsm *fsm, const struct stfsm_seq *seq) { @@ -772,6 +773,68 @@ static void stfsm_read_fifo(struct stfsm *fsm, uint32_t *buf, uint32_t size) } } +/* + * Clear the data FIFO + * + * Typically, this is only required during driver initialisation, where no + * assumptions can be made regarding the state of the FIFO. + * + * The process of clearing the FIFO is complicated by fact that while it is + * possible for the FIFO to contain an arbitrary number of bytes [1], the + * SPI_FAST_SEQ_STA register only reports the number of complete 32-bit words + * present. Furthermore, data can only be drained from the FIFO by reading + * complete 32-bit words. + * + * With this in mind, a two stage process is used to the clear the FIFO: + * + * 1. Read any complete 32-bit words from the FIFO, as reported by the + * SPI_FAST_SEQ_STA register. + * + * 2. Mop up any remaining bytes. At this point, it is not known if there + * are 0, 1, 2, or 3 bytes in the FIFO. To handle all cases, a dummy FSM + * sequence is used to load one byte at a time, until a complete 32-bit + * word is formed; at most, 4 bytes will need to be loaded. + * + * [1] It is theoretically possible for the FIFO to contain an arbitrary number + * of bits. However, since there are no known use-cases that leave + * incomplete bytes in the FIFO, only words and bytes are considered here. + */ +static void stfsm_clear_fifo(struct stfsm *fsm) +{ + const struct stfsm_seq *seq = &stfsm_seq_load_fifo_byte; + uint32_t words, i; + + /* 1. Clear any 32-bit words */ + words = stfsm_fifo_available(fsm); + if (words) { + for (i = 0; i < words; i++) + readl(fsm->base + SPI_FAST_SEQ_DATA_REG); + dev_dbg(fsm->dev, "cleared %d words from FIFO\n", words); + } + + /* + * 2. Clear any remaining bytes + * - Load the FIFO, one byte at a time, until a complete 32-bit word + * is available. + */ + for (i = 0, words = 0; i < 4 && !words; i++) { + stfsm_load_seq(fsm, seq); + stfsm_wait_seq(fsm); + words = stfsm_fifo_available(fsm); + } + + /* - A single word must be available now */ + if (words != 1) { + dev_err(fsm->dev, "failed to clear bytes from the data FIFO\n"); + return; + } + + /* - Read the 32-bit word */ + readl(fsm->base + SPI_FAST_SEQ_DATA_REG); + + dev_dbg(fsm->dev, "cleared %d byte(s) from the data FIFO\n", 4 - i); +} + static int stfsm_write_fifo(struct stfsm *fsm, const uint32_t *buf, uint32_t size) {