From 05e342554e51767830d7e60f2dab09192fd2a0e1 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 29 Jan 2016 13:54:52 +0000 Subject: 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 --- arch/mips/Kconfig | 4 ++++ arch/mips/include/asm/global_data.h | 3 +++ arch/mips/include/asm/io.h | 48 +++++++++++++++++++++---------------- arch/mips/lib/Makefile | 1 - arch/mips/lib/io.c | 12 ---------- 5 files changed, 34 insertions(+), 34 deletions(-) delete mode 100644 arch/mips/lib/io.c diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 1b39c4c..585887c 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -23,6 +23,7 @@ config TARGET_QEMU_MIPS config TARGET_MALTA bool "Support malta" + select DYNAMIC_IO_PORT_BASE select SUPPORTS_BIG_ENDIAN select SUPPORTS_LITTLE_ENDIAN select SUPPORTS_CPU_MIPS32_R1 @@ -217,6 +218,9 @@ config MIPS_L1_CACHE_SHIFT default "4" if MIPS_L1_CACHE_SHIFT_4 default "5" +config DYNAMIC_IO_PORT_BASE + bool + endif endmenu diff --git a/arch/mips/include/asm/global_data.h b/arch/mips/include/asm/global_data.h index 2d9a0c9..a1ca257 100644 --- a/arch/mips/include/asm/global_data.h +++ b/arch/mips/include/asm/global_data.h @@ -12,6 +12,9 @@ /* Architecture-specific global data */ struct arch_global_data { +#ifdef CONFIG_DYNAMIC_IO_PORT_BASE + unsigned long io_port_base; +#endif #ifdef CONFIG_JZSOC /* There are other clocks in the jz4740 */ unsigned long per_clk; /* Peripheral bus clock */ 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 + +static inline ulong mips_io_port_base(void) +{ + DECLARE_GLOBAL_DATA_PTR; + + return gd->arch.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 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 @@ static inline void pfx##out##bwlq##p(type val, unsigned long port) \ \ 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 @@ static inline type pfx##in##bwlq##p(unsigned long port) \ 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)); \ \ diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile index ac536da..b7ce5df 100644 --- a/arch/mips/lib/Makefile +++ b/arch/mips/lib/Makefile @@ -7,7 +7,6 @@ obj-y += cache.o obj-y += cache_init.o -obj-y += io.o obj-$(CONFIG_CMD_BOOTM) += bootm.o diff --git a/arch/mips/lib/io.c b/arch/mips/lib/io.c deleted file mode 100644 index b2d4a09..0000000 --- a/arch/mips/lib/io.c +++ /dev/null @@ -1,12 +0,0 @@ -/* - * (C) Copyright 2003 - * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -/* - * mips_io_port_base is the begin of the address space to which x86 style - * I/O ports are mapped. - */ -const unsigned long mips_io_port_base = -1; -- cgit v1.1