sandbox: Add PCI driver and test for p2sb
[oweals/u-boot.git] / drivers / misc / p2sb_emul.c
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 #define LOG_DEBUG
11
12 #include <common.h>
13 #include <axi.h>
14 #include <dm.h>
15 #include <pci.h>
16 #include <asm/test.h>
17 #include <p2sb.h>
18
19 /**
20  * struct p2sb_emul_platdata - platform data for this device
21  *
22  * @command:    Current PCI command value
23  * @bar:        Current base address values
24  */
25 struct p2sb_emul_platdata {
26         u16 command;
27         u32 bar[6];
28 };
29
30 enum {
31         /* This emulator supports 16 different devices */
32         MEMMAP_SIZE     = 16 << PCR_PORTID_SHIFT,
33 };
34
35 static struct pci_bar {
36         int type;
37         u32 size;
38 } barinfo[] = {
39         { PCI_BASE_ADDRESS_MEM_TYPE_32, MEMMAP_SIZE },
40         { 0, 0 },
41         { 0, 0 },
42         { 0, 0 },
43         { 0, 0 },
44         { 0, 0 },
45 };
46
47 struct p2sb_emul_priv {
48         u8 regs[16];
49 };
50
51 static int sandbox_p2sb_emul_read_config(struct udevice *emul, uint offset,
52                                          ulong *valuep, enum pci_size_t size)
53 {
54         struct p2sb_emul_platdata *plat = dev_get_platdata(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
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_platdata *plat = dev_get_platdata(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
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_platdata *plat = dev_get_platdata(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
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
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
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_platdata *pplat =
199                          dev_get_parent_platdata(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
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;
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_alloc_size = sizeof(struct p2sb_emul_priv),
264         .platdata_auto_alloc_size = sizeof(struct p2sb_emul_platdata),
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);