From patchwork Wed Jun 19 17:26:01 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Tudor Ambarus X-Patchwork-Id: 11004847 X-Patchwork-Delegate: geert@linux-m68k.org Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id DA17C13AF for ; Wed, 19 Jun 2019 17:26:05 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C311628538 for ; Wed, 19 Jun 2019 17:26:05 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B54A9285B6; Wed, 19 Jun 2019 17:26:05 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C295328538 for ; Wed, 19 Jun 2019 17:26:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730070AbfFSR0E (ORCPT ); Wed, 19 Jun 2019 13:26:04 -0400 Received: from esa3.microchip.iphmx.com ([68.232.153.233]:1844 "EHLO esa3.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726380AbfFSR0E (ORCPT ); Wed, 19 Jun 2019 13:26:04 -0400 Received-SPF: Pass (esa3.microchip.iphmx.com: domain of Tudor.Ambarus@microchip.com designates 198.175.253.82 as permitted sender) identity=mailfrom; client-ip=198.175.253.82; receiver=esa3.microchip.iphmx.com; envelope-from="Tudor.Ambarus@microchip.com"; x-sender="Tudor.Ambarus@microchip.com"; x-conformance=spf_only; x-record-type="v=spf1"; x-record-text="v=spf1 mx a:ushub1.microchip.com a:smtpout.microchip.com a:mx1.microchip.iphmx.com a:mx2.microchip.iphmx.com include:servers.mcsv.net include:mktomail.com include:spf.protection.outlook.com ~all" Received-SPF: None (esa3.microchip.iphmx.com: no sender authenticity information available from domain of postmaster@email.microchip.com) identity=helo; client-ip=198.175.253.82; receiver=esa3.microchip.iphmx.com; envelope-from="Tudor.Ambarus@microchip.com"; x-sender="postmaster@email.microchip.com"; x-conformance=spf_only Authentication-Results: esa3.microchip.iphmx.com; spf=Pass smtp.mailfrom=Tudor.Ambarus@microchip.com; spf=None smtp.helo=postmaster@email.microchip.com; dkim=pass (signature verified) header.i=@microchiptechnology.onmicrosoft.com; dmarc=pass (p=none dis=none) d=microchip.com X-IronPort-AV: E=Sophos;i="5.63,393,1557212400"; d="scan'208";a="38251436" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa3.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 19 Jun 2019 10:26:03 -0700 Received: from chn-vm-ex01.mchp-main.com (10.10.87.71) by chn-vm-ex03.mchp-main.com (10.10.87.152) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1713.5; Wed, 19 Jun 2019 10:26:02 -0700 Received: from NAM05-DM3-obe.outbound.protection.outlook.com (10.10.215.89) by email.microchip.com (10.10.87.71) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1713.5 via Frontend Transport; Wed, 19 Jun 2019 10:26:01 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=microchiptechnology.onmicrosoft.com; s=selector1-microchiptechnology-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=SkbQhu91XhvVxZZPEbwR6YZ67Fa97auc3utbb0msb/Y=; b=WFPSccLNZApMA2mnPBTeRWHsl75WOp97zrgJyjdLYkt0eXSzq4SEBDemLBXnL4UFANxXNVuJI0d8VcWAolst0OqpxZC/pGnnjQwxxdAp1NqGq8fAmzr0Fy+57embYXwtPS4VJTdViRkUEcht0W+5t5mA3BNZFjdutpUIJ7vTrsI= Received: from BN6PR11MB1842.namprd11.prod.outlook.com (10.175.98.146) by BN6PR11MB2049.namprd11.prod.outlook.com (10.173.31.9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1987.12; Wed, 19 Jun 2019 17:26:01 +0000 Received: from BN6PR11MB1842.namprd11.prod.outlook.com ([fe80::e581:f807:acdc:cb36]) by BN6PR11MB1842.namprd11.prod.outlook.com ([fe80::e581:f807:acdc:cb36%9]) with mapi id 15.20.1987.014; Wed, 19 Jun 2019 17:26:01 +0000 From: To: , , , , , CC: , , , , , , Subject: [PATCH v2 1/2] mtd: spi-nor: use 16-bit WRR command when QE is set on spansion flashes Thread-Topic: [PATCH v2 1/2] mtd: spi-nor: use 16-bit WRR command when QE is set on spansion flashes Thread-Index: AQHVJsQQBHmc1VGhQ0K5RNzllIyxuA== Date: Wed, 19 Jun 2019 17:26:01 +0000 Message-ID: <20190619172530.27159-1-tudor.ambarus@microchip.com> References: <02babf5a-2a50-848c-27d9-9f810078cbcf@microchip.com> In-Reply-To: <02babf5a-2a50-848c-27d9-9f810078cbcf@microchip.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-clientproxiedby: VI1P195CA0049.EURP195.PROD.OUTLOOK.COM (2603:10a6:802:5a::38) To BN6PR11MB1842.namprd11.prod.outlook.com (2603:10b6:404:101::18) x-ms-exchange-messagesentrepresentingtype: 1 x-mailer: git-send-email 2.9.5 x-originating-ip: [94.177.32.154] x-ms-publictraffictype: Email x-ms-office365-filtering-correlation-id: e1ac724b-ff61-445d-4166-08d6f4db32a8 x-microsoft-antispam: BCL:0;PCL:0;RULEID:(2390118)(7020095)(4652040)(8989299)(4534185)(4627221)(201703031133081)(201702281549075)(8990200)(5600148)(711020)(4605104)(1401327)(2017052603328)(7193020);SRVR:BN6PR11MB2049; x-ms-traffictypediagnostic: BN6PR11MB2049: x-microsoft-antispam-prvs: x-ms-oob-tlc-oobclassifiers: OLM:7219; x-forefront-prvs: 0073BFEF03 x-forefront-antispam-report: SFV:NSPM;SFS:(10009020)(979002)(136003)(366004)(396003)(39860400002)(376002)(346002)(189003)(199004)(72206003)(71190400001)(66066001)(76176011)(486006)(6512007)(66556008)(66476007)(66946007)(36756003)(5660300002)(64756008)(99286004)(446003)(26005)(73956011)(386003)(2616005)(476003)(11346002)(6506007)(102836004)(71200400001)(66446008)(50226002)(81166006)(6116002)(25786009)(7416002)(54906003)(478600001)(305945005)(1076003)(52116002)(14454004)(8676002)(7736002)(4326008)(107886003)(256004)(2906002)(81156014)(8936002)(14444005)(53936002)(68736007)(86362001)(6486002)(2201001)(2501003)(316002)(6436002)(186003)(110136005)(3846002)(969003)(989001)(999001)(1009001)(1019001);DIR:OUT;SFP:1101;SCL:1;SRVR:BN6PR11MB2049;H:BN6PR11MB1842.namprd11.prod.outlook.com;FPR:;SPF:None;LANG:en;PTR:InfoNoRecords;MX:1;A:1; received-spf: None (protection.outlook.com: microchip.com does not designate permitted sender hosts) x-ms-exchange-senderadcheck: 1 x-microsoft-antispam-message-info: Cwzo6VYTSQuOcGtCO0Qqm5160x7zDO/LScgQgdCfhVYyzODyam3GkAyOnX6tvlXSRPvVNk4auCQqNvMQeoWjqaLhtwKL+Cq+gFbY0reNDeRNDGxsKwGH4LnYLpM+XNSMwtgiyuTzdUQvtcKv3WwLFPcKaPcaLTim/0CSPCBxBuNOdPI+4jOhfZu7w7m+85ySVcikS7ji2v8J1wAr6iv81I6Fvjm1MQRIIp8zeXjfF4DPQ6lHapZIKnvI93KziAc5lO6LVrnujF/VEiQahnhrMQAirrfAz9SwdS2K2qumrNSAs+Dn5emNgzVzb1Q40mEIE4JfTko3W77hsYAK5KRh9PyUhq80Lzur/nHLZeac1aIjAhAcQeH75YhqNkhpy2lGxisRupl9CwFRzBFy9Jdj1q1KyUQKBcuvoVMP4YhERUk= Content-ID: <444099ED08B0004DBDC98504A3FA04AE@namprd11.prod.outlook.com> MIME-Version: 1.0 X-MS-Exchange-CrossTenant-Network-Message-Id: e1ac724b-ff61-445d-4166-08d6f4db32a8 X-MS-Exchange-CrossTenant-originalarrivaltime: 19 Jun 2019 17:26:01.1562 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 3f4057f3-b418-4d4e-ba84-d55b4e897d88 X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: tudor.ambarus@microchip.com X-MS-Exchange-Transport-CrossTenantHeadersStamped: BN6PR11MB2049 Sender: linux-renesas-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-renesas-soc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Tudor Ambarus SPI memory devices from different manufacturers have widely different configurations for Status, Control and Configuration registers. JEDEC 216C defines a new map for these common register bits and their functions, and describes how the individual bits may be accessed for a specific device. For the JEDEC 216B compliant flashes, we can partially deduce Status and Configuration registers functions by inspecting the 16th DWORD of BFPT. Older flashes that don't declare the SFDP tables (SPANSION FL512SAIFG1 311QQ063 A ©11 SPANSION) let the software decide how to interact with these registers. The commit dcb4b22eeaf4 ("spi-nor: s25fl512s supports region locking") uncovered a probe error for s25fl512s, when the Quad Enable bit CR[1] was set to one in the bootloader. When this bit is one, only the Write Status (01h) command with two data byts may be used, the 01h command with one data byte is not recognized and hence the error when trying to clear the block protection bits. Fix the above by using the Write Status (01h) command with two data bytes when the Quad Enable bit is one. Backward compatibility should be fine. The newly introduced spi_nor_spansion_clear_sr_bp() is tightly coupled with the spansion_quad_enable() function. Both assume that the Write Register with 16 bits, together with the Read Configuration Register (35h) instructions are supported. Fixes: dcb4b22eeaf44f91 ("spi-nor: s25fl512s supports region locking") Reported-by: Geert Uytterhoeven Signed-off-by: Tudor Ambarus Tested-by: Jonas Bonn Tested-by: Geert Uytterhoeven Reviewed-by: Vignesh Raghavendra Tested-by: Vignesh Raghavendra --- - add Fixes tag. Collect R-b and T-b tags - update comments regarding the Write Register command. Looks like JESD216D uses the "Write Status (01h) command" terminology. Use it. - add description for int (*clear_sr_bp)(struct spi_nor *nor); drivers/mtd/spi-nor/spi-nor.c | 119 ++++++++++++++++++++++++++++++++++++++---- include/linux/mtd/spi-nor.h | 3 ++ 2 files changed, 111 insertions(+), 11 deletions(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 73172d7f512b..0c2ec1c21434 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1636,6 +1636,95 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor) return 0; } +/** + * spi_nor_clear_sr_bp() - clear the Status Register Block Protection bits. + * @nor: pointer to a 'struct spi_nor' + * + * Read-modify-write function that clears the Block Protection bits from the + * Status Register without affecting other bits. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_clear_sr_bp(struct spi_nor *nor) +{ + int ret; + u8 mask = SR_BP2 | SR_BP1 | SR_BP0; + + ret = read_sr(nor); + if (ret < 0) { + dev_err(nor->dev, "error while reading status register\n"); + return ret; + } + + write_enable(nor); + + ret = write_sr(nor, ret & ~mask); + if (ret) { + dev_err(nor->dev, "write to status register failed\n"); + return ret; + } + + ret = spi_nor_wait_till_ready(nor); + if (ret) + dev_err(nor->dev, "timeout while writing status register\n"); + return ret; +} + +/** + * spi_nor_spansion_clear_sr_bp() - clear the Status Register Block Protection + * bits on spansion flashes. + * @nor: pointer to a 'struct spi_nor' + * + * Read-modify-write function that clears the Block Protection bits from the + * Status Register without affecting other bits. The function is tightly + * coupled with the spansion_quad_enable() function. Both assume that the Write + * Register with 16 bits, together with the Read Configuration Register (35h) + * instructions are supported. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_spansion_clear_sr_bp(struct spi_nor *nor) +{ + int ret; + u8 mask = SR_BP2 | SR_BP1 | SR_BP0; + u8 sr_cr[2] = {0}; + + /* Check current Quad Enable bit value. */ + ret = read_cr(nor); + if (ret < 0) { + dev_err(nor->dev, + "error while reading configuration register\n"); + return ret; + } + + /* + * When the configuration register Quad Enable bit is one, only the + * Write Status (01h) command with two data bytes may be used. + */ + if (ret & CR_QUAD_EN_SPAN) { + sr_cr[1] = ret; + + ret = read_sr(nor); + if (ret < 0) { + dev_err(nor->dev, + "error while reading status register\n"); + return ret; + } + sr_cr[0] = ret & ~mask; + + ret = write_sr_cr(nor, sr_cr); + if (ret) + dev_err(nor->dev, "16-bit write register failed\n"); + return ret; + } + + /* + * If the Quad Enable bit is zero, use the Write Status (01h) command + * with one data byte. + */ + return spi_nor_clear_sr_bp(nor); +} + /* Used when the "_ext_id" is two bytes at most */ #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ .id = { \ @@ -3660,6 +3749,8 @@ static int spi_nor_init_params(struct spi_nor *nor, default: /* Kept only for backward compatibility purpose. */ params->quad_enable = spansion_quad_enable; + if (nor->clear_sr_bp) + nor->clear_sr_bp = spi_nor_spansion_clear_sr_bp; break; } @@ -3912,17 +4003,13 @@ static int spi_nor_init(struct spi_nor *nor) { int err; - /* - * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up - * with the software protection bits set - */ - if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL || - JEDEC_MFR(nor->info) == SNOR_MFR_INTEL || - JEDEC_MFR(nor->info) == SNOR_MFR_SST || - nor->info->flags & SPI_NOR_HAS_LOCK) { - write_enable(nor); - write_sr(nor, 0); - spi_nor_wait_till_ready(nor); + if (nor->clear_sr_bp) { + err = nor->clear_sr_bp(nor); + if (err) { + dev_err(nor->dev, + "fail to clear block protection bits\n"); + return err; + } } if (nor->quad_enable) { @@ -4047,6 +4134,16 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, if (info->flags & SPI_S3AN) nor->flags |= SNOR_F_READY_XSR_RDY; + /* + * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up + * with the software protection bits set. + */ + if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL || + JEDEC_MFR(nor->info) == SNOR_MFR_INTEL || + JEDEC_MFR(nor->info) == SNOR_MFR_SST || + nor->info->flags & SPI_NOR_HAS_LOCK) + nor->clear_sr_bp = spi_nor_clear_sr_bp; + /* Parse the Serial Flash Discoverable Parameters table. */ ret = spi_nor_init_params(nor, ¶ms); if (ret) diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index b3d360b0ee3d..9f57cdfcc93d 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -373,6 +373,8 @@ struct flash_info; * @flash_unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR * @flash_is_locked: [FLASH-SPECIFIC] check if a region of the SPI NOR is * @quad_enable: [FLASH-SPECIFIC] enables SPI NOR quad mode + * @clear_sr_bp: [FLASH-SPECIFIC] clears the Block Protection Bits from + * the SPI NOR Status Register. * completely locked * @priv: the private data */ @@ -410,6 +412,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 (*clear_sr_bp)(struct spi_nor *nor); void *priv; };