diff options
| -rw-r--r-- | drivers/mtd/maps/ixp4xx.c | 78 |
1 files changed, 66 insertions, 12 deletions
diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c index a59f8027903c..986c58628390 100644 --- a/drivers/mtd/maps/ixp4xx.c +++ b/drivers/mtd/maps/ixp4xx.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: ixp4xx.c,v 1.12 2005/11/07 11:14:27 gleixner Exp $ | 2 | * $Id: ixp4xx.c,v 1.13 2005/11/16 16:23:21 dvrabel Exp $ |
| 3 | * | 3 | * |
| 4 | * drivers/mtd/maps/ixp4xx.c | 4 | * drivers/mtd/maps/ixp4xx.c |
| 5 | * | 5 | * |
| @@ -34,10 +34,55 @@ | |||
| 34 | 34 | ||
| 35 | #include <linux/reboot.h> | 35 | #include <linux/reboot.h> |
| 36 | 36 | ||
| 37 | /* | ||
| 38 | * Read/write a 16 bit word from flash address 'addr'. | ||
| 39 | * | ||
| 40 | * When the cpu is in little-endian mode it swizzles the address lines | ||
| 41 | * ('address coherency') so we need to undo the swizzling to ensure commands | ||
| 42 | * and the like end up on the correct flash address. | ||
| 43 | * | ||
| 44 | * To further complicate matters, due to the way the expansion bus controller | ||
| 45 | * handles 32 bit reads, the byte stream ABCD is stored on the flash as: | ||
| 46 | * D15 D0 | ||
| 47 | * +---+---+ | ||
| 48 | * | A | B | 0 | ||
| 49 | * +---+---+ | ||
| 50 | * | C | D | 2 | ||
| 51 | * +---+---+ | ||
| 52 | * This means that on LE systems each 16 bit word must be swapped. Note that | ||
| 53 | * this requires CONFIG_MTD_CFI_BE_BYTE_SWAP to be enabled to 'unswap' the CFI | ||
| 54 | * data and other flash commands which are always in D7-D0. | ||
| 55 | */ | ||
| 37 | #ifndef __ARMEB__ | 56 | #ifndef __ARMEB__ |
| 57 | #ifndef CONFIG_MTD_CFI_BE_BYTE_SWAP | ||
| 58 | # error CONFIG_MTD_CFI_BE_BYTE_SWAP required | ||
| 59 | #endif | ||
| 60 | |||
| 61 | static inline u16 flash_read16(void __iomem *addr) | ||
| 62 | { | ||
| 63 | return be16_to_cpu(__raw_readw((void __iomem *)((unsigned long)addr ^ 0x2))); | ||
| 64 | } | ||
| 65 | |||
| 66 | static inline void flash_write16(u16 d, void __iomem *addr) | ||
| 67 | { | ||
| 68 | __raw_writew(cpu_to_be16(d), (void __iomem *)((unsigned long)addr ^ 0x2)); | ||
| 69 | } | ||
| 70 | |||
| 38 | #define BYTE0(h) ((h) & 0xFF) | 71 | #define BYTE0(h) ((h) & 0xFF) |
| 39 | #define BYTE1(h) (((h) >> 8) & 0xFF) | 72 | #define BYTE1(h) (((h) >> 8) & 0xFF) |
| 73 | |||
| 40 | #else | 74 | #else |
| 75 | |||
| 76 | static inline u16 flash_read16(const void __iomem *addr) | ||
| 77 | { | ||
| 78 | return __raw_readw(addr); | ||
| 79 | } | ||
| 80 | |||
| 81 | static inline void flash_write16(u16 d, void __iomem *addr) | ||
| 82 | { | ||
| 83 | __raw_writew(d, addr); | ||
| 84 | } | ||
| 85 | |||
| 41 | #define BYTE0(h) (((h) >> 8) & 0xFF) | 86 | #define BYTE0(h) (((h) >> 8) & 0xFF) |
| 42 | #define BYTE1(h) ((h) & 0xFF) | 87 | #define BYTE1(h) ((h) & 0xFF) |
| 43 | #endif | 88 | #endif |
| @@ -45,7 +90,7 @@ | |||
| 45 | static map_word ixp4xx_read16(struct map_info *map, unsigned long ofs) | 90 | static map_word ixp4xx_read16(struct map_info *map, unsigned long ofs) |
| 46 | { | 91 | { |
| 47 | map_word val; | 92 | map_word val; |
| 48 | val.x[0] = le16_to_cpu(readw(map->virt + ofs)); | 93 | val.x[0] = flash_read16(map->virt + ofs); |
| 49 | return val; | 94 | return val; |
| 50 | } | 95 | } |
| 51 | 96 | ||
| @@ -57,19 +102,28 @@ static map_word ixp4xx_read16(struct map_info *map, unsigned long ofs) | |||
| 57 | static void ixp4xx_copy_from(struct map_info *map, void *to, | 102 | static void ixp4xx_copy_from(struct map_info *map, void *to, |
| 58 | unsigned long from, ssize_t len) | 103 | unsigned long from, ssize_t len) |
| 59 | { | 104 | { |
| 60 | int i; | ||
| 61 | u8 *dest = (u8 *) to; | 105 | u8 *dest = (u8 *) to; |
| 62 | void __iomem *src = map->virt + from; | 106 | void __iomem *src = map->virt + from; |
| 63 | u16 data; | ||
| 64 | 107 | ||
| 65 | for (i = 0; i < (len / 2); i++) { | 108 | if (len <= 0) |
| 66 | data = le16_to_cpu(readw(src + 2*i)); | 109 | return; |
| 67 | dest[i * 2] = BYTE0(data); | 110 | |
| 68 | dest[i * 2 + 1] = BYTE1(data); | 111 | if (from & 1) { |
| 112 | *dest++ = BYTE1(flash_read16(src)); | ||
| 113 | src++; | ||
| 114 | --len; | ||
| 69 | } | 115 | } |
| 70 | 116 | ||
| 71 | if (len & 1) | 117 | while (len >= 2) { |
| 72 | dest[len - 1] = BYTE0(le16_to_cpu(readw(src + 2*i))); | 118 | u16 data = flash_read16(src); |
| 119 | *dest++ = BYTE0(data); | ||
| 120 | *dest++ = BYTE1(data); | ||
| 121 | src += 2; | ||
| 122 | len -= 2; | ||
| 123 | } | ||
| 124 | |||
| 125 | if (len > 0) | ||
| 126 | *dest++ = BYTE0(flash_read16(src)); | ||
| 73 | } | 127 | } |
| 74 | 128 | ||
| 75 | /* | 129 | /* |
| @@ -79,7 +133,7 @@ static void ixp4xx_copy_from(struct map_info *map, void *to, | |||
| 79 | static void ixp4xx_probe_write16(struct map_info *map, map_word d, unsigned long adr) | 133 | static void ixp4xx_probe_write16(struct map_info *map, map_word d, unsigned long adr) |
| 80 | { | 134 | { |
| 81 | if (!(adr & 1)) | 135 | if (!(adr & 1)) |
| 82 | writew(cpu_to_le16(d.x[0]), map->virt + adr); | 136 | flash_write16(d.x[0], map->virt + adr); |
| 83 | } | 137 | } |
| 84 | 138 | ||
| 85 | /* | 139 | /* |
| @@ -87,7 +141,7 @@ static void ixp4xx_probe_write16(struct map_info *map, map_word d, unsigned long | |||
| 87 | */ | 141 | */ |
| 88 | static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr) | 142 | static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr) |
| 89 | { | 143 | { |
| 90 | writew(cpu_to_le16(d.x[0]), map->virt + adr); | 144 | flash_write16(d.x[0], map->virt + adr); |
| 91 | } | 145 | } |
| 92 | 146 | ||
| 93 | struct ixp4xx_flash_info { | 147 | struct ixp4xx_flash_info { |
