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