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
20typedef 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
33static status_t
34pci_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
74static status_t
75register_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
101static status_t
102init_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
190err:
191	free(bus);
192	return status;
193}
194
195
196static void
197uninit_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
208static status_t
209register_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
221static float
222supports_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
430driver_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