3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[Linux-kernel] Advanced Sector Protectionの機能がついてるNORフラッシュのロック・アンロック対応

Posted at

しょっぱなからマニアックな誰得投稿です。

LinuxでAdvanced Sector Protectionの機能がついてるNORフラッシュのロック・アンロック対応してないっぽいので最近のU-bootを見ながら書きました。

NORフラッシュにはいろいろロック形式はありますが、とりあえずSPBだけ対応してます。
これを当てるとmtd-utilsでNORのセクタロック・アンロックが出来るようになります。
つまり、U-boot上でロックされたセクタをアンロックしたり、その逆がLinux上のコマンドで出来るようになります。

もしかしたら最近のカーネルではすでに対応しているかもしれません。

(この記事は私が書いた https://gist.github.com/chromabox/5370360 の転載です。glistだと埋もれて自分が困るので、、、)

cfi_ppb_lock.h
#ifndef PPB_LOCK_H
#define PPB_LOCK_H

#define AMD_CMD_SET_PPB_ENTRY           0xC0
#define AMD_CMD_SET_PPB_EXIT_BC1        0x90
#define AMD_CMD_SET_PPB_EXIT_BC2        0x00
#define AMD_CMD_PPB_UNLOCK_BC1          0x80
#define AMD_CMD_PPB_UNLOCK_BC2          0x30
#define AMD_CMD_PPB_LOCK_BC1            0xA0
#define AMD_CMD_PPB_LOCK_BC2            0x00

enum ppb_lock_state {
    PPB_LOCK = 0,
    PPB_UNLOCK = 1,
};

struct ppb_lock_thunk {
    enum ppb_lock_state val;
};

#define PPB_LOCK_ONEBLOCK_LOCK   ((struct ppb_lock_thunk){ PPB_LOCK })
#define PPB_LOCK_ONEBLOCK_UNLOCK ((struct ppb_lock_thunk){ PPB_UNLOCK })

static int __xipram chip_ready(struct map_info *map, unsigned long addr);

static int do_cfi_ppb_lock_oneblock(struct map_info *map, struct flchip *chip,
    unsigned long adr, int len, void *thunk)
{
    struct cfi_private *cfi = map->fldrv_priv;
    struct ppb_lock_thunk *th = (struct ppb_lock_thunk *)thunk;

    unsigned long timeo;
    int ret = 0;
    uint16_t lock_flag;

    DEBUG(MTD_DEBUG_LEVEL1,
        "do_cfi_ppb_lock_oneblock: start %08lX adr %08lX \n",chip->start,adr);
    adr += chip->start;

    mutex_lock(&chip->mutex);
    ret = get_chip(map, chip, adr, FL_LOCKING);
    if (ret) {
        mutex_unlock(&chip->mutex);
        return ret;
    }
    chip->oldstate = chip->state;
    chip->state = FL_LOCKING;

    DEBUG(MTD_DEBUG_LEVEL1,
        "do_cfi_ppb_lock_oneblock: adr %08lX\n",adr);

    // enter PPB mode
    cfi_send_gen_cmd(0xAA,                  cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
    cfi_send_gen_cmd(0x55,                  cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);  
    cfi_send_gen_cmd(AMD_CMD_SET_PPB_ENTRY, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);

    lock_flag = cfi_read_query16(map,adr);
    DEBUG(MTD_DEBUG_LEVEL1,
        "do_cfi_ppb_lock_oneblock: lockflg=%d,%s\n",lock_flag,(lock_flag == PPB_UNLOCK) ? "Unlocked":"Locked");

    // Lock or Unlock
    if(th->val == PPB_LOCK){
        map_write(map, CMD(AMD_CMD_PPB_LOCK_BC1), adr);
        map_write(map, CMD(AMD_CMD_PPB_LOCK_BC2), adr);
    }else{
        // unlock is no sector spec
        cfi_send_gen_cmd(AMD_CMD_PPB_UNLOCK_BC1,0, chip->start, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(AMD_CMD_PPB_UNLOCK_BC2,0, chip->start, map, cfi, cfi->device_type, NULL);
    }

    // wait...
    timeo = jiffies + (HZ*20);

    for(;;){
        if(chip_ready(map,adr)) break;

        if (time_after(jiffies, timeo)) {
            printk(KERN_WARNING "MTD %s(): software timeout\n",
                __func__ );
            break;
        }
        mutex_unlock(&chip->mutex);
        cfi_udelay(1000000/HZ);
        mutex_lock(&chip->mutex);
    }
    // exit PPB mode
    cfi_send_gen_cmd(AMD_CMD_SET_PPB_EXIT_BC1,0, chip->start, map, cfi, cfi->device_type, NULL);
    cfi_send_gen_cmd(AMD_CMD_SET_PPB_EXIT_BC2,0, chip->start, map, cfi, cfi->device_type, NULL);    

    chip->state = chip->oldstate;
    put_chip(map, chip, adr);
    mutex_unlock(&chip->mutex);
    return ret;
}


static int cfi_ppb_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
    int ret;

    ret = cfi_varsize_frob(mtd, do_cfi_ppb_lock_oneblock, ofs, len,
        (void *)&PPB_LOCK_ONEBLOCK_LOCK);

    return ret;
}


static int cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
    int ret;

    ret = cfi_varsize_frob(mtd, do_cfi_ppb_lock_oneblock, ofs, len,
        (void *)&PPB_LOCK_ONEBLOCK_UNLOCK);

    return ret;
}


/* PBB fixup*/
static void cfi_fixup_ppb_unlock(struct cfi_pri_amdstd *extp,struct mtd_info *mtd)
{
    /* read sector protect/unprotect scheme is 0x08 to old scheme */
    if(extp->BlkProtUnprot != 8) return;

    printk(KERN_INFO "Advanced Sector Protection (PPB) enabled\n");
    printk(KERN_INFO "Use PPB lock/unlock method \n");
    mtd->lock   = cfi_ppb_lock;
    mtd->unlock = cfi_ppb_unlock;
}

#endif /* PPB_LOCK_H */
cfi_cmdset_0002.patch
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002
old mode 100644
new mode 100755
index d81079e..7ba6a65
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -68,6 +68,7 @@ static struct mtd_info *cfi_amdstd_setup (struct mtd_info *);
 static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, i
 static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr);
 #include "fwh_lock.h"
+#include "cfi_ppb_lock.h"

 static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
 static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
@@ -461,6 +462,9 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int prima
                        /* Set the default CFI lock/unlock addresses */
                        cfi->addr_unlock1 = 0x555;
                        cfi->addr_unlock2 = 0x2aa;
+                                               
+                       /* read sector protect/unprotect scheme is 0x08 to old schem
+                       cfi_fixup_ppb_unlock(extp,mtd);
                }
                cfi_fixup(mtd, cfi_nopri_fixup_table);
3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?