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