MIPS: Support dynamic I/O port base address

The existing mips_io_port_base variable isn't suitable for use early
during boot since it will be stored in the .data section which may not
be writable pre-relocation. Fix this by moving the I/O port base address
into struct arch_global_data. In order to avoid adding this field for
all targets, make this dependant upon a new Kconfig entry
CONFIG_DYNAMIC_IO_PORT_BASE. Malta is the only board which sets a
non-zero I/O port base, so select this option only for Malta.

Signed-off-by: Paul Burton <paul.burton@imgtec.com>
diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h
index 4f9ec19..723a60a 100644
--- a/arch/mips/include/asm/io.h
+++ b/arch/mips/include/asm/io.h
@@ -41,31 +41,37 @@
 
 #define IO_SPACE_LIMIT 0xffff
 
-/*
- * On MIPS I/O ports are memory mapped, so we access them using normal
- * load/store instructions. mips_io_port_base is the virtual address to
- * which all ports are being mapped.  For sake of efficiency some code
- * assumes that this is an address that can be loaded with a single lui
- * instruction, so the lower 16 bits must be zero.  Should be true on
- * on any sane architecture; generic code does not use this assumption.
- */
-extern const unsigned long mips_io_port_base;
+#ifdef CONFIG_DYNAMIC_IO_PORT_BASE
 
-/*
- * Gcc will generate code to load the value of mips_io_port_base after each
- * function call which may be fairly wasteful in some cases.  So we don't
- * play quite by the book.  We tell gcc mips_io_port_base is a long variable
- * which solves the code generation issue.  Now we need to violate the
- * aliasing rules a little to make initialization possible and finally we
- * will need the barrier() to fight side effects of the aliasing chat.
- * This trickery will eventually collapse under gcc's optimizer.  Oh well.
- */
+static inline ulong mips_io_port_base(void)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	return gd->arch.io_port_base;
+}
+
 static inline void set_io_port_base(unsigned long base)
 {
-	* (unsigned long *) &mips_io_port_base = base;
+	DECLARE_GLOBAL_DATA_PTR;
+
+	gd->arch.io_port_base = base;
 	barrier();
 }
 
+#else /* !CONFIG_DYNAMIC_IO_PORT_BASE */
+
+static inline ulong mips_io_port_base(void)
+{
+	return 0;
+}
+
+static inline void set_io_port_base(unsigned long base)
+{
+	BUG_ON(base);
+}
+
+#endif /* !CONFIG_DYNAMIC_IO_PORT_BASE */
+
 /*
  *     virt_to_phys    -       map virtual addresses to physical
  *     @address: address to remap
@@ -293,7 +299,7 @@
 									\
 	war_octeon_io_reorder_wmb();					\
 									\
-	__addr = (void *)__swizzle_addr_##bwlq(mips_io_port_base + port); \
+	__addr = (void *)__swizzle_addr_##bwlq(mips_io_port_base() + port); \
 									\
 	__val = pfx##ioswab##bwlq(__addr, val);				\
 									\
@@ -308,7 +314,7 @@
 	volatile type *__addr;						\
 	type __val;							\
 									\
-	__addr = (void *)__swizzle_addr_##bwlq(mips_io_port_base + port); \
+	__addr = (void *)__swizzle_addr_##bwlq(mips_io_port_base() + port); \
 									\
 	BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long));		\
 									\