Module Name:    src
Committed By:   jmcneill
Date:           Sat Dec 14 12:52:39 UTC 2024

Modified Files:
        src/sys/dev/acpi: acpi_i2c.c

Log Message:
acpi: i2c: Honour accessor type attribute in GSB handler.

The accessor type attribute in a GSB field defines how the I2C
transaction should look. Add support for AttribQuick, AttribSendReceive,
AttribByte, AttribWord, AttribBlock, and AttribBytes.


To generate a diff of this commit:
cvs rdiff -u -r1.16 -r1.17 src/sys/dev/acpi/acpi_i2c.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/acpi/acpi_i2c.c
diff -u src/sys/dev/acpi/acpi_i2c.c:1.16 src/sys/dev/acpi/acpi_i2c.c:1.17
--- src/sys/dev/acpi/acpi_i2c.c:1.16	Fri Dec 13 12:25:39 2024
+++ src/sys/dev/acpi/acpi_i2c.c	Sat Dec 14 12:52:39 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: acpi_i2c.c,v 1.16 2024/12/13 12:25:39 jmcneill Exp $ */
+/* $NetBSD: acpi_i2c.c,v 1.17 2024/12/14 12:52:39 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2017, 2021 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
 #include "iic.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: acpi_i2c.c,v 1.16 2024/12/13 12:25:39 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: acpi_i2c.c,v 1.17 2024/12/14 12:52:39 jmcneill Exp $");
 
 #include <sys/device.h>
 
@@ -40,6 +40,7 @@ __KERNEL_RCSID(0, "$NetBSD: acpi_i2c.c,v
 #include <dev/acpi/acpivar.h>
 #include <dev/acpi/acpi_i2c.h>
 #include <external/bsd/acpica/dist/include/acinterp.h>
+#include <external/bsd/acpica/dist/include/amlcode.h>
 #include <dev/i2c/i2cvar.h>
 
 #include <sys/kmem.h>
@@ -238,36 +239,29 @@ acpi_i2c_gsb_handler(UINT32 function, AC
 {
 	ACPI_OPERAND_OBJECT *region_obj = region_ctx;
 	struct acpi_i2c_address_space_context *context = handler_ctx;
-	UINT8 *buffer = ACPI_CAST_PTR(uint8_t, value);
-	UINT8 *data_buffer;
-	UINT8 data_length;
+	UINT8 *buf = ACPI_CAST_PTR(uint8_t, value);
 	ACPI_PHYSICAL_ADDRESS base_address;
 	ACPI_RESOURCE *res;
-	UINT32 length;
-	UINT8 space_id;
 	ACPI_STATUS rv;
-	ACPI_CONNECTION_INFO *conn_info= &context->conn_info;
+	ACPI_CONNECTION_INFO *conn_info = &context->conn_info;
 	i2c_tag_t tag = context->tag;
+	i2c_addr_t i2c_addr;
 	i2c_op_t op;
 	union {
 		uint8_t cmd8;
 		uint16_t cmd16;
+		uint32_t cmd32;
 	} cmd;
+	size_t buflen;
 	size_t cmdlen;
+	bool do_xfer = true;
 
 	if (region_obj->Region.Type != ACPI_TYPE_REGION) {
 		return AE_OK;
 	}
 
 	base_address = region_obj->Region.Address;
-	space_id = region_obj->Region.SpaceId;
-
-	KASSERT(space_id == ACPI_ADR_SPACE_GSBUS);
-
-	rv = AcpiExGetProtocolBufferLength(function >> 16, &length);
-	if (ACPI_FAILURE(rv)) {
-		return rv;
-	}
+	KASSERT(region_obj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS);
 
 	rv = AcpiBufferToResource(conn_info->Connection, conn_info->Length,
 	    &res);
@@ -279,9 +273,7 @@ acpi_i2c_gsb_handler(UINT32 function, AC
 		return AE_TYPE;
 	}
 
-	data_buffer = &buffer[2];
-	data_length = (UINT8)length;
-
+	i2c_addr = res->Data.I2cSerialBus.SlaveAddress;
 	if ((function & ACPI_IO_MASK) != 0) {
 		op = I2C_OP_WRITE_WITH_STOP;
 	} else {
@@ -289,38 +281,96 @@ acpi_i2c_gsb_handler(UINT32 function, AC
 	}
 
 #ifdef ACPI_I2C_DEBUG
+	UINT32 length;
+	rv = AcpiExGetProtocolBufferLength(function >> 16, &length);
+	if (ACPI_FAILURE(rv)) {
+		printf("%s AcpiExGetProtocolBufferLength failed: %s\n",
+		    __func__, AcpiFormatException(rv));
+		length = UINT32_MAX;
+	}
 	printf("%s %s: %s Attr %X Addr %.4X BaseAddr %.4X Length %.2X BitWidth %X BufLen %X",
-	       __func__, AcpiUtGetRegionName (space_id),
+	       __func__, AcpiUtGetRegionName(region_obj->Region.SpaceId),
 	       (function & ACPI_IO_MASK) ? "Write" : "Read ",
 	       (UINT32) (function >> 16),
 	       (UINT32) address, (UINT32) base_address,
-	       length, bit_width, buffer[1]);
+	       length, bit_width, buf[1]);
 	printf(" [AccessLength %.2X Connection %p]\n",
 	       conn_info->AccessLength, conn_info->Connection);
 #endif
 
-	if (bit_width == 8) {
+	switch ((UINT32)(function >> 16)) {
+	case AML_FIELD_ATTRIB_QUICK:
+		cmdlen = 0;
+		buflen = 0;
+		break;
+	case AML_FIELD_ATTRIB_SEND_RECEIVE:
+		cmdlen = 0;
+		buflen = 1;
+		break;
+	case AML_FIELD_ATTRIB_BYTE:
+		cmdlen = bit_width / NBBY;
+		buflen = 1;
+		break;
+	case AML_FIELD_ATTRIB_WORD:
+		cmdlen = bit_width / NBBY;
+		buflen = 2;
+		break;
+	case AML_FIELD_ATTRIB_BYTES:
+		cmdlen = bit_width / NBBY;
+		buflen = buf[1];
+		break;
+	case AML_FIELD_ATTRIB_BLOCK:
+		cmdlen = bit_width / NBBY;
+		buflen = buf[1];
+		op |= I2C_OPMASK_BLKMODE;
+		break;
+	case AML_FIELD_ATTRIB_RAW_BYTES:
+	case AML_FIELD_ATTRIB_RAW_PROCESS_BYTES:
+	case AML_FIELD_ATTRIB_PROCESS_CALL:
+	default:
+		cmdlen = 0;
+		do_xfer = false;
+#ifdef ACPI_I2C_DEBUG
+		printf("field attrib 0x%x not supported\n",
+		    (UINT32)(function >> 16));
+#endif
+		break;
+	}
+
+	switch (cmdlen) {
+	case 0:
+	case 1:
 		cmd.cmd8 = (uint8_t)(base_address + address);
-		cmdlen = 1;
-	} else if (bit_width == 16) {
+		break;
+	case 2:
 		cmd.cmd16 = (uint16_t)(base_address + address);
-		cmdlen = 2;
-	} else {
-		cmdlen = 0;
+		break;
+	case 4:
+		cmd.cmd32 = (uint32_t)(base_address + address);
+		break;
+	default:
+		do_xfer = false;
+#ifdef ACPI_I2C_DEBUG
+		printf("cmdlen %zu not supported\n", cmdlen);
+#endif
+		break;
 	}
-	if (cmdlen == 0) {
-		buffer[0] = EINVAL;
+
+	if (!do_xfer) {
+		buf[0] = EINVAL;
 	} else {
 		const int flags = I2C_F_POLL;
 		iic_acquire_bus(tag, flags);
-		buffer[0] = iic_exec(tag, op, res->Data.I2cSerialBus.SlaveAddress,
-				     &cmd, cmdlen, data_buffer, data_length, flags);
+		buf[0] = iic_exec(tag, op, i2c_addr,
+				  &cmd, cmdlen, &buf[2], buflen, flags);
 		iic_release_bus(tag, flags);
-		if (buffer[0] == 0) {
-			buffer[1] = data_length;
+		if (buf[0] == 0) {
+			buf[1] = buflen;
 		}
 #ifdef ACPI_I2C_DEBUG
-		printf("iic_exec returned %d\n", buffer[0]);
+		printf("%s iic_exec op %u addr 0x%x len %zu/%zu returned %d\n",
+		    __func__, op, res->Data.I2cSerialBus.SlaveAddress, cmdlen,
+		    buflen, buf[0]);
 #endif
 	}
 

Reply via email to