mirror of
https://github.com/torvalds/linux.git
synced 2024-12-26 21:02:19 +00:00
ACPICA: Update to GPIO region handler interface.
Changes to correct several GPIO issues: 1) The update_rule in a GPIO field definition is now ignored; a read-modify-write operation is never performed for GPIO fields. (Internally, this means that the field assembly/disassembly code is completely bypassed for GPIO.) 2) The Address parameter passed to a GPIO region handler is now the bit offset of the field from a previous Connection() operator. Thus, it becomes a "Pin Number Index" into the Connection() resource descriptor. 3) The bit_width parameter passed to a GPIO region handler is now the exact bit width of the GPIO field. Thus, it can be interpreted as "number of pins". Overall, we can now say that the region handler interface to GPIO handlers is a raw "bit/pin" addressed interface, not a byte-addressed interface like the system_memory handler interface. Signed-off-by: Bob Moore <robert.moore@intel.com> Signed-off-by: Lv Zheng <lv.zheng@intel.com> Cc: 3.15+ <stable@vger.kernel.org> # 3.15+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
parent
0f33be009b
commit
75ec6e55f1
@ -254,6 +254,7 @@ struct acpi_create_field_info {
|
|||||||
u32 field_bit_position;
|
u32 field_bit_position;
|
||||||
u32 field_bit_length;
|
u32 field_bit_length;
|
||||||
u16 resource_length;
|
u16 resource_length;
|
||||||
|
u16 pin_number_index;
|
||||||
u8 field_flags;
|
u8 field_flags;
|
||||||
u8 attribute;
|
u8 attribute;
|
||||||
u8 field_type;
|
u8 field_type;
|
||||||
|
@ -264,6 +264,7 @@ struct acpi_object_region_field {
|
|||||||
ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO u16 resource_length;
|
ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO u16 resource_length;
|
||||||
union acpi_operand_object *region_obj; /* Containing op_region object */
|
union acpi_operand_object *region_obj; /* Containing op_region object */
|
||||||
u8 *resource_buffer; /* resource_template for serial regions/fields */
|
u8 *resource_buffer; /* resource_template for serial regions/fields */
|
||||||
|
u16 pin_number_index; /* Index relative to previous Connection/Template */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct acpi_object_bank_field {
|
struct acpi_object_bank_field {
|
||||||
|
@ -360,6 +360,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info,
|
|||||||
*/
|
*/
|
||||||
info->resource_buffer = NULL;
|
info->resource_buffer = NULL;
|
||||||
info->connection_node = NULL;
|
info->connection_node = NULL;
|
||||||
|
info->pin_number_index = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A Connection() is either an actual resource descriptor (buffer)
|
* A Connection() is either an actual resource descriptor (buffer)
|
||||||
@ -437,6 +438,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info,
|
|||||||
}
|
}
|
||||||
|
|
||||||
info->field_bit_position += info->field_bit_length;
|
info->field_bit_position += info->field_bit_length;
|
||||||
|
info->pin_number_index++; /* Index relative to previous Connection() */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -142,6 +142,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
|
|||||||
union acpi_operand_object *region_obj2;
|
union acpi_operand_object *region_obj2;
|
||||||
void *region_context = NULL;
|
void *region_context = NULL;
|
||||||
struct acpi_connection_info *context;
|
struct acpi_connection_info *context;
|
||||||
|
acpi_physical_address address;
|
||||||
|
|
||||||
ACPI_FUNCTION_TRACE(ev_address_space_dispatch);
|
ACPI_FUNCTION_TRACE(ev_address_space_dispatch);
|
||||||
|
|
||||||
@ -231,25 +232,23 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
|
|||||||
/* We have everything we need, we can invoke the address space handler */
|
/* We have everything we need, we can invoke the address space handler */
|
||||||
|
|
||||||
handler = handler_desc->address_space.handler;
|
handler = handler_desc->address_space.handler;
|
||||||
|
address = (region_obj->region.address + region_offset);
|
||||||
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
|
|
||||||
"Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
|
|
||||||
®ion_obj->region.handler->address_space, handler,
|
|
||||||
ACPI_FORMAT_NATIVE_UINT(region_obj->region.address +
|
|
||||||
region_offset),
|
|
||||||
acpi_ut_get_region_name(region_obj->region.
|
|
||||||
space_id)));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Special handling for generic_serial_bus and general_purpose_io:
|
* Special handling for generic_serial_bus and general_purpose_io:
|
||||||
* There are three extra parameters that must be passed to the
|
* There are three extra parameters that must be passed to the
|
||||||
* handler via the context:
|
* handler via the context:
|
||||||
* 1) Connection buffer, a resource template from Connection() op.
|
* 1) Connection buffer, a resource template from Connection() op
|
||||||
* 2) Length of the above buffer.
|
* 2) Length of the above buffer
|
||||||
* 3) Actual access length from the access_as() op.
|
* 3) Actual access length from the access_as() op
|
||||||
|
*
|
||||||
|
* In addition, for general_purpose_io, the Address and bit_width fields
|
||||||
|
* are defined as follows:
|
||||||
|
* 1) Address is the pin number index of the field (bit offset from
|
||||||
|
* the previous Connection)
|
||||||
|
* 2) bit_width is the actual bit length of the field (number of pins)
|
||||||
*/
|
*/
|
||||||
if (((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) ||
|
if ((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) &&
|
||||||
(region_obj->region.space_id == ACPI_ADR_SPACE_GPIO)) &&
|
|
||||||
context && field_obj) {
|
context && field_obj) {
|
||||||
|
|
||||||
/* Get the Connection (resource_template) buffer */
|
/* Get the Connection (resource_template) buffer */
|
||||||
@ -258,6 +257,24 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
|
|||||||
context->length = field_obj->field.resource_length;
|
context->length = field_obj->field.resource_length;
|
||||||
context->access_length = field_obj->field.access_length;
|
context->access_length = field_obj->field.access_length;
|
||||||
}
|
}
|
||||||
|
if ((region_obj->region.space_id == ACPI_ADR_SPACE_GPIO) &&
|
||||||
|
context && field_obj) {
|
||||||
|
|
||||||
|
/* Get the Connection (resource_template) buffer */
|
||||||
|
|
||||||
|
context->connection = field_obj->field.resource_buffer;
|
||||||
|
context->length = field_obj->field.resource_length;
|
||||||
|
context->access_length = field_obj->field.access_length;
|
||||||
|
address = field_obj->field.pin_number_index;
|
||||||
|
bit_width = field_obj->field.bit_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
|
||||||
|
"Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
|
||||||
|
®ion_obj->region.handler->address_space, handler,
|
||||||
|
ACPI_FORMAT_NATIVE_UINT(address),
|
||||||
|
acpi_ut_get_region_name(region_obj->region.
|
||||||
|
space_id)));
|
||||||
|
|
||||||
if (!(handler_desc->address_space.handler_flags &
|
if (!(handler_desc->address_space.handler_flags &
|
||||||
ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
|
ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
|
||||||
@ -271,9 +288,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
|
|||||||
|
|
||||||
/* Call the handler */
|
/* Call the handler */
|
||||||
|
|
||||||
status = handler(function,
|
status = handler(function, address, bit_width, value, context,
|
||||||
(region_obj->region.address + region_offset),
|
|
||||||
bit_width, value, context,
|
|
||||||
region_obj2->extra.region_context);
|
region_obj2->extra.region_context);
|
||||||
|
|
||||||
if (ACPI_FAILURE(status)) {
|
if (ACPI_FAILURE(status)) {
|
||||||
|
@ -253,6 +253,37 @@ acpi_ex_read_data_from_field(struct acpi_walk_state * walk_state,
|
|||||||
buffer = &buffer_desc->integer.value;
|
buffer = &buffer_desc->integer.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
|
||||||
|
(obj_desc->field.region_obj->region.space_id ==
|
||||||
|
ACPI_ADR_SPACE_GPIO)) {
|
||||||
|
/*
|
||||||
|
* For GPIO (general_purpose_io), the Address will be the bit offset
|
||||||
|
* from the previous Connection() operator, making it effectively a
|
||||||
|
* pin number index. The bit_length is the length of the field, which
|
||||||
|
* is thus the number of pins.
|
||||||
|
*/
|
||||||
|
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
|
||||||
|
"GPIO FieldRead [FROM]: Pin %u Bits %u\n",
|
||||||
|
obj_desc->field.pin_number_index,
|
||||||
|
obj_desc->field.bit_length));
|
||||||
|
|
||||||
|
/* Lock entire transaction if requested */
|
||||||
|
|
||||||
|
acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
|
||||||
|
|
||||||
|
/* Perform the write */
|
||||||
|
|
||||||
|
status = acpi_ex_access_region(obj_desc, 0,
|
||||||
|
(u64 *)buffer, ACPI_READ);
|
||||||
|
acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
|
||||||
|
if (ACPI_FAILURE(status)) {
|
||||||
|
acpi_ut_remove_reference(buffer_desc);
|
||||||
|
} else {
|
||||||
|
*ret_buffer_desc = buffer_desc;
|
||||||
|
}
|
||||||
|
return_ACPI_STATUS(status);
|
||||||
|
}
|
||||||
|
|
||||||
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
|
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
|
||||||
"FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n",
|
"FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n",
|
||||||
obj_desc, obj_desc->common.type, buffer,
|
obj_desc, obj_desc->common.type, buffer,
|
||||||
@ -413,6 +444,42 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
|
|||||||
|
|
||||||
*result_desc = buffer_desc;
|
*result_desc = buffer_desc;
|
||||||
return_ACPI_STATUS(status);
|
return_ACPI_STATUS(status);
|
||||||
|
} else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
|
||||||
|
(obj_desc->field.region_obj->region.space_id ==
|
||||||
|
ACPI_ADR_SPACE_GPIO)) {
|
||||||
|
/*
|
||||||
|
* For GPIO (general_purpose_io), we will bypass the entire field
|
||||||
|
* mechanism and handoff the bit address and bit width directly to
|
||||||
|
* the handler. The Address will be the bit offset
|
||||||
|
* from the previous Connection() operator, making it effectively a
|
||||||
|
* pin number index. The bit_length is the length of the field, which
|
||||||
|
* is thus the number of pins.
|
||||||
|
*/
|
||||||
|
if (source_desc->common.type != ACPI_TYPE_INTEGER) {
|
||||||
|
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
|
||||||
|
"GPIO FieldWrite [FROM]: (%s:%X), Val %.8X [TO]: Pin %u Bits %u\n",
|
||||||
|
acpi_ut_get_type_name(source_desc->common.
|
||||||
|
type),
|
||||||
|
source_desc->common.type,
|
||||||
|
(u32)source_desc->integer.value,
|
||||||
|
obj_desc->field.pin_number_index,
|
||||||
|
obj_desc->field.bit_length));
|
||||||
|
|
||||||
|
buffer = &source_desc->integer.value;
|
||||||
|
|
||||||
|
/* Lock entire transaction if requested */
|
||||||
|
|
||||||
|
acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
|
||||||
|
|
||||||
|
/* Perform the write */
|
||||||
|
|
||||||
|
status = acpi_ex_access_region(obj_desc, 0,
|
||||||
|
(u64 *)buffer, ACPI_WRITE);
|
||||||
|
acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
|
||||||
|
return_ACPI_STATUS(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get a pointer to the data to be written */
|
/* Get a pointer to the data to be written */
|
||||||
|
@ -484,6 +484,8 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
|
|||||||
obj_desc->field.resource_length = info->resource_length;
|
obj_desc->field.resource_length = info->resource_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
obj_desc->field.pin_number_index = info->pin_number_index;
|
||||||
|
|
||||||
/* Allow full data read from EC address space */
|
/* Allow full data read from EC address space */
|
||||||
|
|
||||||
if ((obj_desc->field.region_obj->region.space_id ==
|
if ((obj_desc->field.region_obj->region.space_id ==
|
||||||
|
Loading…
Reference in New Issue
Block a user