Created
April 12, 2013 08:05
-
-
Save chromabox/5370360 to your computer and use it in GitHub Desktop.
Advanced Sector Protection (PPB) support for LINUX
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
LinuxでAdvanced Sector Protectionの機能がついてるNORフラッシュのロック・アンロック対応してないっぽいので最近のU-bootを見ながら書きました。
いろいろロック形式はありますが、とりあえずSPBだけ対応してます。
これを当てるとmtd-utilsでNORのセクタロック・アンロックが出来るようになります。