Skip to content

Instantly share code, notes, and snippets.

@chromabox
Created April 12, 2013 08:05
Show Gist options
  • Save chromabox/5370360 to your computer and use it in GitHub Desktop.
Save chromabox/5370360 to your computer and use it in GitHub Desktop.
Advanced Sector Protection (PPB) support for LINUX
#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 */
@chromabox
Copy link
Author

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

いろいろロック形式はありますが、とりあえずSPBだけ対応してます。
これを当てるとmtd-utilsでNORのセクタロック・アンロックが出来るようになります。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment