From patchwork Mon Jan 6 05:21:17 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Insop Song X-Patchwork-Id: 307106 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from casper.infradead.org (unknown [IPv6:2001:770:15f::2]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 256BC2C00B8 for ; Mon, 6 Jan 2014 16:22:00 +1100 (EST) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1W02dK-00020k-81; Mon, 06 Jan 2014 05:21:50 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1W02dI-0008Cq-Lb; Mon, 06 Jan 2014 05:21:48 +0000 Received: from mail-bn1bln0179.outbound.protection.outlook.com ([2a01:111:f400:7c10::1:179] helo=na01-bn1-obe.outbound.protection.outlook.com) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1W02dC-0008CF-M2 for linux-mtd@lists.infradead.org; Mon, 06 Jan 2014 05:21:47 +0000 Received: from BLUPR07MB002.namprd07.prod.outlook.com (10.255.209.36) by BLUPR07MB001.namprd07.prod.outlook.com (10.255.209.35) with Microsoft SMTP Server (TLS) id 15.0.842.7; Mon, 6 Jan 2014 05:21:18 +0000 Received: from BLUPR07MB002.namprd07.prod.outlook.com ([10.255.209.36]) by BLUPR07MB002.namprd07.prod.outlook.com ([169.254.4.61]) with mapi id 15.00.0842.003; Mon, 6 Jan 2014 05:21:18 +0000 From: Insop Song To: "linux-spi@vger.kernel.org" , "linux-mtd@lists.infradead.org" Subject: [PATCH] Check flag status register for Micron n25q512a Thread-Topic: [PATCH] Check flag status register for Micron n25q512a Thread-Index: AQHPCp64mIrjdFelykCYT5F0n0c9pA== Date: Mon, 6 Jan 2014 05:21:17 +0000 Message-ID: <6bf927e513554e628fe15d309aac698e@BLUPR07MB002.namprd07.prod.outlook.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [108.60.97.2] x-forefront-prvs: 0083A7F08A x-forefront-antispam-report: SFV:NSPM; SFS:(10009001)(199002)(189002)(76176001)(79102001)(69226001)(53806001)(51856001)(19580395003)(56816005)(87266001)(19580405001)(74366001)(74316001)(59766001)(74706001)(74876001)(81342001)(81542001)(54316002)(56776001)(74662001)(81686001)(83322001)(15975445006)(81816001)(74502001)(87936001)(2656002)(63696002)(65816001)(47446002)(76796001)(80976001)(76786001)(76576001)(80022001)(66066001)(33646001)(54356001)(90146001)(49866001)(46102001)(4396001)(47976001)(77982001)(47736001)(50986001)(83072002)(85852003)(31966008)(85306002)(24736002); DIR:OUT; SFP:1101; SCL:1; SRVR:BLUPR07MB001; H:BLUPR07MB002.namprd07.prod.outlook.com; CLIP:108.60.97.2; FPR:; RD:InfoNoRecords; A:1; MX:1; LANG:en; MIME-Version: 1.0 X-OriginatorOrg: gainspeed.com X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140106_002145_572661_A76FD12D X-CRM114-Status: GOOD ( 10.85 ) X-Spam-Score: -1.9 (-) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-1.9 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: "Priyanka.Jain@freescale.com" , "computersforpeace@gmail.com" , "linux-spi@vger.kernel.org" X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org All, In order to use Micron n25q512a, MTD, two changes are required as follows: - jedec code should be fixed - flag status should be read for writing. Check flag status register for Micron n25q512a - Programing Micron n25q512a requires to check flag status register - According to datasheet " The flag status register must be read any time a PROGRAM, ERASE, SUSPEND/RESUME command is issued, or after a RESET command while device is busy. The cycle is not complete until bit 7 of the flag status register output 1. " - Ref: https://www.micron.com/~/media/Documents/Products/Data%20Sheet/NOR%20Flash/Serial%20NOR/N25Q/n25q_512mb_1ce_3v_65nm.pdf Signed-off-by: Insop Song --- drivers/mtd/devices/m25p80.c | 91 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 7eda71d..e53e522 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -38,6 +38,7 @@ /* Flash opcodes. */ #define OPCODE_WREN 0x06 /* Write enable */ #define OPCODE_RDSR 0x05 /* Read status register */ +#define OPCODE_RDFSR 0x70 /* Read flag status register */ #define OPCODE_WRSR 0x01 /* Write status register 1 byte */ #define OPCODE_NORM_READ 0x03 /* Read data bytes (low frequency) */ #define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */ @@ -70,6 +71,8 @@ /* Status Register bits. */ #define SR_WIP 1 /* Write in progress */ #define SR_WEL 2 /* Write enable latch */ +/* Flag Status Register bits. */ +#define FSR_RDY 0x80 /* FSR ready */ /* meaning of other SR_* bits may differ between vendors */ #define SR_BP0 4 /* Block protect 0 */ #define SR_BP1 8 /* Block protect 1 */ @@ -95,6 +98,7 @@ struct m25p { u8 program_opcode; u8 *command; bool fast_read; + bool flag_status; }; static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd) @@ -131,6 +135,28 @@ static int read_sr(struct m25p *flash) } /* + * Read the flag status register, returning its value in the location + * Return the status register value. + * Returns negative if error occurred. + */ +static int read_fsr(struct m25p *flash) +{ + ssize_t retval; + u8 code = OPCODE_RDFSR; + u8 val; + + retval = spi_write_then_read(flash->spi, &code, 1, &val, 1); + + if (retval < 0) { + printk(&flash->spi->dev, "error %d reading FSR\n", + (int) retval); + return retval; + } + + return val; +} + +/* * Write status register 1 byte * Returns negative if error occurred. */ @@ -220,6 +246,30 @@ static int wait_till_ready(struct m25p *flash) } /* + * Service routine to read flag status register until ready, or timeout occurs. + * Returns non-zero if error. + */ +static int wait_till_fsr_ready(struct m25p *flash) +{ + unsigned long deadline; + int sr; + + deadline = jiffies + MAX_READY_WAIT_JIFFIES; + + do { + if ((sr = read_fsr(flash)) < 0) + break; + else if ((sr & FSR_RDY)) + return 0; + + cond_resched(); + + } while (!time_after_eq(jiffies, deadline)); + + return 1; +} + +/* * Erase the whole flash memory * * Returns 0 if successful, non-zero otherwise. @@ -273,6 +323,14 @@ static int erase_sector(struct m25p *flash, u32 offset) if (wait_till_ready(flash)) return 1; + /* Flag status, Wait until finished previous write command. */ + if (flash->flag_status == true) { + if (wait_till_fsr_ready(flash)) { + mutex_unlock(&flash->lock); + return 1; + } + } + /* Send write enable, then erase commands. */ write_enable(flash); @@ -427,6 +485,14 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, mutex_lock(&flash->lock); + /* Flag status, Wait until finished previous write command. */ + if (flash->flag_status == true) { + if (wait_till_fsr_ready(flash)) { + mutex_unlock(&flash->lock); + return 1; + } + } + /* Wait until finished previous write command. */ if (wait_till_ready(flash)) { mutex_unlock(&flash->lock); @@ -457,6 +523,14 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, t[1].len = page_size; spi_sync(flash->spi, &m); + /* Flag status, Wait until finished previous write command. */ + if (flash->flag_status == true) { + if (wait_till_fsr_ready(flash)) { + mutex_unlock(&flash->lock); + return 1; + } + } + *retlen = m.actual_length - m25p_cmdsz(flash); /* write everything in flash->page_size chunks */ @@ -477,6 +551,14 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, spi_sync(flash->spi, &m); + /* Flag status, Wait until finished previous write command. */ + if (flash->flag_status == true) { + if (wait_till_fsr_ready(flash)) { + mutex_unlock(&flash->lock); + return 1; + } + } + *retlen += m.actual_length - m25p_cmdsz(flash); } } @@ -782,7 +864,7 @@ static const struct spi_device_id m25p_ids[] = { { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, 0) }, { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, 0) }, { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) }, - { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K) }, + { "n25q512a", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K) }, /* PMC */ { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, @@ -996,6 +1078,13 @@ static int m25p_probe(struct spi_device *spi) spi_set_drvdata(spi, flash); /* + * Micron n25q512a requires to check flag status register + */ + flash->flag_status = false; + if (strcmp(id->name, "n25q512a") == 0) + flash->flag_status = true;; + + /* * Atmel, SST and Intel/Numonyx serial flash tend to power * up with the software protection bits set */