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