1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (c) 2014 Google, Inc 4 * Written by Simon Glass <sjg@chromium.org> 5 */ 6 7#include <common.h> 8#include <dm.h> 9#include <fdtdec.h> 10#include <log.h> 11#include <linux/libfdt.h> 12#include <pci.h> 13#include <dm/lists.h> 14 15struct sandbox_pci_emul_priv { 16 int dev_count; 17}; 18 19int sandbox_pci_get_emul(const struct udevice *bus, pci_dev_t find_devfn, 20 struct udevice **containerp, struct udevice **emulp) 21{ 22 struct pci_emul_uc_priv *upriv; 23 struct udevice *dev; 24 int ret; 25 26 *containerp = NULL; 27 ret = pci_bus_find_devfn(bus, PCI_MASK_BUS(find_devfn), &dev); 28 if (ret) { 29 debug("%s: Could not find emulator for dev %x\n", __func__, 30 find_devfn); 31 return ret; 32 } 33 *containerp = dev; 34 35 ret = uclass_get_device_by_phandle(UCLASS_PCI_EMUL, dev, "sandbox,emul", 36 emulp); 37 if (!ret) { 38 upriv = dev_get_uclass_priv(*emulp); 39 40 upriv->client = dev; 41 } else if (device_get_uclass_id(dev) != UCLASS_PCI_GENERIC) { 42 /* 43 * See commit 4345998ae9df, 44 * "pci: sandbox: Support dynamically binding device driver" 45 */ 46 *emulp = dev; 47 } 48 49 return 0; 50} 51 52int sandbox_pci_get_client(struct udevice *emul, struct udevice **devp) 53{ 54 struct pci_emul_uc_priv *upriv = dev_get_uclass_priv(emul); 55 56 if (!upriv->client) 57 return -ENOENT; 58 *devp = upriv->client; 59 60 return 0; 61} 62 63uint sandbox_pci_read_bar(u32 barval, int type, uint size) 64{ 65 u32 result; 66 67 result = barval; 68 if (result == 0xffffffff) { 69 if (type == PCI_BASE_ADDRESS_SPACE_IO) { 70 result = (~(size - 1) & 71 PCI_BASE_ADDRESS_IO_MASK) | 72 PCI_BASE_ADDRESS_SPACE_IO; 73 } else { 74 result = (~(size - 1) & 75 PCI_BASE_ADDRESS_MEM_MASK) | 76 PCI_BASE_ADDRESS_MEM_TYPE_32; 77 } 78 } 79 80 return result; 81} 82 83static int sandbox_pci_emul_post_probe(struct udevice *dev) 84{ 85 struct sandbox_pci_emul_priv *priv = uclass_get_priv(dev->uclass); 86 87 priv->dev_count++; 88 sandbox_set_enable_pci_map(true); 89 90 return 0; 91} 92 93static int sandbox_pci_emul_pre_remove(struct udevice *dev) 94{ 95 struct sandbox_pci_emul_priv *priv = uclass_get_priv(dev->uclass); 96 97 priv->dev_count--; 98 sandbox_set_enable_pci_map(priv->dev_count > 0); 99 100 return 0; 101} 102 103UCLASS_DRIVER(pci_emul) = { 104 .id = UCLASS_PCI_EMUL, 105 .name = "pci_emul", 106 .post_probe = sandbox_pci_emul_post_probe, 107 .pre_remove = sandbox_pci_emul_pre_remove, 108 .priv_auto = sizeof(struct sandbox_pci_emul_priv), 109 .per_device_auto = sizeof(struct pci_emul_uc_priv), 110}; 111 112/* 113 * This uclass is a child of the pci bus. Its plat is not defined here so 114 * is defined by its parent, UCLASS_PCI, which uses struct pci_child_plat. 115 * See per_child_plat_auto in UCLASS_DRIVER(pci). 116 */ 117UCLASS_DRIVER(pci_emul_parent) = { 118 .id = UCLASS_PCI_EMUL_PARENT, 119 .name = "pci_emul_parent", 120 .post_bind = dm_scan_fdt_dev, 121}; 122 123static const struct udevice_id pci_emul_parent_ids[] = { 124 { .compatible = "sandbox,pci-emul-parent" }, 125 { } 126}; 127 128U_BOOT_DRIVER(pci_emul_parent_drv) = { 129 .name = "pci_emul_parent_drv", 130 .id = UCLASS_PCI_EMUL_PARENT, 131 .of_match = pci_emul_parent_ids, 132}; 133