diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index 950a1ac95d6ad47dd1cc3be2c9da6a01c28d98fc..c1f2671a7b0bb33cb39abaa4228faaddde2e8505 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c @@ -14,17 +14,50 @@ #include "radeon_acpi.h" +struct radeon_atpx_functions { + bool px_params; + bool power_cntl; + bool disp_mux_cntl; + bool i2c_mux_cntl; + bool switch_start; + bool switch_end; + bool disp_connectors_mapping; + bool disp_detetion_ports; +}; + +struct radeon_atpx { + struct radeon_atpx_functions functions; +}; + static struct radeon_atpx_priv { bool atpx_detected; /* handle for device - and atpx */ acpi_handle dhandle; acpi_handle atpx_handle; + struct radeon_atpx atpx; } radeon_atpx_priv; -static int radeon_atpx_get_version(acpi_handle handle) +struct atpx_verify_interface { + u16 size; /* structure size in bytes (includes size field) */ + u16 version; /* version */ + u32 function_bits; /* supported functions bit vector */ +} __packed; + +/** + * radeon_atpx_call - call an ATPX method + * + * @handle: acpi handle + * @function: the ATPX function to execute + * @params: ATPX function params + * + * Executes the requested ATPX function (all asics). + * Returns a pointer to the acpi output buffer. + */ +static union acpi_object *radeon_atpx_call(acpi_handle handle, int function, + struct acpi_buffer *params) { acpi_status status; - union acpi_object atpx_arg_elements[2], *obj; + union acpi_object atpx_arg_elements[2]; struct acpi_object_list atpx_arg; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -32,21 +65,96 @@ static int radeon_atpx_get_version(acpi_handle handle) atpx_arg.pointer = &atpx_arg_elements[0]; atpx_arg_elements[0].type = ACPI_TYPE_INTEGER; - atpx_arg_elements[0].integer.value = ATPX_FUNCTION_VERIFY_INTERFACE; + atpx_arg_elements[0].integer.value = function; + + if (params) { + atpx_arg_elements[1].type = ACPI_TYPE_BUFFER; + atpx_arg_elements[1].buffer.length = params->length; + atpx_arg_elements[1].buffer.pointer = params->pointer; + } else { + /* We need a second fake parameter */ + atpx_arg_elements[1].type = ACPI_TYPE_INTEGER; + atpx_arg_elements[1].integer.value = 0; + } - atpx_arg_elements[1].type = ACPI_TYPE_INTEGER; - atpx_arg_elements[1].integer.value = 0; + status = acpi_evaluate_object(handle, "ATPX", &atpx_arg, &buffer); - status = acpi_evaluate_object(handle, NULL, &atpx_arg, &buffer); - if (ACPI_FAILURE(status)) { - printk("%s: failed to call ATPX: %s\n", __func__, acpi_format_exception(status)); - return -ENOSYS; + /* Fail only if calling the method fails and ATPX is supported */ + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { + printk("failed to evaluate ATPX got %s\n", + acpi_format_exception(status)); + kfree(buffer.pointer); + return NULL; } - obj = (union acpi_object *)buffer.pointer; - if (obj && (obj->type == ACPI_TYPE_BUFFER)) - printk(KERN_INFO "radeon atpx: version is %d\n", *((u8 *)(obj->buffer.pointer) + 2)); - kfree(buffer.pointer); - return 0; + + return buffer.pointer; +} + +/** + * radeon_atpx_parse_functions - parse supported functions + * + * @f: supported functions struct + * @mask: supported functions mask from ATPX + * + * Use the supported functions mask from ATPX function + * ATPX_FUNCTION_VERIFY_INTERFACE to determine what functions + * are supported (all asics). + */ +static void radeon_atpx_parse_functions(struct radeon_atpx_functions *f, u32 mask) +{ + f->px_params = mask & ATPX_GET_PX_PARAMETERS_SUPPORTED; + f->power_cntl = mask & ATPX_POWER_CONTROL_SUPPORTED; + f->disp_mux_cntl = mask & ATPX_DISPLAY_MUX_CONTROL_SUPPORTED; + f->i2c_mux_cntl = mask & ATPX_I2C_MUX_CONTROL_SUPPORTED; + f->switch_start = mask & ATPX_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION_SUPPORTED; + f->switch_end = mask & ATPX_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION_SUPPORTED; + f->disp_connectors_mapping = mask & ATPX_GET_DISPLAY_CONNECTORS_MAPPING_SUPPORTED; + f->disp_detetion_ports = mask & ATPX_GET_DISPLAY_DETECTION_PORTS_SUPPORTED; +} + +/** + * radeon_atpx_verify_interface - verify ATPX + * + * @handle: acpi handle + * @atpx: radeon atpx struct + * + * Execute the ATPX_FUNCTION_VERIFY_INTERFACE ATPX function + * to initialize ATPX and determine what features are supported + * (all asics). + * returns 0 on success, error on failure. + */ +static int radeon_atpx_verify_interface(acpi_handle handle, + struct radeon_atpx *atpx) +{ + union acpi_object *info; + struct atpx_verify_interface output; + size_t size; + int err = 0; + + info = radeon_atpx_call(handle, ATPX_FUNCTION_VERIFY_INTERFACE, NULL); + if (!info) + return -EIO; + + memset(&output, 0, sizeof(output)); + + size = *(u16 *) info->buffer.pointer; + if (size < 8) { + printk("ATPX buffer is too small: %lu\n", size); + err = -EINVAL; + goto out; + } + size = min(sizeof(output), size); + + memcpy(&output, info->buffer.pointer, size); + + /* TODO: check version? */ + printk("ATPX version %u\n", output.version); + + radeon_atpx_parse_functions(&atpx->functions, output.function_bits); + +out: + kfree(info); + return err; } static int radeon_atpx_execute(acpi_handle handle, int cmd_id, u16 value) @@ -161,9 +269,8 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev) static int radeon_atpx_init(void) { /* set up the ATPX handle */ - - radeon_atpx_get_version(radeon_atpx_priv.atpx_handle); - return 0; + return radeon_atpx_verify_interface(radeon_atpx_priv.atpx_handle, + &radeon_atpx_priv.atpx); } static int radeon_atpx_get_client_id(struct pci_dev *pdev)