xref: /haiku/src/add-ons/kernel/busses/i2c/pch/pch_i2c.cpp (revision 86036b7aeaec9cdc06a7ae6221e78c8cc2d9982f)
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 device_manager_info* gDeviceManager;
22 i2c_for_controller_interface* gI2c;
23 acpi_module_info* gACPI;
24 
25 
26 static void
27 enable_device(pch_i2c_sim_info* bus, bool enable)
28 {
29 	uint32 status = enable ? 1 : 0;
30 	for (int tries = 100; tries >= 0; tries--) {
31 		write32(bus->registers + PCH_IC_ENABLE, status);
32 		if ((read32(bus->registers + PCH_IC_ENABLE_STATUS) & 1) == status)
33 			return;
34 		snooze(25);
35 	}
36 
37 	ERROR("enable_device failed\n");
38 }
39 
40 
41 static int32
42 pch_i2c_interrupt_handler(pch_i2c_sim_info* bus)
43 {
44 	int32 handled = B_HANDLED_INTERRUPT;
45 
46 	// Check if this interrupt is ours
47 	uint32 enable = read32(bus->registers + PCH_IC_ENABLE);
48 	if (enable == 0)
49 		return B_UNHANDLED_INTERRUPT;
50 
51 	uint32 status = read32(bus->registers + PCH_IC_INTR_STAT);
52 	if ((status & PCH_IC_INTR_STAT_RX_UNDER) != 0)
53 		write32(bus->registers + PCH_IC_CLR_RX_UNDER, 0);
54 	if ((status & PCH_IC_INTR_STAT_RX_OVER) != 0)
55 		write32(bus->registers + PCH_IC_CLR_RX_OVER, 0);
56 	if ((status & PCH_IC_INTR_STAT_TX_OVER) != 0)
57 		write32(bus->registers + PCH_IC_CLR_TX_OVER, 0);
58 	if ((status & PCH_IC_INTR_STAT_RD_REQ) != 0)
59 		write32(bus->registers + PCH_IC_CLR_RD_REQ, 0);
60 	if ((status & PCH_IC_INTR_STAT_TX_ABRT) != 0)
61 		write32(bus->registers + PCH_IC_CLR_TX_ABRT, 0);
62 	if ((status & PCH_IC_INTR_STAT_RX_DONE) != 0)
63 		write32(bus->registers + PCH_IC_CLR_RX_DONE, 0);
64 	if ((status & PCH_IC_INTR_STAT_ACTIVITY) != 0)
65 		write32(bus->registers + PCH_IC_CLR_ACTIVITY, 0);
66 	if ((status & PCH_IC_INTR_STAT_STOP_DET) != 0)
67 		write32(bus->registers + PCH_IC_CLR_STOP_DET, 0);
68 	if ((status & PCH_IC_INTR_STAT_START_DET) != 0)
69 		write32(bus->registers + PCH_IC_CLR_START_DET, 0);
70 	if ((status & PCH_IC_INTR_STAT_GEN_CALL) != 0)
71 		write32(bus->registers + PCH_IC_CLR_GEN_CALL, 0);
72 
73 	TRACE("pch_i2c_interrupt_handler %" B_PRIx32 "\n", status);
74 
75 	if ((status & ~PCH_IC_INTR_STAT_ACTIVITY) == 0)
76 		return handled;
77 	/*if ((status & PCH_IC_INTR_STAT_TX_ABRT) != 0)
78 		tx error */
79 	if ((status & PCH_IC_INTR_STAT_RX_FULL) != 0)
80 		ConditionVariable::NotifyAll(&bus->readwait, B_OK);
81 	if ((status & PCH_IC_INTR_STAT_TX_EMPTY) != 0)
82 		ConditionVariable::NotifyAll(&bus->writewait, B_OK);
83 	if ((status & PCH_IC_INTR_STAT_STOP_DET) != 0) {
84 		bus->busy = 0;
85 		ConditionVariable::NotifyAll(&bus->busy, B_OK);
86 	}
87 
88 	return handled;
89 }
90 
91 
92 //	#pragma mark -
93 
94 
95 static void
96 set_sim(i2c_bus_cookie cookie, i2c_bus sim)
97 {
98 	CALLED();
99 	pch_i2c_sim_info* bus = (pch_i2c_sim_info*)cookie;
100 	bus->sim = sim;
101 }
102 
103 
104 static status_t
105 exec_command(i2c_bus_cookie cookie, i2c_op op, i2c_addr slaveAddress,
106 	const void *cmdBuffer, size_t cmdLength, void* dataBuffer,
107 	size_t dataLength)
108 {
109 	CALLED();
110 	pch_i2c_sim_info* bus = (pch_i2c_sim_info*)cookie;
111 
112 	if (atomic_test_and_set(&bus->busy, 1, 0) != 0)
113 		return B_BUSY;
114 
115 	TRACE("exec_command: acquired busy flag\n");
116 
117 	uint32 status = 0;
118 	for (int tries = 100; tries >= 0; tries--) {
119 		status = read32(bus->registers + PCH_IC_STATUS);
120 		if ((status & PCH_IC_STATUS_ACTIVITY) == 0)
121 			break;
122 		snooze(1000);
123 	}
124 
125 	if ((status & PCH_IC_STATUS_ACTIVITY) != 0) {
126 		bus->busy = 0;
127 		return B_BUSY;
128 	}
129 
130 	TRACE("exec_command: write slave address\n");
131 
132 	enable_device(bus, false);
133 	write32(bus->registers + PCH_IC_CON,
134 		read32(bus->registers + PCH_IC_CON) & ~PCH_IC_CON_10BIT_ADDR_MASTER);
135 	write32(bus->registers + PCH_IC_TAR, slaveAddress);
136 
137 	write32(bus->registers + PCH_IC_INTR_MASK, 0);
138 	read32(bus->registers + PCH_IC_CLR_INTR);
139 
140 	enable_device(bus, true);
141 
142 	read32(bus->registers + PCH_IC_CLR_INTR);
143 	write32(bus->registers + PCH_IC_INTR_MASK, PCH_IC_INTR_STAT_TX_EMPTY);
144 
145 	// wait for write
146 	// wait_lock
147 
148 	if (cmdLength > 0) {
149 		TRACE("exec_command: write command buffer\n");
150 		uint16 txLimit = bus->tx_fifo_depth
151 			- read32(bus->registers + PCH_IC_TXFLR);
152 		if (cmdLength > txLimit) {
153 			ERROR("exec_command can't write, cmd too long %" B_PRIuSIZE
154 				" (max %d)\n", cmdLength, txLimit);
155 			bus->busy = 0;
156 			return B_BAD_VALUE;
157 		}
158 
159 		uint8* buffer = (uint8*)cmdBuffer;
160 		for (size_t i = 0; i < cmdLength; i++) {
161 			uint32 cmd = buffer[i];
162 			if (i == cmdLength - 1 && dataLength == 0 && IS_STOP_OP(op))
163 				cmd |= PCH_IC_DATA_CMD_STOP;
164 			write32(bus->registers + PCH_IC_DATA_CMD, cmd);
165 		}
166 	}
167 
168 	TRACE("exec_command: processing buffer %" B_PRIuSIZE " bytes\n",
169 		dataLength);
170 	uint16 txLimit = bus->tx_fifo_depth
171 		- read32(bus->registers + PCH_IC_TXFLR);
172 	uint8* buffer = (uint8*)dataBuffer;
173 	size_t readPos = 0;
174 	size_t i = 0;
175 	while (i < dataLength) {
176 		uint32 cmd = PCH_IC_DATA_CMD_READ;
177 		if (IS_WRITE_OP(op))
178 			cmd = buffer[i];
179 
180 		if (i == 0 && cmdLength > 0 && IS_READ_OP(op))
181 			cmd |= PCH_IC_DATA_CMD_RESTART;
182 
183 		if (i == (dataLength - 1) && IS_STOP_OP(op))
184 			cmd |= PCH_IC_DATA_CMD_STOP;
185 
186 		write32(bus->registers + PCH_IC_DATA_CMD, cmd);
187 
188 		if (IS_READ_OP(op) && IS_BLOCK_OP(op) && readPos == 0)
189 			txLimit = 1;
190 		txLimit--;
191 		i++;
192 
193 		// here read the data if needed
194 		while (IS_READ_OP(op) && (txLimit == 0 || i == dataLength)) {
195 			write32(bus->registers + PCH_IC_INTR_MASK,
196 				PCH_IC_INTR_STAT_RX_FULL);
197 
198 			// sleep until wake up by intr handler
199 			struct ConditionVariable condition;
200 			condition.Publish(&bus->readwait, "pch_i2c");
201 			ConditionVariableEntry variableEntry;
202 			status_t status = variableEntry.Wait(&bus->readwait,
203 				B_RELATIVE_TIMEOUT, 500000L);
204 			condition.Unpublish();
205 			if (status != B_OK)
206 				ERROR("exec_command timed out waiting for read\n");
207 			uint32 rxBytes = read32(bus->registers + PCH_IC_RXFLR);
208 			if (rxBytes == 0) {
209 				ERROR("exec_command timed out reading %" B_PRIuSIZE " bytes\n",
210 					dataLength - readPos);
211 				bus->busy = 0;
212 				return B_ERROR;
213 			}
214 			for (; rxBytes > 0; rxBytes--) {
215 				uint32 read = read32(bus->registers + PCH_IC_DATA_CMD);
216 				if (readPos < dataLength)
217 					buffer[readPos++] = read;
218 			}
219 
220 			if (IS_BLOCK_OP(op) && readPos > 0 && dataLength > buffer[0])
221 				dataLength = buffer[0] + 1;
222 			if (readPos >= dataLength)
223 				break;
224 
225 			TRACE("exec_command %" B_PRIuSIZE" bytes to be read\n",
226 				dataLength - readPos);
227 			txLimit = bus->tx_fifo_depth
228 				- read32(bus->registers + PCH_IC_TXFLR);
229 		}
230 	}
231 
232 	status_t err = B_OK;
233 	if (IS_STOP_OP(op) && IS_WRITE_OP(op)) {
234 		TRACE("exec_command: waiting busy condition\n");
235 		while (bus->busy == 1) {
236 			write32(bus->registers + PCH_IC_INTR_MASK,
237 				PCH_IC_INTR_STAT_STOP_DET);
238 
239 			// sleep until wake up by intr handler
240 			struct ConditionVariable condition;
241 			condition.Publish(&bus->busy, "pch_i2c");
242 			ConditionVariableEntry variableEntry;
243 			err = variableEntry.Wait(&bus->busy, B_RELATIVE_TIMEOUT,
244 				500000L);
245 			condition.Unpublish();
246 			if (err != B_OK)
247 				ERROR("exec_command timed out waiting for busy\n");
248 		}
249 	}
250 	TRACE("exec_command: processing done\n");
251 
252 	bus->busy = 0;
253 
254 	return err;
255 }
256 
257 
258 static acpi_status
259 pch_i2c_scan_parse_callback(ACPI_RESOURCE *res, void *context)
260 {
261 	struct pch_i2c_crs* crs = (struct pch_i2c_crs*)context;
262 
263 	if (res->Type == ACPI_RESOURCE_TYPE_SERIAL_BUS &&
264 	    res->Data.CommonSerialBus.Type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
265 		crs->i2c_addr = B_LENDIAN_TO_HOST_INT16(
266 			res->Data.I2cSerialBus.SlaveAddress);
267 		return AE_CTRL_TERMINATE;
268 	} else if (res->Type == ACPI_RESOURCE_TYPE_IRQ) {
269 		crs->irq = res->Data.Irq.Interrupts[0];
270 		crs->irq_triggering = res->Data.Irq.Triggering;
271 		crs->irq_polarity = res->Data.Irq.Polarity;
272 		crs->irq_shareable = res->Data.Irq.Shareable;
273 	} else if (res->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
274 		crs->irq = res->Data.ExtendedIrq.Interrupts[0];
275 		crs->irq_triggering = res->Data.ExtendedIrq.Triggering;
276 		crs->irq_polarity = res->Data.ExtendedIrq.Polarity;
277 		crs->irq_shareable = res->Data.ExtendedIrq.Shareable;
278 	}
279 
280 	return B_OK;
281 }
282 
283 
284 static status_t
285 acpi_GetInteger(acpi_handle acpiCookie,
286 	const char* path, int64* number)
287 {
288 	acpi_data buf;
289 	acpi_object_type object;
290 	buf.pointer = &object;
291 	buf.length = sizeof(acpi_object_type);
292 
293 	// Assume that what we've been pointed at is an Integer object, or
294 	// a method that will return an Integer.
295 	status_t status = gACPI->evaluate_method(acpiCookie, path, NULL, &buf);
296 	if (status == B_OK) {
297 		if (object.object_type == ACPI_TYPE_INTEGER)
298 			*number = object.integer.integer;
299 		else
300 			status = B_BAD_VALUE;
301 	}
302 	return status;
303 }
304 
305 
306 acpi_status
307 pch_i2c_scan_bus_callback(acpi_handle object, uint32 nestingLevel,
308 	void *context, void** returnValue)
309 {
310 	pch_i2c_sim_info* bus = (pch_i2c_sim_info*)context;
311 	TRACE("pch_i2c_scan_bus_callback %p\n", object);
312 
313 	// skip absent devices
314 	int64 sta;
315 	status_t status = acpi_GetInteger(object, "_STA", &sta);
316 	if (status == B_OK && (sta & ACPI_STA_DEVICE_PRESENT) == 0)
317 		return B_OK;
318 
319 	// Attach devices for I2C resources
320 	struct pch_i2c_crs crs;
321 	status = gACPI->walk_resources(object, (ACPI_STRING)"_CRS",
322 		pch_i2c_scan_parse_callback, &crs);
323 	if (status != B_OK) {
324 		ERROR("Error while getting I2C devices\n");
325 		return status;
326 	}
327 
328 	TRACE("pch_i2c_scan_bus_callback deviceAddress %x\n", crs.i2c_addr);
329 
330 	acpi_data buffer;
331 	buffer.pointer = NULL;
332 	buffer.length = ACPI_ALLOCATE_BUFFER;
333 	status = gACPI->ns_handle_to_pathname(object, &buffer);
334 	if (status != B_OK) {
335 		ERROR("pch_i2c_scan_bus_callback ns_handle_to_pathname failed\n");
336 		return status;
337 	}
338 
339 	char* hid = NULL;
340 	char* cidList[8] = { NULL };
341 	status = gACPI->get_device_info((const char*)buffer.pointer, &hid,
342 		(char**)&cidList, 8, NULL);
343 	if (status != B_OK) {
344 		ERROR("pch_i2c_scan_bus_callback get_device_info failed\n");
345 		return status;
346 	}
347 
348 	status = gI2c->register_device(bus->sim, crs.i2c_addr, hid, cidList,
349 		object);
350 	free(hid);
351 	for (int i = 0; cidList[i] != NULL; i++)
352 		free(cidList[i]);
353 	free(buffer.pointer);
354 
355 	TRACE("pch_i2c_scan_bus_callback registered device: %s\n", strerror(status));
356 
357 	return status;
358 }
359 
360 
361 static status_t
362 scan_bus(i2c_bus_cookie cookie)
363 {
364 	CALLED();
365 	pch_i2c_sim_info* bus = (pch_i2c_sim_info*)cookie;
366 	if (bus->scan_bus != NULL)
367 		return bus->scan_bus(bus);
368 	return B_OK;
369 }
370 
371 
372 static status_t
373 acquire_bus(i2c_bus_cookie cookie)
374 {
375 	CALLED();
376 	pch_i2c_sim_info* bus = (pch_i2c_sim_info*)cookie;
377 	return mutex_lock(&bus->lock);
378 }
379 
380 
381 static void
382 release_bus(i2c_bus_cookie cookie)
383 {
384 	CALLED();
385 	pch_i2c_sim_info* bus = (pch_i2c_sim_info*)cookie;
386 	mutex_unlock(&bus->lock);
387 }
388 
389 
390 //	#pragma mark -
391 
392 
393 static status_t
394 init_bus(device_node* node, void** bus_cookie)
395 {
396 	CALLED();
397 	status_t status = B_OK;
398 
399 	driver_module_info* driver;
400 	pch_i2c_sim_info* bus;
401 	device_node* parent = gDeviceManager->get_parent_node(node);
402 	gDeviceManager->get_driver(parent, &driver, (void**)&bus);
403 	gDeviceManager->put_node(parent);
404 
405 	TRACE_ALWAYS("init_bus() addr 0x%" B_PRIxPHYSADDR " size 0x%" B_PRIx64
406 		" irq 0x%x\n", bus->base_addr, bus->map_size, bus->irq);
407 
408 	bus->registersArea = map_physical_memory("PCHI2C memory mapped registers",
409 		bus->base_addr, bus->map_size, B_ANY_KERNEL_ADDRESS,
410 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
411 		(void **)&bus->registers);
412 	// init bus
413 	bus->capabilities = read32(bus->registers + PCH_SUP_CAPABLITIES);
414 	TRACE_ALWAYS("init_bus() 0x%" B_PRIx32 " (0x%" B_PRIx32 ")\n",
415 		(bus->capabilities >> PCH_SUP_CAPABLITIES_TYPE_SHIFT)
416 			& PCH_SUP_CAPABLITIES_TYPE_MASK,
417 		bus->capabilities);
418 	if (((bus->capabilities >> PCH_SUP_CAPABLITIES_TYPE_SHIFT)
419 			& PCH_SUP_CAPABLITIES_TYPE_MASK) != 0) {
420 		status = B_ERROR;
421 		ERROR("init_bus() device type not supported\n");
422 		goto err;
423 	}
424 
425 	write32(bus->registers + PCH_SUP_RESETS, 0);
426 	write32(bus->registers + PCH_SUP_RESETS,
427 		PCH_SUP_RESETS_FUNC | PCH_SUP_RESETS_IDMA);
428 
429 	if (bus->ss_hcnt == 0)
430 		bus->ss_hcnt = read32(bus->registers + PCH_IC_SS_SCL_HCNT);
431 	if (bus->ss_lcnt == 0)
432 		bus->ss_lcnt = read32(bus->registers + PCH_IC_SS_SCL_LCNT);
433 	if (bus->fs_hcnt == 0)
434 		bus->fs_hcnt = read32(bus->registers + PCH_IC_FS_SCL_HCNT);
435 	if (bus->fs_lcnt == 0)
436 		bus->fs_lcnt = read32(bus->registers + PCH_IC_FS_SCL_LCNT);
437 	if (bus->sda_hold_time == 0)
438 		bus->sda_hold_time = read32(bus->registers + PCH_IC_SDA_HOLD);
439 	TRACE_ALWAYS("init_bus() 0x%04" B_PRIx16 " 0x%04" B_PRIx16 " 0x%04" B_PRIx16
440 		" 0x%04" B_PRIx16 " 0x%08" B_PRIx32 "\n", bus->ss_hcnt, bus->ss_lcnt,
441 		bus->fs_hcnt, bus->fs_lcnt, bus->sda_hold_time);
442 
443 	enable_device(bus, false);
444 
445 	write32(bus->registers + PCH_IC_SS_SCL_HCNT, bus->ss_hcnt);
446 	write32(bus->registers + PCH_IC_SS_SCL_LCNT, bus->ss_lcnt);
447 	write32(bus->registers + PCH_IC_FS_SCL_HCNT, bus->fs_hcnt);
448 	write32(bus->registers + PCH_IC_FS_SCL_LCNT, bus->fs_lcnt);
449 	if (bus->hs_hcnt > 0)
450 		write32(bus->registers + PCH_IC_HS_SCL_HCNT, bus->hs_hcnt);
451 	if (bus->hs_lcnt > 0)
452 		write32(bus->registers + PCH_IC_HS_SCL_LCNT, bus->hs_lcnt);
453 	{
454 		uint32 reg = read32(bus->registers + PCH_IC_COMP_VERSION);
455 		if (reg >= PCH_IC_COMP_VERSION_MIN)
456 			write32(bus->registers + PCH_IC_SDA_HOLD, bus->sda_hold_time);
457 	}
458 
459 	{
460 		bus->tx_fifo_depth = 32;
461 		bus->rx_fifo_depth = 32;
462 		uint32 reg = read32(bus->registers + PCH_IC_COMP_PARAM1);
463 		uint8 rx_fifo_depth = PCH_IC_COMP_PARAM1_RX(reg);
464 		uint8 tx_fifo_depth = PCH_IC_COMP_PARAM1_TX(reg);
465 		if (rx_fifo_depth > 1 && rx_fifo_depth < bus->rx_fifo_depth)
466 			bus->rx_fifo_depth = rx_fifo_depth;
467 		if (tx_fifo_depth > 1 && tx_fifo_depth < bus->tx_fifo_depth)
468 			bus->tx_fifo_depth = tx_fifo_depth;
469 		write32(bus->registers + PCH_IC_RX_TL, 0);
470 		write32(bus->registers + PCH_IC_TX_TL, bus->tx_fifo_depth / 2);
471 	}
472 
473 	bus->masterConfig = PCH_IC_CON_MASTER | PCH_IC_CON_SLAVE_DISABLE |
474 	    PCH_IC_CON_RESTART_EN | PCH_IC_CON_SPEED_FAST;
475 	write32(bus->registers + PCH_IC_CON, bus->masterConfig);
476 
477 	write32(bus->registers + PCH_IC_INTR_MASK, 0);
478 	read32(bus->registers + PCH_IC_CLR_INTR);
479 
480 	status = install_io_interrupt_handler(bus->irq,
481 		(interrupt_handler)pch_i2c_interrupt_handler, bus, 0);
482 	if (status != B_OK) {
483 		ERROR("install interrupt handler failed\n");
484 		goto err;
485 	}
486 
487 	mutex_init(&bus->lock, "pch_i2c");
488 	*bus_cookie = bus;
489 	return status;
490 
491 err:
492 	if (bus->registersArea >= 0)
493 		delete_area(bus->registersArea);
494 	return status;
495 }
496 
497 
498 static void
499 uninit_bus(void* bus_cookie)
500 {
501 	pch_i2c_sim_info* bus = (pch_i2c_sim_info*)bus_cookie;
502 
503 	mutex_destroy(&bus->lock);
504 	remove_io_interrupt_handler(bus->irq,
505 		(interrupt_handler)pch_i2c_interrupt_handler, bus);
506 	if (bus->registersArea >= 0)
507 		delete_area(bus->registersArea);
508 
509 }
510 
511 
512 //	#pragma mark -
513 
514 
515 module_dependency module_dependencies[] = {
516 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager },
517 	{ B_ACPI_MODULE_NAME, (module_info**)&gACPI },
518 	{ I2C_FOR_CONTROLLER_MODULE_NAME, (module_info**)&gI2c },
519 	{}
520 };
521 
522 
523 static i2c_sim_interface sPchI2cDeviceModule = {
524 	{
525 		{
526 			PCH_I2C_SIM_MODULE_NAME,
527 			0,
528 			NULL
529 		},
530 
531 		NULL,	// supports device
532 		NULL,	// register device
533 		init_bus,
534 		uninit_bus,
535 		NULL,	// register child devices
536 		NULL,	// rescan
537 		NULL, 	// device removed
538 	},
539 
540 	set_sim,
541 	exec_command,
542 	scan_bus,
543 	acquire_bus,
544 	release_bus,
545 };
546 
547 
548 module_info* modules[] = {
549 	(module_info* )&gPchI2cAcpiDevice,
550 	(module_info* )&gPchI2cPciDevice,
551 	(module_info* )&sPchI2cDeviceModule,
552 	NULL
553 };
554