xref: /haiku/src/add-ons/kernel/busses/i2c/pch/pch_i2c_pci.cpp (revision b289c1e4066d31da5ac6c5e587d9b98b76493af9)
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 		uint8 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 %u\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 		uint8 vector;
165 		if (pci->configure_msi(device, 1, &vector) == B_OK
166 			&& pci->enable_msi(device) == B_OK) {
167 			TRACE_ALWAYS("using MSI vector %u\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 		TRACE_ALWAYS("using legacy interrupt %u\n", bus->info.irq);
177 	}
178 	if (bus->info.irq == 0 || bus->info.irq == 0xff) {
179 		ERROR("PCI IRQ not assigned\n");
180 		status = B_ERROR;
181 		goto err;
182 	}
183 
184 	*device_cookie = bus;
185 	return B_OK;
186 
187 err:
188 	free(bus);
189 	return status;
190 }
191 
192 
193 static void
194 uninit_device(void* device_cookie)
195 {
196 	pch_i2c_pci_sim_info* bus = (pch_i2c_pci_sim_info*)device_cookie;
197 	if (bus->irq_type != PCH_I2C_IRQ_LEGACY) {
198 		bus->pci->disable_msi(bus->device);
199 		bus->pci->unconfigure_msi(bus->device);
200 	}
201 	free(bus);
202 }
203 
204 
205 static status_t
206 register_device(device_node* parent)
207 {
208 	device_attr attrs[] = {
209 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "PCH I2C PCI"}},
210 		{}
211 	};
212 
213 	return gDeviceManager->register_node(parent,
214 		PCH_I2C_PCI_DEVICE_MODULE_NAME, attrs, NULL, NULL);
215 }
216 
217 
218 static float
219 supports_device(device_node* parent)
220 {
221 	CALLED();
222 	const char* bus;
223 	uint16 vendorID, deviceID;
224 
225 	// make sure parent is a PCH I2C PCI device node
226 	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)
227 		< B_OK || gDeviceManager->get_attr_uint16(parent, B_DEVICE_VENDOR_ID,
228 				&vendorID, false) < B_OK
229 		|| gDeviceManager->get_attr_uint16(parent, B_DEVICE_ID, &deviceID,
230 				false) < B_OK) {
231 		return -1;
232 	}
233 
234 	if (strcmp(bus, "pci") != 0)
235 		return 0.0f;
236 
237 	if (vendorID == 0x8086) {
238 		switch (deviceID) {
239 			case 0x02c5:
240 			case 0x02c6:
241 			case 0x02e8:
242 			case 0x02e9:
243 			case 0x02ea:
244 			case 0x02eb:
245 			case 0x06e8:
246 			case 0x06e9:
247 			case 0x06ea:
248 			case 0x06eb:
249 			case 0x0aac:
250 			case 0x0aae:
251 			case 0x0ab0:
252 			case 0x0ab2:
253 			case 0x0ab4:
254 			case 0x0ab6:
255 			case 0x0ab8:
256 			case 0x0aba:
257 			case 0x1aac:
258 			case 0x1aae:
259 
260 			case 0x1ab0:
261 			case 0x1ab2:
262 			case 0x1ab4:
263 			case 0x1ab6:
264 			case 0x1ab8:
265 			case 0x1aba:
266 
267 			case 0x31ac:
268 			case 0x31ae:
269 			case 0x31b0:
270 			case 0x31b2:
271 			case 0x31b4:
272 			case 0x31b6:
273 			case 0x31b8:
274 			case 0x31ba:
275 
276 			case 0x34c5:
277 			case 0x34c6:
278 			case 0x34e8:
279 			case 0x34e9:
280 			case 0x34ea:
281 			case 0x34eb:
282 
283 			case 0x43ad:
284 			case 0x43ae:
285 			case 0x43d8:
286 
287 			case 0x43e8:
288 			case 0x43e9:
289 			case 0x43ea:
290 			case 0x43eb:
291 
292 			case 0x4b44:
293 			case 0x4b45:
294 			case 0x4b4b:
295 			case 0x4b4c:
296 			case 0x4b78:
297 			case 0x4b79:
298 			case 0x4b7a:
299 			case 0x4b7b:
300 
301 			case 0x4dc5:
302 			case 0x4dc6:
303 			case 0x4de8:
304 			case 0x4de9:
305 			case 0x4dea:
306 			case 0x4deb:
307 
308 			case 0x51c5:
309 			case 0x51c6:
310 			case 0x51d8:
311 			case 0x51d9:
312 			case 0x51e8:
313 			case 0x51e9:
314 			case 0x51ea:
315 			case 0x51eb:
316 
317 			case 0x54c5:
318 			case 0x54c6:
319 			case 0x54e8:
320 			case 0x54e9:
321 			case 0x54ea:
322 			case 0x54eb:
323 
324 			case 0x5aac:
325 			case 0x5aae:
326 			case 0x5ab0:
327 			case 0x5ab2:
328 			case 0x5ab4:
329 			case 0x5ab6:
330 			case 0x5ab8:
331 			case 0x5aba:
332 
333 			case 0x7a4c:
334 			case 0x7a4d:
335 			case 0x7a4e:
336 			case 0x7a4f:
337 			case 0x7a7c:
338 			case 0x7a7d:
339 
340 			case 0x7acc:
341 			case 0x7acd:
342 			case 0x7ace:
343 			case 0x7acf:
344 			case 0x7afc:
345 			case 0x7afd:
346 
347 			case 0x7e50:
348 			case 0x7e51:
349 			case 0x7e78:
350 			case 0x7e79:
351 			case 0x7e7a:
352 			case 0x7e7b:
353 
354 			case 0x98c5:
355 			case 0x98c6:
356 			case 0x98e8:
357 			case 0x98e9:
358 			case 0x98ea:
359 			case 0x98eb:
360 
361 			case 0x9d60:
362 			case 0x9d61:
363 			case 0x9d62:
364 			case 0x9d63:
365 			case 0x9d64:
366 			case 0x9d65:
367 
368 			case 0x9dc5:
369 			case 0x9dc6:
370 			case 0x9de8:
371 			case 0x9de9:
372 			case 0x9dea:
373 			case 0x9deb:
374 
375 			case 0xa0c5:
376 			case 0xa0c6:
377 			case 0xa0d8:
378 			case 0xa0d9:
379 			case 0xa0e8:
380 			case 0xa0e9:
381 			case 0xa0ea:
382 			case 0xa0eb:
383 
384 			case 0xa160:
385 			case 0xa161:
386 			case 0xa162:
387 
388 			case 0xa2e0:
389 			case 0xa2e1:
390 			case 0xa2e2:
391 			case 0xa2e3:
392 
393 			case 0xa368:
394 			case 0xa369:
395 			case 0xa36a:
396 			case 0xa36b:
397 
398 			case 0xa3e0:
399 			case 0xa3e1:
400 			case 0xa3e2:
401 			case 0xa3e3:
402 				break;
403 			default:
404 				return 0.0f;
405 		}
406 		pci_device_module_info* pci;
407 		pci_device* device;
408 		gDeviceManager->get_driver(parent, (driver_module_info**)&pci,
409 			(void**)&device);
410 #ifdef TRACE_PCH_I2C
411 		uint8 pciSubDeviceId = pci->read_pci_config(device, PCI_revision,
412 			1);
413 
414 		TRACE("PCH I2C device found! vendor 0x%04x, device 0x%04x, subdevice 0x%02x\n", vendorID,
415 			deviceID, pciSubDeviceId);
416 #endif
417 		return 0.8f;
418 	}
419 
420 	return 0.0f;
421 }
422 
423 
424 //	#pragma mark -
425 
426 
427 driver_module_info gPchI2cPciDevice = {
428 	{
429 		PCH_I2C_PCI_DEVICE_MODULE_NAME,
430 		0,
431 		NULL
432 	},
433 
434 	supports_device,
435 	register_device,
436 	init_device,
437 	uninit_device,
438 	register_child_devices,
439 	NULL,	// rescan
440 	NULL,	// device removed
441 };
442 
443