]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
537849aa SG |
2 | /* |
3 | * Copyright (c) 2014 Google, Inc | |
4 | * Written by Simon Glass <[email protected]> | |
537849aa SG |
5 | */ |
6 | ||
7 | #include <common.h> | |
8 | #include <dm.h> | |
9 | #include <fdtdec.h> | |
537849aa | 10 | #include <pci.h> |
537849aa | 11 | |
4345998a BM |
12 | #define FDT_DEV_INFO_CELLS 4 |
13 | #define FDT_DEV_INFO_SIZE (FDT_DEV_INFO_CELLS * sizeof(u32)) | |
14 | ||
15 | #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 | ||
537849aa SG |
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 | { | |
28 | struct dm_pci_emul_ops *ops; | |
4345998a | 29 | struct udevice *container, *emul; |
537849aa SG |
30 | int ret; |
31 | ||
4345998a | 32 | ret = sandbox_pci_get_emul(bus, devfn, &container, &emul); |
537849aa SG |
33 | if (ret) |
34 | return ret == -ENODEV ? 0 : ret; | |
35 | ops = pci_get_emul_ops(emul); | |
36 | if (!ops || !ops->write_config) | |
37 | return -ENOSYS; | |
38 | ||
39 | return ops->write_config(emul, offset, value, size); | |
40 | } | |
41 | ||
c4e72c4a | 42 | static int sandbox_pci_read_config(const struct udevice *bus, pci_dev_t devfn, |
537849aa SG |
43 | uint offset, ulong *valuep, |
44 | enum pci_size_t size) | |
45 | { | |
46 | struct dm_pci_emul_ops *ops; | |
4345998a BM |
47 | struct udevice *container, *emul; |
48 | struct sandbox_pci_priv *priv = dev_get_priv(bus); | |
537849aa SG |
49 | int ret; |
50 | ||
51 | /* Prepare the default response */ | |
52 | *valuep = pci_get_ff(size); | |
4345998a BM |
53 | ret = sandbox_pci_get_emul(bus, devfn, &container, &emul); |
54 | if (ret) { | |
55 | if (!container) { | |
56 | u16 vendor, device; | |
57 | ||
58 | devfn = SANDBOX_PCI_DEVFN(PCI_DEV(devfn), | |
59 | PCI_FUNC(devfn)); | |
60 | vendor = priv->vendev[devfn].vendor; | |
61 | device = priv->vendev[devfn].device; | |
62 | if (offset == PCI_VENDOR_ID && vendor) | |
63 | *valuep = vendor; | |
64 | else if (offset == PCI_DEVICE_ID && device) | |
65 | *valuep = device; | |
66 | ||
67 | return 0; | |
68 | } else { | |
69 | return ret == -ENODEV ? 0 : ret; | |
70 | } | |
71 | } | |
537849aa SG |
72 | ops = pci_get_emul_ops(emul); |
73 | if (!ops || !ops->read_config) | |
74 | return -ENOSYS; | |
75 | ||
76 | return ops->read_config(emul, offset, valuep, size); | |
77 | } | |
78 | ||
4345998a BM |
79 | static int sandbox_pci_probe(struct udevice *dev) |
80 | { | |
81 | struct sandbox_pci_priv *priv = dev_get_priv(dev); | |
82 | const fdt32_t *cell; | |
83 | u8 pdev, pfn, devfn; | |
84 | int len; | |
85 | ||
86 | cell = ofnode_get_property(dev_ofnode(dev), "sandbox,dev-info", &len); | |
87 | if (!cell) | |
88 | return 0; | |
89 | ||
90 | if ((len % FDT_DEV_INFO_SIZE) == 0) { | |
91 | int num = len / FDT_DEV_INFO_SIZE; | |
92 | int i; | |
93 | ||
94 | for (i = 0; i < num; i++) { | |
95 | debug("dev info #%d: %02x %02x %04x %04x\n", i, | |
96 | fdt32_to_cpu(cell[0]), fdt32_to_cpu(cell[1]), | |
97 | fdt32_to_cpu(cell[2]), fdt32_to_cpu(cell[3])); | |
98 | ||
99 | pdev = fdt32_to_cpu(cell[0]); | |
100 | pfn = fdt32_to_cpu(cell[1]); | |
101 | if (pdev > 31 || pfn > 7) | |
102 | continue; | |
103 | devfn = SANDBOX_PCI_DEVFN(pdev, pfn); | |
104 | priv->vendev[devfn].vendor = fdt32_to_cpu(cell[2]); | |
105 | priv->vendev[devfn].device = fdt32_to_cpu(cell[3]); | |
106 | ||
107 | cell += FDT_DEV_INFO_CELLS; | |
108 | } | |
109 | } | |
110 | ||
111 | return 0; | |
112 | } | |
113 | ||
537849aa SG |
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, | |
4345998a BM |
129 | .probe = sandbox_pci_probe, |
130 | .priv_auto_alloc_size = sizeof(struct sandbox_pci_priv), | |
91195485 SG |
131 | |
132 | /* Attach an emulator if we can */ | |
133 | .child_post_bind = dm_scan_fdt_dev, | |
537849aa SG |
134 | .per_child_platdata_auto_alloc_size = |
135 | sizeof(struct pci_child_platdata), | |
136 | }; |