/src/u-boot/drivers/pci/pci_sandbox.c
Line | Count | Source |
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 <dm.h> |
8 | | #include <fdtdec.h> |
9 | | #include <log.h> |
10 | | #include <pci.h> |
11 | | |
12 | 0 | #define FDT_DEV_INFO_CELLS 4 |
13 | 0 | #define FDT_DEV_INFO_SIZE (FDT_DEV_INFO_CELLS * sizeof(u32)) |
14 | | |
15 | 0 | #define SANDBOX_PCI_DEVFN(d, f) ((d << 3) | f) |
16 | | |
17 | | struct sandbox_pci_priv { |
18 | | struct { |
19 | | u16 vendor; |
20 | | u16 device; |
21 | | } vendev[256]; |
22 | | }; |
23 | | |
24 | | static int sandbox_pci_write_config(struct udevice *bus, pci_dev_t devfn, |
25 | | uint offset, ulong value, |
26 | | enum pci_size_t size) |
27 | 0 | { |
28 | 0 | struct dm_pci_emul_ops *ops; |
29 | 0 | struct udevice *container, *emul; |
30 | 0 | int ret; |
31 | |
|
32 | 0 | ret = sandbox_pci_get_emul(bus, devfn, &container, &emul); |
33 | 0 | if (ret) |
34 | 0 | return ret == -ENODEV ? 0 : ret; |
35 | 0 | ops = pci_get_emul_ops(emul); |
36 | 0 | if (!ops || !ops->write_config) |
37 | 0 | return -ENOSYS; |
38 | | |
39 | 0 | return ops->write_config(emul, offset, value, size); |
40 | 0 | } |
41 | | |
42 | | static int sandbox_pci_read_config(const struct udevice *bus, pci_dev_t devfn, |
43 | | uint offset, ulong *valuep, |
44 | | enum pci_size_t size) |
45 | 0 | { |
46 | 0 | struct dm_pci_emul_ops *ops; |
47 | 0 | struct udevice *container, *emul; |
48 | 0 | struct sandbox_pci_priv *priv = dev_get_priv(bus); |
49 | 0 | int ret; |
50 | | |
51 | | /* Prepare the default response */ |
52 | 0 | *valuep = pci_get_ff(size); |
53 | 0 | ret = sandbox_pci_get_emul(bus, devfn, &container, &emul); |
54 | 0 | if (ret) { |
55 | 0 | if (!container) { |
56 | 0 | u16 vendor, device; |
57 | |
|
58 | 0 | devfn = SANDBOX_PCI_DEVFN(PCI_DEV(devfn), |
59 | 0 | PCI_FUNC(devfn)); |
60 | 0 | vendor = priv->vendev[devfn].vendor; |
61 | 0 | device = priv->vendev[devfn].device; |
62 | 0 | if (offset == PCI_VENDOR_ID && vendor) |
63 | 0 | *valuep = vendor; |
64 | 0 | else if (offset == PCI_DEVICE_ID && device) |
65 | 0 | *valuep = device; |
66 | |
|
67 | 0 | return 0; |
68 | 0 | } else { |
69 | 0 | return ret == -ENODEV ? 0 : ret; |
70 | 0 | } |
71 | 0 | } |
72 | 0 | ops = pci_get_emul_ops(emul); |
73 | 0 | if (!ops || !ops->read_config) |
74 | 0 | return -ENOSYS; |
75 | | |
76 | 0 | return ops->read_config(emul, offset, valuep, size); |
77 | 0 | } |
78 | | |
79 | | static int sandbox_pci_probe(struct udevice *dev) |
80 | 0 | { |
81 | 0 | struct sandbox_pci_priv *priv = dev_get_priv(dev); |
82 | 0 | const fdt32_t *cell; |
83 | 0 | u8 pdev, pfn, devfn; |
84 | 0 | int len; |
85 | |
|
86 | 0 | cell = ofnode_get_property(dev_ofnode(dev), "sandbox,dev-info", &len); |
87 | 0 | if (!cell) |
88 | 0 | return 0; |
89 | | |
90 | 0 | if ((len % FDT_DEV_INFO_SIZE) == 0) { |
91 | 0 | int num = len / FDT_DEV_INFO_SIZE; |
92 | 0 | int i; |
93 | |
|
94 | 0 | for (i = 0; i < num; i++) { |
95 | 0 | debug("dev info #%d: %02x %02x %04x %04x\n", i, |
96 | 0 | fdt32_to_cpu(cell[0]), fdt32_to_cpu(cell[1]), |
97 | 0 | fdt32_to_cpu(cell[2]), fdt32_to_cpu(cell[3])); |
98 | |
|
99 | 0 | pdev = fdt32_to_cpu(cell[0]); |
100 | 0 | pfn = fdt32_to_cpu(cell[1]); |
101 | 0 | if (pdev > 31 || pfn > 7) |
102 | 0 | continue; |
103 | 0 | devfn = SANDBOX_PCI_DEVFN(pdev, pfn); |
104 | 0 | priv->vendev[devfn].vendor = fdt32_to_cpu(cell[2]); |
105 | 0 | priv->vendev[devfn].device = fdt32_to_cpu(cell[3]); |
106 | |
|
107 | 0 | cell += FDT_DEV_INFO_CELLS; |
108 | 0 | } |
109 | 0 | } |
110 | |
|
111 | 0 | return 0; |
112 | 0 | } |
113 | | |
114 | | static const struct dm_pci_ops sandbox_pci_ops = { |
115 | | .read_config = sandbox_pci_read_config, |
116 | | .write_config = sandbox_pci_write_config, |
117 | | }; |
118 | | |
119 | | static const struct udevice_id sandbox_pci_ids[] = { |
120 | | { .compatible = "sandbox,pci" }, |
121 | | { } |
122 | | }; |
123 | | |
124 | | U_BOOT_DRIVER(pci_sandbox) = { |
125 | | .name = "pci_sandbox", |
126 | | .id = UCLASS_PCI, |
127 | | .of_match = sandbox_pci_ids, |
128 | | .ops = &sandbox_pci_ops, |
129 | | .probe = sandbox_pci_probe, |
130 | | .priv_auto = sizeof(struct sandbox_pci_priv), |
131 | | |
132 | | /* Attach an emulator if we can */ |
133 | | .child_post_bind = dm_scan_fdt_dev, |
134 | | .per_child_plat_auto = sizeof(struct pci_child_plat), |
135 | | }; |