[MTD] [NOR] Fix cfi_send_gen_cmd handling of x16 devices in x8 mode (v4)

For "unlock" cycles to 16bit devices in 8bit compatibility mode we need
to use the byte addresses 0xaaa and 0x555. These effectively match
the word address 0x555 and 0x2aa, except the latter has its low bit set.

Most chips don't care about the value of the 'A-1' pin in x8 mode,
but some -- like the ST M29W320D -- do. So we need to be careful to
set it where appropriate.

cfi_send_gen_cmd is only ever passed addresses where the low byte
is 0x00, 0x55 or 0xaa. Of those, only addresses ending 0xaa are
affected by this patch, by masking in the extra low bit when the device
is known to be in compatibility mode.

[dwmw2: Do it only when (cmd_ofs & 0xff) == 0xaa]
v4: Fix stupid typo in cfi_build_cmd_addr that failed to compile
I'm writing this patch way to late at night.
v3: Bring all of the work back into cfi_build_cmd_addr
including calling of map_bankwidth(map) and cfi_interleave(cfi)
So every caller doesn't need to.
v2: Only modified the address if we our device_type is larger than our
bus width.

Cc: stable@kernel.org
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>

authored by Eric W. Biederman and committed by David Woodhouse 467622ef b27cf88e

+23 -22
-13
drivers/mtd/chips/cfi_cmdset_0002.c
··· 406 /* Set the default CFI lock/unlock addresses */ 407 cfi->addr_unlock1 = 0x555; 408 cfi->addr_unlock2 = 0x2aa; 409 - /* Modify the unlock address if we are in compatibility mode */ 410 - if ( /* x16 in x8 mode */ 411 - ((cfi->device_type == CFI_DEVICETYPE_X8) && 412 - (cfi->cfiq->InterfaceDesc == 413 - CFI_INTERFACE_X8_BY_X16_ASYNC)) || 414 - /* x32 in x16 mode */ 415 - ((cfi->device_type == CFI_DEVICETYPE_X16) && 416 - (cfi->cfiq->InterfaceDesc == 417 - CFI_INTERFACE_X16_BY_X32_ASYNC))) 418 - { 419 - cfi->addr_unlock1 = 0xaaa; 420 - cfi->addr_unlock2 = 0x555; 421 - } 422 423 } /* CFI mode */ 424 else if (cfi->cfi_mode == CFI_MODE_JEDEC) {
··· 406 /* Set the default CFI lock/unlock addresses */ 407 cfi->addr_unlock1 = 0x555; 408 cfi->addr_unlock2 = 0x2aa; 409 410 } /* CFI mode */ 411 else if (cfi->cfi_mode == CFI_MODE_JEDEC) {
+4 -6
drivers/mtd/chips/jedec_probe.c
··· 1808 * several first banks can contain 0x7f instead of actual ID 1809 */ 1810 do { 1811 - uint32_t ofs = cfi_build_cmd_addr(0 + (bank << 8), 1812 - cfi_interleave(cfi), 1813 - cfi->device_type); 1814 mask = (1 << (cfi->device_type * 8)) - 1; 1815 result = map_read(map, base + ofs); 1816 bank++; ··· 1822 { 1823 map_word result; 1824 unsigned long mask; 1825 - u32 ofs = cfi_build_cmd_addr(1, cfi_interleave(cfi), cfi->device_type); 1826 mask = (1 << (cfi->device_type * 8)) -1; 1827 result = map_read(map, base + ofs); 1828 return result.x[0] & mask; ··· 2065 2066 } 2067 /* Ensure the unlock addresses we try stay inside the map */ 2068 - probe_offset1 = cfi_build_cmd_addr(cfi->addr_unlock1, cfi_interleave(cfi), cfi->device_type); 2069 - probe_offset2 = cfi_build_cmd_addr(cfi->addr_unlock2, cfi_interleave(cfi), cfi->device_type); 2070 if ( ((base + probe_offset1 + map_bankwidth(map)) >= map->size) || 2071 ((base + probe_offset2 + map_bankwidth(map)) >= map->size)) 2072 goto retry;
··· 1808 * several first banks can contain 0x7f instead of actual ID 1809 */ 1810 do { 1811 + uint32_t ofs = cfi_build_cmd_addr(0 + (bank << 8), map, cfi); 1812 mask = (1 << (cfi->device_type * 8)) - 1; 1813 result = map_read(map, base + ofs); 1814 bank++; ··· 1824 { 1825 map_word result; 1826 unsigned long mask; 1827 + u32 ofs = cfi_build_cmd_addr(1, map, cfi); 1828 mask = (1 << (cfi->device_type * 8)) -1; 1829 result = map_read(map, base + ofs); 1830 return result.x[0] & mask; ··· 2067 2068 } 2069 /* Ensure the unlock addresses we try stay inside the map */ 2070 + probe_offset1 = cfi_build_cmd_addr(cfi->addr_unlock1, map, cfi); 2071 + probe_offset2 = cfi_build_cmd_addr(cfi->addr_unlock2, map, cfi); 2072 if ( ((base + probe_offset1 + map_bankwidth(map)) >= map->size) || 2073 ((base + probe_offset2 + map_bankwidth(map)) >= map->size)) 2074 goto retry;
+19 -3
include/linux/mtd/cfi.h
··· 282 /* 283 * Returns the command address according to the given geometry. 284 */ 285 - static inline uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs, int interleave, int type) 286 { 287 - return (cmd_ofs * type) * interleave; 288 } 289 290 /* ··· 446 int type, map_word *prev_val) 447 { 448 map_word val; 449 - uint32_t addr = base + cfi_build_cmd_addr(cmd_addr, cfi_interleave(cfi), type); 450 val = cfi_build_cmd(cmd, map, cfi); 451 452 if (prev_val)
··· 282 /* 283 * Returns the command address according to the given geometry. 284 */ 285 + static inline uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs, 286 + struct map_info *map, struct cfi_private *cfi) 287 { 288 + unsigned bankwidth = map_bankwidth(map); 289 + unsigned interleave = cfi_interleave(cfi); 290 + unsigned type = cfi->device_type; 291 + uint32_t addr; 292 + 293 + addr = (cmd_ofs * type) * interleave; 294 + 295 + /* Modify the unlock address if we are in compatiblity mode. 296 + * For 16bit devices on 8 bit busses 297 + * and 32bit devices on 16 bit busses 298 + * set the low bit of the alternating bit sequence of the address. 299 + */ 300 + if (((type * interleave) > bankwidth) && ((uint8_t)cmd_ofs == 0xaa)) 301 + addr |= (type >> 1)*interleave; 302 + 303 + return addr; 304 } 305 306 /* ··· 430 int type, map_word *prev_val) 431 { 432 map_word val; 433 + uint32_t addr = base + cfi_build_cmd_addr(cmd_addr, map, cfi); 434 val = cfi_build_cmd(cmd, map, cfi); 435 436 if (prev_val)