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