xref: /OK3568_Linux_fs/kernel/drivers/acpi/acpica/exserial.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2*4882a593Smuzhiyun /******************************************************************************
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Module Name: exserial - field_unit support for serial address spaces
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright (C) 2000 - 2020, Intel Corp.
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  *****************************************************************************/
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <acpi/acpi.h>
11*4882a593Smuzhiyun #include "accommon.h"
12*4882a593Smuzhiyun #include "acdispat.h"
13*4882a593Smuzhiyun #include "acinterp.h"
14*4882a593Smuzhiyun #include "amlcode.h"
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #define _COMPONENT          ACPI_EXECUTER
17*4882a593Smuzhiyun ACPI_MODULE_NAME("exserial")
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun /*******************************************************************************
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  * FUNCTION:    acpi_ex_read_gpio
22*4882a593Smuzhiyun  *
23*4882a593Smuzhiyun  * PARAMETERS:  obj_desc            - The named field to read
24*4882a593Smuzhiyun  *              buffer              - Where the return data is returned
25*4882a593Smuzhiyun  *
26*4882a593Smuzhiyun  * RETURN:      Status
27*4882a593Smuzhiyun  *
28*4882a593Smuzhiyun  * DESCRIPTION: Read from a named field that references a Generic Serial Bus
29*4882a593Smuzhiyun  *              field
30*4882a593Smuzhiyun  *
31*4882a593Smuzhiyun  ******************************************************************************/
acpi_ex_read_gpio(union acpi_operand_object * obj_desc,void * buffer)32*4882a593Smuzhiyun acpi_status acpi_ex_read_gpio(union acpi_operand_object *obj_desc, void *buffer)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun 	acpi_status status;
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun 	ACPI_FUNCTION_TRACE_PTR(ex_read_gpio, obj_desc);
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 	/*
39*4882a593Smuzhiyun 	 * For GPIO (general_purpose_io), the Address will be the bit offset
40*4882a593Smuzhiyun 	 * from the previous Connection() operator, making it effectively a
41*4882a593Smuzhiyun 	 * pin number index. The bit_length is the length of the field, which
42*4882a593Smuzhiyun 	 * is thus the number of pins.
43*4882a593Smuzhiyun 	 */
44*4882a593Smuzhiyun 	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
45*4882a593Smuzhiyun 			  "GPIO FieldRead [FROM]:  Pin %u Bits %u\n",
46*4882a593Smuzhiyun 			  obj_desc->field.pin_number_index,
47*4882a593Smuzhiyun 			  obj_desc->field.bit_length));
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	/* Lock entire transaction if requested */
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	/* Perform the read */
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	status = acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, ACPI_READ);
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
58*4882a593Smuzhiyun 	return_ACPI_STATUS(status);
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun /*******************************************************************************
62*4882a593Smuzhiyun  *
63*4882a593Smuzhiyun  * FUNCTION:    acpi_ex_write_gpio
64*4882a593Smuzhiyun  *
65*4882a593Smuzhiyun  * PARAMETERS:  source_desc         - Contains data to write. Expect to be
66*4882a593Smuzhiyun  *                                    an Integer object.
67*4882a593Smuzhiyun  *              obj_desc            - The named field
68*4882a593Smuzhiyun  *              result_desc         - Where the return value is returned, if any
69*4882a593Smuzhiyun  *
70*4882a593Smuzhiyun  * RETURN:      Status
71*4882a593Smuzhiyun  *
72*4882a593Smuzhiyun  * DESCRIPTION: Write to a named field that references a General Purpose I/O
73*4882a593Smuzhiyun  *              field.
74*4882a593Smuzhiyun  *
75*4882a593Smuzhiyun  ******************************************************************************/
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun acpi_status
acpi_ex_write_gpio(union acpi_operand_object * source_desc,union acpi_operand_object * obj_desc,union acpi_operand_object ** return_buffer)78*4882a593Smuzhiyun acpi_ex_write_gpio(union acpi_operand_object *source_desc,
79*4882a593Smuzhiyun 		   union acpi_operand_object *obj_desc,
80*4882a593Smuzhiyun 		   union acpi_operand_object **return_buffer)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun 	acpi_status status;
83*4882a593Smuzhiyun 	void *buffer;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	ACPI_FUNCTION_TRACE_PTR(ex_write_gpio, obj_desc);
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	/*
88*4882a593Smuzhiyun 	 * For GPIO (general_purpose_io), we will bypass the entire field
89*4882a593Smuzhiyun 	 * mechanism and handoff the bit address and bit width directly to
90*4882a593Smuzhiyun 	 * the handler. The Address will be the bit offset
91*4882a593Smuzhiyun 	 * from the previous Connection() operator, making it effectively a
92*4882a593Smuzhiyun 	 * pin number index. The bit_length is the length of the field, which
93*4882a593Smuzhiyun 	 * is thus the number of pins.
94*4882a593Smuzhiyun 	 */
95*4882a593Smuzhiyun 	if (source_desc->common.type != ACPI_TYPE_INTEGER) {
96*4882a593Smuzhiyun 		return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
97*4882a593Smuzhiyun 	}
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
100*4882a593Smuzhiyun 			  "GPIO FieldWrite [FROM]: (%s:%X), Value %.8X  [TO]: Pin %u Bits %u\n",
101*4882a593Smuzhiyun 			  acpi_ut_get_type_name(source_desc->common.type),
102*4882a593Smuzhiyun 			  source_desc->common.type,
103*4882a593Smuzhiyun 			  (u32)source_desc->integer.value,
104*4882a593Smuzhiyun 			  obj_desc->field.pin_number_index,
105*4882a593Smuzhiyun 			  obj_desc->field.bit_length));
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	buffer = &source_desc->integer.value;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	/* Lock entire transaction if requested */
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	/* Perform the write */
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	status = acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, ACPI_WRITE);
116*4882a593Smuzhiyun 	acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
117*4882a593Smuzhiyun 	return_ACPI_STATUS(status);
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun /*******************************************************************************
121*4882a593Smuzhiyun  *
122*4882a593Smuzhiyun  * FUNCTION:    acpi_ex_read_serial_bus
123*4882a593Smuzhiyun  *
124*4882a593Smuzhiyun  * PARAMETERS:  obj_desc            - The named field to read
125*4882a593Smuzhiyun  *              return_buffer       - Where the return value is returned, if any
126*4882a593Smuzhiyun  *
127*4882a593Smuzhiyun  * RETURN:      Status
128*4882a593Smuzhiyun  *
129*4882a593Smuzhiyun  * DESCRIPTION: Read from a named field that references a serial bus
130*4882a593Smuzhiyun  *              (SMBus, IPMI, or GSBus).
131*4882a593Smuzhiyun  *
132*4882a593Smuzhiyun  ******************************************************************************/
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun acpi_status
acpi_ex_read_serial_bus(union acpi_operand_object * obj_desc,union acpi_operand_object ** return_buffer)135*4882a593Smuzhiyun acpi_ex_read_serial_bus(union acpi_operand_object *obj_desc,
136*4882a593Smuzhiyun 			union acpi_operand_object **return_buffer)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun 	acpi_status status;
139*4882a593Smuzhiyun 	u32 buffer_length;
140*4882a593Smuzhiyun 	union acpi_operand_object *buffer_desc;
141*4882a593Smuzhiyun 	u32 function;
142*4882a593Smuzhiyun 	u16 accessor_type;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	ACPI_FUNCTION_TRACE_PTR(ex_read_serial_bus, obj_desc);
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	/*
147*4882a593Smuzhiyun 	 * This is an SMBus, GSBus or IPMI read. We must create a buffer to
148*4882a593Smuzhiyun 	 * hold the data and then directly access the region handler.
149*4882a593Smuzhiyun 	 *
150*4882a593Smuzhiyun 	 * Note: SMBus and GSBus protocol value is passed in upper 16-bits
151*4882a593Smuzhiyun 	 * of Function
152*4882a593Smuzhiyun 	 *
153*4882a593Smuzhiyun 	 * Common buffer format:
154*4882a593Smuzhiyun 	 *     Status;    (Byte 0 of the data buffer)
155*4882a593Smuzhiyun 	 *     Length;    (Byte 1 of the data buffer)
156*4882a593Smuzhiyun 	 *     Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
157*4882a593Smuzhiyun 	 */
158*4882a593Smuzhiyun 	switch (obj_desc->field.region_obj->region.space_id) {
159*4882a593Smuzhiyun 	case ACPI_ADR_SPACE_SMBUS:
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 		buffer_length = ACPI_SMBUS_BUFFER_SIZE;
162*4882a593Smuzhiyun 		function = ACPI_READ | (obj_desc->field.attribute << 16);
163*4882a593Smuzhiyun 		break;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	case ACPI_ADR_SPACE_IPMI:
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 		buffer_length = ACPI_IPMI_BUFFER_SIZE;
168*4882a593Smuzhiyun 		function = ACPI_READ;
169*4882a593Smuzhiyun 		break;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	case ACPI_ADR_SPACE_GSBUS:
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 		accessor_type = obj_desc->field.attribute;
174*4882a593Smuzhiyun 		if (accessor_type == AML_FIELD_ATTRIB_RAW_PROCESS_BYTES) {
175*4882a593Smuzhiyun 			ACPI_ERROR((AE_INFO,
176*4882a593Smuzhiyun 				    "Invalid direct read using bidirectional write-then-read protocol"));
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 			return_ACPI_STATUS(AE_AML_PROTOCOL);
179*4882a593Smuzhiyun 		}
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 		status =
182*4882a593Smuzhiyun 		    acpi_ex_get_protocol_buffer_length(accessor_type,
183*4882a593Smuzhiyun 						       &buffer_length);
184*4882a593Smuzhiyun 		if (ACPI_FAILURE(status)) {
185*4882a593Smuzhiyun 			ACPI_ERROR((AE_INFO,
186*4882a593Smuzhiyun 				    "Invalid protocol ID for GSBus: 0x%4.4X",
187*4882a593Smuzhiyun 				    accessor_type));
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 			return_ACPI_STATUS(status);
190*4882a593Smuzhiyun 		}
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 		/* Add header length to get the full size of the buffer */
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 		buffer_length += ACPI_SERIAL_HEADER_SIZE;
195*4882a593Smuzhiyun 		function = ACPI_READ | (accessor_type << 16);
196*4882a593Smuzhiyun 		break;
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	default:
199*4882a593Smuzhiyun 		return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID);
200*4882a593Smuzhiyun 	}
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	/* Create the local transfer buffer that is returned to the caller */
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	buffer_desc = acpi_ut_create_buffer_object(buffer_length);
205*4882a593Smuzhiyun 	if (!buffer_desc) {
206*4882a593Smuzhiyun 		return_ACPI_STATUS(AE_NO_MEMORY);
207*4882a593Smuzhiyun 	}
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	/* Lock entire transaction if requested */
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	/* Call the region handler for the write-then-read */
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	status = acpi_ex_access_region(obj_desc, 0,
216*4882a593Smuzhiyun 				       ACPI_CAST_PTR(u64,
217*4882a593Smuzhiyun 						     buffer_desc->buffer.
218*4882a593Smuzhiyun 						     pointer), function);
219*4882a593Smuzhiyun 	acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	*return_buffer = buffer_desc;
222*4882a593Smuzhiyun 	return_ACPI_STATUS(status);
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun /*******************************************************************************
226*4882a593Smuzhiyun  *
227*4882a593Smuzhiyun  * FUNCTION:    acpi_ex_write_serial_bus
228*4882a593Smuzhiyun  *
229*4882a593Smuzhiyun  * PARAMETERS:  source_desc         - Contains data to write
230*4882a593Smuzhiyun  *              obj_desc            - The named field
231*4882a593Smuzhiyun  *              return_buffer       - Where the return value is returned, if any
232*4882a593Smuzhiyun  *
233*4882a593Smuzhiyun  * RETURN:      Status
234*4882a593Smuzhiyun  *
235*4882a593Smuzhiyun  * DESCRIPTION: Write to a named field that references a serial bus
236*4882a593Smuzhiyun  *              (SMBus, IPMI, GSBus).
237*4882a593Smuzhiyun  *
238*4882a593Smuzhiyun  ******************************************************************************/
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 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)241*4882a593Smuzhiyun acpi_ex_write_serial_bus(union acpi_operand_object *source_desc,
242*4882a593Smuzhiyun 			 union acpi_operand_object *obj_desc,
243*4882a593Smuzhiyun 			 union acpi_operand_object **return_buffer)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun 	acpi_status status;
246*4882a593Smuzhiyun 	u32 buffer_length;
247*4882a593Smuzhiyun 	u32 data_length;
248*4882a593Smuzhiyun 	void *buffer;
249*4882a593Smuzhiyun 	union acpi_operand_object *buffer_desc;
250*4882a593Smuzhiyun 	u32 function;
251*4882a593Smuzhiyun 	u16 accessor_type;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	ACPI_FUNCTION_TRACE_PTR(ex_write_serial_bus, obj_desc);
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	/*
256*4882a593Smuzhiyun 	 * This is an SMBus, GSBus or IPMI write. We will bypass the entire
257*4882a593Smuzhiyun 	 * field mechanism and handoff the buffer directly to the handler.
258*4882a593Smuzhiyun 	 * For these address spaces, the buffer is bidirectional; on a
259*4882a593Smuzhiyun 	 * write, return data is returned in the same buffer.
260*4882a593Smuzhiyun 	 *
261*4882a593Smuzhiyun 	 * Source must be a buffer of sufficient size, these are fixed size:
262*4882a593Smuzhiyun 	 * ACPI_SMBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE.
263*4882a593Smuzhiyun 	 *
264*4882a593Smuzhiyun 	 * Note: SMBus and GSBus protocol type is passed in upper 16-bits
265*4882a593Smuzhiyun 	 * of Function
266*4882a593Smuzhiyun 	 *
267*4882a593Smuzhiyun 	 * Common buffer format:
268*4882a593Smuzhiyun 	 *     Status;    (Byte 0 of the data buffer)
269*4882a593Smuzhiyun 	 *     Length;    (Byte 1 of the data buffer)
270*4882a593Smuzhiyun 	 *     Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
271*4882a593Smuzhiyun 	 */
272*4882a593Smuzhiyun 	if (source_desc->common.type != ACPI_TYPE_BUFFER) {
273*4882a593Smuzhiyun 		ACPI_ERROR((AE_INFO,
274*4882a593Smuzhiyun 			    "SMBus/IPMI/GenericSerialBus write requires "
275*4882a593Smuzhiyun 			    "Buffer, found type %s",
276*4882a593Smuzhiyun 			    acpi_ut_get_object_type_name(source_desc)));
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 		return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
279*4882a593Smuzhiyun 	}
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	switch (obj_desc->field.region_obj->region.space_id) {
282*4882a593Smuzhiyun 	case ACPI_ADR_SPACE_SMBUS:
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 		buffer_length = ACPI_SMBUS_BUFFER_SIZE;
285*4882a593Smuzhiyun 		function = ACPI_WRITE | (obj_desc->field.attribute << 16);
286*4882a593Smuzhiyun 		break;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	case ACPI_ADR_SPACE_IPMI:
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 		buffer_length = ACPI_IPMI_BUFFER_SIZE;
291*4882a593Smuzhiyun 		function = ACPI_WRITE;
292*4882a593Smuzhiyun 		break;
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	case ACPI_ADR_SPACE_GSBUS:
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 		accessor_type = obj_desc->field.attribute;
297*4882a593Smuzhiyun 		status =
298*4882a593Smuzhiyun 		    acpi_ex_get_protocol_buffer_length(accessor_type,
299*4882a593Smuzhiyun 						       &buffer_length);
300*4882a593Smuzhiyun 		if (ACPI_FAILURE(status)) {
301*4882a593Smuzhiyun 			ACPI_ERROR((AE_INFO,
302*4882a593Smuzhiyun 				    "Invalid protocol ID for GSBus: 0x%4.4X",
303*4882a593Smuzhiyun 				    accessor_type));
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 			return_ACPI_STATUS(status);
306*4882a593Smuzhiyun 		}
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 		/* Add header length to get the full size of the buffer */
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 		buffer_length += ACPI_SERIAL_HEADER_SIZE;
311*4882a593Smuzhiyun 		function = ACPI_WRITE | (accessor_type << 16);
312*4882a593Smuzhiyun 		break;
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	default:
315*4882a593Smuzhiyun 		return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID);
316*4882a593Smuzhiyun 	}
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	/* Create the transfer/bidirectional/return buffer */
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	buffer_desc = acpi_ut_create_buffer_object(buffer_length);
321*4882a593Smuzhiyun 	if (!buffer_desc) {
322*4882a593Smuzhiyun 		return_ACPI_STATUS(AE_NO_MEMORY);
323*4882a593Smuzhiyun 	}
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	/* Copy the input buffer data to the transfer buffer */
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	buffer = buffer_desc->buffer.pointer;
328*4882a593Smuzhiyun 	data_length = (buffer_length < source_desc->buffer.length ?
329*4882a593Smuzhiyun 		       buffer_length : source_desc->buffer.length);
330*4882a593Smuzhiyun 	memcpy(buffer, source_desc->buffer.pointer, data_length);
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	/* Lock entire transaction if requested */
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	/*
337*4882a593Smuzhiyun 	 * Perform the write (returns status and perhaps data in the
338*4882a593Smuzhiyun 	 * same buffer)
339*4882a593Smuzhiyun 	 */
340*4882a593Smuzhiyun 	status = acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, function);
341*4882a593Smuzhiyun 	acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	*return_buffer = buffer_desc;
344*4882a593Smuzhiyun 	return_ACPI_STATUS(status);
345*4882a593Smuzhiyun }
346