From patchwork Fri Dec 7 09:26:06 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 1009289 X-Patchwork-Delegate: tudor.ambarus@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=bootlin.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="khgiZdnT"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43B6t61yz9z9s3q for ; Fri, 7 Dec 2018 20:41:18 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=dD8mUr+ol5VXl3z94u4BaaUGNFgNHgqaTcBU5boem/4=; b=khgiZdnTPCga9AJySbDjuqG/8m qrBVrVTK3MBnuK+qrK8g1Q8lODZIev+0mZ7CTEey6Ln1CWRkKncEiIjfwR5RJnmQZPTquchkrPNu6 N20QDLq5GCnFMsB1R5IkhlcQdnxkZXvOcGXju3eO0ONKYlfi1W0DEYNTNa2bVWHSm8v5fMgdW09n1 P6mwLhStpbVmiWP4TVsk8+8cPKv6jTnboo7m5VW/jfJD7C3iAB4clmc5dLDukOkTY/kuNqChk91t0 /YQyOkUGdvl4u4LGDXCAorT5rTZ5tQ6PTj5vKwlJNqV3EKkpEmRg4rYP2Oc8/JaHjotSC4CJHcsES ryORj++A==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1gVCdB-0005eJ-AT; Fri, 07 Dec 2018 09:41:09 +0000 Received: from mail.bootlin.com ([62.4.15.54]) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1gVCPT-0000wt-8o for linux-mtd@lists.infradead.org; Fri, 07 Dec 2018 09:27:02 +0000 Received: by mail.bootlin.com (Postfix, from userid 110) id 93F6820CC5; Fri, 7 Dec 2018 10:26:48 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on mail.bootlin.com X-Spam-Level: X-Spam-Status: No, score=-1.0 required=5.0 tests=ALL_TRUSTED,SHORTCIRCUIT, URIBL_BLOCKED shortcircuit=ham autolearn=disabled version=3.4.2 Received: from localhost.localdomain (aaubervilliers-681-1-79-44.w90-88.abo.wanadoo.fr [90.88.21.44]) by mail.bootlin.com (Postfix) with ESMTPSA id 4411920CDF; Fri, 7 Dec 2018 10:26:38 +0100 (CET) From: Boris Brezillon To: Tudor Ambarus , Marek Vasut Subject: [RFC PATCH 03/34] mtd: spi-nor: Create a ->set_4byte() method Date: Fri, 7 Dec 2018 10:26:06 +0100 Message-Id: <20181207092637.18687-4-boris.brezillon@bootlin.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181207092637.18687-1-boris.brezillon@bootlin.com> References: <20181207092637.18687-1-boris.brezillon@bootlin.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20181207_012659_742300_CD0226D5 X-CRM114-Status: GOOD ( 18.07 ) X-Spam-Score: -0.0 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Yogesh Narayan Gaur , Vignesh R , Richard Weinberger , Boris Brezillon , linux-mtd@lists.infradead.org, Miquel Raynal , Brian Norris , David Woodhouse MIME-Version: 1.0 Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org The procedure used to enable 4 byte addressing mode depends on the NOR device, so let's provide a hook so that manufacturer specific handling can be implemented in a sane way. This is also an opportunity to create a per-manufacturer post SFDP fixups function where we'll put all the manufacturer specific tweaks. Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/spi-nor.c | 138 +++++++++++++++++++++++----------- include/linux/mtd/spi-nor.h | 3 + 2 files changed, 99 insertions(+), 42 deletions(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 6b458ff4effa..bea267c446b5 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -470,46 +470,15 @@ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor) /* Enable/disable 4-byte addressing mode. */ static int set_4byte(struct spi_nor *nor, bool enable) { - int status; - bool need_wren = false; - u8 cmd; + if (nor->set_4byte) + return nor->set_4byte(nor, enable); - switch (JEDEC_MFR(nor->info)) { - case SNOR_MFR_ST: - case SNOR_MFR_MICRON: - /* Some Micron need WREN command; all will accept it */ - need_wren = true; - /* fall through */ - case SNOR_MFR_MACRONIX: - case SNOR_MFR_WINBOND: - if (need_wren) - write_enable(nor); - - cmd = enable ? SPINOR_OP_EN4B : SPINOR_OP_EX4B; - status = nor->write_reg(nor, cmd, NULL, 0); - if (need_wren) - write_disable(nor); - - if (!status && !enable && - JEDEC_MFR(nor->info) == SNOR_MFR_WINBOND) { - /* - * On Winbond W25Q256FV, leaving 4byte mode causes - * the Extended Address Register to be set to 1, so all - * 3-byte-address reads come from the second 16M. - * We must clear the register to enable normal behavior. - */ - write_enable(nor); - nor->cmd_buf[0] = 0; - nor->write_reg(nor, SPINOR_OP_WREAR, nor->cmd_buf, 1); - write_disable(nor); - } - - return status; - default: - /* Spansion style */ - nor->cmd_buf[0] = enable << 7; - return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1); - } + /* + * Spansion style. Should work for all NORs that do not have their own + * ->set_4byte() implementation. + */ + nor->cmd_buf[0] = enable << 7; + return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1); } static int s3an_sr_ready(struct spi_nor *nor) @@ -3666,13 +3635,98 @@ void spi_nor_restore(struct spi_nor *nor) } EXPORT_SYMBOL_GPL(spi_nor_restore); +static int macronix_set_4byte(struct spi_nor *nor, bool enable) +{ + return nor->write_reg(nor, enable ? SPINOR_OP_EN4B : SPINOR_OP_EX4B, + NULL, 0); +} + +static int st_micron_set_4byte(struct spi_nor *nor, bool enable) +{ + int ret; + + write_enable(nor); + ret = macronix_set_4byte(nor, enable); + write_disable(nor); + + return ret; +} + +static int winbond_set_4byte(struct spi_nor *nor, bool enable) +{ + int ret; + + ret = macronix_set_4byte(nor, enable); + if (ret || enable) + return ret; + + /* + * On Winbond W25Q256FV, leaving 4byte mode causes the Extended Address + * Register to be set to 1, so all 3-byte-address reads come from the + * second 16M. + * We must clear the register to enable normal behavior. + */ + write_enable(nor); + nor->cmd_buf[0] = 0; + nor->write_reg(nor, SPINOR_OP_WREAR, nor->cmd_buf, 1); + write_disable(nor); + + return ret; +} + +static void st_micron_post_sfdp_fixups(struct spi_nor *nor) +{ + nor->set_4byte = st_micron_set_4byte; +} + +static void macronix_post_sfdp_fixups(struct spi_nor *nor) +{ + nor->set_4byte = macronix_set_4byte; +} + +static void winbond_post_sfdp_fixups(struct spi_nor *nor) +{ + nor->set_4byte = winbond_set_4byte; +} + +static int +spi_nor_manufacturer_post_sfdp_fixups(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + switch (JEDEC_MFR(nor->info)) { + case SNOR_MFR_ST: + case SNOR_MFR_MICRON: + st_micron_post_sfdp_fixups(nor); + break; + + case SNOR_MFR_MACRONIX: + macronix_post_sfdp_fixups(nor); + break; + + case SNOR_MFR_WINBOND: + winbond_post_sfdp_fixups(nor); + break; + + default: + break; + } + + return 0; +} + static int spi_nor_post_sfdp_fixups(struct spi_nor *nor, struct spi_nor_flash_parameter *params) { - if (nor->info->fixups && nor->info->fixups->post_sfdp) - return nor->info->fixups->post_sfdp(nor, params); + int ret; - return 0; + ret = spi_nor_manufacturer_post_sfdp_fixups(nor, params); + if (ret) + return ret; + + if (nor->info->fixups && nor->info->fixups->post_sfdp) + ret = nor->info->fixups->post_sfdp(nor, params); + + return ret; } static const struct flash_info *spi_nor_match_id(const char *name) diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 5f177aa39f68..d28a9913b165 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -365,6 +365,8 @@ struct flash_info; * @flash_is_locked: [FLASH-SPECIFIC] check if a region of the SPI NOR is * @quad_enable: [FLASH-SPECIFIC] enables SPI NOR quad mode * completely locked + * @set_4byte: [FLASH-SPECIFIC] put the SPI NOR in 4 byte addressing + * mode * @priv: the private data */ struct spi_nor { @@ -401,6 +403,7 @@ struct spi_nor { int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len); int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len); int (*quad_enable)(struct spi_nor *nor); + int (*set_4byte)(struct spi_nor *nor, bool enable); void *priv; };