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