From patchwork Tue Feb 18 14:55:54 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lee Jones X-Patchwork-Id: 24865 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-ve0-f199.google.com (mail-ve0-f199.google.com [209.85.128.199]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 82F2620676 for ; Tue, 18 Feb 2014 14:58:27 +0000 (UTC) Received: by mail-ve0-f199.google.com with SMTP id oy12sf35626013veb.10 for ; Tue, 18 Feb 2014 06:58:27 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:sender:precedence:list-id :x-original-sender:x-original-authentication-results:mailing-list :list-post:list-help:list-archive:list-unsubscribe; bh=DfPJ2Kdqw85fHNO0W9OZn70X7tTKLbaW8GtF8nO0uBk=; b=ihaga01wLALS9uLtqTdEo5xKtez8L4a6jxeRjQ7kPlHMBLoKwx0gmXO+3314ENeY7i InT+RZ01GMxg+/gsBUAmUZi8UZ7mP+Ok6bjd81ld2h/wNIapkJyz29QkTOaXQmFZOYBX kG91AenX/SeywGtf2sNV76qBcLuXJETJ7k7ctd7JZLIp1AjxC/2FwRdjZIpFBoaTwiv7 BUKKEyQ2XH48wHW+3MqVQwXPzNv7wC+KkyGKaaM6igdAlDVavuVTqKp/3MO7gkuAu6Jy C8BdE+Sq0ifOeErsS/LfUPVEbLR5xmAgSXya4m9O3386W+12S8BcEG7g1+/ld8cGpa8b qtaQ== X-Gm-Message-State: ALoCoQlOwSVfFgmwYScTD+3HctIGmVrUQPRyiPSZggQyaBhVeHO+ISYMJ3iKM2l8oV4iHwa2KV29 X-Received: by 10.236.69.35 with SMTP id m23mr11404046yhd.6.1392735507248; Tue, 18 Feb 2014 06:58:27 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.94.41 with SMTP id f38ls1353067qge.55.gmail; Tue, 18 Feb 2014 06:58:27 -0800 (PST) X-Received: by 10.52.26.106 with SMTP id k10mr125368vdg.85.1392735507002; Tue, 18 Feb 2014 06:58:27 -0800 (PST) Received: from mail-ve0-f171.google.com (mail-ve0-f171.google.com [209.85.128.171]) by mx.google.com with ESMTPS id b20si1364589veu.144.2014.02.18.06.58.26 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 18 Feb 2014 06:58:26 -0800 (PST) Received-SPF: neutral (google.com: 209.85.128.171 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.128.171; Received: by mail-ve0-f171.google.com with SMTP id pa12so13571793veb.16 for ; Tue, 18 Feb 2014 06:58:26 -0800 (PST) X-Received: by 10.220.98.204 with SMTP id r12mr830919vcn.48.1392735506873; Tue, 18 Feb 2014 06:58:26 -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.220.174.196 with SMTP id u4csp222625vcz; Tue, 18 Feb 2014 06:58:26 -0800 (PST) X-Received: by 10.68.185.1 with SMTP id ey1mr33920139pbc.33.1392735505425; Tue, 18 Feb 2014 06:58:25 -0800 (PST) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id zk9si18584091pac.231.2014.02.18.06.58.24; Tue, 18 Feb 2014 06:58:24 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932360AbaBRO5n (ORCPT + 27 others); Tue, 18 Feb 2014 09:57:43 -0500 Received: from mail-we0-f176.google.com ([74.125.82.176]:61999 "EHLO mail-we0-f176.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932342AbaBRO5j (ORCPT ); Tue, 18 Feb 2014 09:57:39 -0500 Received: by mail-we0-f176.google.com with SMTP id q58so11461069wes.7 for ; Tue, 18 Feb 2014 06:57:38 -0800 (PST) X-Received: by 10.180.77.74 with SMTP id q10mr18480538wiw.39.1392735458246; Tue, 18 Feb 2014 06:57:38 -0800 (PST) Received: from localhost.localdomain ([80.76.198.141]) by mx.google.com with ESMTPSA id h13sm46039687wjr.22.2014.02.18.06.57.35 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 18 Feb 2014 06:57:37 -0800 (PST) From: Lee Jones To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Cc: lee.jones@linaro.org, DCG_UPD_stlinux_kernel@list.st.com, dwmw2@infradead.org, linux-mtd@lists.infradead.org, computersforpeace@gmail.com, Angus.Clark@st.com Subject: [PATCH 27/35] mtd: st_spi_fsm: Supply a busy wait for post-write status Date: Tue, 18 Feb 2014 14:55:54 +0000 Message-Id: <1392735362-1245-28-git-send-email-lee.jones@linaro.org> X-Mailer: git-send-email 1.8.3.2 In-Reply-To: <1392735362-1245-1-git-send-email-lee.jones@linaro.org> References: <1392735362-1245-1-git-send-email-lee.jones@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: lee.jones@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.128.171 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) 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 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , When we write data to the Serial Flash chip we'll wait a predetermined period of time before giving up. During that period of time we poll the status register until completion. Acked-by Angus Clark Signed-off-by: Lee Jones --- drivers/mtd/devices/st_spi_fsm.c | 223 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c index ea55548..0eacfbf 100644 --- a/drivers/mtd/devices/st_spi_fsm.c +++ b/drivers/mtd/devices/st_spi_fsm.c @@ -238,8 +238,18 @@ #define FLASH_CMD_READ4_1_1_4 0x6c #define FLASH_CMD_READ4_1_4_4 0xec +/* Status register */ +#define FLASH_STATUS_BUSY 0x01 +#define FLASH_STATUS_WEL 0x02 +#define FLASH_STATUS_BP0 0x04 +#define FLASH_STATUS_BP1 0x08 +#define FLASH_STATUS_BP2 0x10 +#define FLASH_STATUS_SRWP0 0x80 +#define FLASH_STATUS_TIMEOUT 0xff + #define FLASH_PAGESIZE 256 /* In Bytes */ #define FLASH_PAGESIZE_32 (FLASH_PAGESIZE / 4) /* In uint32_t */ +#define FLASH_MAX_BUSY_WAIT (300 * HZ) /* Maximum 'CHIPERASE' time */ /* * Flags to tweak operation of default read/write/erase routines @@ -519,6 +529,22 @@ static struct stfsm_seq stfsm_seq_read_jedec = { SEQ_CFG_STARTSEQ), }; +static struct stfsm_seq stfsm_seq_read_status_fifo = { + .data_size = TRANSFER_SIZE(4), + .seq_opc[0] = (SEQ_OPC_PADS_1 | + SEQ_OPC_CYCLES(8) | + SEQ_OPC_OPCODE(FLASH_CMD_RDSR)), + .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 struct stfsm_seq stfsm_seq_erase_sector = { /* 'addr_cfg' configured during initialisation */ .seq_opc = { @@ -699,6 +725,53 @@ static int stfsm_enter_32bit_addr(struct stfsm *fsm, int enter) return 0; } +static uint8_t stfsm_wait_busy(struct stfsm *fsm) +{ + struct stfsm_seq *seq = &stfsm_seq_read_status_fifo; + unsigned long deadline; + uint32_t status; + int timeout = 0; + + /* Use RDRS1 */ + seq->seq_opc[0] = (SEQ_OPC_PADS_1 | + SEQ_OPC_CYCLES(8) | + SEQ_OPC_OPCODE(FLASH_CMD_RDSR)); + + /* Load read_status sequence */ + stfsm_load_seq(fsm, seq); + + /* + * Repeat until busy bit is deasserted, or timeout, or error (S25FLxxxS) + */ + deadline = jiffies + FLASH_MAX_BUSY_WAIT; + while (!timeout) { + cond_resched(); + + if (time_after_eq(jiffies, deadline)) + timeout = 1; + + stfsm_wait_seq(fsm); + + stfsm_read_fifo(fsm, &status, 4); + + if ((status & FLASH_STATUS_BUSY) == 0) + return 0; + + if ((fsm->configuration & CFG_S25FL_CHECK_ERROR_FLAGS) && + ((status & S25FL_STATUS_P_ERR) || + (status & S25FL_STATUS_E_ERR))) + return (uint8_t)(status & 0xff); + + if (!timeout) + /* Restart */ + writel(seq->seq_cfg, fsm->base + SPI_FAST_SEQ_CFG); + } + + dev_err(fsm->dev, "timeout on wait_busy\n"); + + return FLASH_STATUS_TIMEOUT; +} + static int stfsm_wrvcr(struct stfsm *fsm, uint8_t data) { struct stfsm_seq *seq = &stfsm_seq_wrvcr; @@ -1020,6 +1093,98 @@ static int stfsm_read(struct stfsm *fsm, uint8_t *buf, uint32_t size, return 0; } +static int stfsm_write(struct stfsm *fsm, const uint8_t *const buf, + const uint32_t size, const uint32_t offset) +{ + struct stfsm_seq *seq = &stfsm_seq_write; + uint32_t data_pads; + uint32_t write_mask; + uint32_t size_ub; + uint32_t size_lb; + uint32_t size_mop; + uint32_t tmp[4]; + uint32_t page_buf[FLASH_PAGESIZE_32]; + uint8_t *t = (uint8_t *)&tmp; + const uint8_t *p; + int ret; + int i; + + dev_dbg(fsm->dev, "writing %d bytes to 0x%08x\n", size, offset); + + /* Enter 32-bit address mode, if required */ + if (fsm->configuration & CFG_WRITE_TOGGLE_32BIT_ADDR) + stfsm_enter_32bit_addr(fsm, 1); + + /* Must write in multiples of 32 cycles (or 32*pads/8 bytes) */ + data_pads = ((seq->seq_cfg >> 16) & 0x3) + 1; + write_mask = (data_pads << 2) - 1; + + /* Handle non-aligned buf */ + if ((uint32_t)buf & 0x3) { + memcpy(page_buf, buf, size); + p = (uint8_t *)page_buf; + } else { + p = buf; + } + + /* Handle non-aligned size */ + size_ub = (size + write_mask) & ~write_mask; + size_lb = size & ~write_mask; + size_mop = size & write_mask; + + seq->data_size = TRANSFER_SIZE(size_ub); + seq->addr1 = (offset >> 16) & 0xffff; + seq->addr2 = offset & 0xffff; + + /* Need to set FIFO to write mode, before writing data to FIFO (see + * GNBvb79594) + */ + writel(0x00040000, fsm->base + SPI_FAST_SEQ_CFG); + + /* + * Before writing data to the FIFO, apply a small delay to allow a + * potential change of FIFO direction to complete. + */ + if (fsm->fifo_dir_delay == 0) + readl(fsm->base + SPI_FAST_SEQ_CFG); + else + udelay(fsm->fifo_dir_delay); + + + /* Write data to FIFO, before starting sequence (see GNBvd79593) */ + if (size_lb) { + stfsm_write_fifo(fsm, (uint32_t *)p, size_lb); + p += size_lb; + } + + /* Handle non-aligned size */ + if (size_mop) { + memset(t, 0xff, write_mask + 1); /* fill with 0xff's */ + for (i = 0; i < size_mop; i++) + t[i] = *p++; + + stfsm_write_fifo(fsm, tmp, write_mask + 1); + } + + /* Start sequence */ + stfsm_load_seq(fsm, seq); + + /* Wait for sequence to finish */ + stfsm_wait_seq(fsm); + + /* Wait for completion */ + ret = stfsm_wait_busy(fsm); + + /* Exit 32-bit address mode, if required */ + if (fsm->configuration & CFG_WRITE_TOGGLE_32BIT_ADDR) { + stfsm_enter_32bit_addr(fsm, 0); + if (fsm->configuration & CFG_WRITE_EX_32BIT_ADDR_DELAY) + udelay(1); + } + + return 0; +} + /* * Read an address range from the flash chip. The address range * may be any size provided it is within the physical boundaries. @@ -1053,6 +1218,63 @@ static int stfsm_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, return 0; } +/* + * Write an address range to the flash chip. Data must be written in + * FLASH_PAGESIZE chunks. The address range may be any size provided + * it is within the physical boundaries. + */ +static int stfsm_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct stfsm *fsm = dev_get_drvdata(mtd->dev.parent); + + u32 page_offs; + u32 bytes; + uint8_t *b = (uint8_t *)buf; + int ret = 0; + + dev_dbg(fsm->dev, "%s to 0x%08x, len %zd\n", __func__, (u32)to, len); + + if (retlen) + *retlen = 0; + + if (!len) + return 0; + + if (to + len > mtd->size) + return -EINVAL; + + /* Offset within page */ + page_offs = to % FLASH_PAGESIZE; + + mutex_lock(&fsm->lock); + + while (len) { + /* Write up to page boundary */ + bytes = min(FLASH_PAGESIZE - page_offs, len); + + ret = stfsm_write(fsm, b, bytes, to); + if (ret) + goto out1; + + b += bytes; + len -= bytes; + to += bytes; + + /* We are now page-aligned */ + page_offs = 0; + + if (retlen) + *retlen += bytes; + + } + +out1: + mutex_unlock(&fsm->lock); + + return ret; +} + static void stfsm_read_jedec(struct stfsm *fsm, uint8_t *const jedec) { const struct stfsm_seq *seq = &stfsm_seq_read_jedec; @@ -1310,6 +1532,7 @@ static int stfsm_probe(struct platform_device *pdev) fsm->mtd.erasesize = info->sector_size; fsm->mtd._read = stfsm_mtd_read; + fsm->mtd._write = stfsm_mtd_write; dev_err(&pdev->dev, "Found serial flash device: %s\n"