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 }