しょっぱなからマニアックな誰得投稿です。
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);