Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mtd: OneNAND OTP support rework

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 good
block.

Why it is done?
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

[comments were slightly tweaked by Artem]

Signed-off-by: Amul Kumar Saha <amul.saha@samsung.com>
Reviewed-by: Adrian Hunter <adrian.hunter@nokia.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>

authored by

Amul Kumar Saha and committed by
David Woodhouse
3cf60253 782e5711

+264 -32
+261 -31
drivers/mtd/onenand/onenand_base.c
··· 1 1 /* 2 2 * linux/drivers/mtd/onenand/onenand_base.c 3 3 * 4 - * Copyright (C) 2005-2007 Samsung Electronics 4 + * Copyright © 2005-2009 Samsung Electronics 5 + * Copyright © 2007 Nokia Corporation 6 + * 5 7 * Kyungmin Park <kyungmin.park@samsung.com> 6 8 * 7 9 * Credits: 8 10 * Adrian Hunter <ext-adrian.hunter@nokia.com>: 9 11 * auto-placement support, read-while load support, various fixes 10 - * Copyright (C) Nokia Corporation, 2007 11 12 * 12 13 * Vishak G <vishak.g at samsung.com>, Rohit Hagargundgi <h.rohit at samsung.com> 13 14 * Flex-OneNAND support 14 - * Copyright (C) Samsung Electronics, 2008 15 + * Amul Kumar Saha <amul.saha at samsung.com> 16 + * OTP support 15 17 * 16 18 * This program is free software; you can redistribute it and/or modify 17 19 * it under the terms of the GNU General Public License version 2 as ··· 44 42 "LOCK: Locking information for SLC boundary" 45 43 " : 0->Set boundary in unlocked status" 46 44 " : 1->Set boundary in locked status"); 45 + 46 + /* Default OneNAND/Flex-OneNAND OTP options*/ 47 + static int otp; 48 + 49 + module_param(otp, int, 0400); 50 + MODULE_PARM_DESC(otp, "Corresponding behaviour of OneNAND in OTP" 51 + "Syntax : otp=LOCK_TYPE" 52 + "LOCK_TYPE : Keys issued, for specific OTP Lock type" 53 + " : 0 -> Default (No Blocks Locked)" 54 + " : 1 -> OTP Block lock" 55 + " : 2 -> 1st Block lock" 56 + " : 3 -> BOTH OTP Block and 1st Block lock"); 47 57 48 58 /** 49 59 * onenand_oob_128 - oob info for Flex-Onenand with 4KB page ··· 2605 2591 2606 2592 #ifdef CONFIG_MTD_ONENAND_OTP 2607 2593 2594 + /** 2595 + * onenand_otp_command - Send OTP specific command to OneNAND device 2596 + * @param mtd MTD device structure 2597 + * @param cmd the command to be sent 2598 + * @param addr offset to read from or write to 2599 + * @param len number of bytes to read or write 2600 + */ 2601 + static int onenand_otp_command(struct mtd_info *mtd, int cmd, loff_t addr, 2602 + size_t len) 2603 + { 2604 + struct onenand_chip *this = mtd->priv; 2605 + int value, block, page; 2606 + 2607 + /* Address translation */ 2608 + switch (cmd) { 2609 + case ONENAND_CMD_OTP_ACCESS: 2610 + block = (int) (addr >> this->erase_shift); 2611 + page = -1; 2612 + break; 2613 + 2614 + default: 2615 + block = (int) (addr >> this->erase_shift); 2616 + page = (int) (addr >> this->page_shift); 2617 + 2618 + if (ONENAND_IS_2PLANE(this)) { 2619 + /* Make the even block number */ 2620 + block &= ~1; 2621 + /* Is it the odd plane? */ 2622 + if (addr & this->writesize) 2623 + block++; 2624 + page >>= 1; 2625 + } 2626 + page &= this->page_mask; 2627 + break; 2628 + } 2629 + 2630 + if (block != -1) { 2631 + /* Write 'DFS, FBA' of Flash */ 2632 + value = onenand_block_address(this, block); 2633 + this->write_word(value, this->base + 2634 + ONENAND_REG_START_ADDRESS1); 2635 + } 2636 + 2637 + if (page != -1) { 2638 + /* Now we use page size operation */ 2639 + int sectors = 4, count = 4; 2640 + int dataram; 2641 + 2642 + switch (cmd) { 2643 + default: 2644 + if (ONENAND_IS_2PLANE(this) && cmd == ONENAND_CMD_PROG) 2645 + cmd = ONENAND_CMD_2X_PROG; 2646 + dataram = ONENAND_CURRENT_BUFFERRAM(this); 2647 + break; 2648 + } 2649 + 2650 + /* Write 'FPA, FSA' of Flash */ 2651 + value = onenand_page_address(page, sectors); 2652 + this->write_word(value, this->base + 2653 + ONENAND_REG_START_ADDRESS8); 2654 + 2655 + /* Write 'BSA, BSC' of DataRAM */ 2656 + value = onenand_buffer_address(dataram, sectors, count); 2657 + this->write_word(value, this->base + ONENAND_REG_START_BUFFER); 2658 + } 2659 + 2660 + /* Interrupt clear */ 2661 + this->write_word(ONENAND_INT_CLEAR, this->base + ONENAND_REG_INTERRUPT); 2662 + 2663 + /* Write command */ 2664 + this->write_word(cmd, this->base + ONENAND_REG_COMMAND); 2665 + 2666 + return 0; 2667 + } 2668 + 2669 + /** 2670 + * onenand_otp_write_oob_nolock - [Internal] OneNAND write out-of-band, specific to OTP 2671 + * @param mtd MTD device structure 2672 + * @param to offset to write to 2673 + * @param len number of bytes to write 2674 + * @param retlen pointer to variable to store the number of written bytes 2675 + * @param buf the data to write 2676 + * 2677 + * OneNAND write out-of-band only for OTP 2678 + */ 2679 + static int onenand_otp_write_oob_nolock(struct mtd_info *mtd, loff_t to, 2680 + struct mtd_oob_ops *ops) 2681 + { 2682 + struct onenand_chip *this = mtd->priv; 2683 + int column, ret = 0, oobsize; 2684 + int written = 0; 2685 + u_char *oobbuf; 2686 + size_t len = ops->ooblen; 2687 + const u_char *buf = ops->oobbuf; 2688 + int block, value, status; 2689 + 2690 + to += ops->ooboffs; 2691 + 2692 + /* Initialize retlen, in case of early exit */ 2693 + ops->oobretlen = 0; 2694 + 2695 + oobsize = mtd->oobsize; 2696 + 2697 + column = to & (mtd->oobsize - 1); 2698 + 2699 + oobbuf = this->oob_buf; 2700 + 2701 + /* Loop until all data write */ 2702 + while (written < len) { 2703 + int thislen = min_t(int, oobsize, len - written); 2704 + 2705 + cond_resched(); 2706 + 2707 + block = (int) (to >> this->erase_shift); 2708 + /* 2709 + * Write 'DFS, FBA' of Flash 2710 + * Add: F100h DQ=DFS, FBA 2711 + */ 2712 + 2713 + value = onenand_block_address(this, block); 2714 + this->write_word(value, this->base + 2715 + ONENAND_REG_START_ADDRESS1); 2716 + 2717 + /* 2718 + * Select DataRAM for DDP 2719 + * Add: F101h DQ=DBS 2720 + */ 2721 + 2722 + value = onenand_bufferram_address(this, block); 2723 + this->write_word(value, this->base + 2724 + ONENAND_REG_START_ADDRESS2); 2725 + ONENAND_SET_NEXT_BUFFERRAM(this); 2726 + 2727 + /* 2728 + * Enter OTP access mode 2729 + */ 2730 + this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); 2731 + this->wait(mtd, FL_OTPING); 2732 + 2733 + /* We send data to spare ram with oobsize 2734 + * to prevent byte access */ 2735 + memcpy(oobbuf + column, buf, thislen); 2736 + 2737 + /* 2738 + * Write Data into DataRAM 2739 + * Add: 8th Word 2740 + * in sector0/spare/page0 2741 + * DQ=XXFCh 2742 + */ 2743 + this->write_bufferram(mtd, ONENAND_SPARERAM, 2744 + oobbuf, 0, mtd->oobsize); 2745 + 2746 + onenand_otp_command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize); 2747 + onenand_update_bufferram(mtd, to, 0); 2748 + if (ONENAND_IS_2PLANE(this)) { 2749 + ONENAND_SET_BUFFERRAM1(this); 2750 + onenand_update_bufferram(mtd, to + this->writesize, 0); 2751 + } 2752 + 2753 + ret = this->wait(mtd, FL_WRITING); 2754 + if (ret) { 2755 + printk(KERN_ERR "%s: write failed %d\n", __func__, ret); 2756 + break; 2757 + } 2758 + 2759 + /* Exit OTP access mode */ 2760 + this->command(mtd, ONENAND_CMD_RESET, 0, 0); 2761 + this->wait(mtd, FL_RESETING); 2762 + 2763 + status = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); 2764 + status &= 0x60; 2765 + 2766 + if (status == 0x60) { 2767 + printk(KERN_DEBUG "\nBLOCK\tSTATUS\n"); 2768 + printk(KERN_DEBUG "1st Block\tLOCKED\n"); 2769 + printk(KERN_DEBUG "OTP Block\tLOCKED\n"); 2770 + } else if (status == 0x20) { 2771 + printk(KERN_DEBUG "\nBLOCK\tSTATUS\n"); 2772 + printk(KERN_DEBUG "1st Block\tLOCKED\n"); 2773 + printk(KERN_DEBUG "OTP Block\tUN-LOCKED\n"); 2774 + } else if (status == 0x40) { 2775 + printk(KERN_DEBUG "\nBLOCK\tSTATUS\n"); 2776 + printk(KERN_DEBUG "1st Block\tUN-LOCKED\n"); 2777 + printk(KERN_DEBUG "OTP Block\tLOCKED\n"); 2778 + } else { 2779 + printk(KERN_DEBUG "Reboot to check\n"); 2780 + } 2781 + 2782 + written += thislen; 2783 + if (written == len) 2784 + break; 2785 + 2786 + to += mtd->writesize; 2787 + buf += thislen; 2788 + column = 0; 2789 + } 2790 + 2791 + ops->oobretlen = written; 2792 + 2793 + return ret; 2794 + } 2795 + 2608 2796 /* Internal OTP operation */ 2609 2797 typedef int (*otp_op_t)(struct mtd_info *mtd, loff_t form, size_t len, 2610 2798 size_t *retlen, u_char *buf); ··· 2909 2693 struct mtd_oob_ops ops; 2910 2694 int ret; 2911 2695 2912 - /* Enter OTP access mode */ 2913 - this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); 2914 - this->wait(mtd, FL_OTPING); 2915 - 2916 2696 if (FLEXONENAND(this)) { 2697 + 2698 + /* Enter OTP access mode */ 2699 + this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); 2700 + this->wait(mtd, FL_OTPING); 2917 2701 /* 2918 2702 * For Flex-OneNAND, we write lock mark to 1st word of sector 4 of 2919 2703 * main area of page 49. ··· 2924 2708 ops.oobbuf = NULL; 2925 2709 ret = onenand_write_ops_nolock(mtd, mtd->writesize * 49, &ops); 2926 2710 *retlen = ops.retlen; 2711 + 2712 + /* Exit OTP access mode */ 2713 + this->command(mtd, ONENAND_CMD_RESET, 0, 0); 2714 + this->wait(mtd, FL_RESETING); 2927 2715 } else { 2928 2716 ops.mode = MTD_OOB_PLACE; 2929 2717 ops.ooblen = len; 2930 2718 ops.oobbuf = buf; 2931 2719 ops.ooboffs = 0; 2932 - ret = onenand_write_oob_nolock(mtd, from, &ops); 2720 + ret = onenand_otp_write_oob_nolock(mtd, from, &ops); 2933 2721 *retlen = ops.oobretlen; 2934 2722 } 2935 - 2936 - /* Exit OTP access mode */ 2937 - this->command(mtd, ONENAND_CMD_RESET, 0, 0); 2938 - this->wait(mtd, FL_RESETING); 2939 2723 2940 2724 return ret; 2941 2725 } ··· 2967 2751 if (density < ONENAND_DEVICE_DENSITY_512Mb) 2968 2752 otp_pages = 20; 2969 2753 else 2970 - otp_pages = 10; 2754 + otp_pages = 50; 2971 2755 2972 2756 if (mode == MTD_OTP_FACTORY) { 2973 2757 from += mtd->writesize * otp_pages; 2974 - otp_pages = 64 - otp_pages; 2758 + otp_pages = ONENAND_PAGES_PER_BLOCK - otp_pages; 2975 2759 } 2976 2760 2977 2761 /* Check User/Factory boundary */ 2978 - if (((mtd->writesize * otp_pages) - (from + len)) < 0) 2979 - return 0; 2762 + if (mode == MTD_OTP_USER) { 2763 + if (((mtd->writesize * otp_pages) - (from + len)) < 0) 2764 + return 0; 2765 + } else { 2766 + if (((mtd->writesize * otp_pages) - len) < 0) 2767 + return 0; 2768 + } 2980 2769 2981 2770 onenand_get_device(mtd, FL_OTPING); 2982 2771 while (len > 0 && otp_pages > 0) { ··· 3004 2783 *retlen += sizeof(struct otp_info); 3005 2784 } else { 3006 2785 size_t tmp_retlen; 3007 - int size = len; 3008 2786 3009 2787 ret = action(mtd, from, len, &tmp_retlen, buf); 3010 2788 3011 - buf += size; 3012 - len -= size; 3013 - *retlen += size; 2789 + buf += tmp_retlen; 2790 + len -= tmp_retlen; 2791 + *retlen += tmp_retlen; 3014 2792 3015 2793 if (ret) 3016 2794 break; ··· 3122 2902 u_char *buf = FLEXONENAND(this) ? this->page_buf : this->oob_buf; 3123 2903 size_t retlen; 3124 2904 int ret; 2905 + unsigned int otp_lock_offset = ONENAND_OTP_LOCK_OFFSET; 3125 2906 3126 2907 memset(buf, 0xff, FLEXONENAND(this) ? this->writesize 3127 2908 : mtd->oobsize); 3128 - /* 3129 - * Note: OTP lock operation 3130 - * OTP block : 0xXXFC 3131 - * 1st block : 0xXXF3 (If chip support) 3132 - * Both : 0xXXF0 (If chip support) 3133 - */ 3134 - if (FLEXONENAND(this)) 3135 - buf[FLEXONENAND_OTP_LOCK_OFFSET] = 0xFC; 3136 - else 3137 - buf[ONENAND_OTP_LOCK_OFFSET] = 0xFC; 3138 - 3139 2909 /* 3140 2910 * Write lock mark to 8th word of sector0 of page0 of the spare0. 3141 2911 * We write 16 bytes spare area instead of 2 bytes. ··· 3136 2926 from = 0; 3137 2927 len = FLEXONENAND(this) ? mtd->writesize : 16; 3138 2928 2929 + /* 2930 + * Note: OTP lock operation 2931 + * OTP block : 0xXXFC XX 1111 1100 2932 + * 1st block : 0xXXF3 (If chip support) XX 1111 0011 2933 + * Both : 0xXXF0 (If chip support) XX 1111 0000 2934 + */ 2935 + if (FLEXONENAND(this)) 2936 + otp_lock_offset = FLEXONENAND_OTP_LOCK_OFFSET; 2937 + 2938 + /* ONENAND_OTP_AREA | ONENAND_OTP_BLOCK0 | ONENAND_OTP_AREA_BLOCK0 */ 2939 + if (otp == 1) 2940 + buf[otp_lock_offset] = 0xFC; 2941 + else if (otp == 2) 2942 + buf[otp_lock_offset] = 0xF3; 2943 + else if (otp == 3) 2944 + buf[otp_lock_offset] = 0xF0; 2945 + else if (otp != 0) 2946 + printk(KERN_DEBUG "[OneNAND] Invalid option selected for OTP\n"); 2947 + 3139 2948 ret = onenand_otp_walk(mtd, from, len, &retlen, buf, do_otp_lock, MTD_OTP_USER); 3140 2949 3141 2950 return ret ? : retlen; 3142 2951 } 2952 + 3143 2953 #endif /* CONFIG_MTD_ONENAND_OTP */ 3144 2954 3145 2955 /**
+3 -1
include/linux/mtd/onenand.h
··· 1 1 /* 2 2 * linux/include/linux/mtd/onenand.h 3 3 * 4 - * Copyright (C) 2005-2007 Samsung Electronics 4 + * Copyright © 2005-2009 Samsung Electronics 5 5 * Kyungmin Park <kyungmin.park@samsung.com> 6 6 * 7 7 * This program is free software; you can redistribute it and/or modify ··· 137 137 /* 138 138 * Helper macros 139 139 */ 140 + #define ONENAND_PAGES_PER_BLOCK (1<<6) 141 + 140 142 #define ONENAND_CURRENT_BUFFERRAM(this) (this->bufferram_index) 141 143 #define ONENAND_NEXT_BUFFERRAM(this) (this->bufferram_index ^ 1) 142 144 #define ONENAND_SET_NEXT_BUFFERRAM(this) (this->bufferram_index ^= 1)