diff options
Diffstat (limited to 'drivers')
-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 { |