xref: /openbmc/linux/drivers/acpi/acpica/exserial.c (revision bac36a17)
19e9f8733SBob Moore // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
29e9f8733SBob Moore /******************************************************************************
39e9f8733SBob Moore  *
49e9f8733SBob Moore  * Module Name: exserial - field_unit support for serial address spaces
59e9f8733SBob Moore  *
6612c2932SBob Moore  * Copyright (C) 2000 - 2023, Intel Corp.
79e9f8733SBob Moore  *
89e9f8733SBob Moore  *****************************************************************************/
99e9f8733SBob Moore 
109e9f8733SBob Moore #include <acpi/acpi.h>
119e9f8733SBob Moore #include "accommon.h"
129e9f8733SBob Moore #include "acdispat.h"
139e9f8733SBob Moore #include "acinterp.h"
149e9f8733SBob Moore #include "amlcode.h"
159e9f8733SBob Moore 
169e9f8733SBob Moore #define _COMPONENT          ACPI_EXECUTER
179e9f8733SBob Moore ACPI_MODULE_NAME("exserial")
189e9f8733SBob Moore 
199e9f8733SBob Moore /*******************************************************************************
209e9f8733SBob Moore  *
219e9f8733SBob Moore  * FUNCTION:    acpi_ex_read_gpio
229e9f8733SBob Moore  *
239e9f8733SBob Moore  * PARAMETERS:  obj_desc            - The named field to read
24c163f90cSErik Schmauss  *              buffer              - Where the return data is returned
259e9f8733SBob Moore  *
269e9f8733SBob Moore  * RETURN:      Status
279e9f8733SBob Moore  *
289e9f8733SBob Moore  * DESCRIPTION: Read from a named field that references a Generic Serial Bus
299e9f8733SBob Moore  *              field
309e9f8733SBob Moore  *
319e9f8733SBob Moore  ******************************************************************************/
acpi_ex_read_gpio(union acpi_operand_object * obj_desc,void * buffer)329e9f8733SBob Moore acpi_status acpi_ex_read_gpio(union acpi_operand_object *obj_desc, void *buffer)
339e9f8733SBob Moore {
349e9f8733SBob Moore 	acpi_status status;
359e9f8733SBob Moore 
369e9f8733SBob Moore 	ACPI_FUNCTION_TRACE_PTR(ex_read_gpio, obj_desc);
379e9f8733SBob Moore 
389e9f8733SBob Moore 	/*
399e9f8733SBob Moore 	 * For GPIO (general_purpose_io), the Address will be the bit offset
409e9f8733SBob Moore 	 * from the previous Connection() operator, making it effectively a
419e9f8733SBob Moore 	 * pin number index. The bit_length is the length of the field, which
429e9f8733SBob Moore 	 * is thus the number of pins.
439e9f8733SBob Moore 	 */
449e9f8733SBob Moore 	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
459e9f8733SBob Moore 			  "GPIO FieldRead [FROM]:  Pin %u Bits %u\n",
469e9f8733SBob Moore 			  obj_desc->field.pin_number_index,
479e9f8733SBob Moore 			  obj_desc->field.bit_length));
489e9f8733SBob Moore 
499e9f8733SBob Moore 	/* Lock entire transaction if requested */
509e9f8733SBob Moore 
519e9f8733SBob Moore 	acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
529e9f8733SBob Moore 
539e9f8733SBob Moore 	/* Perform the read */
549e9f8733SBob Moore 
559e9f8733SBob Moore 	status = acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, ACPI_READ);
569e9f8733SBob Moore 
579e9f8733SBob Moore 	acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
589e9f8733SBob Moore 	return_ACPI_STATUS(status);
599e9f8733SBob Moore }
609e9f8733SBob Moore 
619e9f8733SBob Moore /*******************************************************************************
629e9f8733SBob Moore  *
639e9f8733SBob Moore  * FUNCTION:    acpi_ex_write_gpio
649e9f8733SBob Moore  *
659e9f8733SBob Moore  * PARAMETERS:  source_desc         - Contains data to write. Expect to be
669e9f8733SBob Moore  *                                    an Integer object.
679e9f8733SBob Moore  *              obj_desc            - The named field
689e9f8733SBob Moore  *              result_desc         - Where the return value is returned, if any
699e9f8733SBob Moore  *
709e9f8733SBob Moore  * RETURN:      Status
719e9f8733SBob Moore  *
729e9f8733SBob Moore  * DESCRIPTION: Write to a named field that references a General Purpose I/O
739e9f8733SBob Moore  *              field.
749e9f8733SBob Moore  *
759e9f8733SBob Moore  ******************************************************************************/
769e9f8733SBob Moore 
779e9f8733SBob Moore acpi_status
acpi_ex_write_gpio(union acpi_operand_object * source_desc,union acpi_operand_object * obj_desc,union acpi_operand_object ** return_buffer)789e9f8733SBob Moore acpi_ex_write_gpio(union acpi_operand_object *source_desc,
799e9f8733SBob Moore 		   union acpi_operand_object *obj_desc,
809e9f8733SBob Moore 		   union acpi_operand_object **return_buffer)
819e9f8733SBob Moore {
829e9f8733SBob Moore 	acpi_status status;
839e9f8733SBob Moore 	void *buffer;
849e9f8733SBob Moore 
859e9f8733SBob Moore 	ACPI_FUNCTION_TRACE_PTR(ex_write_gpio, obj_desc);
869e9f8733SBob Moore 
879e9f8733SBob Moore 	/*
889e9f8733SBob Moore 	 * For GPIO (general_purpose_io), we will bypass the entire field
899e9f8733SBob Moore 	 * mechanism and handoff the bit address and bit width directly to
909e9f8733SBob Moore 	 * the handler. The Address will be the bit offset
919e9f8733SBob Moore 	 * from the previous Connection() operator, making it effectively a
929e9f8733SBob Moore 	 * pin number index. The bit_length is the length of the field, which
939e9f8733SBob Moore 	 * is thus the number of pins.
949e9f8733SBob Moore 	 */
959e9f8733SBob Moore 	if (source_desc->common.type != ACPI_TYPE_INTEGER) {
969e9f8733SBob Moore 		return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
979e9f8733SBob Moore 	}
989e9f8733SBob Moore 
999e9f8733SBob Moore 	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
1009e9f8733SBob Moore 			  "GPIO FieldWrite [FROM]: (%s:%X), Value %.8X  [TO]: Pin %u Bits %u\n",
1019e9f8733SBob Moore 			  acpi_ut_get_type_name(source_desc->common.type),
1029e9f8733SBob Moore 			  source_desc->common.type,
1039e9f8733SBob Moore 			  (u32)source_desc->integer.value,
1049e9f8733SBob Moore 			  obj_desc->field.pin_number_index,
1059e9f8733SBob Moore 			  obj_desc->field.bit_length));
1069e9f8733SBob Moore 
1079e9f8733SBob Moore 	buffer = &source_desc->integer.value;
1089e9f8733SBob Moore 
1099e9f8733SBob Moore 	/* Lock entire transaction if requested */
1109e9f8733SBob Moore 
1119e9f8733SBob Moore 	acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
1129e9f8733SBob Moore 
1139e9f8733SBob Moore 	/* Perform the write */
1149e9f8733SBob Moore 
1159e9f8733SBob Moore 	status = acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, ACPI_WRITE);
1169e9f8733SBob Moore 	acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
1179e9f8733SBob Moore 	return_ACPI_STATUS(status);
1189e9f8733SBob Moore }
1199e9f8733SBob Moore 
1209e9f8733SBob Moore /*******************************************************************************
1219e9f8733SBob Moore  *
1229e9f8733SBob Moore  * FUNCTION:    acpi_ex_read_serial_bus
1239e9f8733SBob Moore  *
1249e9f8733SBob Moore  * PARAMETERS:  obj_desc            - The named field to read
1259e9f8733SBob Moore  *              return_buffer       - Where the return value is returned, if any
1269e9f8733SBob Moore  *
1279e9f8733SBob Moore  * RETURN:      Status
1289e9f8733SBob Moore  *
1299e9f8733SBob Moore  * DESCRIPTION: Read from a named field that references a serial bus
1309e9f8733SBob Moore  *              (SMBus, IPMI, or GSBus).
1319e9f8733SBob Moore  *
1329e9f8733SBob Moore  ******************************************************************************/
1339e9f8733SBob Moore 
1349e9f8733SBob Moore acpi_status
acpi_ex_read_serial_bus(union acpi_operand_object * obj_desc,union acpi_operand_object ** return_buffer)1359e9f8733SBob Moore acpi_ex_read_serial_bus(union acpi_operand_object *obj_desc,
1369e9f8733SBob Moore 			union acpi_operand_object **return_buffer)
1379e9f8733SBob Moore {
1389e9f8733SBob Moore 	acpi_status status;
1399e9f8733SBob Moore 	u32 buffer_length;
1409e9f8733SBob Moore 	union acpi_operand_object *buffer_desc;
1419e9f8733SBob Moore 	u32 function;
1429e9f8733SBob Moore 	u16 accessor_type;
1439e9f8733SBob Moore 
1449e9f8733SBob Moore 	ACPI_FUNCTION_TRACE_PTR(ex_read_serial_bus, obj_desc);
1459e9f8733SBob Moore 
1469e9f8733SBob Moore 	/*
1479e9f8733SBob Moore 	 * This is an SMBus, GSBus or IPMI read. We must create a buffer to
1489e9f8733SBob Moore 	 * hold the data and then directly access the region handler.
1499e9f8733SBob Moore 	 *
1509e9f8733SBob Moore 	 * Note: SMBus and GSBus protocol value is passed in upper 16-bits
1519e9f8733SBob Moore 	 * of Function
1529e9f8733SBob Moore 	 *
1539e9f8733SBob Moore 	 * Common buffer format:
1549e9f8733SBob Moore 	 *     Status;    (Byte 0 of the data buffer)
1559e9f8733SBob Moore 	 *     Length;    (Byte 1 of the data buffer)
1569e9f8733SBob Moore 	 *     Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
1579e9f8733SBob Moore 	 */
1589e9f8733SBob Moore 	switch (obj_desc->field.region_obj->region.space_id) {
1599e9f8733SBob Moore 	case ACPI_ADR_SPACE_SMBUS:
1609e9f8733SBob Moore 
1619e9f8733SBob Moore 		buffer_length = ACPI_SMBUS_BUFFER_SIZE;
1629e9f8733SBob Moore 		function = ACPI_READ | (obj_desc->field.attribute << 16);
1639e9f8733SBob Moore 		break;
1649e9f8733SBob Moore 
1659e9f8733SBob Moore 	case ACPI_ADR_SPACE_IPMI:
1669e9f8733SBob Moore 
1679e9f8733SBob Moore 		buffer_length = ACPI_IPMI_BUFFER_SIZE;
1689e9f8733SBob Moore 		function = ACPI_READ;
1699e9f8733SBob Moore 		break;
1709e9f8733SBob Moore 
1719e9f8733SBob Moore 	case ACPI_ADR_SPACE_GSBUS:
1729e9f8733SBob Moore 
1739e9f8733SBob Moore 		accessor_type = obj_desc->field.attribute;
1749e9f8733SBob Moore 		if (accessor_type == AML_FIELD_ATTRIB_RAW_PROCESS_BYTES) {
1759e9f8733SBob Moore 			ACPI_ERROR((AE_INFO,
1769e9f8733SBob Moore 				    "Invalid direct read using bidirectional write-then-read protocol"));
1779e9f8733SBob Moore 
1789e9f8733SBob Moore 			return_ACPI_STATUS(AE_AML_PROTOCOL);
1799e9f8733SBob Moore 		}
1809e9f8733SBob Moore 
1819e9f8733SBob Moore 		status =
1829e9f8733SBob Moore 		    acpi_ex_get_protocol_buffer_length(accessor_type,
1839e9f8733SBob Moore 						       &buffer_length);
1849e9f8733SBob Moore 		if (ACPI_FAILURE(status)) {
1859e9f8733SBob Moore 			ACPI_ERROR((AE_INFO,
1869e9f8733SBob Moore 				    "Invalid protocol ID for GSBus: 0x%4.4X",
1879e9f8733SBob Moore 				    accessor_type));
1889e9f8733SBob Moore 
1899e9f8733SBob Moore 			return_ACPI_STATUS(status);
1909e9f8733SBob Moore 		}
1919e9f8733SBob Moore 
1929e9f8733SBob Moore 		/* Add header length to get the full size of the buffer */
1939e9f8733SBob Moore 
1949e9f8733SBob Moore 		buffer_length += ACPI_SERIAL_HEADER_SIZE;
1959e9f8733SBob Moore 		function = ACPI_READ | (accessor_type << 16);
1969e9f8733SBob Moore 		break;
1979e9f8733SBob Moore 
19804da290dSErik Kaneda 	case ACPI_ADR_SPACE_PLATFORM_RT:
19904da290dSErik Kaneda 
20004da290dSErik Kaneda 		buffer_length = ACPI_PRM_INPUT_BUFFER_SIZE;
20104da290dSErik Kaneda 		function = ACPI_READ;
20204da290dSErik Kaneda 		break;
20304da290dSErik Kaneda 
2049e9f8733SBob Moore 	default:
2059e9f8733SBob Moore 		return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID);
2069e9f8733SBob Moore 	}
2079e9f8733SBob Moore 
2089e9f8733SBob Moore 	/* Create the local transfer buffer that is returned to the caller */
2099e9f8733SBob Moore 
2109e9f8733SBob Moore 	buffer_desc = acpi_ut_create_buffer_object(buffer_length);
2119e9f8733SBob Moore 	if (!buffer_desc) {
2129e9f8733SBob Moore 		return_ACPI_STATUS(AE_NO_MEMORY);
2139e9f8733SBob Moore 	}
2149e9f8733SBob Moore 
2159e9f8733SBob Moore 	/* Lock entire transaction if requested */
2169e9f8733SBob Moore 
2179e9f8733SBob Moore 	acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
2189e9f8733SBob Moore 
2199e9f8733SBob Moore 	/* Call the region handler for the write-then-read */
2209e9f8733SBob Moore 
2219e9f8733SBob Moore 	status = acpi_ex_access_region(obj_desc, 0,
2229e9f8733SBob Moore 				       ACPI_CAST_PTR(u64,
2239e9f8733SBob Moore 						     buffer_desc->buffer.
2249e9f8733SBob Moore 						     pointer), function);
2259e9f8733SBob Moore 	acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
2269e9f8733SBob Moore 
2279e9f8733SBob Moore 	*return_buffer = buffer_desc;
2289e9f8733SBob Moore 	return_ACPI_STATUS(status);
2299e9f8733SBob Moore }
2309e9f8733SBob Moore 
2319e9f8733SBob Moore /*******************************************************************************
2329e9f8733SBob Moore  *
2339e9f8733SBob Moore  * FUNCTION:    acpi_ex_write_serial_bus
2349e9f8733SBob Moore  *
2359e9f8733SBob Moore  * PARAMETERS:  source_desc         - Contains data to write
2369e9f8733SBob Moore  *              obj_desc            - The named field
2379e9f8733SBob Moore  *              return_buffer       - Where the return value is returned, if any
2389e9f8733SBob Moore  *
2399e9f8733SBob Moore  * RETURN:      Status
2409e9f8733SBob Moore  *
2419e9f8733SBob Moore  * DESCRIPTION: Write to a named field that references a serial bus
2429e9f8733SBob Moore  *              (SMBus, IPMI, GSBus).
2439e9f8733SBob Moore  *
2449e9f8733SBob Moore  ******************************************************************************/
2459e9f8733SBob Moore 
2469e9f8733SBob Moore acpi_status
acpi_ex_write_serial_bus(union acpi_operand_object * source_desc,union acpi_operand_object * obj_desc,union acpi_operand_object ** return_buffer)2479e9f8733SBob Moore acpi_ex_write_serial_bus(union acpi_operand_object *source_desc,
2489e9f8733SBob Moore 			 union acpi_operand_object *obj_desc,
2499e9f8733SBob Moore 			 union acpi_operand_object **return_buffer)
2509e9f8733SBob Moore {
2519e9f8733SBob Moore 	acpi_status status;
2529e9f8733SBob Moore 	u32 buffer_length;
25355e8054dSErik Schmauss 	u32 data_length;
2549e9f8733SBob Moore 	void *buffer;
2559e9f8733SBob Moore 	union acpi_operand_object *buffer_desc;
2569e9f8733SBob Moore 	u32 function;
2579e9f8733SBob Moore 	u16 accessor_type;
2589e9f8733SBob Moore 
2599e9f8733SBob Moore 	ACPI_FUNCTION_TRACE_PTR(ex_write_serial_bus, obj_desc);
2609e9f8733SBob Moore 
2619e9f8733SBob Moore 	/*
2629e9f8733SBob Moore 	 * This is an SMBus, GSBus or IPMI write. We will bypass the entire
2639e9f8733SBob Moore 	 * field mechanism and handoff the buffer directly to the handler.
2649e9f8733SBob Moore 	 * For these address spaces, the buffer is bidirectional; on a
2659e9f8733SBob Moore 	 * write, return data is returned in the same buffer.
2669e9f8733SBob Moore 	 *
2679e9f8733SBob Moore 	 * Source must be a buffer of sufficient size, these are fixed size:
2689e9f8733SBob Moore 	 * ACPI_SMBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE.
2699e9f8733SBob Moore 	 *
2709e9f8733SBob Moore 	 * Note: SMBus and GSBus protocol type is passed in upper 16-bits
2719e9f8733SBob Moore 	 * of Function
2729e9f8733SBob Moore 	 *
2739e9f8733SBob Moore 	 * Common buffer format:
2749e9f8733SBob Moore 	 *     Status;    (Byte 0 of the data buffer)
2759e9f8733SBob Moore 	 *     Length;    (Byte 1 of the data buffer)
2769e9f8733SBob Moore 	 *     Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
2779e9f8733SBob Moore 	 */
2789e9f8733SBob Moore 	if (source_desc->common.type != ACPI_TYPE_BUFFER) {
2799e9f8733SBob Moore 		ACPI_ERROR((AE_INFO,
2809e9f8733SBob Moore 			    "SMBus/IPMI/GenericSerialBus write requires "
2819e9f8733SBob Moore 			    "Buffer, found type %s",
2829e9f8733SBob Moore 			    acpi_ut_get_object_type_name(source_desc)));
2839e9f8733SBob Moore 
2849e9f8733SBob Moore 		return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
2859e9f8733SBob Moore 	}
2869e9f8733SBob Moore 
2879e9f8733SBob Moore 	switch (obj_desc->field.region_obj->region.space_id) {
2889e9f8733SBob Moore 	case ACPI_ADR_SPACE_SMBUS:
2899e9f8733SBob Moore 
2909e9f8733SBob Moore 		buffer_length = ACPI_SMBUS_BUFFER_SIZE;
2919e9f8733SBob Moore 		function = ACPI_WRITE | (obj_desc->field.attribute << 16);
2929e9f8733SBob Moore 		break;
2939e9f8733SBob Moore 
2949e9f8733SBob Moore 	case ACPI_ADR_SPACE_IPMI:
2959e9f8733SBob Moore 
2969e9f8733SBob Moore 		buffer_length = ACPI_IPMI_BUFFER_SIZE;
2979e9f8733SBob Moore 		function = ACPI_WRITE;
2989e9f8733SBob Moore 		break;
2999e9f8733SBob Moore 
3009e9f8733SBob Moore 	case ACPI_ADR_SPACE_GSBUS:
3019e9f8733SBob Moore 
3029e9f8733SBob Moore 		accessor_type = obj_desc->field.attribute;
3039e9f8733SBob Moore 		status =
3049e9f8733SBob Moore 		    acpi_ex_get_protocol_buffer_length(accessor_type,
3059e9f8733SBob Moore 						       &buffer_length);
3069e9f8733SBob Moore 		if (ACPI_FAILURE(status)) {
3079e9f8733SBob Moore 			ACPI_ERROR((AE_INFO,
3089e9f8733SBob Moore 				    "Invalid protocol ID for GSBus: 0x%4.4X",
3099e9f8733SBob Moore 				    accessor_type));
3109e9f8733SBob Moore 
3119e9f8733SBob Moore 			return_ACPI_STATUS(status);
3129e9f8733SBob Moore 		}
3139e9f8733SBob Moore 
3149e9f8733SBob Moore 		/* Add header length to get the full size of the buffer */
3159e9f8733SBob Moore 
3169e9f8733SBob Moore 		buffer_length += ACPI_SERIAL_HEADER_SIZE;
3179e9f8733SBob Moore 		function = ACPI_WRITE | (accessor_type << 16);
3189e9f8733SBob Moore 		break;
3199e9f8733SBob Moore 
32004da290dSErik Kaneda 	case ACPI_ADR_SPACE_PLATFORM_RT:
32104da290dSErik Kaneda 
32204da290dSErik Kaneda 		buffer_length = ACPI_PRM_INPUT_BUFFER_SIZE;
32304da290dSErik Kaneda 		function = ACPI_WRITE;
32404da290dSErik Kaneda 		break;
32504da290dSErik Kaneda 
326ee64b827SSudeep Holla 	case ACPI_ADR_SPACE_FIXED_HARDWARE:
327ee64b827SSudeep Holla 
328ee64b827SSudeep Holla 		buffer_length = ACPI_FFH_INPUT_BUFFER_SIZE;
329ee64b827SSudeep Holla 		function = ACPI_WRITE;
330ee64b827SSudeep Holla 		break;
331ee64b827SSudeep Holla 
3329e9f8733SBob Moore 	default:
3339e9f8733SBob Moore 		return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID);
3349e9f8733SBob Moore 	}
3359e9f8733SBob Moore 
3369e9f8733SBob Moore 	/* Create the transfer/bidirectional/return buffer */
3379e9f8733SBob Moore 
3389e9f8733SBob Moore 	buffer_desc = acpi_ut_create_buffer_object(buffer_length);
3399e9f8733SBob Moore 	if (!buffer_desc) {
3409e9f8733SBob Moore 		return_ACPI_STATUS(AE_NO_MEMORY);
3419e9f8733SBob Moore 	}
3429e9f8733SBob Moore 
3439e9f8733SBob Moore 	/* Copy the input buffer data to the transfer buffer */
3449e9f8733SBob Moore 
3459e9f8733SBob Moore 	buffer = buffer_desc->buffer.pointer;
346*bac36a17SJiangshan Yi 	data_length = ACPI_MIN(buffer_length, source_desc->buffer.length);
34755e8054dSErik Schmauss 	memcpy(buffer, source_desc->buffer.pointer, data_length);
3489e9f8733SBob Moore 
3499e9f8733SBob Moore 	/* Lock entire transaction if requested */
3509e9f8733SBob Moore 
3519e9f8733SBob Moore 	acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
3529e9f8733SBob Moore 
3539e9f8733SBob Moore 	/*
3549e9f8733SBob Moore 	 * Perform the write (returns status and perhaps data in the
3559e9f8733SBob Moore 	 * same buffer)
3569e9f8733SBob Moore 	 */
3579e9f8733SBob Moore 	status = acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, function);
3589e9f8733SBob Moore 	acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
3599e9f8733SBob Moore 
3609e9f8733SBob Moore 	*return_buffer = buffer_desc;
3619e9f8733SBob Moore 	return_ACPI_STATUS(status);
3629e9f8733SBob Moore }
363