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