xref: /haiku/src/add-ons/kernel/busses/i2c/pch/pch_i2c_pci.cpp (revision 52c4471a3024d2eb81fe88e2c3982b9f8daa5e56)
1 /*
2  * Copyright 2020, Jérôme Duval, jerome.duval@gmail.com.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <new>
8 #include <stdio.h>
9 #include <string.h>
10 
11 #include <ACPI.h>
12 #include <ByteOrder.h>
13 #include <condition_variable.h>
14 #include <bus/PCI.h>
15 #include <PCI_x86.h>
16 
17 
18 #include "pch_i2c.h"
19 
20 
21 typedef struct {
22 	pch_i2c_sim_info info;
23 	pci_device_module_info* pci;
24 	pci_device* device;
25 	pch_i2c_irq_type irq_type;
26 
27 	pci_info pciinfo;
28 } pch_i2c_pci_sim_info;
29 
30 
31 static pci_x86_module_info* sPCIx86Module;
32 
33 
34 //	#pragma mark -
35 
36 
37 static status_t
38 pci_scan_bus(i2c_bus_cookie cookie)
39 {
40 	CALLED();
41 	pch_i2c_pci_sim_info* bus = (pch_i2c_pci_sim_info*)cookie;
42 	device_node *acpiNode = NULL;
43 
44 	pci_info *pciInfo = &bus->pciinfo;
45 
46 	// search ACPI I2C nodes for this device
47 	{
48 		device_node* deviceRoot = gDeviceManager->get_root_node();
49 		uint32 addr = (pciInfo->device << 16) | pciInfo->function;
50 		device_attr acpiAttrs[] = {
51 			{ B_DEVICE_BUS, B_STRING_TYPE, { .string = "acpi" }},
52 			{ ACPI_DEVICE_ADDR_ITEM, B_UINT32_TYPE, {.ui32 = addr}},
53 			{ NULL }
54 		};
55 		if (addr != 0 && gDeviceManager->find_child_node(deviceRoot, acpiAttrs,
56 				&acpiNode) != B_OK) {
57 			ERROR("init_bus() acpi device not found\n");
58 			return B_DEV_CONFIGURATION_ERROR;
59 		}
60 	}
61 
62 	TRACE("init_bus() find_child_node() found %x %x %p\n",
63 		pciInfo->device, pciInfo->function, acpiNode);
64 	// TODO eventually check timings on acpi
65 	acpi_device_module_info *acpi;
66 	acpi_device	acpiDevice;
67 	if (gDeviceManager->get_driver(acpiNode, (driver_module_info **)&acpi,
68 		(void **)&acpiDevice) == B_OK) {
69 		// find out I2C device nodes
70 		acpi->walk_namespace(acpiDevice, ACPI_TYPE_DEVICE, 1,
71 			pch_i2c_scan_bus_callback, NULL, bus, NULL);
72 	}
73 
74 	return B_OK;
75 }
76 
77 
78 static status_t
79 register_child_devices(void* cookie)
80 {
81 	CALLED();
82 
83 	pch_i2c_pci_sim_info* bus = (pch_i2c_pci_sim_info*)cookie;
84 	device_node* node = bus->info.driver_node;
85 
86 	char prettyName[25];
87 	sprintf(prettyName, "PCH I2C Controller %" B_PRIu16, 0);
88 
89 	device_attr attrs[] = {
90 		// properties of this controller for i2c bus manager
91 		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
92 			{ .string = prettyName }},
93 		{ B_DEVICE_FIXED_CHILD, B_STRING_TYPE,
94 			{ .string = I2C_FOR_CONTROLLER_MODULE_NAME }},
95 
96 		// private data to identify the device
97 		{ NULL }
98 	};
99 
100 	return gDeviceManager->register_node(node, PCH_I2C_SIM_MODULE_NAME,
101 		attrs, NULL, NULL);
102 }
103 
104 
105 static status_t
106 init_device(device_node* node, void** device_cookie)
107 {
108 	CALLED();
109 	status_t status = B_OK;
110 
111 	pch_i2c_pci_sim_info* bus = (pch_i2c_pci_sim_info*)calloc(1,
112 		sizeof(pch_i2c_pci_sim_info));
113 	if (bus == NULL)
114 		return B_NO_MEMORY;
115 
116 	pci_device_module_info* pci;
117 	pci_device* device;
118 	{
119 		device_node* pciParent = gDeviceManager->get_parent_node(node);
120 		gDeviceManager->get_driver(pciParent, (driver_module_info**)&pci,
121 			(void**)&device);
122 		gDeviceManager->put_node(pciParent);
123 	}
124 
125 	bus->pci = pci;
126 	bus->device = device;
127 	bus->info.driver_node = node;
128 	bus->info.scan_bus = pci_scan_bus;
129 
130 	pci_info *pciInfo = &bus->pciinfo;
131 	pci->get_pci_info(device, pciInfo);
132 
133 	bus->info.base_addr = pciInfo->u.h0.base_registers[0];
134 	bus->info.map_size = pciInfo->u.h0.base_register_sizes[0];
135 	if ((pciInfo->u.h0.base_register_flags[0] & PCI_address_type)
136 			== PCI_address_type_64) {
137 		bus->info.base_addr |= (uint64)pciInfo->u.h0.base_registers[1] << 32;
138 		bus->info.map_size |= (uint64)pciInfo->u.h0.base_register_sizes[1] << 32;
139 	}
140 
141 	if (bus->info.base_addr == 0) {
142 		ERROR("PCI BAR not assigned\n");
143 		free(bus);
144 		return B_ERROR;
145 	}
146 
147 	// enable power
148 	pci->set_powerstate(device, PCI_pm_state_d0);
149 
150 	// enable bus master and memory
151 	uint16 pcicmd = pci->read_pci_config(device, PCI_command, 2);
152 	pcicmd |= PCI_command_master | PCI_command_memory;
153 	pci->write_pci_config(device, PCI_command, 2, pcicmd);
154 
155 	if (get_module(B_PCI_X86_MODULE_NAME, (module_info**)&sPCIx86Module)
156 			!= B_OK) {
157 		sPCIx86Module = NULL;
158 	}
159 
160 	if (sPCIx86Module != NULL) {
161 		// try MSI-X
162 		uint8 msixCount = sPCIx86Module->get_msix_count(
163 			pciInfo->bus, pciInfo->device, pciInfo->function);
164 		if (msixCount >= 1) {
165 			uint8 vector;
166 			if (sPCIx86Module->configure_msix(pciInfo->bus, pciInfo->device,
167 					pciInfo->function, 1, &vector) == B_OK
168 				&& sPCIx86Module->enable_msix(pciInfo->bus, pciInfo->device,
169 					pciInfo->function) == B_OK) {
170 				TRACE_ALWAYS("using MSI-X vector %u\n", vector);
171 				bus->info.irq = vector;
172 				bus->irq_type = PCH_I2C_IRQ_MSI_X_SHARED;
173 			} else {
174 				ERROR("couldn't use MSI-X SHARED\n");
175 			}
176 		} else if (sPCIx86Module->get_msi_count(
177 			pciInfo->bus, pciInfo->device, pciInfo->function) >= 1) {
178 			// try MSI
179 			uint8 vector;
180 			if (sPCIx86Module->configure_msi(pciInfo->bus, pciInfo->device,
181 					pciInfo->function, 1, &vector) == B_OK
182 				&& sPCIx86Module->enable_msi(pciInfo->bus, pciInfo->device,
183 					pciInfo->function) == B_OK) {
184 				TRACE_ALWAYS("using MSI vector %u\n", vector);
185 				bus->info.irq = vector;
186 				bus->irq_type = PCH_I2C_IRQ_MSI;
187 			} else {
188 				ERROR("couldn't use MSI\n");
189 			}
190 		}
191 	}
192 	if (bus->irq_type == PCH_I2C_IRQ_LEGACY) {
193 		bus->info.irq = pciInfo->u.h0.interrupt_line;
194 		TRACE_ALWAYS("using legacy interrupt %u\n", bus->info.irq);
195 	}
196 	if (bus->info.irq == 0 || bus->info.irq == 0xff) {
197 		ERROR("PCI IRQ not assigned\n");
198 		status = B_ERROR;
199 		goto err;
200 	}
201 
202 	*device_cookie = bus;
203 	return B_OK;
204 
205 err:
206 	free(bus);
207 	return status;
208 }
209 
210 
211 static void
212 uninit_device(void* device_cookie)
213 {
214 	pch_i2c_pci_sim_info* bus = (pch_i2c_pci_sim_info*)device_cookie;
215 	if (bus->irq_type != PCH_I2C_IRQ_LEGACY) {
216 		if (sPCIx86Module != NULL) {
217 			sPCIx86Module->disable_msi(bus->pciinfo.bus,
218 				bus->pciinfo.device, bus->pciinfo.function);
219 			sPCIx86Module->unconfigure_msi(bus->pciinfo.bus,
220 				bus->pciinfo.device, bus->pciinfo.function);
221 		}
222 	}
223 	if (sPCIx86Module != NULL) {
224 		put_module(B_PCI_X86_MODULE_NAME);
225 		sPCIx86Module = NULL;
226 	}
227 	free(bus);
228 }
229 
230 
231 static status_t
232 register_device(device_node* parent)
233 {
234 	device_attr attrs[] = {
235 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "PCH I2C PCI"}},
236 		{}
237 	};
238 
239 	return gDeviceManager->register_node(parent,
240 		PCH_I2C_PCI_DEVICE_MODULE_NAME, attrs, NULL, NULL);
241 }
242 
243 
244 static float
245 supports_device(device_node* parent)
246 {
247 	CALLED();
248 	const char* bus;
249 	uint16 vendorID, deviceID;
250 
251 	// make sure parent is a PCH I2C PCI device node
252 	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)
253 		< B_OK || gDeviceManager->get_attr_uint16(parent, B_DEVICE_VENDOR_ID,
254 				&vendorID, false) < B_OK
255 		|| gDeviceManager->get_attr_uint16(parent, B_DEVICE_ID, &deviceID,
256 				false) < B_OK) {
257 		return -1;
258 	}
259 
260 	if (strcmp(bus, "pci") != 0)
261 		return 0.0f;
262 
263 	if (vendorID == 0x8086) {
264 		switch (deviceID) {
265 			case 0x02c5:
266 			case 0x02c6:
267 			case 0x02e8:
268 			case 0x02e9:
269 			case 0x02ea:
270 			case 0x02eb:
271 			case 0x06e8:
272 			case 0x06e9:
273 			case 0x06ea:
274 			case 0x06eb:
275 			case 0x0aac:
276 			case 0x0aae:
277 			case 0x0ab0:
278 			case 0x0ab2:
279 			case 0x0ab4:
280 			case 0x0ab6:
281 			case 0x0ab8:
282 			case 0x0aba:
283 			case 0x1aac:
284 			case 0x1aae:
285 
286 			case 0x1ab0:
287 			case 0x1ab2:
288 			case 0x1ab4:
289 			case 0x1ab6:
290 			case 0x1ab8:
291 			case 0x1aba:
292 
293 			case 0x31ac:
294 			case 0x31ae:
295 			case 0x31b0:
296 			case 0x31b2:
297 			case 0x31b4:
298 			case 0x31b6:
299 			case 0x31b8:
300 			case 0x31ba:
301 
302 			case 0x34c5:
303 			case 0x34c6:
304 			case 0x34e8:
305 			case 0x34e9:
306 			case 0x34ea:
307 			case 0x34eb:
308 
309 			case 0x43ad:
310 			case 0x43ae:
311 			case 0x43d8:
312 
313 			case 0x43e8:
314 			case 0x43e9:
315 			case 0x43ea:
316 			case 0x43eb:
317 
318 			case 0x4b44:
319 			case 0x4b45:
320 			case 0x4b4b:
321 			case 0x4b4c:
322 			case 0x4b78:
323 			case 0x4b79:
324 			case 0x4b7a:
325 			case 0x4b7b:
326 
327 			case 0x4dc5:
328 			case 0x4dc6:
329 			case 0x4de8:
330 			case 0x4de9:
331 			case 0x4dea:
332 			case 0x4deb:
333 
334 			case 0x51c5:
335 			case 0x51c6:
336 			case 0x51d8:
337 			case 0x51d9:
338 			case 0x51e8:
339 			case 0x51e9:
340 			case 0x51ea:
341 			case 0x51eb:
342 
343 			case 0x54c5:
344 			case 0x54c6:
345 			case 0x54e8:
346 			case 0x54e9:
347 			case 0x54ea:
348 			case 0x54eb:
349 
350 			case 0x5aac:
351 			case 0x5aae:
352 			case 0x5ab0:
353 			case 0x5ab2:
354 			case 0x5ab4:
355 			case 0x5ab6:
356 			case 0x5ab8:
357 			case 0x5aba:
358 
359 			case 0x7a4c:
360 			case 0x7a4d:
361 			case 0x7a4e:
362 			case 0x7a4f:
363 			case 0x7a7c:
364 			case 0x7a7d:
365 
366 			case 0x7acc:
367 			case 0x7acd:
368 			case 0x7ace:
369 			case 0x7acf:
370 			case 0x7afc:
371 			case 0x7afd:
372 
373 			case 0x7e50:
374 			case 0x7e51:
375 			case 0x7e78:
376 			case 0x7e79:
377 			case 0x7e7a:
378 			case 0x7e7b:
379 
380 			case 0x98c5:
381 			case 0x98c6:
382 			case 0x98e8:
383 			case 0x98e9:
384 			case 0x98ea:
385 			case 0x98eb:
386 
387 			case 0x9d60:
388 			case 0x9d61:
389 			case 0x9d62:
390 			case 0x9d63:
391 			case 0x9d64:
392 			case 0x9d65:
393 
394 			case 0x9dc5:
395 			case 0x9dc6:
396 			case 0x9de8:
397 			case 0x9de9:
398 			case 0x9dea:
399 			case 0x9deb:
400 
401 			case 0xa0c5:
402 			case 0xa0c6:
403 			case 0xa0d8:
404 			case 0xa0d9:
405 			case 0xa0e8:
406 			case 0xa0e9:
407 			case 0xa0ea:
408 			case 0xa0eb:
409 
410 			case 0xa160:
411 			case 0xa161:
412 			case 0xa162:
413 
414 			case 0xa2e0:
415 			case 0xa2e1:
416 			case 0xa2e2:
417 			case 0xa2e3:
418 
419 			case 0xa368:
420 			case 0xa369:
421 			case 0xa36a:
422 			case 0xa36b:
423 
424 			case 0xa3e0:
425 			case 0xa3e1:
426 			case 0xa3e2:
427 			case 0xa3e3:
428 				break;
429 			default:
430 				return 0.0f;
431 		}
432 		pci_device_module_info* pci;
433 		pci_device* device;
434 		gDeviceManager->get_driver(parent, (driver_module_info**)&pci,
435 			(void**)&device);
436 #ifdef TRACE_PCH_I2C
437 		uint8 pciSubDeviceId = pci->read_pci_config(device, PCI_revision,
438 			1);
439 
440 		TRACE("PCH I2C device found! vendor 0x%04x, device 0x%04x, subdevice 0x%02x\n", vendorID,
441 			deviceID, pciSubDeviceId);
442 #endif
443 		return 0.8f;
444 	}
445 
446 	return 0.0f;
447 }
448 
449 
450 //	#pragma mark -
451 
452 
453 driver_module_info gPchI2cPciDevice = {
454 	{
455 		PCH_I2C_PCI_DEVICE_MODULE_NAME,
456 		0,
457 		NULL
458 	},
459 
460 	supports_device,
461 	register_device,
462 	init_device,
463 	uninit_device,
464 	register_child_devices,
465 	NULL,	// rescan
466 	NULL,	// device removed
467 };
468 
469