summaryrefslogtreecommitdiff
path: root/packages/linux/nslu2-kernel/2.6.15/90-ixp4xx-nslu2.patch
diff options
context:
space:
mode:
Diffstat (limited to 'packages/linux/nslu2-kernel/2.6.15/90-ixp4xx-nslu2.patch')
-rw-r--r--packages/linux/nslu2-kernel/2.6.15/90-ixp4xx-nslu2.patch144
1 files changed, 144 insertions, 0 deletions
diff --git a/packages/linux/nslu2-kernel/2.6.15/90-ixp4xx-nslu2.patch b/packages/linux/nslu2-kernel/2.6.15/90-ixp4xx-nslu2.patch
new file mode 100644
index 0000000000..d3497850cd
--- /dev/null
+++ b/packages/linux/nslu2-kernel/2.6.15/90-ixp4xx-nslu2.patch
@@ -0,0 +1,144 @@
+--- linux-2.6.15/drivers/mtd/maps/ixp4xx.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/mtd/maps/ixp4xx.c 1970-01-01 00:00:00.000000000 +0000
+@@ -28,24 +28,45 @@
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/map.h>
+ #include <linux/mtd/partitions.h>
++#include <linux/mtd/cfi_endian.h>
+
+ #include <asm/io.h>
+ #include <asm/mach/flash.h>
+
+ #include <linux/reboot.h>
+
+-#ifndef __ARMEB__
+-#define BYTE0(h) ((h) & 0xFF)
+-#define BYTE1(h) (((h) >> 8) & 0xFF)
++/*
++ * Read a 16 bit word from flash address 'addr'.
++ * This code ensures that the ixp4xx flash behaves as a consistent byte
++ * stream (same bytes in same order) regardless of whether the CPU is
++ * running in BE or LE mode, and regardless of whether the read16 or
++ * copyfrom method is used to read the flash data.
++ *
++ * When the cpu is in little-endian mode the hardware inverts the low
++ * address lines between the MMU (including the cache) and the flash chip
++ * ('address coherency') so we need to undo the swizzling to ensure commands
++ * and the like end up on the correct flash address. This requirement
++ * only applies to command operations, however this code cannot distinguish
++ * a command read from a data read, therefore the fix applies to the data
++ * as well as the command and must be implemented consistently throughout
++ * the map driver (here).
++ */
++static inline u16 flash_read16(const void __iomem *virt, unsigned long offset)
++{
++#ifdef __ARMEB__
++ return *(const volatile u16 __iomem *)(virt + offset);
+ #else
+-#define BYTE0(h) (((h) >> 8) & 0xFF)
+-#define BYTE1(h) ((h) & 0xFF)
++ /* Cancel the address coherency invert of address line 1 in the
++ * hardware on LE systems.
++ */
++ return *(const volatile u16 __iomem *)(virt + (offset ^ 2));
+ #endif
++}
+
+ static map_word ixp4xx_read16(struct map_info *map, unsigned long ofs)
+ {
+ map_word val;
+- val.x[0] = le16_to_cpu(readw(map->virt + ofs));
++ val.x[0] = cfi16_to_cpu(flash_read16(map->virt, ofs));
+ return val;
+ }
+
+@@ -53,41 +74,70 @@ static map_word ixp4xx_read16(struct map
+ * The IXP4xx expansion bus only allows 16-bit wide acceses
+ * when attached to a 16-bit wide device (such as the 28F128J3A),
+ * so we can't just memcpy_fromio().
++ *
++ * This code must obtain the correct bytes in the correct order
++ * according to the configuration of the CFI subsystem.
+ */
++#if (defined CFI_BIG_ENDIAN) || ((defined CFI_HOST_ENDIAN) && (defined __ARMEB__))
++ /* BE flash */
++#define BYTE0(h) (((h) >> 8) & 0xFF)
++#define BYTE1(h) ((h) & 0xFF)
++#else
++ /* LE flash */
++#define BYTE0(h) ((h) & 0xFF)
++#define BYTE1(h) (((h) >> 8) & 0xFF)
++#endif
++
+ static void ixp4xx_copy_from(struct map_info *map, void *to,
+ unsigned long from, ssize_t len)
+ {
+- int i;
+- u8 *dest = (u8 *) to;
+- void __iomem *src = map->virt + from;
+- u16 data;
+-
+- for (i = 0; i < (len / 2); i++) {
+- data = le16_to_cpu(readw(src + 2*i));
+- dest[i * 2] = BYTE0(data);
+- dest[i * 2 + 1] = BYTE1(data);
++ u8 *dest = to;
++ const void __iomem * const virt = map->virt;
++
++ if (len <= 0)
++ return;
++
++ if (from & 1) {
++ *dest++ = BYTE1(flash_read16(virt, from-1));
++ ++from;
++ --len;
++ }
++
++ while (len >= 2) {
++ u16 data = flash_read16(virt, from);
++ *dest++ = BYTE0(data);
++ *dest++ = BYTE1(data);
++ from += 2;
++ len -= 2;
+ }
+
+- if (len & 1)
+- dest[len - 1] = BYTE0(le16_to_cpu(readw(src + 2*i)));
++ if (len > 0)
++ *dest++ = BYTE0(flash_read16(virt, from));
+ }
+
+ /*
+- * Unaligned writes are ignored, causing the 8-bit
+- * probe to fail and proceed to the 16-bit probe (which succeeds).
++ * Fast write16 function without the probing check below.
+ */
+-static void ixp4xx_probe_write16(struct map_info *map, map_word d, unsigned long adr)
++static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr)
+ {
+- if (!(adr & 1))
+- writew(cpu_to_le16(d.x[0]), map->virt + adr);
++#ifdef __ARMEB__
++ *(volatile u16 __iomem*)(map->virt + adr) = cpu_to_cfi16(d.x[0]);
++#else
++ /* Cancel the address coherency invert of address line 1 in the
++ * hardware on LE systems.
++ */
++ *(volatile u16 __iomem*)(map->virt + (adr ^ 2)) = cpu_to_cfi16(d.x[0]);
++#endif
+ }
+
+ /*
+- * Fast write16 function without the probing check above
++ * Unaligned writes are ignored, causing the 8-bit
++ * probe to fail and proceed to the 16-bit probe (which succeeds).
+ */
+-static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr)
++static void ixp4xx_probe_write16(struct map_info *map, map_word d, unsigned long adr)
+ {
+- writew(cpu_to_le16(d.x[0]), map->virt + adr);
++ if (!(adr & 1))
++ ixp4xx_write16(map, d, adr);
+ }
+
+ struct ixp4xx_flash_info {