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