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_MSIX_OFFSET:
169 		if (sandbox_swap_case_use_ea(emul))
170 			*valuep = (PCI_CAP_ID_EA_OFFSET << 8) | PCI_CAP_ID_MSIX;
171 		else
172 			*valuep = PCI_CAP_ID_MSIX;
173 		break;
174 	case PCI_CAP_ID_MSIX_OFFSET + PCI_CAP_LIST_NEXT:
175 		if (sandbox_swap_case_use_ea(emul))
176 			*valuep = PCI_CAP_ID_EA_OFFSET;
177 		else
178 			*valuep = 0;
179 		break;
180 	case PCI_CAP_ID_EA_OFFSET:
181 		*valuep = (PCI_CAP_ID_EA_ENTRY_CNT << 16) | PCI_CAP_ID_EA;
182 		break;
183 	case PCI_CAP_ID_EA_OFFSET + PCI_CAP_LIST_NEXT:
184 		*valuep = 0;
185 		break;
186 	case PCI_EXT_CAP_ID_ERR_OFFSET:
187 		*valuep = (PCI_EXT_CAP_ID_VC_OFFSET << 20) | PCI_EXT_CAP_ID_ERR;
188 		break;
189 	case PCI_EXT_CAP_ID_VC_OFFSET:
190 		*valuep = (PCI_EXT_CAP_ID_DSN_OFFSET << 20) | PCI_EXT_CAP_ID_VC;
191 		break;
192 	case PCI_EXT_CAP_ID_DSN_OFFSET:
193 		*valuep = PCI_EXT_CAP_ID_DSN;
194 		break;
195 	}
196 
197 	return 0;
198 }
199 
sandbox_swap_case_write_config(struct udevice * emul,uint offset,ulong value,enum pci_size_t size)200 static int sandbox_swap_case_write_config(struct udevice *emul, uint offset,
201 					  ulong value, enum pci_size_t size)
202 {
203 	struct swap_case_plat *plat = dev_get_plat(emul);
204 
205 	switch (offset) {
206 	case PCI_COMMAND:
207 		plat->command = value;
208 		break;
209 	case PCI_BASE_ADDRESS_0:
210 	case PCI_BASE_ADDRESS_1: {
211 		int barnum;
212 		u32 *bar;
213 
214 		barnum = pci_offset_to_barnum(offset);
215 		bar = &plat->bar[barnum];
216 
217 		debug("w bar %d=%lx\n", barnum, value);
218 		*bar = value;
219 		/* space indicator (bit#0) is read-only */
220 		*bar |= barinfo[barnum].type;
221 		break;
222 	}
223 	}
224 
225 	return 0;
226 }
227 
sandbox_swap_case_find_bar(struct udevice * emul,unsigned int addr,int * barnump,unsigned int * offsetp)228 static int sandbox_swap_case_find_bar(struct udevice *emul, unsigned int addr,
229 				      int *barnump, unsigned int *offsetp)
230 {
231 	struct swap_case_plat *plat = dev_get_plat(emul);
232 	int barnum;
233 
234 	for (barnum = 0; barnum < ARRAY_SIZE(barinfo); barnum++) {
235 		unsigned int size = barinfo[barnum].size;
236 		u32 base = plat->bar[barnum] & ~PCI_BASE_ADDRESS_SPACE;
237 
238 		if (addr >= base && addr < base + size) {
239 			*barnump = barnum;
240 			*offsetp = addr - base;
241 			return 0;
242 		}
243 	}
244 	*barnump = -1;
245 
246 	return -ENOENT;
247 }
248 
sandbox_swap_case_do_op(enum swap_case_op op,char * str,int len)249 static void sandbox_swap_case_do_op(enum swap_case_op op, char *str, int len)
250 {
251 	for (; len > 0; len--, str++) {
252 		switch (op) {
253 		case OP_TO_UPPER:
254 			*str = toupper(*str);
255 			break;
256 		case OP_TO_LOWER:
257 			*str = tolower(*str);
258 			break;
259 		case OP_SWAP:
260 			if (isupper(*str))
261 				*str = tolower(*str);
262 			else
263 				*str = toupper(*str);
264 			break;
265 		}
266 	}
267 }
268 
sandbox_swap_case_read_io(struct udevice * dev,unsigned int addr,ulong * valuep,enum pci_size_t size)269 static int sandbox_swap_case_read_io(struct udevice *dev, unsigned int addr,
270 				     ulong *valuep, enum pci_size_t size)
271 {
272 	struct swap_case_priv *priv = dev_get_priv(dev);
273 	unsigned int offset;
274 	int barnum;
275 	int ret;
276 
277 	ret = sandbox_swap_case_find_bar(dev, addr, &barnum, &offset);
278 	if (ret)
279 		return ret;
280 
281 	if (barnum == 0 && offset == 0)
282 		*valuep = (*valuep & ~0xff) | priv->op;
283 
284 	return 0;
285 }
286 
sandbox_swap_case_write_io(struct udevice * dev,unsigned int addr,ulong value,enum pci_size_t size)287 static int sandbox_swap_case_write_io(struct udevice *dev, unsigned int addr,
288 				      ulong value, enum pci_size_t size)
289 {
290 	struct swap_case_priv *priv = dev_get_priv(dev);
291 	unsigned int offset;
292 	int barnum;
293 	int ret;
294 
295 	ret = sandbox_swap_case_find_bar(dev, addr, &barnum, &offset);
296 	if (ret)
297 		return ret;
298 	if (barnum == 0 && offset == 0)
299 		priv->op = value;
300 
301 	return 0;
302 }
303 
304 static int pci_ea_bar2_magic = PCI_EA_BAR2_MAGIC;
305 static int pci_ea_bar4_magic = PCI_EA_BAR4_MAGIC;
306 
sandbox_swap_case_map_physmem(struct udevice * dev,phys_addr_t addr,unsigned long * lenp,void ** ptrp)307 static int sandbox_swap_case_map_physmem(struct udevice *dev,
308 		phys_addr_t addr, unsigned long *lenp, void **ptrp)
309 {
310 	struct swap_case_priv *priv = dev_get_priv(dev);
311 	unsigned int offset, avail;
312 	int barnum;
313 	int ret;
314 
315 	if (sandbox_swap_case_use_ea(dev)) {
316 		/*
317 		 * only support mapping base address in EA test for now, we
318 		 * don't handle mapping an offset inside a BAR.  Seems good
319 		 * enough for the current test.
320 		 */
321 		switch (addr) {
322 		case (phys_addr_t)PCI_CAP_EA_BASE_LO0:
323 			*ptrp = &priv->op;
324 			*lenp = 4;
325 			break;
326 		case (phys_addr_t)PCI_CAP_EA_BASE_LO1:
327 			*ptrp = priv->mem_text;
328 			*lenp = barinfo[1].size - 1;
329 			break;
330 		case (phys_addr_t)((PCI_CAP_EA_BASE_HI2 << 32) |
331 				   PCI_CAP_EA_BASE_LO2):
332 			*ptrp = &pci_ea_bar2_magic;
333 			*lenp = PCI_CAP_EA_SIZE_LO;
334 			break;
335 		case (phys_addr_t)((PCI_CAP_EA_BASE_HI4 << 32) |
336 				   PCI_CAP_EA_BASE_LO4):
337 			*ptrp = &pci_ea_bar4_magic;
338 			*lenp = (PCI_CAP_EA_SIZE_HI << 32) |
339 				PCI_CAP_EA_SIZE_LO;
340 			break;
341 		default:
342 			return -ENOENT;
343 		}
344 		return 0;
345 	}
346 
347 	ret = sandbox_swap_case_find_bar(dev, addr, &barnum, &offset);
348 	if (ret)
349 		return ret;
350 
351 	if (barnum == 1) {
352 		*ptrp = priv->mem_text + offset;
353 		avail = barinfo[1].size - offset;
354 		if (avail > barinfo[1].size)
355 			*lenp = 0;
356 		else
357 			*lenp = min(*lenp, (ulong)avail);
358 
359 		return 0;
360 	}
361 
362 	return -ENOENT;
363 }
364 
sandbox_swap_case_unmap_physmem(struct udevice * dev,const void * vaddr,unsigned long len)365 static int sandbox_swap_case_unmap_physmem(struct udevice *dev,
366 					   const void *vaddr, unsigned long len)
367 {
368 	struct swap_case_priv *priv = dev_get_priv(dev);
369 
370 	sandbox_swap_case_do_op(priv->op, (void *)vaddr, len);
371 
372 	return 0;
373 }
374 
375 static struct dm_pci_emul_ops sandbox_swap_case_emul_ops = {
376 	.read_config = sandbox_swap_case_read_config,
377 	.write_config = sandbox_swap_case_write_config,
378 	.read_io = sandbox_swap_case_read_io,
379 	.write_io = sandbox_swap_case_write_io,
380 	.map_physmem = sandbox_swap_case_map_physmem,
381 	.unmap_physmem = sandbox_swap_case_unmap_physmem,
382 };
383 
384 static const struct udevice_id sandbox_swap_case_ids[] = {
385 	{ .compatible = "sandbox,swap-case" },
386 	{ }
387 };
388 
389 U_BOOT_DRIVER(sandbox_swap_case_emul) = {
390 	.name		= "sandbox_swap_case_emul",
391 	.id		= UCLASS_PCI_EMUL,
392 	.of_match	= sandbox_swap_case_ids,
393 	.ops		= &sandbox_swap_case_emul_ops,
394 	.priv_auto	= sizeof(struct swap_case_priv),
395 	.plat_auto	= sizeof(struct swap_case_plat),
396 };
397 
398 static struct pci_device_id sandbox_swap_case_supported[] = {
399 	{ PCI_VDEVICE(SANDBOX, SANDBOX_PCI_SWAP_CASE_EMUL_ID),
400 		SWAP_CASE_DRV_DATA },
401 	{},
402 };
403 
404 U_BOOT_PCI_DEVICE(sandbox_swap_case_emul, sandbox_swap_case_supported);
405