2018-05-06 21:58:06 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
2015-03-05 19:25:28 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2014 Google, Inc
|
|
|
|
* Written by Simon Glass <sjg@chromium.org>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <common.h>
|
|
|
|
#include <dm.h>
|
|
|
|
#include <fdtdec.h>
|
2020-05-10 17:40:05 +00:00
|
|
|
#include <log.h>
|
2018-03-04 16:20:11 +00:00
|
|
|
#include <linux/libfdt.h>
|
2015-03-05 19:25:28 +00:00
|
|
|
#include <pci.h>
|
|
|
|
#include <dm/lists.h>
|
|
|
|
|
2018-08-03 08:14:49 +00:00
|
|
|
struct sandbox_pci_emul_priv {
|
2015-03-05 19:25:28 +00:00
|
|
|
int dev_count;
|
|
|
|
};
|
|
|
|
|
2020-01-27 15:49:37 +00:00
|
|
|
int sandbox_pci_get_emul(const struct udevice *bus, pci_dev_t find_devfn,
|
2018-08-03 08:14:45 +00:00
|
|
|
struct udevice **containerp, struct udevice **emulp)
|
2015-03-05 19:25:28 +00:00
|
|
|
{
|
2019-09-21 20:32:41 +00:00
|
|
|
struct pci_emul_uc_priv *upriv;
|
2015-03-05 19:25:28 +00:00
|
|
|
struct udevice *dev;
|
|
|
|
int ret;
|
|
|
|
|
2018-08-03 08:14:45 +00:00
|
|
|
*containerp = NULL;
|
2018-08-03 08:14:43 +00:00
|
|
|
ret = pci_bus_find_devfn(bus, PCI_MASK_BUS(find_devfn), &dev);
|
2015-03-05 19:25:28 +00:00
|
|
|
if (ret) {
|
|
|
|
debug("%s: Could not find emulator for dev %x\n", __func__,
|
|
|
|
find_devfn);
|
|
|
|
return ret;
|
|
|
|
}
|
2018-08-03 08:14:45 +00:00
|
|
|
*containerp = dev;
|
2015-03-05 19:25:28 +00:00
|
|
|
|
2019-08-31 23:59:32 +00:00
|
|
|
ret = uclass_get_device_by_phandle(UCLASS_PCI_EMUL, dev, "sandbox,emul",
|
|
|
|
emulp);
|
2019-09-21 20:32:41 +00:00
|
|
|
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"
|
|
|
|
*/
|
2018-08-03 08:14:45 +00:00
|
|
|
*emulp = dev;
|
2019-09-21 20:32:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2015-03-05 19:25:28 +00:00
|
|
|
|
2019-09-21 20:32:41 +00:00
|
|
|
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;
|
2015-03-05 19:25:28 +00:00
|
|
|
}
|
|
|
|
|
2019-09-25 14:56:42 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-03-05 19:25:28 +00:00
|
|
|
static int sandbox_pci_emul_post_probe(struct udevice *dev)
|
|
|
|
{
|
2020-12-23 02:30:28 +00:00
|
|
|
struct sandbox_pci_emul_priv *priv = uclass_get_priv(dev->uclass);
|
2015-03-05 19:25:28 +00:00
|
|
|
|
|
|
|
priv->dev_count++;
|
|
|
|
sandbox_set_enable_pci_map(true);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sandbox_pci_emul_pre_remove(struct udevice *dev)
|
|
|
|
{
|
2020-12-23 02:30:28 +00:00
|
|
|
struct sandbox_pci_emul_priv *priv = uclass_get_priv(dev->uclass);
|
2015-03-05 19:25:28 +00:00
|
|
|
|
|
|
|
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,
|
2020-12-03 23:55:17 +00:00
|
|
|
.priv_auto = sizeof(struct sandbox_pci_emul_priv),
|
|
|
|
.per_device_auto = sizeof(struct pci_emul_uc_priv),
|
2015-03-05 19:25:28 +00:00
|
|
|
};
|
pci: sandbox: Move the emulators into their own node
Sandbox pci works using emulation drivers which are currently children of
the pci device:
pci-controller {
pci@1f,0 {
compatible = "pci-generic";
reg = <0xf800 0 0 0 0>;
emul@1f,0 {
compatible = "sandbox,swap-case";
};
};
};
In this case the emulation device is attached to pci device on address
f800 (device 1f, function 0) and provides the swap-case functionality.
However this is not ideal, since every device on a PCI bus has a child
device. This is only really the case for sandbox, but we want to avoid
special-case code for sandbox.
Worse, child devices cannot be probed before their parents. This forces
us to use 'find' rather than 'get' to obtain the emulator device. In fact
the emulator devices are never probed. There is code in
sandbox_pci_emul_post_probe() which tries to track when emulators are
active, but at present this does not work.
A better approach seems to be to add a separate node elsewhere in the
device tree, an 'emulation parent'. This could be given a bogus address
(such as -1) to hide the emulators away from the 'pci' command, but it
seems better to keep it at the root node to avoid such hacks.
Then we can use a phandle to point from the device to the correct
emulator, and only on sandbox. The code to find an emulator does not
interfere with normal pci operation.
Add a new UCLASS_PCI_EMUL_PARENT uclass which allows finding an emulator
given a bus, and finding a bus given an emulator. Update the existing
device trees and the code for finding an emulator.
This brings PCI emulators more into line with I2C.
Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Bin Meng <bmeng.cn@gmail.com>
[bmeng: fix 3 typos in the commit message;
encode bus number in the labels of swap_case_emul nodes;
mention commit 4345998ae9df in sandbox_pci_get_emul()]
Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
2019-09-25 14:56:10 +00:00
|
|
|
|
|
|
|
/*
|
2020-12-03 23:55:18 +00:00
|
|
|
* This uclass is a child of the pci bus. Its plat is not defined here so
|
2020-12-03 23:55:23 +00:00
|
|
|
* is defined by its parent, UCLASS_PCI, which uses struct pci_child_plat.
|
2020-12-03 23:55:18 +00:00
|
|
|
* See per_child_plat_auto in UCLASS_DRIVER(pci).
|
pci: sandbox: Move the emulators into their own node
Sandbox pci works using emulation drivers which are currently children of
the pci device:
pci-controller {
pci@1f,0 {
compatible = "pci-generic";
reg = <0xf800 0 0 0 0>;
emul@1f,0 {
compatible = "sandbox,swap-case";
};
};
};
In this case the emulation device is attached to pci device on address
f800 (device 1f, function 0) and provides the swap-case functionality.
However this is not ideal, since every device on a PCI bus has a child
device. This is only really the case for sandbox, but we want to avoid
special-case code for sandbox.
Worse, child devices cannot be probed before their parents. This forces
us to use 'find' rather than 'get' to obtain the emulator device. In fact
the emulator devices are never probed. There is code in
sandbox_pci_emul_post_probe() which tries to track when emulators are
active, but at present this does not work.
A better approach seems to be to add a separate node elsewhere in the
device tree, an 'emulation parent'. This could be given a bogus address
(such as -1) to hide the emulators away from the 'pci' command, but it
seems better to keep it at the root node to avoid such hacks.
Then we can use a phandle to point from the device to the correct
emulator, and only on sandbox. The code to find an emulator does not
interfere with normal pci operation.
Add a new UCLASS_PCI_EMUL_PARENT uclass which allows finding an emulator
given a bus, and finding a bus given an emulator. Update the existing
device trees and the code for finding an emulator.
This brings PCI emulators more into line with I2C.
Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Bin Meng <bmeng.cn@gmail.com>
[bmeng: fix 3 typos in the commit message;
encode bus number in the labels of swap_case_emul nodes;
mention commit 4345998ae9df in sandbox_pci_get_emul()]
Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
2019-09-25 14:56:10 +00:00
|
|
|
*/
|
|
|
|
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,
|
|
|
|
};
|