diff options
Diffstat (limited to 'drivers/mtd/chips/cfi_cmdset_0002.c')
-rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0002.c | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 9885726a16e4..a482e8922de1 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c | |||
@@ -45,9 +45,11 @@ | |||
45 | #define MAX_WORD_RETRIES 3 | 45 | #define MAX_WORD_RETRIES 3 |
46 | 46 | ||
47 | #define MANUFACTURER_AMD 0x0001 | 47 | #define MANUFACTURER_AMD 0x0001 |
48 | #define MANUFACTURER_ATMEL 0x001F | ||
48 | #define MANUFACTURER_SST 0x00BF | 49 | #define MANUFACTURER_SST 0x00BF |
49 | #define SST49LF004B 0x0060 | 50 | #define SST49LF004B 0x0060 |
50 | #define SST49LF008A 0x005a | 51 | #define SST49LF008A 0x005a |
52 | #define AT49BV6416 0x00d6 | ||
51 | 53 | ||
52 | static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); | 54 | static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); |
53 | static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); | 55 | 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 | |||
68 | static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr); | 70 | static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr); |
69 | #include "fwh_lock.h" | 71 | #include "fwh_lock.h" |
70 | 72 | ||
73 | static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, size_t len); | ||
74 | static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, size_t len); | ||
75 | |||
71 | static struct mtd_chip_driver cfi_amdstd_chipdrv = { | 76 | static struct mtd_chip_driver cfi_amdstd_chipdrv = { |
72 | .probe = NULL, /* Not usable directly */ | 77 | .probe = NULL, /* Not usable directly */ |
73 | .destroy = cfi_amdstd_destroy, | 78 | .destroy = cfi_amdstd_destroy, |
@@ -161,6 +166,26 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) | |||
161 | } | 166 | } |
162 | } | 167 | } |
163 | 168 | ||
169 | /* Atmel chips don't use the same PRI format as AMD chips */ | ||
170 | static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param) | ||
171 | { | ||
172 | struct map_info *map = mtd->priv; | ||
173 | struct cfi_private *cfi = map->fldrv_priv; | ||
174 | struct cfi_pri_amdstd *extp = cfi->cmdset_priv; | ||
175 | struct cfi_pri_atmel atmel_pri; | ||
176 | |||
177 | memcpy(&atmel_pri, extp, sizeof(atmel_pri)); | ||
178 | memset((char *)extp + 5, 0, sizeof(*extp) - 5); | ||
179 | |||
180 | if (atmel_pri.Features & 0x02) | ||
181 | extp->EraseSuspend = 2; | ||
182 | |||
183 | if (atmel_pri.BottomBoot) | ||
184 | extp->TopBottom = 2; | ||
185 | else | ||
186 | extp->TopBottom = 3; | ||
187 | } | ||
188 | |||
164 | static void fixup_use_secsi(struct mtd_info *mtd, void *param) | 189 | static void fixup_use_secsi(struct mtd_info *mtd, void *param) |
165 | { | 190 | { |
166 | /* Setup for chips with a secsi area */ | 191 | /* Setup for chips with a secsi area */ |
@@ -179,6 +204,16 @@ static void fixup_use_erase_chip(struct mtd_info *mtd, void *param) | |||
179 | 204 | ||
180 | } | 205 | } |
181 | 206 | ||
207 | /* | ||
208 | * Some Atmel chips (e.g. the AT49BV6416) power-up with all sectors | ||
209 | * locked by default. | ||
210 | */ | ||
211 | static void fixup_use_atmel_lock(struct mtd_info *mtd, void *param) | ||
212 | { | ||
213 | mtd->lock = cfi_atmel_lock; | ||
214 | mtd->unlock = cfi_atmel_unlock; | ||
215 | } | ||
216 | |||
182 | static struct cfi_fixup cfi_fixup_table[] = { | 217 | static struct cfi_fixup cfi_fixup_table[] = { |
183 | #ifdef AMD_BOOTLOC_BUG | 218 | #ifdef AMD_BOOTLOC_BUG |
184 | { CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock, NULL }, | 219 | { CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock, NULL }, |
@@ -192,6 +227,7 @@ static struct cfi_fixup cfi_fixup_table[] = { | |||
192 | #if !FORCE_WORD_WRITE | 227 | #if !FORCE_WORD_WRITE |
193 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, }, | 228 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, }, |
194 | #endif | 229 | #endif |
230 | { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL }, | ||
195 | { 0, 0, NULL, NULL } | 231 | { 0, 0, NULL, NULL } |
196 | }; | 232 | }; |
197 | static struct cfi_fixup jedec_fixup_table[] = { | 233 | static struct cfi_fixup jedec_fixup_table[] = { |
@@ -207,6 +243,7 @@ static struct cfi_fixup fixup_table[] = { | |||
207 | * we know that is the case. | 243 | * we know that is the case. |
208 | */ | 244 | */ |
209 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_erase_chip, NULL }, | 245 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_erase_chip, NULL }, |
246 | { CFI_MFR_ATMEL, AT49BV6416, fixup_use_atmel_lock, NULL }, | ||
210 | { 0, 0, NULL, NULL } | 247 | { 0, 0, NULL, NULL } |
211 | }; | 248 | }; |
212 | 249 | ||
@@ -1607,6 +1644,80 @@ static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr) | |||
1607 | return 0; | 1644 | return 0; |
1608 | } | 1645 | } |
1609 | 1646 | ||
1647 | static int do_atmel_lock(struct map_info *map, struct flchip *chip, | ||
1648 | unsigned long adr, int len, void *thunk) | ||
1649 | { | ||
1650 | struct cfi_private *cfi = map->fldrv_priv; | ||
1651 | int ret; | ||
1652 | |||
1653 | spin_lock(chip->mutex); | ||
1654 | ret = get_chip(map, chip, adr + chip->start, FL_LOCKING); | ||
1655 | if (ret) | ||
1656 | goto out_unlock; | ||
1657 | chip->state = FL_LOCKING; | ||
1658 | |||
1659 | DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): LOCK 0x%08lx len %d\n", | ||
1660 | __func__, adr, len); | ||
1661 | |||
1662 | cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, | ||
1663 | cfi->device_type, NULL); | ||
1664 | cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, | ||
1665 | cfi->device_type, NULL); | ||
1666 | cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, | ||
1667 | cfi->device_type, NULL); | ||
1668 | cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, | ||
1669 | cfi->device_type, NULL); | ||
1670 | cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, | ||
1671 | cfi->device_type, NULL); | ||
1672 | map_write(map, CMD(0x40), chip->start + adr); | ||
1673 | |||
1674 | chip->state = FL_READY; | ||
1675 | put_chip(map, chip, adr + chip->start); | ||
1676 | ret = 0; | ||
1677 | |||
1678 | out_unlock: | ||
1679 | spin_unlock(chip->mutex); | ||
1680 | return ret; | ||
1681 | } | ||
1682 | |||
1683 | static int do_atmel_unlock(struct map_info *map, struct flchip *chip, | ||
1684 | unsigned long adr, int len, void *thunk) | ||
1685 | { | ||
1686 | struct cfi_private *cfi = map->fldrv_priv; | ||
1687 | int ret; | ||
1688 | |||
1689 | spin_lock(chip->mutex); | ||
1690 | ret = get_chip(map, chip, adr + chip->start, FL_UNLOCKING); | ||
1691 | if (ret) | ||
1692 | goto out_unlock; | ||
1693 | chip->state = FL_UNLOCKING; | ||
1694 | |||
1695 | DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): LOCK 0x%08lx len %d\n", | ||
1696 | __func__, adr, len); | ||
1697 | |||
1698 | cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, | ||
1699 | cfi->device_type, NULL); | ||
1700 | map_write(map, CMD(0x70), adr); | ||
1701 | |||
1702 | chip->state = FL_READY; | ||
1703 | put_chip(map, chip, adr + chip->start); | ||
1704 | ret = 0; | ||
1705 | |||
1706 | out_unlock: | ||
1707 | spin_unlock(chip->mutex); | ||
1708 | return ret; | ||
1709 | } | ||
1710 | |||
1711 | static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, size_t len) | ||
1712 | { | ||
1713 | return cfi_varsize_frob(mtd, do_atmel_lock, ofs, len, NULL); | ||
1714 | } | ||
1715 | |||
1716 | static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) | ||
1717 | { | ||
1718 | return cfi_varsize_frob(mtd, do_atmel_unlock, ofs, len, NULL); | ||
1719 | } | ||
1720 | |||
1610 | 1721 | ||
1611 | static void cfi_amdstd_sync (struct mtd_info *mtd) | 1722 | static void cfi_amdstd_sync (struct mtd_info *mtd) |
1612 | { | 1723 | { |