diff options
author | 2023-10-10 14:33:42 +0000 | |
---|---|---|
committer | 2023-10-10 14:33:42 +0000 | |
commit | af1a266670d040d2f4083ff309d732d648afba2a (patch) | |
tree | 2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/u-boot/drivers/pci/pci-emul-uclass.c | |
parent | e02cda008591317b1625707ff8e115a4841aa889 (diff) |
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/u-boot/drivers/pci/pci-emul-uclass.c')
-rw-r--r-- | roms/u-boot/drivers/pci/pci-emul-uclass.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/pci/pci-emul-uclass.c b/roms/u-boot/drivers/pci/pci-emul-uclass.c new file mode 100644 index 000000000..a0b8afb87 --- /dev/null +++ b/roms/u-boot/drivers/pci/pci-emul-uclass.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2014 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <common.h> +#include <dm.h> +#include <fdtdec.h> +#include <log.h> +#include <linux/libfdt.h> +#include <pci.h> +#include <dm/lists.h> + +struct sandbox_pci_emul_priv { + int dev_count; +}; + +int sandbox_pci_get_emul(const struct udevice *bus, pci_dev_t find_devfn, + struct udevice **containerp, struct udevice **emulp) +{ + struct pci_emul_uc_priv *upriv; + struct udevice *dev; + int ret; + + *containerp = NULL; + ret = pci_bus_find_devfn(bus, PCI_MASK_BUS(find_devfn), &dev); + if (ret) { + debug("%s: Could not find emulator for dev %x\n", __func__, + find_devfn); + return ret; + } + *containerp = dev; + + ret = uclass_get_device_by_phandle(UCLASS_PCI_EMUL, dev, "sandbox,emul", + emulp); + if (!ret) { + upriv = dev_get_uclass_priv(*emulp); + + upriv->client = dev; + } else if (device_get_uclass_id(dev) != UCLASS_PCI_GENERIC) { + /* + * See commit 4345998ae9df, + * "pci: sandbox: Support dynamically binding device driver" + */ + *emulp = dev; + } + + return 0; +} + +int sandbox_pci_get_client(struct udevice *emul, struct udevice **devp) +{ + struct pci_emul_uc_priv *upriv = dev_get_uclass_priv(emul); + + if (!upriv->client) + return -ENOENT; + *devp = upriv->client; + + return 0; +} + +uint sandbox_pci_read_bar(u32 barval, int type, uint size) +{ + u32 result; + + result = barval; + if (result == 0xffffffff) { + if (type == PCI_BASE_ADDRESS_SPACE_IO) { + result = (~(size - 1) & + PCI_BASE_ADDRESS_IO_MASK) | + PCI_BASE_ADDRESS_SPACE_IO; + } else { + result = (~(size - 1) & + PCI_BASE_ADDRESS_MEM_MASK) | + PCI_BASE_ADDRESS_MEM_TYPE_32; + } + } + + return result; +} + +static int sandbox_pci_emul_post_probe(struct udevice *dev) +{ + struct sandbox_pci_emul_priv *priv = uclass_get_priv(dev->uclass); + + priv->dev_count++; + sandbox_set_enable_pci_map(true); + + return 0; +} + +static int sandbox_pci_emul_pre_remove(struct udevice *dev) +{ + struct sandbox_pci_emul_priv *priv = uclass_get_priv(dev->uclass); + + priv->dev_count--; + sandbox_set_enable_pci_map(priv->dev_count > 0); + + return 0; +} + +UCLASS_DRIVER(pci_emul) = { + .id = UCLASS_PCI_EMUL, + .name = "pci_emul", + .post_probe = sandbox_pci_emul_post_probe, + .pre_remove = sandbox_pci_emul_pre_remove, + .priv_auto = sizeof(struct sandbox_pci_emul_priv), + .per_device_auto = sizeof(struct pci_emul_uc_priv), +}; + +/* + * This uclass is a child of the pci bus. Its plat is not defined here so + * is defined by its parent, UCLASS_PCI, which uses struct pci_child_plat. + * See per_child_plat_auto in UCLASS_DRIVER(pci). + */ +UCLASS_DRIVER(pci_emul_parent) = { + .id = UCLASS_PCI_EMUL_PARENT, + .name = "pci_emul_parent", + .post_bind = dm_scan_fdt_dev, +}; + +static const struct udevice_id pci_emul_parent_ids[] = { + { .compatible = "sandbox,pci-emul-parent" }, + { } +}; + +U_BOOT_DRIVER(pci_emul_parent_drv) = { + .name = "pci_emul_parent_drv", + .id = UCLASS_PCI_EMUL_PARENT, + .of_match = pci_emul_parent_ids, +}; |