[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 406 /* Set the default CFI lock/unlock addresses */ 407 407 cfi->addr_unlock1 = 0x555; 408 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 409 423 410 } /* CFI mode */ 424 411 else if (cfi->cfi_mode == CFI_MODE_JEDEC) {
+4 -6
drivers/mtd/chips/jedec_probe.c
··· 1808 1808 * several first banks can contain 0x7f instead of actual ID 1809 1809 */ 1810 1810 do { 1811 - uint32_t ofs = cfi_build_cmd_addr(0 + (bank << 8), 1812 - cfi_interleave(cfi), 1813 - cfi->device_type); 1811 + uint32_t ofs = cfi_build_cmd_addr(0 + (bank << 8), map, cfi); 1814 1812 mask = (1 << (cfi->device_type * 8)) - 1; 1815 1813 result = map_read(map, base + ofs); 1816 1814 bank++; ··· 1822 1824 { 1823 1825 map_word result; 1824 1826 unsigned long mask; 1825 - u32 ofs = cfi_build_cmd_addr(1, cfi_interleave(cfi), cfi->device_type); 1827 + u32 ofs = cfi_build_cmd_addr(1, map, cfi); 1826 1828 mask = (1 << (cfi->device_type * 8)) -1; 1827 1829 result = map_read(map, base + ofs); 1828 1830 return result.x[0] & mask; ··· 2065 2067 2066 2068 } 2067 2069 /* 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 + probe_offset1 = cfi_build_cmd_addr(cfi->addr_unlock1, map, cfi); 2071 + probe_offset2 = cfi_build_cmd_addr(cfi->addr_unlock2, map, cfi); 2070 2072 if ( ((base + probe_offset1 + map_bankwidth(map)) >= map->size) || 2071 2073 ((base + probe_offset2 + map_bankwidth(map)) >= map->size)) 2072 2074 goto retry;
+19 -3
include/linux/mtd/cfi.h
··· 282 282 /* 283 283 * Returns the command address according to the given geometry. 284 284 */ 285 - static inline uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs, int interleave, int type) 285 + static inline uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs, 286 + struct map_info *map, struct cfi_private *cfi) 286 287 { 287 - return (cmd_ofs * type) * interleave; 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; 288 304 } 289 305 290 306 /* ··· 446 430 int type, map_word *prev_val) 447 431 { 448 432 map_word val; 449 - uint32_t addr = base + cfi_build_cmd_addr(cmd_addr, cfi_interleave(cfi), type); 433 + uint32_t addr = base + cfi_build_cmd_addr(cmd_addr, map, cfi); 450 434 val = cfi_build_cmd(cmd, map, cfi); 451 435 452 436 if (prev_val)