diff options
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0002.c | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 8901c4412daf..ddc5bd783354 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -45,9 +45,11 @@ #define MAX_WORD_RETRIES 3 #define MANUFACTURER_AMD 0x0001 +#define MANUFACTURER_ATMEL 0x001F #define MANUFACTURER_SST 0x00BF #define SST49LF004B 0x0060 #define SST49LF008A 0x005a +#define AT49BV6416 0x00d6 static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); @@ -68,6 +70,9 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr); #include "fwh_lock.h" +static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, size_t len); +static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, size_t len); + static struct mtd_chip_driver cfi_amdstd_chipdrv = { .probe = NULL, /* Not usable directly */ .destroy = cfi_amdstd_destroy, @@ -199,6 +204,16 @@ static void fixup_use_erase_chip(struct mtd_info *mtd, void *param) } +/* + * Some Atmel chips (e.g. the AT49BV6416) power-up with all sectors + * locked by default. + */ +static void fixup_use_atmel_lock(struct mtd_info *mtd, void *param) +{ + mtd->lock = cfi_atmel_lock; + mtd->unlock = cfi_atmel_unlock; +} + static struct cfi_fixup cfi_fixup_table[] = { #ifdef AMD_BOOTLOC_BUG { CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock, NULL }, @@ -228,6 +243,7 @@ static struct cfi_fixup fixup_table[] = { * we know that is the case. */ { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_erase_chip, NULL }, + { CFI_MFR_ATMEL, AT49BV6416, fixup_use_atmel_lock, NULL }, { 0, 0, NULL, NULL } }; @@ -1628,6 +1644,80 @@ static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr) return 0; } +static int do_atmel_lock(struct map_info *map, struct flchip *chip, + unsigned long adr, int len, void *thunk) +{ + struct cfi_private *cfi = map->fldrv_priv; + int ret; + + spin_lock(chip->mutex); + ret = get_chip(map, chip, adr + chip->start, FL_LOCKING); + if (ret) + goto out_unlock; + chip->state = FL_LOCKING; + + DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): LOCK 0x%08lx len %d\n", + __func__, adr, len); + + 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(0x80, cfi->addr_unlock1, chip->start, map, cfi, + cfi->device_type, NULL); + 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); + map_write(map, CMD(0x40), chip->start + adr); + + chip->state = FL_READY; + put_chip(map, chip, adr + chip->start); + ret = 0; + +out_unlock: + spin_unlock(chip->mutex); + return ret; +} + +static int do_atmel_unlock(struct map_info *map, struct flchip *chip, + unsigned long adr, int len, void *thunk) +{ + struct cfi_private *cfi = map->fldrv_priv; + int ret; + + spin_lock(chip->mutex); + ret = get_chip(map, chip, adr + chip->start, FL_UNLOCKING); + if (ret) + goto out_unlock; + chip->state = FL_UNLOCKING; + + DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): LOCK 0x%08lx len %d\n", + __func__, adr, len); + + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, + cfi->device_type, NULL); + map_write(map, CMD(0x70), adr); + + chip->state = FL_READY; + put_chip(map, chip, adr + chip->start); + ret = 0; + +out_unlock: + spin_unlock(chip->mutex); + return ret; +} + +static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + return cfi_varsize_frob(mtd, do_atmel_lock, ofs, len, NULL); +} + +static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + return cfi_varsize_frob(mtd, do_atmel_unlock, ofs, len, NULL); +} + static void cfi_amdstd_sync (struct mtd_info *mtd) { |