sandbox: Rename PCI ID for swap_case to be more specific
[oweals/u-boot.git] / drivers / misc / swap_case.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * PCI emulation device which swaps the case of text
4  *
5  * Copyright (c) 2014 Google, Inc
6  * Written by Simon Glass <sjg@chromium.org>
7  */
8
9 #include <common.h>
10 #include <dm.h>
11 #include <errno.h>
12 #include <pci.h>
13 #include <asm/test.h>
14 #include <linux/ctype.h>
15
16 /**
17  * struct swap_case_platdata - platform data for this device
18  *
19  * @command:    Current PCI command value
20  * @bar:        Current base address values
21  */
22 struct swap_case_platdata {
23         u16 command;
24         u32 bar[6];
25 };
26
27 #define offset_to_barnum(offset)        \
28                 (((offset) - PCI_BASE_ADDRESS_0) / sizeof(u32))
29
30 enum {
31         MEM_TEXT_SIZE   = 0x100,
32 };
33
34 enum swap_case_op {
35         OP_TO_LOWER,
36         OP_TO_UPPER,
37         OP_SWAP,
38 };
39
40 static struct pci_bar {
41         int type;
42         u32 size;
43 } barinfo[] = {
44         { PCI_BASE_ADDRESS_SPACE_IO, 1 },
45         { PCI_BASE_ADDRESS_MEM_TYPE_32, MEM_TEXT_SIZE },
46         { 0, 0 },
47         { 0, 0 },
48         { 0, 0 },
49         { 0, 0 },
50 };
51
52 struct swap_case_priv {
53         enum swap_case_op op;
54         char mem_text[MEM_TEXT_SIZE];
55 };
56
57 static int sandbox_swap_case_get_devfn(struct udevice *dev)
58 {
59         struct pci_child_platdata *plat = dev_get_parent_platdata(dev);
60
61         return plat->devfn;
62 }
63
64 static int sandbox_swap_case_use_ea(struct udevice *dev)
65 {
66         return !!ofnode_get_property(dev->node, "use-ea", NULL);
67 }
68
69 /* Please keep these macros in sync with ea_regs below */
70 #define PCI_CAP_ID_EA_SIZE              (sizeof(ea_regs) + 4)
71 #define PCI_CAP_ID_EA_ENTRY_CNT         4
72 /* Hardcoded EA structure, excluding 1st DW. */
73 static const u32 ea_regs[] = {
74         /* BEI=0, ES=2, BAR0 32b Base + 32b MaxOffset, I/O space */
75         (2 << 8) | 2,
76         PCI_CAP_EA_BASE_LO0,
77         0,
78         /* BEI=1, ES=2, BAR1 32b Base + 32b MaxOffset */
79         (1 << 4) | 2,
80         PCI_CAP_EA_BASE_LO1,
81         MEM_TEXT_SIZE - 1,
82         /* BEI=2, ES=3, BAR2 64b Base + 32b MaxOffset */
83         (2 << 4) | 3,
84         PCI_CAP_EA_BASE_LO2 | PCI_EA_IS_64,
85         PCI_CAP_EA_SIZE_LO,
86         PCI_CAP_EA_BASE_HI2,
87         /* BEI=4, ES=4, BAR4 64b Base + 64b MaxOffset */
88         (4 << 4) | 4,
89         PCI_CAP_EA_BASE_LO4 | PCI_EA_IS_64,
90         PCI_CAP_EA_SIZE_LO | PCI_EA_IS_64,
91         PCI_CAP_EA_BASE_HI4,
92         PCI_CAP_EA_SIZE_HI,
93 };
94
95 static int sandbox_swap_case_read_ea(struct udevice *emul, uint offset,
96                                      ulong *valuep, enum pci_size_t size)
97 {
98         u32 reg;
99
100         offset = offset - PCI_CAP_ID_EA_OFFSET - 4;
101         reg = ea_regs[offset >> 2];
102         reg >>= (offset % 4) * 8;
103
104         *valuep = reg;
105         return 0;
106 }
107
108 static int sandbox_swap_case_read_config(struct udevice *emul, uint offset,
109                                          ulong *valuep, enum pci_size_t size)
110 {
111         struct swap_case_platdata *plat = dev_get_platdata(emul);
112
113         /*
114          * The content of the EA capability structure is handled elsewhere to
115          * keep the switch/case below sane
116          */
117         if (offset > PCI_CAP_ID_EA_OFFSET + PCI_CAP_LIST_NEXT &&
118             offset < PCI_CAP_ID_EA_OFFSET + PCI_CAP_ID_EA_SIZE)
119                 return sandbox_swap_case_read_ea(emul, offset, valuep, size);
120
121         switch (offset) {
122         case PCI_COMMAND:
123                 *valuep = plat->command;
124                 break;
125         case PCI_HEADER_TYPE:
126                 *valuep = 0;
127                 break;
128         case PCI_VENDOR_ID:
129                 *valuep = SANDBOX_PCI_VENDOR_ID;
130                 break;
131         case PCI_DEVICE_ID:
132                 *valuep = SANDBOX_PCI_SWAP_CASE_EMUL_ID;
133                 break;
134         case PCI_CLASS_DEVICE:
135                 if (size == PCI_SIZE_8) {
136                         *valuep = SANDBOX_PCI_CLASS_SUB_CODE;
137                 } else {
138                         *valuep = (SANDBOX_PCI_CLASS_CODE << 8) |
139                                         SANDBOX_PCI_CLASS_SUB_CODE;
140                 }
141                 break;
142         case PCI_CLASS_CODE:
143                 *valuep = SANDBOX_PCI_CLASS_CODE;
144                 break;
145         case PCI_BASE_ADDRESS_0:
146         case PCI_BASE_ADDRESS_1:
147         case PCI_BASE_ADDRESS_2:
148         case PCI_BASE_ADDRESS_3:
149         case PCI_BASE_ADDRESS_4:
150         case PCI_BASE_ADDRESS_5: {
151                 int barnum;
152                 u32 *bar, result;
153
154                 barnum = offset_to_barnum(offset);
155                 bar = &plat->bar[barnum];
156
157                 result = *bar;
158                 if (*bar == 0xffffffff) {
159                         if (barinfo[barnum].type) {
160                                 result = (~(barinfo[barnum].size - 1) &
161                                         PCI_BASE_ADDRESS_IO_MASK) |
162                                         PCI_BASE_ADDRESS_SPACE_IO;
163                         } else {
164                                 result = (~(barinfo[barnum].size - 1) &
165                                         PCI_BASE_ADDRESS_MEM_MASK) |
166                                         PCI_BASE_ADDRESS_MEM_TYPE_32;
167                         }
168                 }
169                 debug("r bar %d=%x\n", barnum, result);
170                 *valuep = result;
171                 break;
172         }
173         case PCI_CAPABILITY_LIST:
174                 *valuep = PCI_CAP_ID_PM_OFFSET;
175                 break;
176         case PCI_CAP_ID_PM_OFFSET:
177                 *valuep = (PCI_CAP_ID_EXP_OFFSET << 8) | PCI_CAP_ID_PM;
178                 break;
179         case PCI_CAP_ID_PM_OFFSET + PCI_CAP_LIST_NEXT:
180                 *valuep = PCI_CAP_ID_EXP_OFFSET;
181                 break;
182         case PCI_CAP_ID_EXP_OFFSET:
183                 *valuep = (PCI_CAP_ID_MSIX_OFFSET << 8) | PCI_CAP_ID_EXP;
184                 break;
185         case PCI_CAP_ID_EXP_OFFSET + PCI_CAP_LIST_NEXT:
186                 *valuep = PCI_CAP_ID_MSIX_OFFSET;
187                 break;
188         case PCI_CAP_ID_MSIX_OFFSET:
189                 if (sandbox_swap_case_use_ea(emul))
190                         *valuep = (PCI_CAP_ID_EA_OFFSET << 8) | PCI_CAP_ID_MSIX;
191                 else
192                         *valuep = PCI_CAP_ID_MSIX;
193                 break;
194         case PCI_CAP_ID_MSIX_OFFSET + PCI_CAP_LIST_NEXT:
195                 if (sandbox_swap_case_use_ea(emul))
196                         *valuep = PCI_CAP_ID_EA_OFFSET;
197                 else
198                         *valuep = 0;
199                 break;
200         case PCI_CAP_ID_EA_OFFSET:
201                 *valuep = (PCI_CAP_ID_EA_ENTRY_CNT << 16) | PCI_CAP_ID_EA;
202                 break;
203         case PCI_CAP_ID_EA_OFFSET + PCI_CAP_LIST_NEXT:
204                 *valuep = 0;
205                 break;
206         case PCI_EXT_CAP_ID_ERR_OFFSET:
207                 *valuep = (PCI_EXT_CAP_ID_VC_OFFSET << 20) | PCI_EXT_CAP_ID_ERR;
208                 break;
209         case PCI_EXT_CAP_ID_VC_OFFSET:
210                 *valuep = (PCI_EXT_CAP_ID_DSN_OFFSET << 20) | PCI_EXT_CAP_ID_VC;
211                 break;
212         case PCI_EXT_CAP_ID_DSN_OFFSET:
213                 *valuep = PCI_EXT_CAP_ID_DSN;
214                 break;
215         }
216
217         return 0;
218 }
219
220 static int sandbox_swap_case_write_config(struct udevice *emul, uint offset,
221                                           ulong value, enum pci_size_t size)
222 {
223         struct swap_case_platdata *plat = dev_get_platdata(emul);
224
225         switch (offset) {
226         case PCI_COMMAND:
227                 plat->command = value;
228                 break;
229         case PCI_BASE_ADDRESS_0:
230         case PCI_BASE_ADDRESS_1: {
231                 int barnum;
232                 u32 *bar;
233
234                 barnum = offset_to_barnum(offset);
235                 bar = &plat->bar[barnum];
236
237                 debug("w bar %d=%lx\n", barnum, value);
238                 *bar = value;
239                 /* space indicator (bit#0) is read-only */
240                 *bar |= barinfo[barnum].type;
241                 break;
242         }
243         }
244
245         return 0;
246 }
247
248 static int sandbox_swap_case_find_bar(struct udevice *emul, unsigned int addr,
249                                       int *barnump, unsigned int *offsetp)
250 {
251         struct swap_case_platdata *plat = dev_get_platdata(emul);
252         int barnum;
253
254         for (barnum = 0; barnum < ARRAY_SIZE(barinfo); barnum++) {
255                 unsigned int size = barinfo[barnum].size;
256                 u32 base = plat->bar[barnum] & ~PCI_BASE_ADDRESS_SPACE;
257
258                 if (addr >= base && addr < base + size) {
259                         *barnump = barnum;
260                         *offsetp = addr - base;
261                         return 0;
262                 }
263         }
264         *barnump = -1;
265
266         return -ENOENT;
267 }
268
269 static void sandbox_swap_case_do_op(enum swap_case_op op, char *str, int len)
270 {
271         for (; len > 0; len--, str++) {
272                 switch (op) {
273                 case OP_TO_UPPER:
274                         *str = toupper(*str);
275                         break;
276                 case OP_TO_LOWER:
277                         *str = tolower(*str);
278                         break;
279                 case OP_SWAP:
280                         if (isupper(*str))
281                                 *str = tolower(*str);
282                         else
283                                 *str = toupper(*str);
284                         break;
285                 }
286         }
287 }
288
289 int sandbox_swap_case_read_io(struct udevice *dev, unsigned int addr,
290                               ulong *valuep, enum pci_size_t size)
291 {
292         struct swap_case_priv *priv = dev_get_priv(dev);
293         unsigned int offset;
294         int barnum;
295         int ret;
296
297         ret = sandbox_swap_case_find_bar(dev, addr, &barnum, &offset);
298         if (ret)
299                 return ret;
300
301         if (barnum == 0 && offset == 0)
302                 *valuep = (*valuep & ~0xff) | priv->op;
303
304         return 0;
305 }
306
307 int sandbox_swap_case_write_io(struct udevice *dev, unsigned int addr,
308                                ulong value, enum pci_size_t size)
309 {
310         struct swap_case_priv *priv = dev_get_priv(dev);
311         unsigned int offset;
312         int barnum;
313         int ret;
314
315         ret = sandbox_swap_case_find_bar(dev, addr, &barnum, &offset);
316         if (ret)
317                 return ret;
318         if (barnum == 0 && offset == 0)
319                 priv->op = value;
320
321         return 0;
322 }
323
324 static int pci_ea_bar2_magic = PCI_EA_BAR2_MAGIC;
325 static int pci_ea_bar4_magic = PCI_EA_BAR4_MAGIC;
326
327 static int sandbox_swap_case_map_physmem(struct udevice *dev,
328                 phys_addr_t addr, unsigned long *lenp, void **ptrp)
329 {
330         struct swap_case_priv *priv = dev_get_priv(dev);
331         unsigned int offset, avail;
332         int barnum;
333         int ret;
334
335         if (sandbox_swap_case_use_ea(dev)) {
336                 /*
337                  * only support mapping base address in EA test for now, we
338                  * don't handle mapping an offset inside a BAR.  Seems good
339                  * enough for the current test.
340                  */
341                 switch (addr) {
342                 case (phys_addr_t)PCI_CAP_EA_BASE_LO0:
343                         *ptrp = &priv->op;
344                         *lenp = 4;
345                         break;
346                 case (phys_addr_t)PCI_CAP_EA_BASE_LO1:
347                         *ptrp = priv->mem_text;
348                         *lenp = barinfo[1].size - 1;
349                         break;
350                 case (phys_addr_t)((PCI_CAP_EA_BASE_HI2 << 32) |
351                                    PCI_CAP_EA_BASE_LO2):
352                         *ptrp = &pci_ea_bar2_magic;
353                         *lenp = PCI_CAP_EA_SIZE_LO;
354                         break;
355                 case (phys_addr_t)((PCI_CAP_EA_BASE_HI4 << 32) |
356                                    PCI_CAP_EA_BASE_LO4):
357                         *ptrp = &pci_ea_bar4_magic;
358                         *lenp = (PCI_CAP_EA_SIZE_HI << 32) |
359                                 PCI_CAP_EA_SIZE_LO;
360                         break;
361                 default:
362                         return -ENOENT;
363                 }
364                 return 0;
365         }
366
367         ret = sandbox_swap_case_find_bar(dev, addr, &barnum, &offset);
368         if (ret)
369                 return ret;
370
371         if (barnum == 1) {
372                 *ptrp = priv->mem_text + offset;
373                 avail = barinfo[1].size - offset;
374                 if (avail > barinfo[1].size)
375                         *lenp = 0;
376                 else
377                         *lenp = min(*lenp, (ulong)avail);
378
379                 return 0;
380         }
381
382         return -ENOENT;
383 }
384
385 static int sandbox_swap_case_unmap_physmem(struct udevice *dev,
386                                            const void *vaddr, unsigned long len)
387 {
388         struct swap_case_priv *priv = dev_get_priv(dev);
389
390         sandbox_swap_case_do_op(priv->op, (void *)vaddr, len);
391
392         return 0;
393 }
394
395 struct dm_pci_emul_ops sandbox_swap_case_emul_ops = {
396         .get_devfn = sandbox_swap_case_get_devfn,
397         .read_config = sandbox_swap_case_read_config,
398         .write_config = sandbox_swap_case_write_config,
399         .read_io = sandbox_swap_case_read_io,
400         .write_io = sandbox_swap_case_write_io,
401         .map_physmem = sandbox_swap_case_map_physmem,
402         .unmap_physmem = sandbox_swap_case_unmap_physmem,
403 };
404
405 static const struct udevice_id sandbox_swap_case_ids[] = {
406         { .compatible = "sandbox,swap-case" },
407         { }
408 };
409
410 U_BOOT_DRIVER(sandbox_swap_case_emul) = {
411         .name           = "sandbox_swap_case_emul",
412         .id             = UCLASS_PCI_EMUL,
413         .of_match       = sandbox_swap_case_ids,
414         .ops            = &sandbox_swap_case_emul_ops,
415         .priv_auto_alloc_size = sizeof(struct swap_case_priv),
416         .platdata_auto_alloc_size = sizeof(struct swap_case_platdata),
417 };
418
419 static struct pci_device_id sandbox_swap_case_supported[] = {
420         { PCI_VDEVICE(SANDBOX, SANDBOX_PCI_SWAP_CASE_EMUL_ID),
421                 SWAP_CASE_DRV_DATA },
422         {},
423 };
424
425 U_BOOT_PCI_DEVICE(sandbox_swap_case_emul, sandbox_swap_case_supported);