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 <s...@chromium.org>
---

 arch/sandbox/Kconfig                      |   7 ++
 arch/sandbox/cpu/cpu.c                    |  37 +++++++-
 arch/sandbox/dts/sandbox.dts              |  22 ++++-
 arch/sandbox/include/asm/io.h             |  16 +++-
 arch/sandbox/include/asm/processor.h      |  12 +++
 arch/sandbox/include/asm/test.h           |   7 +-
 arch/sandbox/include/asm/u-boot-sandbox.h |  48 +++++++++++
 arch/sandbox/lib/Makefile                 |   2 +-
 arch/sandbox/lib/pci_io.c                 | 138 ++++++++++++++++++++++++++++++
 9 files changed, 281 insertions(+), 8 deletions(-)
 create mode 100644 arch/sandbox/include/asm/processor.h
 create mode 100644 arch/sandbox/lib/pci_io.c

diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig
index 2098b9c..477a20a 100644
--- a/arch/sandbox/Kconfig
+++ b/arch/sandbox/Kconfig
@@ -34,4 +34,11 @@ config DM_I2C
 config DM_TEST
        default y
 
+config PCI
+       bool "PCI support"
+       help
+         Enable support for PCI (Peripheral Interconnect Bus), a type of bus
+         used on some devices to allow the CPU to communicate with its
+         peripherals.
+
 endmenu
diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c
index 1aa397c..1e67a31 100644
--- a/arch/sandbox/cpu/cpu.c
+++ b/arch/sandbox/cpu/cpu.c
@@ -2,7 +2,7 @@
  * Copyright (c) 2011 The Chromium OS Authors.
  * SPDX-License-Identifier:    GPL-2.0+
  */
-
+#define DEBUG
 #include <common.h>
 #include <dm/root.h>
 #include <os.h>
@@ -10,6 +10,13 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+/* Enable access to PCI memory with map_sysmem() */
+static bool enable_pci_map;
+
+/* Last device that was mapped into memory, and length of mapping */
+static struct udevice *map_dev;
+unsigned long map_len;
+
 void reset_cpu(ulong ignored)
 {
        if (state_uninit())
@@ -59,9 +66,37 @@ int cleanup_before_linux(void)
 
 void *map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
 {
+#ifdef CONFIG_PCI
+       unsigned long plen = len;
+       void *ptr;
+
+       map_dev = NULL;
+       if (enable_pci_map && !pci_map_physmem(paddr, &len, &map_dev, &ptr)) {
+               if (plen != len) {
+                       printf("%s: Warning: partial map at %x, wanted %lx, got 
%lx\n",
+                              __func__, paddr, len, plen);
+               }
+               map_len = len;
+               return ptr;
+       }
+#endif
+
        return (void *)(gd->arch.ram_buf + paddr);
 }
 
+void unmap_physmem(const void *vaddr, unsigned long flags)
+{
+       if (map_dev) {
+               pci_unmap_physmem(vaddr, map_len, map_dev);
+               map_dev = NULL;
+       }
+}
+
+void sandbox_set_enable_pci_map(int enable)
+{
+       enable_pci_map = enable;
+}
+
 phys_addr_t map_to_sysmem(const void *ptr)
 {
        return (u8 *)ptr - gd->arch.ram_buf;
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts
index 1ccfdee..42a1f21 100644
--- a/arch/sandbox/dts/sandbox.dts
+++ b/arch/sandbox/dts/sandbox.dts
@@ -2,7 +2,11 @@
 
 / {
        #address-cells = <1>;
-       #size-cells = <0>;
+       #size-cells = <1>;
+
+       aliases {
+               pci0 = &pci;
+       };
 
        chosen {
                stdout-path = "/serial";
@@ -181,4 +185,20 @@
                };
        };
 
+       pci: pci-controller {
+               compatible = "sandbox,pci";
+               device_type = "pci";
+               #address-cells = <3>;
+               #size-cells = <2>;
+               ranges = <0x02000000 0 0x10000000 0x10000000 0 0x2000
+                               0x01000000 0 0x20000000 0x20000000 0 0x2000>;
+               pci@1f,0 {
+                       compatible = "pci-generic";
+                       reg = <0xf800 0 0 0 0>;
+                       emul@1f,0 {
+                               compatible = "sandbox,swap-case";
+                       };
+               };
+       };
+
 };
diff --git a/arch/sandbox/include/asm/io.h b/arch/sandbox/include/asm/io.h
index 895fcb8..5b87fde 100644
--- a/arch/sandbox/include/asm/io.h
+++ b/arch/sandbox/include/asm/io.h
@@ -22,10 +22,7 @@ void *map_physmem(phys_addr_t paddr, unsigned long len, 
unsigned long flags);
 /*
  * Take down a mapping set up by map_physmem().
  */
-static inline void unmap_physmem(void *vaddr, unsigned long flags)
-{
-
-}
+void unmap_physmem(const void *vaddr, unsigned long flags);
 
 /* For sandbox, we want addresses to point into our RAM buffer */
 static inline void *map_sysmem(phys_addr_t paddr, unsigned long len)
@@ -33,8 +30,10 @@ static inline void *map_sysmem(phys_addr_t paddr, unsigned 
long len)
        return map_physmem(paddr, len, MAP_WRBACK);
 }
 
