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 
sandbox_swap_case_use_ea(const struct udevice * dev)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 
sandbox_swap_case_read_ea(const struct udevice * emul,uint offset,ulong * valuep,enum pci_size_t size)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 
sandbox_swap_case_read_config(const struct udevice * emul,uint offset,ulong * valuep,enum pci_size_t size)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 
sandbox_swap_case_write_config(struct udevice * emul,uint offset,ulong value,enum pci_size_t size)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 
sandbox_swap_case_find_bar(struct udevice * emul,unsigned int addr,int * barnump,unsigned int * offsetp)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 
sandbox_swap_case_do_op(enum swap_case_op op,char * str,int len)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 
sandbox_swap_case_read_io(struct udevice * dev,unsigned int addr,ulong * valuep,enum pci_size_t size)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 
sandbox_swap_case_write_io(struct udevice * dev,unsigned int addr,ulong value,enum pci_size_t size)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 
sandbox_swap_case_map_physmem(struct udevice * dev,phys_addr_t addr,unsigned long * lenp,void ** ptrp)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 
sandbox_swap_case_unmap_physmem(struct udevice * dev,const void * vaddr,unsigned long len)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);
417