From patchwork Wed Sep 9 13:24:13 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cyrille Pitchen X-Patchwork-Id: 7146481 Return-Path: X-Original-To: patchwork-linux-spi@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id E38CE9F32B for ; Wed, 9 Sep 2015 13:25:23 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id EBD7620937 for ; Wed, 9 Sep 2015 13:25:22 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D26832092C for ; Wed, 9 Sep 2015 13:25:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753696AbbIINZV (ORCPT ); Wed, 9 Sep 2015 09:25:21 -0400 Received: from eusmtp01.atmel.com ([212.144.249.243]:33140 "EHLO eusmtp01.atmel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752868AbbIINZU (ORCPT ); Wed, 9 Sep 2015 09:25:20 -0400 Received: from tenerife.corp.atmel.com (10.161.101.13) by eusmtp01.atmel.com (10.161.101.31) with Microsoft SMTP Server id 14.3.235.1; Wed, 9 Sep 2015 15:25:14 +0200 From: Cyrille Pitchen To: , , , , , , , , , CC: , , , , , , , , , Cyrille Pitchen Subject: [PATCH linux-next v6 3/8] mtd: spi-nor: update the SPI protocol when enabling manufacturer Quad mode Date: Wed, 9 Sep 2015 15:24:13 +0200 Message-ID: X-Mailer: git-send-email 1.8.2.2 In-Reply-To: References: MIME-Version: 1.0 Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Micron: Once their Quad SPI protocol enabled, Micron spi-nor memories expect all commands to use the SPI 4-4-4 protocol. Also when the Dual SPI protocol is enabled, all commands must use the SPI 2-2-2 protocol. Macronix: When the QPI mode is enabled, all commands must use the SPI 4-4-4 protocol. Spansion: When Quad I/O operations are enabled, the Fast Read Quad Output (0x6b / 0x6c) commands use the SPI 1-1-4 protocol, the Page Program Quad Output (0x32 / 0x34) command use the SPI 1-1-4 protocol whereas other commands use the SPI 1-1-1 protocol. Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/spi-nor.c | 74 ++++++++++++++++++++++++++++++++++++++++--- include/linux/mtd/spi-nor.h | 1 + 2 files changed, 70 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 80a0db078aaa..4b36aada3f4c 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -891,6 +891,12 @@ static int macronix_quad_enable(struct spi_nor *nor) nor->cmd_buf[0] = val | SR_QUAD_EN_MX; nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1, 0); + /* Once QPI mode enabled, all commands use SPI 4-4-4 protocol. */ + nor->erase_proto = SPI_PROTO_4_4_4; + nor->read_proto = SPI_PROTO_4_4_4; + nor->write_proto = SPI_PROTO_4_4_4; + nor->reg_proto = SPI_PROTO_4_4_4; + if (spi_nor_wait_till_ready(nor)) return 1; @@ -938,10 +944,16 @@ static int spansion_quad_enable(struct spi_nor *nor) return -EINVAL; } + /* set read/write protocols */ + nor->read_proto = SPI_PROTO_1_1_4; + nor->write_proto = SPI_PROTO_1_1_4; + return 0; } -static int micron_quad_enable(struct spi_nor *nor) +static int micron_set_protocol(struct spi_nor *nor, + u8 mask, u8 value, + enum spi_protocol proto) { int ret; u8 val; @@ -954,14 +966,20 @@ static int micron_quad_enable(struct spi_nor *nor) write_enable(nor); - /* set EVCR, enable quad I/O */ - nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON; + /* set EVCR protocol bits */ + nor->cmd_buf[0] = (val & ~mask) | value; ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1, 0); if (ret < 0) { dev_err(nor->dev, "error while writing EVCR register\n"); return ret; } + /* switch protocol for ALL commands */ + nor->erase_proto = proto; + nor->read_proto = proto; + nor->write_proto = proto; + nor->reg_proto = proto; + ret = spi_nor_wait_till_ready(nor); if (ret) return ret; @@ -972,14 +990,23 @@ static int micron_quad_enable(struct spi_nor *nor) dev_err(nor->dev, "error %d reading EVCR\n", ret); return ret; } - if (val & EVCR_QUAD_EN_MICRON) { - dev_err(nor->dev, "Micron EVCR Quad bit not clear\n"); + if ((val & mask) != value) { + dev_err(nor->dev, "Micron EVCR protocol bits not valid\n"); return -EINVAL; } return 0; } +static inline int micron_quad_enable(struct spi_nor *nor) +{ + /* Clear Quad bit to enable quad mode */ + return micron_set_protocol(nor, + EVCR_QUAD_EN_MICRON | EVCR_DUAL_EN_MICRON, + EVCR_DUAL_EN_MICRON, + SPI_PROTO_4_4_4); +} + static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info) { int status; @@ -1009,6 +1036,38 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info) } } +static inline int micron_dual_enable(struct spi_nor *nor) +{ + /* Clear Dual bit but keep Quad bit set to enable dual mode */ + return micron_set_protocol(nor, + EVCR_QUAD_EN_MICRON | EVCR_DUAL_EN_MICRON, + EVCR_QUAD_EN_MICRON, + SPI_PROTO_2_2_2); +} + +static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info) +{ + int status; + + switch (JEDEC_MFR(info)) { + case CFI_MFR_ST: + status = micron_dual_enable(nor); + if (status) { + dev_err(nor->dev, "Micron dual-read not enabled\n"); + return -EINVAL; + } + return status; + case CFI_MFR_MACRONIX: + case CFI_MFR_AMD: + nor->read_proto = SPI_PROTO_1_1_2; + break; + default: + break; + } + + return 0; +} + static int spi_nor_check(struct spi_nor *nor) { if (!nor->dev || !nor->read || !nor->write || @@ -1160,6 +1219,11 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) } nor->flash_read = SPI_NOR_QUAD; } else if (mode == SPI_NOR_DUAL && info->flags & SPI_NOR_DUAL_READ) { + ret = set_dual_mode(nor, info); + if (ret) { + dev_err(dev, "dual mode not supported\n"); + return ret; + } nor->flash_read = SPI_NOR_DUAL; } diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 08e405cbb6af..ce81b0e2cb37 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -74,6 +74,7 @@ /* Enhanced Volatile Configuration Register bits */ #define EVCR_QUAD_EN_MICRON 0x80 /* Micron Quad I/O */ +#define EVCR_DUAL_EN_MICRON 0x40 /* Micron Dual I/O */ /* Flag Status Register bits */ #define FSR_READY 0x80