From patchwork Tue Feb 18 14:55:59 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lee Jones X-Patchwork-Id: 24868 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-pa0-f71.google.com (mail-pa0-f71.google.com [209.85.220.71]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 47292202B2 for ; Tue, 18 Feb 2014 14:58:30 +0000 (UTC) Received: by mail-pa0-f71.google.com with SMTP id kp14sf41090231pab.2 for ; Tue, 18 Feb 2014 06:58:29 -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=Pj16NP52O1wF4nC/hPxYNisTKMEDiO4WCyFaagXhEzk=; b=CuOJkAntz6tCINktqmWDOVhUdtHeDfg1vIMZjSkMhtQb+fZsgtFQPndYkmvqG/EjkC 3lAIuHPiGsDza4qjhl7Kmf0+CTsd77HZhb2rxrokVzSIy5l1aHX5XDRUELOBgIbcPsv9 jXd68CpavlFiG//SNNb27VKkWFYIwAtMtiqCFzJfBP3kd48FBAlxQ+baXrhDbxW1WPGa Son3zIIvW5JlV+5oDEg7DQxQLfFfbakhjpQwhtLP5tRo3i2OQAabeFyLZQDc15KkmeI4 ISHLeRFINqA2tZaCv8HOOjdL6pVmd1BQeDMJz3Y45UPDV35ID8Trj2Tzeg961dHb1htS ONDQ== X-Gm-Message-State: ALoCoQmVvkdh1itNB30IdB4w2OMuh+KpiDUSDk3+sn1dBy4/xX4axYcoIh7HmN8J4dkpZYqCYJZH X-Received: by 10.67.21.145 with SMTP id hk17mr12697894pad.35.1392735509533; Tue, 18 Feb 2014 06:58:29 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.92.240 with SMTP id b103ls1304084qge.57.gmail; Tue, 18 Feb 2014 06:58:29 -0800 (PST) X-Received: by 10.220.131.210 with SMTP id y18mr21804627vcs.12.1392735509358; Tue, 18 Feb 2014 06:58:29 -0800 (PST) Received: from mail-vc0-f171.google.com (mail-vc0-f171.google.com [209.85.220.171]) by mx.google.com with ESMTPS id xn5si475933vdc.29.2014.02.18.06.58.29 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 18 Feb 2014 06:58:29 -0800 (PST) Received-SPF: neutral (google.com: 209.85.220.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.220.171; Received: by mail-vc0-f171.google.com with SMTP id le5so13058382vcb.2 for ; Tue, 18 Feb 2014 06:58:29 -0800 (PST) X-Received: by 10.220.81.71 with SMTP id w7mr150217vck.71.1392735509257; Tue, 18 Feb 2014 06:58:29 -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 u4csp222628vcz; Tue, 18 Feb 2014 06:58:28 -0800 (PST) X-Received: by 10.66.240.4 with SMTP id vw4mr33447739pac.26.1392735508040; Tue, 18 Feb 2014 06:58:28 -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.27; Tue, 18 Feb 2014 06:58:27 -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 S932411AbaBRO55 (ORCPT + 27 others); Tue, 18 Feb 2014 09:57:57 -0500 Received: from mail-wi0-f172.google.com ([209.85.212.172]:41472 "EHLO mail-wi0-f172.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932396AbaBRO5x (ORCPT ); Tue, 18 Feb 2014 09:57:53 -0500 Received: by mail-wi0-f172.google.com with SMTP id e4so3580130wiv.5 for ; Tue, 18 Feb 2014 06:57:52 -0800 (PST) X-Received: by 10.194.59.210 with SMTP id b18mr2708918wjr.60.1392735472105; Tue, 18 Feb 2014 06:57:52 -0800 (PST) Received: from localhost.localdomain ([80.76.198.141]) by mx.google.com with ESMTPSA id h13sm46039687wjr.22.2014.02.18.06.57.49 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 18 Feb 2014 06:57:51 -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 32/35] mtd: st_spi_fsm: Supply the S25FLxxx chip specific configuration call-back Date: Tue, 18 Feb 2014 14:55:59 +0000 Message-Id: <1392735362-1245-33-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.220.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: , This patch allows us to prepare some of the message sequences which will be required to talk to the S25FLxxx family of Serial Flash devices. It also allows us to do some required extra operations after any busy wait failures. Acked-by Angus Clark Signed-off-by: Lee Jones --- drivers/mtd/devices/st_spi_fsm.c | 266 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 260 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c index 8ffbd95a..b6f395c 100644 --- a/drivers/mtd/devices/st_spi_fsm.c +++ b/drivers/mtd/devices/st_spi_fsm.c @@ -238,6 +238,16 @@ #define FLASH_CMD_READ4_1_1_4 0x6c #define FLASH_CMD_READ4_1_4_4 0xec +/* S25FLxxxS commands */ +#define S25FL_CMD_WRITE4_1_1_4 0x34 +#define S25FL_CMD_SE4 0xdc +#define S25FL_CMD_CLSR 0x30 +#define S25FL_CMD_DYBWR 0xe1 +#define S25FL_CMD_DYBRD 0xe0 +#define S25FL_CMD_WRITE4 0x12 /* Note, opcode clashes with + * 'FLASH_CMD_WRITE_1_4_4' + * as found on N25Qxxx devices! */ + /* Status register */ #define FLASH_STATUS_BUSY 0x01 #define FLASH_STATUS_WEL 0x02 @@ -246,6 +256,9 @@ #define FLASH_STATUS_BP2 0x10 #define FLASH_STATUS_SRWP0 0x80 #define FLASH_STATUS_TIMEOUT 0xff +/* S25FL Error Flags */ +#define S25FL_STATUS_E_ERR 0x20 +#define S25FL_STATUS_P_ERR 0x40 #define FLASH_PAGESIZE 256 /* In Bytes */ #define FLASH_PAGESIZE_32 (FLASH_PAGESIZE / 4) /* In uint32_t */ @@ -327,6 +340,7 @@ struct flash_info { static int stfsm_n25q_config(struct stfsm *fsm); static int stfsm_mx25_config(struct stfsm *fsm); +static int stfsm_s25fl_config(struct stfsm *fsm); static struct flash_info flash_types[] = { /* @@ -388,9 +402,9 @@ static struct flash_info flash_types[] = { FLASH_FLAG_WRITE_1_1_4 | \ FLASH_FLAG_READ_FAST) { "s25fl129p0", 0x012018, 0x4d00, 256 * 1024, 64, S25FLXXXP_FLAG, 80, - NULL }, + stfsm_s25fl_config }, { "s25fl129p1", 0x012018, 0x4d01, 64 * 1024, 256, S25FLXXXP_FLAG, 80, - NULL }, + stfsm_s25fl_config }, /* * Spansion S25FLxxxS @@ -405,13 +419,13 @@ static struct flash_info flash_types[] = { FLASH_FLAG_RESET | \ FLASH_FLAG_DYB_LOCKING) { "s25fl128s0", 0x012018, 0x0300, 256 * 1024, 64, S25FLXXXS_FLAG, 80, - NULL }, + stfsm_s25fl_config }, { "s25fl128s1", 0x012018, 0x0301, 64 * 1024, 256, S25FLXXXS_FLAG, 80, - NULL }, + stfsm_s25fl_config }, { "s25fl256s0", 0x010219, 0x4d00, 256 * 1024, 128, - S25FLXXXS_FLAG | FLASH_FLAG_32BIT_ADDR, 80, NULL }, + S25FLXXXS_FLAG | FLASH_FLAG_32BIT_ADDR, 80, stfsm_s25fl_config }, { "s25fl256s1", 0x010219, 0x4d01, 64 * 1024, 512, - S25FLXXXS_FLAG | FLASH_FLAG_32BIT_ADDR, 80, NULL }, + S25FLXXXS_FLAG | FLASH_FLAG_32BIT_ADDR, 80, stfsm_s25fl_config }, /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ #define W25X_FLAG (FLASH_FLAG_READ_WRITE | \ @@ -536,6 +550,33 @@ static int stfsm_mx25_en_32bit_addr_seq(struct stfsm_seq *seq) return 0; } +/* + * [S25FLxxx] Configuration + */ +#define STFSM_S25FL_CONFIG_QE (0x1 << 1) + +/* + * S25FLxxxS devices provide three ways of supporting 32-bit addressing: Bank + * Register, Extended Address Modes, and a 32-bit address command set. The + * 32-bit address command set is used here, since it avoids any problems with + * entering a state that is incompatible with the SPIBoot Controller. + */ +static struct seq_rw_config stfsm_s25fl_read4_configs[] = { + {FLASH_FLAG_READ_1_4_4, FLASH_CMD_READ4_1_4_4, 0, 4, 4, 0x00, 2, 4}, + {FLASH_FLAG_READ_1_1_4, FLASH_CMD_READ4_1_1_4, 0, 1, 4, 0x00, 0, 8}, + {FLASH_FLAG_READ_1_2_2, FLASH_CMD_READ4_1_2_2, 0, 2, 2, 0x00, 4, 0}, + {FLASH_FLAG_READ_1_1_2, FLASH_CMD_READ4_1_1_2, 0, 1, 2, 0x00, 0, 8}, + {FLASH_FLAG_READ_FAST, FLASH_CMD_READ4_FAST, 0, 1, 1, 0x00, 0, 8}, + {FLASH_FLAG_READ_WRITE, FLASH_CMD_READ4, 0, 1, 1, 0x00, 0, 0}, + {0x00, 0, 0, 0, 0, 0x00, 0, 0}, +}; + +static struct seq_rw_config stfsm_s25fl_write4_configs[] = { + {FLASH_FLAG_WRITE_1_1_4, S25FL_CMD_WRITE4_1_1_4, 1, 1, 4, 0x00, 0, 0}, + {FLASH_FLAG_READ_WRITE, S25FL_CMD_WRITE4, 1, 1, 1, 0x00, 0, 0}, + {0x00, 0, 0, 0, 0, 0x00, 0, 0}, +}; + static struct stfsm_seq stfsm_seq_read; /* Dynamically populated */ static struct stfsm_seq stfsm_seq_write; /* Dynamically populated */ static struct stfsm_seq stfsm_seq_en_32bit_addr;/* Dynamically populated */ @@ -1193,6 +1234,215 @@ static int stfsm_n25q_config(struct stfsm *fsm) return 0; } +static void stfsm_s25fl_prepare_erasesec_seq_32(struct stfsm_seq *seq) +{ + seq->seq_opc[1] = (SEQ_OPC_PADS_1 | + SEQ_OPC_CYCLES(8) | + SEQ_OPC_OPCODE(S25FL_CMD_SE4)); + + seq->addr_cfg = (ADR_CFG_CYCLES_ADD1(16) | + ADR_CFG_PADS_1_ADD1 | + ADR_CFG_CYCLES_ADD2(16) | + ADR_CFG_PADS_1_ADD2 | + ADR_CFG_CSDEASSERT_ADD2); +} + +static void stfsm_s25fl_read_dyb(struct stfsm *fsm, uint32_t offs, uint8_t *dby) +{ + uint32_t tmp; + struct stfsm_seq seq = { + .data_size = TRANSFER_SIZE(4), + .seq_opc[0] = (SEQ_OPC_PADS_1 | + SEQ_OPC_CYCLES(8) | + SEQ_OPC_OPCODE(S25FL_CMD_DYBRD)), + .addr_cfg = (ADR_CFG_CYCLES_ADD1(16) | + ADR_CFG_PADS_1_ADD1 | + ADR_CFG_CYCLES_ADD2(16) | + ADR_CFG_PADS_1_ADD2), + .addr1 = (offs >> 16) & 0xffff, + .addr2 = offs & 0xffff, + .seq = { + STFSM_INST_CMD1, + STFSM_INST_ADD1, + STFSM_INST_ADD2, + STFSM_INST_DATA_READ, + STFSM_INST_STOP, + }, + .seq_cfg = (SEQ_CFG_PADS_1 | + SEQ_CFG_READNOTWRITE | + SEQ_CFG_CSDEASSERT | + SEQ_CFG_STARTSEQ), + }; + + stfsm_load_seq(fsm, &seq); + + stfsm_read_fifo(fsm, &tmp, 4); + + *dby = (uint8_t)(tmp >> 24); + + stfsm_wait_seq(fsm); +} + +static void stfsm_s25fl_write_dyb(struct stfsm *fsm, uint32_t offs, uint8_t dby) +{ + struct stfsm_seq seq = { + .seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | + SEQ_OPC_OPCODE(FLASH_CMD_WREN) | + SEQ_OPC_CSDEASSERT), + .seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | + SEQ_OPC_OPCODE(S25FL_CMD_DYBWR)), + .addr_cfg = (ADR_CFG_CYCLES_ADD1(16) | + ADR_CFG_PADS_1_ADD1 | + ADR_CFG_CYCLES_ADD2(16) | + ADR_CFG_PADS_1_ADD2), + .status = (uint32_t)dby | STA_PADS_1 | STA_CSDEASSERT, + .addr1 = (offs >> 16) & 0xffff, + .addr2 = offs & 0xffff, + .seq = { + STFSM_INST_CMD1, + STFSM_INST_CMD2, + STFSM_INST_ADD1, + STFSM_INST_ADD2, + STFSM_INST_STA_WR1, + STFSM_INST_STOP, + }, + .seq_cfg = (SEQ_CFG_PADS_1 | + SEQ_CFG_READNOTWRITE | + SEQ_CFG_CSDEASSERT | + SEQ_CFG_STARTSEQ), + }; + + stfsm_load_seq(fsm, &seq); + stfsm_wait_seq(fsm); + + stfsm_wait_busy(fsm); +} + +static int stfsm_s25fl_clear_status_reg(struct stfsm *fsm) +{ + struct stfsm_seq seq = { + .seq_opc[0] = (SEQ_OPC_PADS_1 | + SEQ_OPC_CYCLES(8) | + SEQ_OPC_OPCODE(S25FL_CMD_CLSR) | + SEQ_OPC_CSDEASSERT), + .seq_opc[1] = (SEQ_OPC_PADS_1 | + SEQ_OPC_CYCLES(8) | + SEQ_OPC_OPCODE(FLASH_CMD_WRDI) | + SEQ_OPC_CSDEASSERT), + .seq = { + STFSM_INST_CMD1, + STFSM_INST_CMD2, + STFSM_INST_WAIT, + STFSM_INST_STOP, + }, + .seq_cfg = (SEQ_CFG_PADS_1 | + SEQ_CFG_ERASE | + SEQ_CFG_READNOTWRITE | + SEQ_CFG_CSDEASSERT | + SEQ_CFG_STARTSEQ), + }; + + stfsm_load_seq(fsm, &seq); + + stfsm_wait_seq(fsm); + + return 0; +} + +static int stfsm_s25fl_config(struct stfsm *fsm) +{ + struct flash_info *info = fsm->info; + uint32_t flags = info->flags; + uint32_t data_pads; + uint32_t offs; + uint16_t sta_wr; + uint8_t sr1, cr1, dyb; + int ret; + + if (flags & FLASH_FLAG_32BIT_ADDR) { + /* + * Prepare Read/Write/Erase sequences according to S25FLxxx + * 32-bit address command set + */ + ret = stfsm_search_prepare_rw_seq(fsm, &stfsm_seq_read, + stfsm_s25fl_read4_configs); + if (ret) + return ret; + + ret = stfsm_search_prepare_rw_seq(fsm, &stfsm_seq_write, + stfsm_s25fl_write4_configs); + if (ret) + return ret; + + stfsm_s25fl_prepare_erasesec_seq_32(&stfsm_seq_erase_sector); + + } else { + /* Use default configurations for 24-bit addressing */ + ret = stfsm_prepare_rwe_seqs_default(fsm); + if (ret) + return ret; + } + + /* + * For devices that support 'DYB' sector locking, check lock status and + * unlock sectors if necessary (some variants power-on with sectors + * locked by default) + */ + if (flags & FLASH_FLAG_DYB_LOCKING) { + offs = 0; + for (offs = 0; offs < info->sector_size * info->n_sectors;) { + stfsm_s25fl_read_dyb(fsm, offs, &dyb); + if (dyb == 0x00) + stfsm_s25fl_write_dyb(fsm, offs, 0xff); + + /* Handle bottom/top 4KiB parameter sectors */ + if ((offs < info->sector_size * 2) || + (offs >= (info->sector_size - info->n_sectors * 4))) + offs += 0x1000; + else + offs += 0x10000; + } + } + + /* Check status of 'QE' bit */ + data_pads = ((stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1; + stfsm_read_status(fsm, FLASH_CMD_RDSR2, &cr1); + if (data_pads == 4) { + if (!(cr1 & STFSM_S25FL_CONFIG_QE)) { + /* Set 'QE' */ + cr1 |= STFSM_S25FL_CONFIG_QE; + + stfsm_read_status(fsm, FLASH_CMD_RDSR, &sr1); + sta_wr = ((uint16_t)cr1 << 8) | sr1; + + stfsm_write_status(fsm, sta_wr, 2); + + stfsm_wait_busy(fsm); + } + } else { + if ((cr1 & STFSM_S25FL_CONFIG_QE)) { + /* Clear 'QE' */ + cr1 &= ~STFSM_S25FL_CONFIG_QE; + + stfsm_read_status(fsm, FLASH_CMD_RDSR, &sr1); + sta_wr = ((uint16_t)cr1 << 8) | sr1; + + stfsm_write_status(fsm, sta_wr, 2); + + stfsm_wait_busy(fsm); + } + + } + + /* + * S25FLxxx devices support Program and Error error flags. + * Configure driver to check flags and clear if necessary. + */ + fsm->configuration |= CFG_S25FL_CHECK_ERROR_FLAGS; + + return 0; +} + static int stfsm_read(struct stfsm *fsm, uint8_t *buf, uint32_t size, uint32_t offset) { @@ -1335,6 +1585,8 @@ static int stfsm_write(struct stfsm *fsm, const uint8_t *const buf, /* Wait for completion */ ret = stfsm_wait_busy(fsm); + if (ret && fsm->configuration & CFG_S25FL_CHECK_ERROR_FLAGS) + stfsm_s25fl_clear_status_reg(fsm); /* Exit 32-bit address mode, if required */ if (fsm->configuration & CFG_WRITE_TOGGLE_32BIT_ADDR) { @@ -1399,6 +1651,8 @@ static int stfsm_erase_sector(struct stfsm *fsm, const uint32_t offset) /* Wait for completion */ ret = stfsm_wait_busy(fsm); + if (ret && fsm->configuration & CFG_S25FL_CHECK_ERROR_FLAGS) + stfsm_s25fl_clear_status_reg(fsm); /* Exit 32-bit address mode, if required */ if (fsm->configuration & CFG_ERASESEC_TOGGLE_32BIT_ADDR)