@@ -163,6 +163,12 @@ config ARCH_MMAP_RND_COMPAT_BITS_MIN
config ARCH_MMAP_RND_COMPAT_BITS_MAX
default 16
+config ARM64_INDIRECT_PIO
+ bool "access peripherals with legacy I/O port"
+ help
+ Support special accessors for ISA I/O devices. This is needed for
+ SoCs that do not support standard read/write for the ISA range.
+
config NO_IOPORT_MAP
def_bool y if !PCI
new file mode 100644
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2016 Hisilicon Limited, All Rights Reserved.
+ * Author: Zhichang Yuan <yuanzhichang@hisilicon.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LINUX_EXTIO_H
+#define __LINUX_EXTIO_H
+
+struct extio_ops {
+ unsigned long start;/* inclusive, sys io addr */
+ unsigned long end;/* inclusive, sys io addr */
+
+ u64 (*pfin)(void *devobj, unsigned long ptaddr, size_t dlen);
+ void (*pfout)(void *devobj, unsigned long ptaddr, u32 outval,
+ size_t dlen);
+ u64 (*pfins)(void *devobj, unsigned long ptaddr, void *inbuf,
+ size_t dlen, unsigned int count);
+ void (*pfouts)(void *devobj, unsigned long ptaddr,
+ const void *outbuf, size_t dlen,
+ unsigned int count);
+ void *devpara;
+};
+
+extern struct extio_ops *arm64_extio_ops;
+
+#define DECLARE_EXTIO(bw, type) \
+extern type in##bw(unsigned long addr); \
+extern void out##bw(type value, unsigned long addr); \
+extern void ins##bw(unsigned long addr, void *buffer, unsigned int count);\
+extern void outs##bw(unsigned long addr, const void *buffer, unsigned int count);
+
+#define BUILD_EXTIO(bw, type) \
+type in##bw(unsigned long addr) \
+{ \
+ if (!arm64_extio_ops || arm64_extio_ops->start > addr || \
+ arm64_extio_ops->end < addr) \
+ return read##bw(PCI_IOBASE + addr); \
+ return arm64_extio_ops->pfin ? \
+ arm64_extio_ops->pfin(arm64_extio_ops->devpara, \
+ addr, sizeof(type)) : -1; \
+} \
+ \
+void out##bw(type value, unsigned long addr) \
+{ \
+ if (!arm64_extio_ops || arm64_extio_ops->start > addr || \
+ arm64_extio_ops->end < addr) \
+ write##bw(value, PCI_IOBASE + addr); \
+ else \
+ if (arm64_extio_ops->pfout) \
+ arm64_extio_ops->pfout(arm64_extio_ops->devpara,\
+ addr, value, sizeof(type)); \
+} \
+ \
+void ins##bw(unsigned long addr, void *buffer, unsigned int count) \
+{ \
+ if (!arm64_extio_ops || arm64_extio_ops->start > addr || \
+ arm64_extio_ops->end < addr) \
+ reads##bw(PCI_IOBASE + addr, buffer, count); \
+ else \
+ if (arm64_extio_ops->pfins) \
+ arm64_extio_ops->pfins(arm64_extio_ops->devpara,\
+ addr, buffer, sizeof(type), count); \
+} \
+ \
+void outs##bw(unsigned long addr, const void *buffer, unsigned int count) \
+{ \
+ if (!arm64_extio_ops || arm64_extio_ops->start > addr || \
+ arm64_extio_ops->end < addr) \
+ writes##bw(PCI_IOBASE + addr, buffer, count); \
+ else \
+ if (arm64_extio_ops->pfouts) \
+ arm64_extio_ops->pfouts(arm64_extio_ops->devpara,\
+ addr, buffer, sizeof(type), count); \
+}
+
+static inline void arm64_set_extops(struct extio_ops *ops)
+{
+ if (ops)
+ WRITE_ONCE(arm64_extio_ops, ops);
+}
+
+#endif /* __LINUX_EXTIO_H*/
@@ -31,6 +31,7 @@
#include <asm/early_ioremap.h>
#include <asm/alternative.h>
#include <asm/cpufeature.h>
+#include <asm/extio.h>
#include <xen/xen.h>
@@ -149,6 +150,34 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
#define IO_SPACE_LIMIT (PCI_IO_SIZE - 1)
#define PCI_IOBASE ((void __iomem *)PCI_IO_START)
+
+/*
+ * redefine the in(s)b/out(s)b for indirect-IO.
+ */
+#ifdef CONFIG_ARM64_INDIRECT_PIO
+#define inb inb
+#define outb outb
+#define insb insb
+#define outsb outsb
+/* external declaration */
+DECLARE_EXTIO(b, u8)
+
+#define inw inw
+#define outw outw
+#define insw insw
+#define outsw outsw
+
+DECLARE_EXTIO(w, u16)
+
+#define inl inl
+#define outl outl
+#define insl insl
+#define outsl outsl
+
+DECLARE_EXTIO(l, u32)
+#endif
+
+
/*
* String version of I/O memory access operations.
*/
@@ -31,6 +31,7 @@ arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
sys_compat.o entry32.o
arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
+arm64-obj-$(CONFIG_ARM64_INDIRECT_PIO) += extio.o
arm64-obj-$(CONFIG_ARM64_MODULE_PLTS) += module-plts.o
arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o
arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
new file mode 100644
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 Hisilicon Limited, All Rights Reserved.
+ * Author: Zhichang Yuan <yuanzhichang@hisilicon.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/io.h>
+
+struct extio_ops *arm64_extio_ops;
+
+
+BUILD_EXTIO(b, u8)
+
+BUILD_EXTIO(w, u16)
+
+BUILD_EXTIO(l, u32)
+
+#endif