dm: sandbox: pci: Add PCI support for sandbox

Add the required header information, device tree nodes and I/O accessor
functions to support PCI on sandbox. All devices are emulated by drivers
which can be added as required for testing or development.

Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/arch/sandbox/lib/Makefile b/arch/sandbox/lib/Makefile
index 4c1a38d..75b135c 100644
--- a/arch/sandbox/lib/Makefile
+++ b/arch/sandbox/lib/Makefile
@@ -7,5 +7,5 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
-
 obj-y	+= interrupts.o
+obj-$(CONFIG_PCI)	+= pci_io.o
diff --git a/arch/sandbox/lib/pci_io.c b/arch/sandbox/lib/pci_io.c
new file mode 100644
index 0000000..0de124f
--- /dev/null
+++ b/arch/sandbox/lib/pci_io.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+/*
+ * IO space access commands.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <asm/io.h>
+
+int pci_map_physmem(phys_addr_t paddr, unsigned long *lenp,
+		    struct udevice **devp, void **ptrp)
+{
+	struct udevice *dev;
+	int ret;
+
+	*ptrp = 0;
+	for (uclass_first_device(UCLASS_PCI_EMUL, &dev);
+	     dev;
+	     uclass_next_device(&dev)) {
+		struct dm_pci_emul_ops *ops = pci_get_emul_ops(dev);
+
+		if (!ops || !ops->map_physmem)
+			continue;
+		ret = (ops->map_physmem)(dev, paddr, lenp, ptrp);
+		if (ret)
+			continue;
+		*devp = dev;
+		return 0;
+	}
+
+	debug("%s: failed: addr=%x\n", __func__, paddr);
+	return -ENOSYS;
+}
+
+int pci_unmap_physmem(const void *vaddr, unsigned long len,
+		      struct udevice *dev)
+{
+	struct dm_pci_emul_ops *ops = pci_get_emul_ops(dev);
+
+	if (!ops || !ops->unmap_physmem)
+		return -ENOSYS;
+	return (ops->unmap_physmem)(dev, vaddr, len);
+}
+
+static int pci_io_read(unsigned int addr, ulong *valuep, pci_size_t size)
+{
+	struct udevice *dev;
+	int ret;
+
+	*valuep = pci_get_ff(size);
+	for (uclass_first_device(UCLASS_PCI_EMUL, &dev);
+	     dev;
+	     uclass_next_device(&dev)) {
+		struct dm_pci_emul_ops *ops = pci_get_emul_ops(dev);
+
+		if (ops && ops->read_io) {
+			ret = (ops->read_io)(dev, addr, valuep, size);
+			if (!ret)
+				return 0;
+		}
+	}
+
+	debug("%s: failed: addr=%x\n", __func__, addr);
+	return -ENOSYS;
+}
+
+static int pci_io_write(unsigned int addr, ulong value, pci_size_t size)
+{
+	struct udevice *dev;
+	int ret;
+
+	for (uclass_first_device(UCLASS_PCI_EMUL, &dev);
+	     dev;
+	     uclass_next_device(&dev)) {
+		struct dm_pci_emul_ops *ops = pci_get_emul_ops(dev);
+
+		if (ops && ops->write_io) {
+			ret = (ops->write_io)(dev, addr, value, size);
+			if (!ret)
+				return 0;
+		}
+	}
+
+	debug("%s: failed: addr=%x, value=%lx\n", __func__, addr, value);
+	return -ENOSYS;
+}
+
+int inl(unsigned int addr)
+{
+	unsigned long value;
+	int ret;
+
+	ret = pci_io_read(addr, &value, PCI_SIZE_32);
+
+	return ret ? 0 : value;
+}
+
+int inw(unsigned int addr)
+{
+	unsigned long value;
+	int ret;
+
+	ret = pci_io_read(addr, &value, PCI_SIZE_16);
+
+	return ret ? 0 : value;
+}
+
+int inb(unsigned int addr)
+{
+	unsigned long value;
+	int ret;
+
+	ret = pci_io_read(addr, &value, PCI_SIZE_8);
+
+	return ret ? 0 : value;
+}
+
+void outl(unsigned int value, unsigned int addr)
+{
+	pci_io_write(addr, value, PCI_SIZE_32);
+}
+
+void outw(unsigned int value, unsigned int addr)
+{
+	pci_io_write(addr, value, PCI_SIZE_16);
+}
+
+void outb(unsigned int value, unsigned int addr)
+{
+	pci_io_write(addr, value, PCI_SIZE_8);
+}