1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * PCI emulation device for an x86 Primary-to-Sideband bus
4 *
5 * Copyright 2019 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
7 */
8
9 #define LOG_CATEGORY UCLASS_MISC
10
11 #include <axi.h>
12 #include <dm.h>
13 #include <log.h>
14 #include <pci.h>
15 #include <asm/test.h>
16 #include <p2sb.h>
17
18 /**
19 * struct p2sb_emul_plat - platform data for this device
20 *
21 * @command: Current PCI command value
22 * @bar: Current base address values
23 */
24 struct p2sb_emul_plat {
25 u16 command;
26 u32 bar[6];
27 };
28
29 enum {
30 /* This emulator supports 16 different devices */
31 MEMMAP_SIZE = 16 << PCR_PORTID_SHIFT,
32 };
33
34 static struct pci_bar {
35 int type;
36 u32 size;
37 } barinfo[] = {
38 { PCI_BASE_ADDRESS_MEM_TYPE_32, MEMMAP_SIZE },
39 { 0, 0 },
40 { 0, 0 },
41 { 0, 0 },
42 { 0, 0 },
43 { 0, 0 },
44 };
45
46 struct p2sb_emul_priv {
47 u8 regs[16];
48 };
49
sandbox_p2sb_emul_read_config(const struct udevice * emul,uint offset,ulong * valuep,enum pci_size_t size)50 static int sandbox_p2sb_emul_read_config(const struct udevice *emul,
51 uint offset, ulong *valuep,
52 enum pci_size_t size)
53 {
54 struct p2sb_emul_plat *plat = dev_get_plat(emul);
55
56 switch (offset) {
57 case PCI_COMMAND:
58 *valuep = plat->command;
59 break;
60 case PCI_HEADER_TYPE:
61 *valuep = PCI_HEADER_TYPE_NORMAL;
62 break;
63 case PCI_VENDOR_ID:
64 *valuep = SANDBOX_PCI_VENDOR_ID;
65 break;
66 case PCI_DEVICE_ID:
67 *valuep = SANDBOX_PCI_P2SB_EMUL_ID;
68 break;
69 case PCI_CLASS_DEVICE:
70 if (size == PCI_SIZE_8) {
71 *valuep = SANDBOX_PCI_CLASS_SUB_CODE;
72 } else {
73 *valuep = (SANDBOX_PCI_CLASS_CODE << 8) |
74 SANDBOX_PCI_CLASS_SUB_CODE;
75 }
76 break;
77 case PCI_CLASS_CODE:
78 *valuep = SANDBOX_PCI_CLASS_CODE;
79 break;
80 case PCI_BASE_ADDRESS_0:
81 case PCI_BASE_ADDRESS_1:
82 case PCI_BASE_ADDRESS_2:
83 case PCI_BASE_ADDRESS_3:
84 case PCI_BASE_ADDRESS_4:
85 case PCI_BASE_ADDRESS_5: {
86 int barnum;
87 u32 *bar;
88
89 barnum = pci_offset_to_barnum(offset);
90 bar = &plat->bar[barnum];
91
92 *valuep = sandbox_pci_read_bar(*bar, barinfo[barnum].type,
93 barinfo[barnum].size);
94 break;
95 }
96 case PCI_CAPABILITY_LIST:
97 *valuep = PCI_CAP_ID_PM_OFFSET;
98 break;
99 }
100
101 return 0;
102 }
103
sandbox_p2sb_emul_write_config(struct udevice * emul,uint offset,ulong value,enum pci_size_t size)104 static int sandbox_p2sb_emul_write_config(struct udevice *emul, uint offset,
105 ulong value, enum pci_size_t size)
106 {
107 struct p2sb_emul_plat *plat = dev_get_plat(emul);
108
109 switch (offset) {
110 case PCI_COMMAND:
111 plat->command = value;
112 break;
113 case PCI_BASE_ADDRESS_0:
114 case PCI_BASE_ADDRESS_1: {
115 int barnum;
116 u32 *bar;
117
118 barnum = pci_offset_to_barnum(offset);
119 bar = &plat->bar[barnum];
120
121 log_debug("w bar %d=%lx\n", barnum, value);
122 *bar = value;
123 /* space indicator (bit#0) is read-only */
124 *bar |= barinfo[barnum].type;
125 break;
126 }
127 }
128
129 return 0;
130 }
131
sandbox_p2sb_emul_find_bar(struct udevice * emul,unsigned int addr,int * barnump,unsigned int * offsetp)132 static int sandbox_p2sb_emul_find_bar(struct udevice *emul, unsigned int addr,
133 int *barnump, unsigned int *offsetp)
134 {
135 struct p2sb_emul_plat *plat = dev_get_plat(emul);
136 int barnum;
137
138 for (barnum = 0; barnum < ARRAY_SIZE(barinfo); barnum++) {
139 unsigned int size = barinfo[barnum].size;
140 u32 base = plat->bar[barnum] & ~PCI_BASE_ADDRESS_SPACE;
141
142 if (addr >= base && addr < base + size) {
143 *barnump = barnum;
144 *offsetp = addr - base;
145 return 0;
146 }
147 }
148 *barnump = -1;
149
150 return -ENOENT;
151 }
152
sandbox_p2sb_emul_read_io(struct udevice * dev,unsigned int addr,ulong * valuep,enum pci_size_t size)153 static int sandbox_p2sb_emul_read_io(struct udevice *dev, unsigned int addr,
154 ulong *valuep, enum pci_size_t size)
155 {
156 unsigned int offset;
157 int barnum;
158 int ret;
159
160 ret = sandbox_p2sb_emul_find_bar(dev, addr, &barnum, &offset);
161 if (ret)
162 return ret;
163
164 if (barnum == 4)
165 *valuep = offset;
166 else if (barnum == 0)
167 *valuep = offset;
168
169 return 0;
170 }
171
sandbox_p2sb_emul_write_io(struct udevice * dev,unsigned int addr,ulong value,enum pci_size_t size)172 static int sandbox_p2sb_emul_write_io(struct udevice *dev, unsigned int addr,
173 ulong value, enum pci_size_t size)
174 {
175 unsigned int offset;
176 int barnum;
177 int ret;
178
179 ret = sandbox_p2sb_emul_find_bar(dev, addr, &barnum, &offset);
180 if (ret)
181 return ret;
182
183 return 0;
184 }
185
find_p2sb_channel(struct udevice * emul,uint offset,struct udevice ** devp)186 static int find_p2sb_channel(struct udevice *emul, uint offset,
187 struct udevice **devp)
188 {
189 uint pid = offset >> PCR_PORTID_SHIFT;
190 struct udevice *p2sb, *dev;
191 int ret;
192
193 ret = sandbox_pci_get_client(emul, &p2sb);
194 if (ret)
195 return log_msg_ret("No client", ret);
196
197 device_foreach_child(dev, p2sb) {
198 struct p2sb_child_plat *pplat =
199 dev_get_parent_plat(dev);
200
201 log_debug(" - child %s, pid %d, want %d\n", dev->name,
202 pplat->pid, pid);
203 if (pid == pplat->pid) {
204 *devp = dev;
205 return 0;
206 }
207 }
208
209 return -ENOENT;
210 }
211
sandbox_p2sb_emul_map_physmem(struct udevice * dev,phys_addr_t addr,unsigned long * lenp,void ** ptrp)212 static int sandbox_p2sb_emul_map_physmem(struct udevice *dev,
213 phys_addr_t addr, unsigned long *lenp,
214 void **ptrp)
215 {
216 struct p2sb_emul_priv *priv = dev_get_priv(dev);
217 struct udevice *child = NULL; /* Silence compiler warning */
218 unsigned int offset;
219 int barnum;
220 int ret;
221
222 log_debug("map %x: ", (uint)addr);
223 ret = sandbox_p2sb_emul_find_bar(dev, addr, &barnum, &offset);
224 if (ret)
225 return log_msg_ret("Cannot find bar", ret);
226 log_debug("bar %d, offset %x\n", barnum, offset);
227
228 if (barnum != 0)
229 return log_msg_ret("Unknown BAR", -EINVAL);
230
231 ret = find_p2sb_channel(dev, offset, &child);
232 if (ret)
233 return log_msg_ret("Cannot find channel", ret);
234
235 offset &= ((1 << PCR_PORTID_SHIFT) - 1);
236 ret = axi_read(child, offset, priv->regs, AXI_SIZE_32);
237 if (ret)
238 return log_msg_ret("Child read failed", ret);
239 *ptrp = priv->regs + (offset & 3);
240 *lenp = 4;
241
242 return 0;
243 }
244
245 static struct dm_pci_emul_ops sandbox_p2sb_emul_emul_ops = {
246 .read_config = sandbox_p2sb_emul_read_config,
247 .write_config = sandbox_p2sb_emul_write_config,
248 .read_io = sandbox_p2sb_emul_read_io,
249 .write_io = sandbox_p2sb_emul_write_io,
250 .map_physmem = sandbox_p2sb_emul_map_physmem,
251 };
252
253 static const struct udevice_id sandbox_p2sb_emul_ids[] = {
254 { .compatible = "sandbox,p2sb-emul" },
255 { }
256 };
257
258 U_BOOT_DRIVER(sandbox_p2sb_emul_emul) = {
259 .name = "sandbox_p2sb_emul_emul",
260 .id = UCLASS_PCI_EMUL,
261 .of_match = sandbox_p2sb_emul_ids,
262 .ops = &sandbox_p2sb_emul_emul_ops,
263 .priv_auto = sizeof(struct p2sb_emul_priv),
264 .plat_auto = sizeof(struct p2sb_emul_plat),
265 };
266
267 static struct pci_device_id sandbox_p2sb_emul_supported[] = {
268 { PCI_VDEVICE(SANDBOX, SANDBOX_PCI_PMC_EMUL_ID) },
269 {},
270 };
271
272 U_BOOT_PCI_DEVICE(sandbox_p2sb_emul_emul, sandbox_p2sb_emul_supported);
273