diff options
-rw-r--r-- | drivers/pci/Kconfig | 10 | ||||
-rw-r--r-- | drivers/pci/Makefile | 1 | ||||
-rw-r--r-- | drivers/pci/pci_sandbox.c | 79 |
3 files changed, 90 insertions, 0 deletions
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 8b7e2ee..167d405 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -9,4 +9,14 @@ config DM_PCI available PCI devices, allows scanning of PCI buses and provides device configuration support. +config PCI_SANDBOX + bool "Sandbox PCI support" + depends on SANDBOX && DM_PCI + help + Support PCI on sandbox, as an emulated bus. This permits testing of + PCI feature such as bus scanning, device configuration and device + access. The available (emulated) devices are defined statically in + the device tree but the normal PCI scan technique is used to find + then. + endmenu diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index db82786..9e2e5f9 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -7,6 +7,7 @@ ifneq ($(CONFIG_DM_PCI),) obj-$(CONFIG_PCI) += pci-uclass.o pci_compat.o +obj-$(CONFIG_PCI_SANDBOX) += pci_sandbox.o else obj-$(CONFIG_PCI) += pci.o endif diff --git a/drivers/pci/pci_sandbox.c b/drivers/pci/pci_sandbox.c new file mode 100644 index 0000000..6de5130 --- /dev/null +++ b/drivers/pci/pci_sandbox.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2014 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <fdtdec.h> +#include <inttypes.h> +#include <pci.h> +#include <dm/root.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int sandbox_pci_write_config(struct udevice *bus, pci_dev_t devfn, + uint offset, ulong value, + enum pci_size_t size) +{ + struct dm_pci_emul_ops *ops; + struct udevice *emul; + int ret; + + ret = sandbox_pci_get_emul(bus, devfn, &emul); + if (ret) + return ret == -ENODEV ? 0 : ret; + ops = pci_get_emul_ops(emul); + if (!ops || !ops->write_config) + return -ENOSYS; + + return ops->write_config(emul, offset, value, size); +} + +static int sandbox_pci_read_config(struct udevice *bus, pci_dev_t devfn, + uint offset, ulong *valuep, + enum pci_size_t size) +{ + struct dm_pci_emul_ops *ops; + struct udevice *emul; + int ret; + + /* Prepare the default response */ + *valuep = pci_get_ff(size); + ret = sandbox_pci_get_emul(bus, devfn, &emul); + if (ret) + return ret == -ENODEV ? 0 : ret; + ops = pci_get_emul_ops(emul); + if (!ops || !ops->read_config) + return -ENOSYS; + + return ops->read_config(emul, offset, valuep, size); +} + +static int sandbox_pci_child_post_bind(struct udevice *dev) +{ + /* Attach an emulator if we can */ + return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); +} + +static const struct dm_pci_ops sandbox_pci_ops = { + .read_config = sandbox_pci_read_config, + .write_config = sandbox_pci_write_config, +}; + +static const struct udevice_id sandbox_pci_ids[] = { + { .compatible = "sandbox,pci" }, + { } +}; + +U_BOOT_DRIVER(pci_sandbox) = { + .name = "pci_sandbox", + .id = UCLASS_PCI, + .of_match = sandbox_pci_ids, + .ops = &sandbox_pci_ops, + .child_post_bind = sandbox_pci_child_post_bind, + .per_child_platdata_auto_alloc_size = + sizeof(struct pci_child_platdata), +}; |