+/* Remove a previous mapping */
 static inline void unmap_sysmem(const void *vaddr)
 {
+       unmap_physmem(vaddr, MAP_WRBACK);
 }
 
 /* Map from a pointer to our RAM buffer */
@@ -48,6 +47,15 @@ phys_addr_t map_to_sysmem(const void *ptr);
 #define writew(v, addr)
 #define writel(v, addr)
 
+/* I/O access functions */
+int inl(unsigned int addr);
+int inw(unsigned int addr);
+int inb(unsigned int addr);
+
+void outl(unsigned int value, unsigned int addr);
+void outw(unsigned int value, unsigned int addr);
+void outb(unsigned int value, unsigned int addr);
+
 #include <iotrace.h>
 
 #endif
diff --git a/arch/sandbox/include/asm/processor.h 
b/arch/sandbox/include/asm/processor.h
new file mode 100644
index 0000000..3c1794e
--- /dev/null
+++ b/arch/sandbox/include/asm/processor.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _ASM_PROCESSOR_H
+#define _ASM_PROCESSOR_H
+
+/* This file is required for PCI */
+
+#endif
diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h
index 25a0c85..8e490e9 100644
--- a/arch/sandbox/include/asm/test.h
+++ b/arch/sandbox/include/asm/test.h
@@ -10,7 +10,12 @@
 #define __ASM_TEST_H
 
 /* The sandbox driver always permits an I2C device with this address */
-#define SANDBOX_I2C_TEST_ADDR  0x59
+#define SANDBOX_I2C_TEST_ADDR          0x59
+
+#define SANDBOX_PCI_VENDOR_ID          0x1234
+#define SANDBOX_PCI_DEVICE_ID          0x5678
+#define SANDBOX_PCI_CLASS_CODE         PCI_CLASS_CODE_COMM
+#define SANDBOX_PCI_CLASS_SUB_CODE     PCI_CLASS_SUB_CODE_COMM_SERIAL
 
 enum sandbox_i2c_eeprom_test_mode {
        SIE_TEST_MODE_NONE,
diff --git a/arch/sandbox/include/asm/u-boot-sandbox.h 
b/arch/sandbox/include/asm/u-boot-sandbox.h
index 770ab5c..d5b9361 100644
--- a/arch/sandbox/include/asm/u-boot-sandbox.h
+++ b/arch/sandbox/include/asm/u-boot-sandbox.h
@@ -27,4 +27,52 @@ int cleanup_before_linux(void);
 /* drivers/video/sandbox_sdl.c */
 int sandbox_lcd_sdl_early_init(void);
 
+/**
+ * pci_map_physmem() - map a PCI device into memory
+ *
+ * This is used on sandbox to map a device into memory so that it can be
+ * used with normal memory access. After this call, some part of the device's
+ * internal structure becomes visible.
+ *
+ * This function is normally called from sandbox's map_sysmem() automatically.
+ *
+ * @paddr:     Physical memory address, normally corresponding to a PCI BAR
+ * @lenp:      On entry, the size of the area to map, On exit it is updated
+ *             to the size actually mapped, which may be less if the device
+ *             has less space
+ * @devp:      Returns the device which mapped into this space
+ * @ptrp:      Returns a pointer to the mapped address. The device's space
+ *             can be accessed as @lenp bytes starting here
+ * @return 0 if OK, -ve on error
+ */
+int pci_map_physmem(phys_addr_t paddr, unsigned long *lenp,
+                   struct udevice **devp, void **ptrp);
+
+/**
+ * pci_unmap_physmem() - undo a memory mapping
+ *
+ * This must be called after pci_map_physmem() to undo the mapping.
+ *
+ * @paddr:     Physical memory address, as passed to pci_map_physmem()
+ * @len:       Size of area mapped, as returned by pci_map_physmem()
+ * @dev:       Device to unmap, as returned by pci_map_physmem()
+ * @return 0 if OK, -ve on error
+ */
+int pci_unmap_physmem(const void *addr, unsigned long len,
+                     struct udevice *dev);
+
+/**
+ * sandbox_set_enable_pci_map() - Enable / disable PCI address mapping
+ *
+ * Since address mapping involves calling every driver, provide a way to
+ * enable and disable this. It can be handled automatically by the emulator
+ * uclass, which knows if any emulators are currently active.
+ *
+ * If this is disabled, pci_map_physmem() will not be called from
+ * map_sysmem().
+ *
+ * @enable: 0 to disable, 1 to enable
+ */
+void sandbox_set_enable_pci_map(int enable);
+
 #endif /* _U_BOOT_SANDBOX_H_ */
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 <s...@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);
+}
-- 
2.2.0.rc0.207.ga3a616c

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to