linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: lee.jones@linaro.org (Lee Jones)
To: linux-arm-kernel@lists.infradead.org
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	[thread overview]
Message-ID: <1392735362-1245-33-git-send-email-lee.jones@linaro.org> (raw)
In-Reply-To: <1392735362-1245-1-git-send-email-lee.jones@linaro.org>

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 <angus.clark@st.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
 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)
-- 
1.8.3.2

  parent reply	other threads:[~2014-02-18 14:55 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-02-18 14:55 [PATCH v5 00/35] mtd: st_spi_fsm: Add new driver Lee Jones
2014-02-18 14:55 ` [PATCH 01/35] mtd: st_spi_fsm: Allocate resources and register with MTD framework Lee Jones
2014-03-09  5:33   ` Brian Norris
2014-03-11  8:23     ` [PATCH v6 " Lee Jones
2014-03-20  7:10       ` Brian Norris
2014-02-18 14:55 ` [PATCH 02/35] mtd: st_spi_fsm: Supply all register address and bit logic defines Lee Jones
2014-02-18 14:55 ` [PATCH 03/35] mtd: st_spi_fsm: Initialise and configure the FSM for normal working conditions Lee Jones
2014-02-18 14:55 ` [PATCH 04/35] mtd: st_spi_fsm: Supply framework for device requests Lee Jones
2014-02-18 14:55 ` [PATCH 05/35] mtd: st_spi_fsm: Supply a method to read from the FSM's FIFO Lee Jones
2014-02-18 14:55 ` [PATCH 06/35] mtd: st_spi_fsm: Add support for JEDEC ID extraction Lee Jones
2014-02-18 14:55 ` [PATCH 07/35] mtd: devices: Provide header for shared OPCODEs and SFDP commands Lee Jones
2014-02-18 14:55 ` [PATCH 08/35] mtd: st_spi_fsm: Provide device look-up table Lee Jones
2014-02-18 14:55 ` [PATCH 09/35] mtd: st_spi_fsm: Dynamically setup flash device based on JEDEC ID Lee Jones
2014-02-18 14:55 ` [PATCH 10/35] mtd: st_spi_fsm: Search for preferred FSM message sequence configurations Lee Jones
2014-02-18 14:55 ` [PATCH 11/35] mtd: st_spi_fsm: Use device size to determine address width Lee Jones
2014-03-20  7:30   ` Brian Norris
2014-02-18 14:55 ` [PATCH 12/35] mtd: st_spi_fsm: Prepare the read/write FSM message sequence(s) Lee Jones
2014-02-18 14:55 ` [PATCH 13/35] mtd: st_spi_fsm: Add device-tree binding documentation Lee Jones
2014-02-18 14:55 ` [PATCH 14/35] mtd: st_spi_fsm: Fetch boot-device from mode pins Lee Jones
2014-02-18 14:55 ` [PATCH 15/35] mtd: st_spi_fsm: Provide the erase one sector sequence Lee Jones
2014-02-18 14:55 ` [PATCH 16/35] mtd: st_spi_fsm: Provide the sequence for enabling 32bit addressing mode Lee Jones
2014-02-18 14:55 ` [PATCH 17/35] mtd: st_spi_fsm: Prepare read/write sequences according to configuration Lee Jones
2014-02-18 14:55 ` [PATCH 18/35] mtd: st_spi_fsm: Add a check to if the chip can handle an SoC reset Lee Jones
2014-02-18 14:55 ` [PATCH 19/35] mtd: st_spi_fsm: Provide a method to put the chip into 32bit addressing mode Lee Jones
2014-02-18 14:55 ` [PATCH 20/35] mtd: st_spi_fsm: Update the flash Volatile Configuration Register Lee Jones
2014-02-18 14:55 ` [PATCH 21/35] mtd: st_spi_fsm: Provide the default read/write configurations Lee Jones
2014-02-18 14:55 ` [PATCH 22/35] mtd: st_spi_fsm: Supply the N25Qxxx specific read configurations Lee Jones
2014-02-18 14:55 ` [PATCH 23/35] mtd: st_spi_fsm: Supply the N25Qxxx chip specific configuration call-back Lee Jones
2014-02-18 14:55 ` [PATCH 24/35] mtd: st_spi_fsm: Prepare default sequences for read/write/erase Lee Jones
2014-02-18 14:55 ` [PATCH 25/35] mtd: st_spi_fsm: Add the ability to read from a Serial Flash device Lee Jones
2014-03-20  7:55   ` Brian Norris
2014-02-18 14:55 ` [PATCH 26/35] mtd: st_spi_fsm: Write to Flash via the FSM FIFO Lee Jones
2014-02-18 14:55 ` [PATCH 27/35] mtd: st_spi_fsm: Supply a busy wait for post-write status Lee Jones
2014-03-20  7:27   ` Brian Norris
2014-02-18 14:55 ` [PATCH 28/35] mtd: st_spi_fsm: Erase partly or as a whole a Serial Flash device Lee Jones
2014-02-18 14:55 ` [PATCH 29/35] mtd: st_spi_fsm: Add the ability to read the FSM's status Lee Jones
2014-02-18 14:55 ` [PATCH 30/35] mtd: st_spi_fsm: Add the ability to write to FSM's status register Lee Jones
2014-02-18 14:55 ` [PATCH 31/35] mtd: st_spi_fsm: Supply the MX25xxx chip specific configuration call-back Lee Jones
2014-02-18 14:55 ` Lee Jones [this message]
2014-02-18 14:56 ` [PATCH 33/35] mtd: st_spi_fsm: Supply the W25Qxxx " Lee Jones
2014-02-18 14:56 ` [PATCH 34/35] mtd: st_spi_fsm: Move runtime configurable msg sequences into device's struct Lee Jones
2014-02-18 14:56 ` [PATCH 35/35] ARM: STi: Add support for the FSM Serial Flash Controller Lee Jones
2014-03-20  8:06 ` [PATCH v5 00/35] mtd: st_spi_fsm: Add new driver Brian Norris

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1392735362-1245-33-git-send-email-lee.jones@linaro.org \
    --to=lee.jones@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).