#endif
#ifndef inw
+#ifdef CONFIG_INDIRECT_PIO
+#define inw extio_inw
+#else
#define inw inw
static inline u16 inw(unsigned long addr)
{
return readw(PCI_IOBASE + addr);
}
+#endif /* CONFIG_INDIRECT_PIO */
#endif
#ifndef inl
+#ifdef CONFIG_INDIRECT_PIO
+#define inl extio_inl
+#else
#define inl inl
static inline u32 inl(unsigned long addr)
{
return readl(PCI_IOBASE + addr);
}
+#endif /* CONFIG_INDIRECT_PIO */
#endif
#ifndef outb
+#ifdef CONFIG_INDIRECT_PIO
+#define outb extio_outb
+#else
#define outb outb
static inline void outb(u8 value, unsigned long addr)
{
writeb(value, PCI_IOBASE + addr);
}
+#endif /* CONFIG_INDIRECT_PIO */
#endif
#ifndef outw
+#ifdef CONFIG_INDIRECT_PIO
+#define outw extio_outw
+#else
#define outw outw
static inline void outw(u16 value, unsigned long addr)
{
writew(value, PCI_IOBASE + addr);
}
+#endif /* CONFIG_INDIRECT_PIO */
#endif
#ifndef outl
+#ifdef CONFIG_INDIRECT_PIO
+#define outl extio_outl
+#else
#define outl outl
static inline void outl(u32 value, unsigned long addr)
{
writel(value, PCI_IOBASE + addr);
}
+#endif /* CONFIG_INDIRECT_PIO */
#endif
#ifndef inb_p
@@ -459,54 +485,78 @@ static inline void outl_p(u32 value, unsigned long addr)
*/
#ifndef insb
+#ifdef CONFIG_INDIRECT_PIO
+#define insb extio_insb
+#else
#define insb insb
static inline void insb(unsigned long addr, void *buffer, unsigned int count)
{
readsb(PCI_IOBASE + addr, buffer, count);
}
+#endif /* CONFIG_INDIRECT_PIO */
#endif
#ifndef insw
+#ifdef CONFIG_INDIRECT_PIO
+#define insw extio_insw
+#else
#define insw insw
static inline void insw(unsigned long addr, void *buffer, unsigned int count)
{
readsw(PCI_IOBASE + addr, buffer, count);
}
+#endif /* CONFIG_INDIRECT_PIO */
#endif
#ifndef insl
+#ifdef CONFIG_INDIRECT_PIO
+#define insl extio_insl
+#else
#define insl insl
static inline void insl(unsigned long addr, void *buffer, unsigned int count)
{
readsl(PCI_IOBASE + addr, buffer, count);
}
+#endif /* CONFIG_INDIRECT_PIO */
#endif
#ifndef outsb
+#ifdef CONFIG_INDIRECT_PIO
+#define outsb extio_outsb
+#else
#define outsb outsb
static inline void outsb(unsigned long addr, const void *buffer,
unsigned int count)
{
writesb(PCI_IOBASE + addr, buffer, count);
}
+#endif /* CONFIG_INDIRECT_PIO */
#endif
#ifndef outsw
+#ifdef CONFIG_INDIRECT_PIO
+#define outsw extio_outsw
+#else
#define outsw outsw
static inline void outsw(unsigned long addr, const void *buffer,
unsigned int count)
{
writesw(PCI_IOBASE + addr, buffer, count);
}
+#endif /* CONFIG_INDIRECT_PIO */
#endif
#ifndef outsl
+#ifdef CONFIG_INDIRECT_PIO
+#define outsl extio_outsl
+#else
#define outsl outsl
static inline void outsl(unsigned long addr, const void *buffer,
unsigned int count)
{
writesl(PCI_IOBASE + addr, buffer, count);
}
+#endif /* CONFIG_INDIRECT_PIO */
#endif
#ifndef insb_p
diff --git a/include/linux/extio.h b/include/linux/extio.h
new file mode 100644
index 0000000..2ca7eab
--- /dev/null
+++ b/include/linux/extio.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2016 Hisilicon Limited, All Rights Reserved.
+ * Author: Zhichang Yuan <yuanzhichang@xxxxxxxxxxxxx>
+ *
+ * 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
+
+#ifdef __KERNEL__
+
+#include <linux/fwnode.h>
+
+struct extio_ops {
+ 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);
+};
+
+struct extio_node {
+ unsigned long bus_start; /* bus start address */
+ unsigned long io_start; /* io port token corresponding to bus_start */
+ size_t range_size; /* size of the extio node operating range */
+ struct fwnode_handle *fwnode;
+ struct list_head list;
+ struct extio_ops *ops; /* ops operating on this node */
+ void *devpara; /* private parameter of the host device */
+};
+
+extern u8 extio_inb(unsigned long addr);
+extern void extio_outb(u8 value, unsigned long addr);
+extern void extio_outw(u16 value, unsigned long addr);
+extern void extio_outl(u32 value, unsigned long addr);
+extern u16 extio_inw(unsigned long addr);
+extern u32 extio_inl(unsigned long addr);
+extern void extio_outb(u8 value, unsigned long addr);
+extern void extio_outw(u16 value, unsigned long addr);
+extern void extio_outl(u32 value, unsigned long addr);
+extern void extio_insb(unsigned long addr, void *buffer, unsigned int count);
+extern void extio_insl(unsigned long addr, void *buffer, unsigned int count);
+extern void extio_insw(unsigned long addr, void *buffer, unsigned int count);
+extern void extio_outsb(unsigned long addr, const void *buffer,
+ unsigned int count);
+extern void extio_outsw(unsigned long addr, const void *buffer,
+ unsigned int count);
+extern void extio_outsl(unsigned long addr, const void *buffer,
+ unsigned int count);
+
+#ifdef CONFIG_INDIRECT_PIO
+extern struct extio_node *extio_find_node(struct fwnode_handle *node);
+
+extern unsigned long
+extio_translate(struct fwnode_handle *node, unsigned long bus_addr);
+#else
+static inline struct extio_node *extio_find_node(struct fwnode_handle *node)
+{
+ return NULL;
+}
+
+static inline unsigned long
+extio_translate(struct fwnode_handle *node, unsigned long bus_addr)
+{
+ return -1;
+}
+#endif
+extern void register_extio(struct extio_node *node);
+
+#endif /* __KERNEL__ */
+#endif /* __LINUX_EXTIO_H */
diff --git a/include/linux/io.h b/include/linux/io.h
index 82ef36e..6c68478 100644
--- a/include/linux/io.h
+++ b/include/linux/io.h
@@ -24,6 +24,7 @@
#include <linux/err.h>
#include <asm/io.h>
#include <asm/page.h>
+#include <linux/extio.h>
struct device;
struct resource;
diff --git a/lib/Kconfig b/lib/Kconfig
index 260a80e..1d27c44 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -59,6 +59,14 @@ config ARCH_USE_CMPXCHG_LOCKREF
config ARCH_HAS_FAST_MULTIPLIER
bool
+config INDIRECT_PIO
+ bool "access peripherals with legacy I/O port"
+ depends on PCI
+ help
+ Support special accessors for ISA I/O devices. This is needed for
+ SoCs that have not I/O space and do not support standard MMIO
+ read/write for the ISA range.
+
config CRC_CCITT
tristate "CRC-CCITT functions"
help
diff --git a/lib/Makefile b/lib/Makefile
index bc4073a..bf03e05 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -70,6 +70,8 @@ obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o
obj-$(CONFIG_CHECK_SIGNATURE) += check_signature.o
obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o
+obj-$(CONFIG_INDIRECT_PIO) += extio.o
+
obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
obj-$(CONFIG_BTREE) += btree.o
diff --git a/lib/extio.c b/lib/extio.c
new file mode 100644
index 0000000..46228de
--- /dev/null
+++ b/lib/extio.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2016 Hisilicon Limited, All Rights Reserved.
+ * Author: Zhichang Yuan <yuanzhichang@xxxxxxxxxxxxx>
+ *
+ * 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>
+#include <linux/spinlock.h>
+
+static LIST_HEAD(extio_dev_list);
+static DEFINE_RWLOCK(extio_list_lock);