From mboxrd@z Thu Jan 1 00:00:00 1970 Message-ID: <4ADDC5A3.50607@nokia.com> Date: Tue, 20 Oct 2009 17:13:55 +0300 From: Adrian Hunter MIME-Version: 1.0 To: "dedekind1@gmail.com" Subject: Re: [PATCH] [OneNAND] OTP support re-implementation 1/1 References: <7C266C6722224724BF9456BA7986FC05@sisodomain.com> <1256028984.29856.144.camel@localhost> In-Reply-To: <1256028984.29856.144.camel@localhost> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit Cc: Amul Kumar Saha , Kyungmin Park , David Woodhouse , "linux-mtd@lists.infradead.org" List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Artem Bityutskiy wrote: > I'm still waiting for Adrian to review this. Yesterday he said he will > do this soon. In any case, I remember about this patch, just FYI. Seems fine except why aren't onenand_otp_command() onenand_otp_write_oob_nolock() inside an #ifdef CONFIG_MTD_ONENAND_OTP ... #endif > On Mon, 2009-10-12 at 11:31 +0530, Amul Kumar Saha wrote: >> What is OTP in OneNAND? >> The device includes, >> 1. one block-sized OTP (One Time Programmable) area and >> 2. user-controlled 1st block OTP(Block 0) >> that can be used to increase system security or to provide identification capabilities. >> >> What is done? >> In OneNAND, one block of the NAND Array is set aside as an OTP memory area, and 1st Block (Block 0) >> can be used as OTP area. >> This area, available to the user, can be configured and locked with secured user information. >> The OTP block can be read, programmed and locked using the same operations as any other NAND Flash >> Array >> memory block. After issuing an OTP-Lock, OTP block cannot be erased. OTP block is fully-guaranteed >> to be a valid block. >> >> Why it is done? (Impact) >> Locking the 1st Block OTP has the effect of a 'Write-protect' to guard against accidental >> re-programming of data stored in the 1st block and OTP Block. >> >> Which problem it solves? >> OTP support is provided in the existing implementation of OneNAND/Flex-OneNAND driver, but it is not >> working with OneNAND devices. >> Have observed the following in current OTP OneNAND Implmentation, >> 1. DataSheet specific sequence to lock the OTP Area is not followed. >> 2. Certain functions are quiet generic to cope with OTP specific activity. >> This patch re-implements OTP support for OneNAND device. >> >> How it is done? >> For all blocks, 8th word is available to the user. >> However,in case of OTP Block, 8th word of sector 0, page 0 is reserved as OTP Locking Bit area. >> Therefore, in case of OTP Block, user usage on this area is prohibited. >> Condition specific values are entered in the 8th word, sector0, page 0 of the OTP block during the >> process of issuing an OTP-Lock. >> The possible conditions are:- >> 1. Only 1st Block Lock >> 2. Only OTP Block Lock >> 3. Lock both the 1st Block and the OTP Block >> >> What Other feature additions have been done in this patch? >> This patch adds feature for:- >> 1. Only 1st Block Lock >> 2. Lock both the 1st Block and the OTP Blocks >> >> Re-implemented OTP support for OneNAND >> Added following features to OneNAND >> 1. Lock only 1st Block in OneNAND >> 2. Lock BOTH 1st Block and OTP Block in OneNAND >> >> Signed-off-by: Amul Kumar Saha >> --- >> drivers/mtd/onenand/onenand_base.c | 287 +++++++++++++++++++++++++++++++++---- >> include/linux/mtd/onenand.h | 2 >> 2 files changed, 260 insertions(+), 29 deletions(-) >> >> diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c >> index cb405bc..4d28268 100644 >> --- a/drivers/mtd/onenand/onenand_base.c >> +++ b/drivers/mtd/onenand/onenand_base.c >> @@ -11,7 +11,9 @@ >> * >> * Vishak G , Rohit Hagargundgi >> * Flex-OneNAND support >> - * Copyright (C) Samsung Electronics, 2008 >> + * Amul Kumar Saha >> + * OTP support >> + * Copyright (C) Samsung Electronics, 2009 >> * >> * This program is free software; you can redistribute it and/or modify >> * it under the terms of the GNU General Public License version 2 as >> @@ -43,6 +45,18 @@ MODULE_PARM_DESC(flex_bdry, "SLC Boundary information for Flex-OneNAND" >> " : 0->Set boundary in unlocked status" >> " : 1->Set boundary in locked status"); >> >> +/* Default OneNAND/Flex-OneNAND OTP options*/ >> +static int otp; >> + >> +module_param(otp, int, 0400); >> +MODULE_PARM_DESC(otp, "Corresponding behaviour of OneNAND in OTP" >> + "Syntax : otp=LOCK_TYPE" >> + "LOCK_TYPE : Keys issued, for specific OTP Lock type" >> + " : 0 -> Default (No Blocks Locked)" >> + " : 1 -> OTP Block lock" >> + " : 2 -> 1st Block lock" >> + " : 3 -> BOTH OTP Block and 1st Block lock"); >> + >> /** >> * onenand_oob_128 - oob info for Flex-Onenand with 4KB page >> * For now, we expose only 64 out of 80 ecc bytes >> @@ -308,6 +322,81 @@ int flexonenand_region(struct mtd_info *mtd, loff_t addr) >> EXPORT_SYMBOL(flexonenand_region); >> >> /** >> + * onenand_otp_command - Send OTP specific command to OneNAND device >> + * @param mtd MTD device structure >> + * @param cmd the command to be sent >> + * @param addr offset to read from or write to >> + * @param len number of bytes to read or write >> + */ >> +static int onenand_otp_command(struct mtd_info *mtd, int cmd, loff_t addr, >> + size_t len) >> +{ >> + struct onenand_chip *this = mtd->priv; >> + int value, block, page; >> + >> + /* Address translation */ >> + switch (cmd) { >> + case ONENAND_CMD_OTP_ACCESS: >> + block = (int) (addr >> this->erase_shift); >> + page = -1; >> + break; >> + >> + default: >> + block = (int) (addr >> this->erase_shift); >> + page = (int) (addr >> this->page_shift); >> + >> + if (ONENAND_IS_2PLANE(this)) { >> + /* Make the even block number */ >> + block &= ~1; >> + /* Is it the odd plane? */ >> + if (addr & this->writesize) >> + block++; >> + page >>= 1; >> + } >> + page &= this->page_mask; >> + break; >> + } >> + >> + if (block != -1) { >> + /* Write 'DFS, FBA' of Flash */ >> + value = onenand_block_address(this, block); >> + this->write_word(value, this->base + >> + ONENAND_REG_START_ADDRESS1); >> + } >> + >> + if (page != -1) { >> + /* Now we use page size operation */ >> + int sectors = 4, count = 4; >> + int dataram; >> + >> + switch (cmd) { >> + default: >> + if (ONENAND_IS_2PLANE(this) && cmd == ONENAND_CMD_PROG) >> + cmd = ONENAND_CMD_2X_PROG; >> + dataram = ONENAND_CURRENT_BUFFERRAM(this); >> + break; >> + } >> + >> + /* Write 'FPA, FSA' of Flash */ >> + value = onenand_page_address(page, sectors); >> + this->write_word(value, this->base + >> + ONENAND_REG_START_ADDRESS8); >> + >> + /* Write 'BSA, BSC' of DataRAM */ >> + value = onenand_buffer_address(dataram, sectors, count); >> + this->write_word(value, this->base + ONENAND_REG_START_BUFFER); >> + } >> + >> + /* Interrupt clear */ >> + this->write_word(ONENAND_INT_CLEAR, this->base + ONENAND_REG_INTERRUPT); >> + >> + /* Write command */ >> + this->write_word(cmd, this->base + ONENAND_REG_COMMAND); >> + >> + return 0; >> +} >> + >> +/** >> * onenand_command - [DEFAULT] Send command to OneNAND device >> * @param mtd MTD device structure >> * @param cmd the command to be sent >> @@ -1969,6 +2058,133 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, >> >> >> /** >> + * onenand_otp_write_oob_nolock - [Internal] OneNAND write out-of-band, specific to OTP >> + * @param mtd MTD device structure >> + * @param to offset to write to >> + * @param len number of bytes to write >> + * @param retlen pointer to variable to store the number of written bytes >> + * @param buf the data to write >> + * >> + * OneNAND write out-of-band only for OTP >> + */ >> +static int onenand_otp_write_oob_nolock(struct mtd_info *mtd, loff_t to, >> + struct mtd_oob_ops *ops) >> +{ >> + struct onenand_chip *this = mtd->priv; >> + int column, ret = 0, oobsize; >> + int written = 0; >> + u_char *oobbuf; >> + size_t len = ops->ooblen; >> + const u_char *buf = ops->oobbuf; >> + int block, value, status; >> + >> + to += ops->ooboffs; >> + >> + /* Initialize retlen, in case of early exit */ >> + ops->oobretlen = 0; >> + >> + oobsize = mtd->oobsize; >> + >> + column = to & (mtd->oobsize - 1); >> + >> + oobbuf = this->oob_buf; >> + >> + /* Loop until all data write */ >> + while (written < len) { >> + int thislen = min_t(int, oobsize, len - written); >> + >> + cond_resched(); >> + >> + block = (int) (to >> this->erase_shift); >> + /* >> + * Write 'DFS, FBA' of Flash >> + * Add: F100h DQ=DFS, FBA >> + */ >> + >> + value = onenand_block_address(this, block); >> + this->write_word(value, this->base + >> + ONENAND_REG_START_ADDRESS1); >> + >> + /* >> + * Select DataRAM for DDP >> + * Add: F101h DQ=DBS >> + */ >> + >> + value = onenand_bufferram_address(this, block); >> + this->write_word(value, this->base + >> + ONENAND_REG_START_ADDRESS2); >> + ONENAND_SET_NEXT_BUFFERRAM(this); >> + >> + /* >> + * Enter OTP access mode >> + */ >> + this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); >> + this->wait(mtd, FL_OTPING); >> + >> + /* We send data to spare ram with oobsize >> + * to prevent byte access */ >> + memcpy(oobbuf + column, buf, thislen); >> + >> + /* >> + * Write Data into DataRAM >> + * Add: 8th Word >> + * in sector0/spare/page0 >> + * DQ=XXFCh >> + */ >> + this->write_bufferram(mtd, ONENAND_SPARERAM, >> + oobbuf, 0, mtd->oobsize); >> + >> + onenand_otp_command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize); >> + onenand_update_bufferram(mtd, to, 0); >> + if (ONENAND_IS_2PLANE(this)) { >> + ONENAND_SET_BUFFERRAM1(this); >> + onenand_update_bufferram(mtd, to + this->writesize, 0); >> + } >> + >> + ret = this->wait(mtd, FL_WRITING); >> + if (ret) { >> + printk(KERN_ERR "%s: write failed %d\n", __func__, ret); >> + break; >> + } >> + >> + /* Exit OTP access mode */ >> + this->command(mtd, ONENAND_CMD_RESET, 0, 0); >> + this->wait(mtd, FL_RESETING); >> + >> + status = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); >> + status &= 0x60; >> + >> + if (status == 0x60) { >> + printk(KERN_DEBUG "\nBLOCK\tSTATUS\n"); >> + printk(KERN_DEBUG "1st Block\tLOCKED\n"); >> + printk(KERN_DEBUG "OTP Block\tLOCKED\n"); >> + } else if (status == 0x20) { >> + printk(KERN_DEBUG "\nBLOCK\tSTATUS\n"); >> + printk(KERN_DEBUG "1st Block\tLOCKED\n"); >> + printk(KERN_DEBUG "OTP Block\tUN-LOCKED\n"); >> + } else if (status == 0x40) { >> + printk(KERN_DEBUG "\nBLOCK\tSTATUS\n"); >> + printk(KERN_DEBUG "1st Block\tUN-LOCKED\n"); >> + printk(KERN_DEBUG "OTP Block\tLOCKED\n"); >> + } else { >> + printk(KERN_DEBUG "Reboot to check\n"); >> + } >> + >> + written += thislen; >> + if (written == len) >> + break; >> + >> + to += mtd->writesize; >> + buf += thislen; >> + column = 0; >> + } >> + >> + ops->oobretlen = written; >> + >> + return ret; >> +} >> + >> +/** >> * onenand_write_oob_nolock - [Internal] OneNAND write out-of-band >> * @param mtd MTD device structure >> * @param to offset to write to >> @@ -2693,11 +2909,11 @@ static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len, >> struct mtd_oob_ops ops; >> int ret; >> >> - /* Enter OTP access mode */ >> - this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); >> - this->wait(mtd, FL_OTPING); >> - >> if (FLEXONENAND(this)) { >> + >> + /* Enter OTP access mode */ >> + this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); >> + this->wait(mtd, FL_OTPING); >> /* >> * For Flex-OneNAND, we write lock mark to 1st word of sector 4 of >> * main area of page 49. >> @@ -2708,19 +2924,19 @@ static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len, >> ops.oobbuf = NULL; >> ret = onenand_write_ops_nolock(mtd, mtd->writesize * 49, &ops); >> *retlen = ops.retlen; >> + >> + /* Exit OTP access mode */ >> + this->command(mtd, ONENAND_CMD_RESET, 0, 0); >> + this->wait(mtd, FL_RESETING); >> } else { >> ops.mode = MTD_OOB_PLACE; >> ops.ooblen = len; >> ops.oobbuf = buf; >> ops.ooboffs = 0; >> - ret = onenand_write_oob_nolock(mtd, from, &ops); >> + ret = onenand_otp_write_oob_nolock(mtd, from, &ops); >> *retlen = ops.oobretlen; >> } >> >> - /* Exit OTP access mode */ >> - this->command(mtd, ONENAND_CMD_RESET, 0, 0); >> - this->wait(mtd, FL_RESETING); >> - >> return ret; >> } >> >> @@ -2751,16 +2967,21 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, >> if (density < ONENAND_DEVICE_DENSITY_512Mb) >> otp_pages = 20; >> else >> - otp_pages = 10; >> + otp_pages = 50; >> >> if (mode == MTD_OTP_FACTORY) { >> from += mtd->writesize * otp_pages; >> - otp_pages = 64 - otp_pages; >> + otp_pages = ONENAND_PAGES_PER_BLOCK - otp_pages; >> } >> >> /* Check User/Factory boundary */ >> - if (((mtd->writesize * otp_pages) - (from + len)) < 0) >> - return 0; >> + if (mode == MTD_OTP_USER) { >> + if (((mtd->writesize * otp_pages) - (from + len)) < 0) >> + return 0; >> + } else { >> + if (((mtd->writesize * otp_pages) - len) < 0) >> + return 0; >> + } >> >> onenand_get_device(mtd, FL_OTPING); >> while (len > 0 && otp_pages > 0) { >> @@ -2783,13 +3004,12 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, >> *retlen += sizeof(struct otp_info); >> } else { >> size_t tmp_retlen; >> - int size = len; >> >> ret = action(mtd, from, len, &tmp_retlen, buf); >> >> - buf += size; >> - len -= size; >> - *retlen += size; >> + buf += tmp_retlen; >> + len -= tmp_retlen; >> + *retlen += tmp_retlen; >> >> if (ret) >> break; >> @@ -2902,21 +3122,11 @@ static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, >> u_char *buf = FLEXONENAND(this) ? this->page_buf : this->oob_buf; >> size_t retlen; >> int ret; >> + unsigned int otp_lock_offset = ONENAND_OTP_LOCK_OFFSET; >> >> memset(buf, 0xff, FLEXONENAND(this) ? this->writesize >> : mtd->oobsize); >> /* >> - * Note: OTP lock operation >> - * OTP block : 0xXXFC >> - * 1st block : 0xXXF3 (If chip support) >> - * Both : 0xXXF0 (If chip support) >> - */ >> - if (FLEXONENAND(this)) >> - buf[FLEXONENAND_OTP_LOCK_OFFSET] = 0xFC; >> - else >> - buf[ONENAND_OTP_LOCK_OFFSET] = 0xFC; >> - >> - /* >> * Write lock mark to 8th word of sector0 of page0 of the spare0. >> * We write 16 bytes spare area instead of 2 bytes. >> * For Flex-OneNAND, we write lock mark to 1st word of sector 4 of >> @@ -2926,6 +3136,25 @@ static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, >> from = 0; >> len = FLEXONENAND(this) ? mtd->writesize : 16; >> >> + /* >> + * Note: OTP lock operation >> + * OTP block : 0xXXFC XX 1111 1100 >> + * 1st block : 0xXXF3 (If chip support) XX 1111 0011 >> + * Both : 0xXXF0 (If chip support) XX 1111 0000 >> + */ >> + if (FLEXONENAND(this)) >> + otp_lock_offset = FLEXONENAND_OTP_LOCK_OFFSET; >> + >> + /* ONENAND_OTP_AREA | ONENAND_OTP_BLOCK0 | ONENAND_OTP_AREA_BLOCK0 */ >> + if (otp == 1) >> + buf[otp_lock_offset] = 0xFC; >> + else if (otp == 2) >> + buf[otp_lock_offset] = 0xF3; >> + else if (otp == 3) >> + buf[otp_lock_offset] = 0xF0; >> + else if (otp != 0) >> + printk(KERN_DEBUG "[OneNAND] Invalid option selected for OTP\n"); >> + >> ret = onenand_otp_walk(mtd, from, len, &retlen, buf, do_otp_lock, MTD_OTP_USER); >> >> return ret ? : retlen; >> diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h >> index 4e49f33..3c00b55 100644 >> --- a/include/linux/mtd/onenand.h >> +++ b/include/linux/mtd/onenand.h >> @@ -152,6 +152,8 @@ struct onenand_chip { >> /* >> * Helper macros >> */ >> +#define ONENAND_PAGES_PER_BLOCK (1<<6) >> + >> #define ONENAND_CURRENT_BUFFERRAM(this) (this->bufferram_index) >> #define ONENAND_NEXT_BUFFERRAM(this) (this->bufferram_index ^ 1) >> #define ONENAND_SET_NEXT_BUFFERRAM(this) (this->bufferram_index ^= 1) >> >> > -- > Best Regards, > Artem Bityutskiy (Артём Битюцкий) >