From 9e05b2f49eb9484e857e9b6c70dea3bbbe564290 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 18 Jul 2012 13:28:52 -0400 Subject: drm/radeon: add new AMD ACPI header and update relevant code (v2) Add a new header that defines the AMD ACPI interface used for laptops, PowerXpress, and chipset specific functionality and update the current code to use it. Todo: - properly verify the ACPI interfaces - hook up and handle ACPI notifications - make PX code more robust - implement PCIe Gen and width switching using ACPI v2: fix typo in header Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_acpi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon/radeon_acpi.c') diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index 3516a6081dc..5b32e499903 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -9,6 +9,7 @@ #include "drm_sarea.h" #include "drm_crtc_helper.h" #include "radeon.h" +#include "radeon_acpi.h" #include @@ -27,7 +28,7 @@ static int radeon_atif_call(acpi_handle handle) atif_arg.pointer = &atif_arg_elements[0]; atif_arg_elements[0].type = ACPI_TYPE_INTEGER; - atif_arg_elements[0].integer.value = 0; + atif_arg_elements[0].integer.value = ATIF_FUNCTION_VERIFY_INTERFACE; atif_arg_elements[1].type = ACPI_TYPE_INTEGER; atif_arg_elements[1].integer.value = 0; -- cgit v1.2.3-70-g09d2 From efd4e418f2bb8a8b21f96fd44e775eaf6dd55905 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 31 Jul 2012 17:18:17 -0400 Subject: drm/radeon: add a license header to radeon_apci.c Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_acpi.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers/gpu/drm/radeon/radeon_acpi.c') diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index 5b32e499903..e94929c6924 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -1,3 +1,26 @@ +/* + * Copyright 2012 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + #include #include #include -- cgit v1.2.3-70-g09d2 From 86504672f7d79986a8ef618fb120044220e3d1eb Mon Sep 17 00:00:00 2001 From: Luca Tettamanti Date: Sun, 29 Jul 2012 17:04:43 +0200 Subject: drm/radeon: refactor radeon_atif_call Don't hard-code function number, this will allow to reuse the function. v2: add support for the 2nd parameter (from Lee, Chun-Yi ). Signed-off-by: Luca Tettamanti Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_acpi.c | 38 ++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 15 deletions(-) (limited to 'drivers/gpu/drm/radeon/radeon_acpi.c') diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index e94929c6924..f7b511dcba3 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -37,23 +37,30 @@ #include /* Call the ATIF method - * - * Note: currently we discard the output */ -static int radeon_atif_call(acpi_handle handle) +static union acpi_object *radeon_atif_call(acpi_handle handle, int function, + struct acpi_buffer *params) { acpi_status status; union acpi_object atif_arg_elements[2]; struct acpi_object_list atif_arg; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL}; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; atif_arg.count = 2; atif_arg.pointer = &atif_arg_elements[0]; atif_arg_elements[0].type = ACPI_TYPE_INTEGER; - atif_arg_elements[0].integer.value = ATIF_FUNCTION_VERIFY_INTERFACE; - atif_arg_elements[1].type = ACPI_TYPE_INTEGER; - atif_arg_elements[1].integer.value = 0; + atif_arg_elements[0].integer.value = function; + + if (params) { + atif_arg_elements[1].type = ACPI_TYPE_BUFFER; + atif_arg_elements[1].buffer.length = params->length; + atif_arg_elements[1].buffer.pointer = params->pointer; + } else { + /* We need a second fake parameter */ + atif_arg_elements[1].type = ACPI_TYPE_INTEGER; + atif_arg_elements[1].integer.value = 0; + } status = acpi_evaluate_object(handle, "ATIF", &atif_arg, &buffer); @@ -62,18 +69,18 @@ static int radeon_atif_call(acpi_handle handle) DRM_DEBUG_DRIVER("failed to evaluate ATIF got %s\n", acpi_format_exception(status)); kfree(buffer.pointer); - return 1; + return NULL; } - kfree(buffer.pointer); - return 0; + return buffer.pointer; } /* Call all ACPI methods here */ int radeon_acpi_init(struct radeon_device *rdev) { acpi_handle handle; - int ret; + union acpi_object *info; + int ret = 0; /* Get the device handle */ handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev); @@ -83,10 +90,11 @@ int radeon_acpi_init(struct radeon_device *rdev) return 0; /* Call the ATIF method */ - ret = radeon_atif_call(handle); - if (ret) - return ret; + info = radeon_atif_call(handle, ATIF_FUNCTION_VERIFY_INTERFACE, NULL); + if (!info) + ret = -EIO; - return 0; + kfree(info); + return ret; } -- cgit v1.2.3-70-g09d2 From fd64ca8a9d9d7e92fc81fe0b23dcf324246fd356 Mon Sep 17 00:00:00 2001 From: Luca Tettamanti Date: Thu, 16 Aug 2012 11:11:18 -0400 Subject: drm/radeon: implement radeon_atif_verify_interface Wrap the call to VERIFY_INTERFACE and add the parsing of the support vectors. v2: use a packed struct for handling the output of ACPI calls, hides ugly pointer arithmetics (Lee, Chun-Yi ). v3: fix radeon_atif_parse_functions handling (Alex Deucher) Signed-off-by: Luca Tettamanti Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon.h | 40 ++++++++++++++++++ drivers/gpu/drm/radeon/radeon_acpi.c | 79 +++++++++++++++++++++++++++++++++--- 2 files changed, 113 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/radeon/radeon_acpi.c') diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 5dbd591818f..763f3333776 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1424,6 +1424,44 @@ struct r600_vram_scratch { u64 gpu_addr; }; +/* + * ACPI + */ +struct radeon_atif_notification_cfg { + bool enabled; + int command_code; +}; + +struct radeon_atif_notifications { + bool display_switch; + bool expansion_mode_change; + bool thermal_state; + bool forced_power_state; + bool system_power_state; + bool display_conf_change; + bool px_gfx_switch; + bool brightness_change; + bool dgpu_display_event; +}; + +struct radeon_atif_functions { + bool system_params; + bool sbios_requests; + bool select_active_disp; + bool lid_state; + bool get_tv_standard; + bool set_tv_standard; + bool get_panel_expansion_mode; + bool set_panel_expansion_mode; + bool temperature_change; + bool graphics_device_types; +}; + +struct radeon_atif { + struct radeon_atif_notifications notifications; + struct radeon_atif_functions functions; + struct radeon_atif_notification_cfg notification_cfg; +}; /* * Core structure, functions and helpers. @@ -1516,6 +1554,8 @@ struct radeon_device { /* virtual memory */ struct radeon_vm_manager vm_manager; struct mutex gpu_clock_mutex; + /* ACPI interface */ + struct radeon_atif atif; }; int radeon_device_init(struct radeon_device *rdev, diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index f7b511dcba3..2f6cef2acad 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -36,6 +36,13 @@ #include +struct atif_verify_interface { + u16 size; /* structure size in bytes (includes size field) */ + u16 version; /* version */ + u32 notification_mask; /* supported notifications mask */ + u32 function_bits; /* supported functions bit vector */ +} __packed; + /* Call the ATIF method */ static union acpi_object *radeon_atif_call(acpi_handle handle, int function, @@ -75,12 +82,73 @@ static union acpi_object *radeon_atif_call(acpi_handle handle, int function, return buffer.pointer; } +static void radeon_atif_parse_notification(struct radeon_atif_notifications *n, u32 mask) +{ + n->display_switch = mask & ATIF_DISPLAY_SWITCH_REQUEST_SUPPORTED; + n->expansion_mode_change = mask & ATIF_EXPANSION_MODE_CHANGE_REQUEST_SUPPORTED; + n->thermal_state = mask & ATIF_THERMAL_STATE_CHANGE_REQUEST_SUPPORTED; + n->forced_power_state = mask & ATIF_FORCED_POWER_STATE_CHANGE_REQUEST_SUPPORTED; + n->system_power_state = mask & ATIF_SYSTEM_POWER_SOURCE_CHANGE_REQUEST_SUPPORTED; + n->display_conf_change = mask & ATIF_DISPLAY_CONF_CHANGE_REQUEST_SUPPORTED; + n->px_gfx_switch = mask & ATIF_PX_GFX_SWITCH_REQUEST_SUPPORTED; + n->brightness_change = mask & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST_SUPPORTED; + n->dgpu_display_event = mask & ATIF_DGPU_DISPLAY_EVENT_SUPPORTED; +} + +static void radeon_atif_parse_functions(struct radeon_atif_functions *f, u32 mask) +{ + f->system_params = mask & ATIF_GET_SYSTEM_PARAMETERS_SUPPORTED; + f->sbios_requests = mask & ATIF_GET_SYSTEM_BIOS_REQUESTS_SUPPORTED; + f->select_active_disp = mask & ATIF_SELECT_ACTIVE_DISPLAYS_SUPPORTED; + f->lid_state = mask & ATIF_GET_LID_STATE_SUPPORTED; + f->get_tv_standard = mask & ATIF_GET_TV_STANDARD_FROM_CMOS_SUPPORTED; + f->set_tv_standard = mask & ATIF_SET_TV_STANDARD_IN_CMOS_SUPPORTED; + f->get_panel_expansion_mode = mask & ATIF_GET_PANEL_EXPANSION_MODE_FROM_CMOS_SUPPORTED; + f->set_panel_expansion_mode = mask & ATIF_SET_PANEL_EXPANSION_MODE_IN_CMOS_SUPPORTED; + f->temperature_change = mask & ATIF_TEMPERATURE_CHANGE_NOTIFICATION_SUPPORTED; + f->graphics_device_types = mask & ATIF_GET_GRAPHICS_DEVICE_TYPES_SUPPORTED; +} + +static int radeon_atif_verify_interface(acpi_handle handle, + struct radeon_atif *atif) +{ + union acpi_object *info; + struct atif_verify_interface output; + size_t size; + int err = 0; + + info = radeon_atif_call(handle, ATIF_FUNCTION_VERIFY_INTERFACE, NULL); + if (!info) + return -EIO; + + memset(&output, 0, sizeof(output)); + + size = *(u16 *) info->buffer.pointer; + if (size < 12) { + DRM_INFO("ATIF 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? */ + DRM_DEBUG_DRIVER("ATIF version %u\n", output.version); + + radeon_atif_parse_notification(&atif->notifications, output.notification_mask); + radeon_atif_parse_functions(&atif->functions, output.function_bits); + +out: + kfree(info); + return err; +} + /* Call all ACPI methods here */ int radeon_acpi_init(struct radeon_device *rdev) { acpi_handle handle; - union acpi_object *info; - int ret = 0; + int ret; /* Get the device handle */ handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev); @@ -90,11 +158,10 @@ int radeon_acpi_init(struct radeon_device *rdev) return 0; /* Call the ATIF method */ - info = radeon_atif_call(handle, ATIF_FUNCTION_VERIFY_INTERFACE, NULL); - if (!info) - ret = -EIO; + ret = radeon_atif_verify_interface(handle, &rdev->atif); + if (ret) + DRM_DEBUG_DRIVER("Call to verify_interface failed: %d\n", ret); - kfree(info); return ret; } -- cgit v1.2.3-70-g09d2 From ce3cf821a31f9824eda788cbd3e710d8047e82df Mon Sep 17 00:00:00 2001 From: Luca Tettamanti Date: Mon, 30 Jul 2012 21:16:06 +0200 Subject: drm/radeon: implement wrapper for GET_SYSTEM_PARAMS Use GET_SYSTEM_PARAMS for retrieving the configuration for the system BIOS notifications. v2: packed struct (Lee, Chun-Yi ) v3: fix enable with device specific command code Signed-off-by: Luca Tettamanti Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_acpi.c | 85 +++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/radeon/radeon_acpi.c') diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index 2f6cef2acad..0454eccc9c0 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -43,6 +43,18 @@ struct atif_verify_interface { u32 function_bits; /* supported functions bit vector */ } __packed; +struct atif_system_params { + u16 size; + u32 valid_mask; + u32 flags; + u8 command_code; +} __packed; + +#define ATIF_NOTIFY_MASK 0x3 +#define ATIF_NOTIFY_NONE 0 +#define ATIF_NOTIFY_81 1 +#define ATIF_NOTIFY_N 2 + /* Call the ATIF method */ static union acpi_object *radeon_atif_call(acpi_handle handle, int function, @@ -144,10 +156,57 @@ out: return err; } +static int radeon_atif_get_notification_params(acpi_handle handle, + struct radeon_atif_notification_cfg *n) +{ + union acpi_object *info; + struct atif_system_params params; + size_t size; + int err = 0; + + info = radeon_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_PARAMETERS, NULL); + if (!info) { + err = -EIO; + goto out; + } + + size = *(u16 *) info->buffer.pointer; + if (size < 10) { + err = -EINVAL; + goto out; + } + + memset(¶ms, 0, sizeof(params)); + size = min(sizeof(params), size); + memcpy(¶ms, info->buffer.pointer, size); + + params.flags = params.flags & params.valid_mask; + + if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_NONE) { + n->enabled = false; + n->command_code = 0; + } else if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_81) { + n->enabled = true; + n->command_code = 0x81; + } else { + if (size < 11) { + err = -EINVAL; + goto out; + } + n->enabled = true; + n->command_code = params.command_code; + } + +out: + kfree(info); + return err; +} + /* Call all ACPI methods here */ int radeon_acpi_init(struct radeon_device *rdev) { acpi_handle handle; + struct radeon_atif *atif = &rdev->atif; int ret; /* Get the device handle */ @@ -158,10 +217,32 @@ int radeon_acpi_init(struct radeon_device *rdev) return 0; /* Call the ATIF method */ - ret = radeon_atif_verify_interface(handle, &rdev->atif); - if (ret) + ret = radeon_atif_verify_interface(handle, atif); + if (ret) { DRM_DEBUG_DRIVER("Call to verify_interface failed: %d\n", ret); + goto out; + } + + if (atif->functions.sbios_requests && !atif->functions.system_params) { + /* XXX check this workraround, if sbios request function is + * present we have to see how it's configured in the system + * params + */ + atif->functions.system_params = true; + } + + if (atif->functions.system_params) { + ret = radeon_atif_get_notification_params(handle, + &atif->notification_cfg); + if (ret) { + DRM_DEBUG_DRIVER("Call to GET_SYSTEM_PARAMS failed: %d\n", + ret); + /* Disable notification */ + atif->notification_cfg.enabled = false; + } + } +out: return ret; } -- cgit v1.2.3-70-g09d2 From fda4b25c55a59ba12378e4b9e4553f6ea57d802d Mon Sep 17 00:00:00 2001 From: Luca Tettamanti Date: Mon, 30 Jul 2012 21:20:35 +0200 Subject: drm/radeon: implement handler for ACPI event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set up an handler for ACPI events and respond to brightness change requests from the system BIOS. v2: fix notification when using device-specific command codes (tested by Pali Rohár ); cache the encoder controlling the backlight during the initialization to avoid searching it every time (suggested by Alex Deucher). v3: whitespace fixes (Alex Deucher). Signed-off-by: Luca Tettamanti Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/atombios_encoders.c | 2 +- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_acpi.c | 132 ++++++++++++++++++++++++++++- drivers/gpu/drm/radeon/radeon_acpi.h | 6 ++ drivers/gpu/drm/radeon/radeon_kms.c | 16 ++-- drivers/gpu/drm/radeon/radeon_mode.h | 2 + drivers/gpu/drm/radeon/radeon_pm.c | 4 +- 7 files changed, 152 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm/radeon/radeon_acpi.c') diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index f3645e15ef1..370b2c4a7c8 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -72,7 +72,7 @@ radeon_atom_set_backlight_level_to_reg(struct radeon_device *rdev, WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch); } -static void +void atombios_set_panel_brightness(struct radeon_encoder *radeon_encoder) { struct drm_encoder *encoder = &radeon_encoder->base; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 763f3333776..dea5f08bd23 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1461,6 +1461,7 @@ struct radeon_atif { struct radeon_atif_notifications notifications; struct radeon_atif_functions functions; struct radeon_atif_notification_cfg notification_cfg; + struct radeon_encoder *backlight_ctl; }; /* diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index 0454eccc9c0..b052a556db7 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "drmP.h" #include "drm.h" @@ -33,6 +34,7 @@ #include "drm_crtc_helper.h" #include "radeon.h" #include "radeon_acpi.h" +#include "atom.h" #include @@ -44,10 +46,22 @@ struct atif_verify_interface { } __packed; struct atif_system_params { - u16 size; - u32 valid_mask; - u32 flags; - u8 command_code; + u16 size; /* structure size in bytes (includes size field) */ + u32 valid_mask; /* valid flags mask */ + u32 flags; /* flags */ + u8 command_code; /* notify command code */ +} __packed; + +struct atif_sbios_requests { + u16 size; /* structure size in bytes (includes size field) */ + u32 pending; /* pending sbios requests */ + u8 panel_exp_mode; /* panel expansion mode */ + u8 thermal_gfx; /* thermal state: target gfx controller */ + u8 thermal_state; /* thermal state: state id (0: exit state, non-0: state) */ + u8 forced_power_gfx; /* forced power state: target gfx controller */ + u8 forced_power_state; /* forced power state: state id */ + u8 system_power_src; /* system power source */ + u8 backlight_level; /* panel backlight level (0-255) */ } __packed; #define ATIF_NOTIFY_MASK 0x3 @@ -180,6 +194,8 @@ static int radeon_atif_get_notification_params(acpi_handle handle, size = min(sizeof(params), size); memcpy(¶ms, info->buffer.pointer, size); + DRM_DEBUG_DRIVER("SYSTEM_PARAMS: mask = %#x, flags = %#x\n", + params.flags, params.valid_mask); params.flags = params.flags & params.valid_mask; if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_NONE) { @@ -198,10 +214,91 @@ static int radeon_atif_get_notification_params(acpi_handle handle, } out: + DRM_DEBUG_DRIVER("Notification %s, command code = %#x\n", + (n->enabled ? "enabled" : "disabled"), + n->command_code); kfree(info); return err; } +static int radeon_atif_get_sbios_requests(acpi_handle handle, + struct atif_sbios_requests *req) +{ + union acpi_object *info; + size_t size; + int count = 0; + + info = radeon_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS, NULL); + if (!info) + return -EIO; + + size = *(u16 *)info->buffer.pointer; + if (size < 0xd) { + count = -EINVAL; + goto out; + } + memset(req, 0, sizeof(*req)); + + size = min(sizeof(*req), size); + memcpy(req, info->buffer.pointer, size); + DRM_DEBUG_DRIVER("SBIOS pending requests: %#x\n", req->pending); + + count = hweight32(req->pending); + +out: + kfree(info); + return count; +} + +int radeon_atif_handler(struct radeon_device *rdev, + struct acpi_bus_event *event) +{ + struct radeon_atif *atif = &rdev->atif; + struct atif_sbios_requests req; + acpi_handle handle; + int count; + + DRM_DEBUG_DRIVER("event, device_class = %s, type = %#x\n", + event->device_class, event->type); + + if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0) + return NOTIFY_DONE; + + if (!atif->notification_cfg.enabled || + event->type != atif->notification_cfg.command_code) + /* Not our event */ + return NOTIFY_DONE; + + /* Check pending SBIOS requests */ + handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev); + count = radeon_atif_get_sbios_requests(handle, &req); + + if (count <= 0) + return NOTIFY_DONE; + + DRM_DEBUG_DRIVER("ATIF: %d pending SBIOS requests\n", count); + + if (req.pending & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST) { + struct radeon_encoder *enc = atif->backlight_ctl; + + if (enc) { + struct radeon_encoder_atom_dig *dig = enc->enc_priv; + dig->backlight_level = req.backlight_level; + + DRM_DEBUG_DRIVER("Changing brightness to %d\n", + req.backlight_level); + + atombios_set_panel_brightness(enc); + + backlight_force_update(dig->bl_dev, + BACKLIGHT_UPDATE_HOTKEY); + } + } + /* TODO: check other events */ + + return NOTIFY_OK; +} + /* Call all ACPI methods here */ int radeon_acpi_init(struct radeon_device *rdev) { @@ -223,6 +320,33 @@ int radeon_acpi_init(struct radeon_device *rdev) goto out; } + if (atif->notifications.brightness_change) { + struct drm_encoder *tmp; + struct radeon_encoder *target = NULL; + + /* Find the encoder controlling the brightness */ + list_for_each_entry(tmp, &rdev->ddev->mode_config.encoder_list, + head) { + struct radeon_encoder *enc = to_radeon_encoder(tmp); + struct radeon_encoder_atom_dig *dig = enc->enc_priv; + + if ((enc->devices & (ATOM_DEVICE_LCD_SUPPORT)) && + dig->bl_dev != NULL) { + target = enc; + break; + } + } + + atif->backlight_ctl = target; + if (!target) { + /* Brightness change notification is enabled, but we + * didn't find a backlight controller, this should + * never happen. + */ + DRM_ERROR("Cannot find a backlight controller\n"); + } + } + if (atif->functions.sbios_requests && !atif->functions.system_params) { /* XXX check this workraround, if sbios request function is * present we have to see how it's configured in the system diff --git a/drivers/gpu/drm/radeon/radeon_acpi.h b/drivers/gpu/drm/radeon/radeon_acpi.h index 642aa471945..be4af76f213 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.h +++ b/drivers/gpu/drm/radeon/radeon_acpi.h @@ -24,6 +24,12 @@ #ifndef RADEON_ACPI_H #define RADEON_ACPI_H +struct radeon_device; +struct acpi_bus_event; + +int radeon_atif_handler(struct radeon_device *rdev, + struct acpi_bus_event *event); + /* AMD hw uses four ACPI control methods: * 1. ATIF * ARG0: (ACPI_INTEGER) function code diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 414b4acf694..8c2471854cd 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -103,11 +103,6 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags) goto out; } - /* Call ACPI methods */ - acpi_status = radeon_acpi_init(rdev); - if (acpi_status) - dev_dbg(&dev->pdev->dev, "Error during ACPI methods call\n"); - /* Again modeset_init should fail only on fatal error * otherwise it should provide enough functionalities * for shadowfb to run @@ -115,6 +110,17 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags) r = radeon_modeset_init(rdev); if (r) dev_err(&dev->pdev->dev, "Fatal error during modeset init\n"); + + /* Call ACPI methods: require modeset init + * but failure is not fatal + */ + if (!r) { + acpi_status = radeon_acpi_init(rdev); + if (acpi_status) + dev_dbg(&dev->pdev->dev, + "Error during ACPI methods call\n"); + } + out: if (r) radeon_driver_unload_kms(dev); diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 5005057974b..1f411c2609d 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -698,6 +698,8 @@ void radeon_panel_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode); void atom_rv515_force_tv_scaler(struct radeon_device *rdev, struct radeon_crtc *radeon_crtc); +void atombios_set_panel_brightness(struct radeon_encoder *radeon_encoder); + /* legacy tv */ void radeon_legacy_tv_adjust_crtc_reg(struct drm_encoder *encoder, uint32_t *h_total_disp, uint32_t *h_sync_strt_wid, diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 2c2c901226f..14e544e0eb3 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -22,6 +22,7 @@ */ #include "drmP.h" #include "radeon.h" +#include "radeon_acpi.h" #include "avivod.h" #include "atom.h" #ifdef CONFIG_ACPI @@ -94,7 +95,8 @@ static int radeon_acpi_event(struct notifier_block *nb, } } - return NOTIFY_OK; + /* Check for pending SBIOS requests */ + return radeon_atif_handler(rdev, entry); } #endif -- cgit v1.2.3-70-g09d2 From c49170742d6928b16fb3839b47a94cc41630dbe0 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 31 Jul 2012 17:14:35 -0400 Subject: drm/radeon: re-organize the acpi notifier callback Move it out of the radeon_pm.c and into radeon_acpi.c since we use it for more than just pm now. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon.h | 14 +++++++----- drivers/gpu/drm/radeon/radeon_acpi.c | 32 ++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_kms.c | 1 + drivers/gpu/drm/radeon/radeon_pm.c | 44 ++++++------------------------------ 4 files changed, 48 insertions(+), 43 deletions(-) (limited to 'drivers/gpu/drm/radeon/radeon_acpi.c') diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index dea5f08bd23..b5b16878f0c 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1869,12 +1869,14 @@ extern void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_displ extern int ni_init_microcode(struct radeon_device *rdev); extern int ni_mc_load_microcode(struct radeon_device *rdev); -/* radeon_acpi.c */ -#if defined(CONFIG_ACPI) -extern int radeon_acpi_init(struct radeon_device *rdev); -#else -static inline int radeon_acpi_init(struct radeon_device *rdev) { return 0; } -#endif +/* radeon_acpi.c */ +#if defined(CONFIG_ACPI) +extern int radeon_acpi_init(struct radeon_device *rdev); +extern void radeon_acpi_fini(struct radeon_device *rdev); +#else +static inline int radeon_acpi_init(struct radeon_device *rdev) { return 0; } +static inline void radeon_acpi_fini(struct radeon_device *rdev) { } +#endif #include "radeon_object.h" diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index b052a556db7..ea22f4416f4 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,10 @@ #include +#define ACPI_AC_CLASS "ac_adapter" + +extern void radeon_pm_acpi_event_handler(struct radeon_device *rdev); + struct atif_verify_interface { u16 size; /* structure size in bytes (includes size field) */ u16 version; /* version */ @@ -299,6 +304,26 @@ int radeon_atif_handler(struct radeon_device *rdev, return NOTIFY_OK; } +static int radeon_acpi_event(struct notifier_block *nb, + unsigned long val, + void *data) +{ + struct radeon_device *rdev = container_of(nb, struct radeon_device, acpi_nb); + struct acpi_bus_event *entry = (struct acpi_bus_event *)data; + + if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) { + if (power_supply_is_system_supplied() > 0) + DRM_DEBUG_DRIVER("pm: AC\n"); + else + DRM_DEBUG_DRIVER("pm: DC\n"); + + radeon_pm_acpi_event_handler(rdev); + } + + /* Check for pending SBIOS requests */ + return radeon_atif_handler(rdev, entry); +} + /* Call all ACPI methods here */ int radeon_acpi_init(struct radeon_device *rdev) { @@ -367,6 +392,13 @@ int radeon_acpi_init(struct radeon_device *rdev) } out: + rdev->acpi_nb.notifier_call = radeon_acpi_event; + register_acpi_notifier(&rdev->acpi_nb); + return ret; } +void radeon_acpi_fini(struct radeon_device *rdev) +{ + unregister_acpi_notifier(&rdev->acpi_nb); +} diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 8c2471854cd..cb8e94d1a2b 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -51,6 +51,7 @@ int radeon_driver_unload_kms(struct drm_device *dev) if (rdev == NULL) return 0; + radeon_acpi_fini(rdev); radeon_modeset_fini(rdev); radeon_device_fini(rdev); kfree(rdev); diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 14e544e0eb3..c15e505a15b 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -22,12 +22,8 @@ */ #include "drmP.h" #include "radeon.h" -#include "radeon_acpi.h" #include "avivod.h" #include "atom.h" -#ifdef CONFIG_ACPI -#include -#endif #include #include #include @@ -51,8 +47,6 @@ static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish static void radeon_pm_update_profile(struct radeon_device *rdev); static void radeon_pm_set_clocks(struct radeon_device *rdev); -#define ACPI_AC_CLASS "ac_adapter" - int radeon_pm_get_type_index(struct radeon_device *rdev, enum radeon_pm_state_type ps_type, int instance) @@ -71,34 +65,17 @@ int radeon_pm_get_type_index(struct radeon_device *rdev, return rdev->pm.default_power_state_index; } -#ifdef CONFIG_ACPI -static int radeon_acpi_event(struct notifier_block *nb, - unsigned long val, - void *data) +void radeon_pm_acpi_event_handler(struct radeon_device *rdev) { - struct radeon_device *rdev = container_of(nb, struct radeon_device, acpi_nb); - struct acpi_bus_event *entry = (struct acpi_bus_event *)data; - - if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) { - if (power_supply_is_system_supplied() > 0) - DRM_DEBUG_DRIVER("pm: AC\n"); - else - DRM_DEBUG_DRIVER("pm: DC\n"); - - if (rdev->pm.pm_method == PM_METHOD_PROFILE) { - if (rdev->pm.profile == PM_PROFILE_AUTO) { - mutex_lock(&rdev->pm.mutex); - radeon_pm_update_profile(rdev); - radeon_pm_set_clocks(rdev); - mutex_unlock(&rdev->pm.mutex); - } + if (rdev->pm.pm_method == PM_METHOD_PROFILE) { + if (rdev->pm.profile == PM_PROFILE_AUTO) { + mutex_lock(&rdev->pm.mutex); + radeon_pm_update_profile(rdev); + radeon_pm_set_clocks(rdev); + mutex_unlock(&rdev->pm.mutex); } } - - /* Check for pending SBIOS requests */ - return radeon_atif_handler(rdev, entry); } -#endif static void radeon_pm_update_profile(struct radeon_device *rdev) { @@ -629,10 +606,6 @@ int radeon_pm_init(struct radeon_device *rdev) if (ret) DRM_ERROR("failed to create device file for power method\n"); -#ifdef CONFIG_ACPI - rdev->acpi_nb.notifier_call = radeon_acpi_event; - register_acpi_notifier(&rdev->acpi_nb); -#endif if (radeon_debugfs_pm_init(rdev)) { DRM_ERROR("Failed to register debugfs file for PM!\n"); } @@ -663,9 +636,6 @@ void radeon_pm_fini(struct radeon_device *rdev) device_remove_file(rdev->dev, &dev_attr_power_profile); device_remove_file(rdev->dev, &dev_attr_power_method); -#ifdef CONFIG_ACPI - unregister_acpi_notifier(&rdev->acpi_nb); -#endif } if (rdev->pm.power_state) -- cgit v1.2.3-70-g09d2 From 92fdf89aa95de32dba1cb44fe7f5c54824b4b2c4 Mon Sep 17 00:00:00 2001 From: Luca Tettamanti Date: Thu, 2 Aug 2012 11:39:38 -0400 Subject: drm/radeon: block the keypress on ATIF events The AMD ACPI interface may use ACPI_VIDEO_NOTIFY_PROBE to signal SBIOS requests; block the keypress in this case since the user did not actually press the mode switch key. Signed-off-by: Luca Tettamanti Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_acpi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon/radeon_acpi.c') diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index ea22f4416f4..3486292892b 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -301,7 +301,12 @@ int radeon_atif_handler(struct radeon_device *rdev, } /* TODO: check other events */ - return NOTIFY_OK; + /* We've handled the event, stop the notifier chain. The ACPI interface + * overloads ACPI_VIDEO_NOTIFY_PROBE, we don't want to send that to + * userspace if the event was generated only to signal a SBIOS + * request. + */ + return NOTIFY_BAD; } static int radeon_acpi_event(struct notifier_block *nb, -- cgit v1.2.3-70-g09d2 From c3c651600bd83de5e1cbb5d9ec34a88efd2856e8 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 2 Aug 2012 12:30:49 -0400 Subject: drm/radeon: document radeon_acpi.c Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_acpi.c | 101 +++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) (limited to 'drivers/gpu/drm/radeon/radeon_acpi.c') diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index 3486292892b..49a7d64be9e 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -76,6 +76,16 @@ struct atif_sbios_requests { /* Call the ATIF method */ +/** + * radeon_atif_call - call an ATIF method + * + * @handle: acpi handle + * @function: the ATIF function to execute + * @params: ATIF function params + * + * Executes the requested ATIF function (all asics). + * Returns a pointer to the acpi output buffer. + */ static union acpi_object *radeon_atif_call(acpi_handle handle, int function, struct acpi_buffer *params) { @@ -113,6 +123,16 @@ static union acpi_object *radeon_atif_call(acpi_handle handle, int function, return buffer.pointer; } +/** + * radeon_atif_parse_notification - parse supported notifications + * + * @n: supported notifications struct + * @mask: supported notifications mask from ATIF + * + * Use the supported notifications mask from ATIF function + * ATIF_FUNCTION_VERIFY_INTERFACE to determine what notifications + * are supported (all asics). + */ static void radeon_atif_parse_notification(struct radeon_atif_notifications *n, u32 mask) { n->display_switch = mask & ATIF_DISPLAY_SWITCH_REQUEST_SUPPORTED; @@ -126,6 +146,16 @@ static void radeon_atif_parse_notification(struct radeon_atif_notifications *n, n->dgpu_display_event = mask & ATIF_DGPU_DISPLAY_EVENT_SUPPORTED; } +/** + * radeon_atif_parse_functions - parse supported functions + * + * @f: supported functions struct + * @mask: supported functions mask from ATIF + * + * Use the supported functions mask from ATIF function + * ATIF_FUNCTION_VERIFY_INTERFACE to determine what functions + * are supported (all asics). + */ static void radeon_atif_parse_functions(struct radeon_atif_functions *f, u32 mask) { f->system_params = mask & ATIF_GET_SYSTEM_PARAMETERS_SUPPORTED; @@ -140,6 +170,17 @@ static void radeon_atif_parse_functions(struct radeon_atif_functions *f, u32 mas f->graphics_device_types = mask & ATIF_GET_GRAPHICS_DEVICE_TYPES_SUPPORTED; } +/** + * radeon_atif_verify_interface - verify ATIF + * + * @handle: acpi handle + * @atif: radeon atif struct + * + * Execute the ATIF_FUNCTION_VERIFY_INTERFACE ATIF function + * to initialize ATIF and determine what features are supported + * (all asics). + * returns 0 on success, error on failure. + */ static int radeon_atif_verify_interface(acpi_handle handle, struct radeon_atif *atif) { @@ -175,6 +216,18 @@ out: return err; } +/** + * radeon_atif_get_notification_params - determine notify configuration + * + * @handle: acpi handle + * @n: atif notification configuration struct + * + * Execute the ATIF_FUNCTION_GET_SYSTEM_PARAMETERS ATIF function + * to determine if a notifier is used and if so which one + * (all asics). This is either Notify(VGA, 0x81) or Notify(VGA, n) + * where n is specified in the result if a notifier is used. + * Returns 0 on success, error on failure. + */ static int radeon_atif_get_notification_params(acpi_handle handle, struct radeon_atif_notification_cfg *n) { @@ -226,6 +279,17 @@ out: return err; } +/** + * radeon_atif_get_sbios_requests - get requested sbios event + * + * @handle: acpi handle + * @req: atif sbios request struct + * + * Execute the ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS ATIF function + * to determine what requests the sbios is making to the driver + * (all asics). + * Returns 0 on success, error on failure. + */ static int radeon_atif_get_sbios_requests(acpi_handle handle, struct atif_sbios_requests *req) { @@ -255,6 +319,16 @@ out: return count; } +/** + * radeon_atif_handler - handle ATIF notify requests + * + * @rdev: radeon_device pointer + * @event: atif sbios request struct + * + * Checks the acpi event and if it matches an atif event, + * handles it. + * Returns NOTIFY code + */ int radeon_atif_handler(struct radeon_device *rdev, struct acpi_bus_event *event) { @@ -309,6 +383,17 @@ int radeon_atif_handler(struct radeon_device *rdev, return NOTIFY_BAD; } +/** + * radeon_acpi_event - handle notify events + * + * @nb: notifier block + * @val: val + * @data: acpi event + * + * Calls relevant radeon functions in response to various + * acpi events. + * Returns NOTIFY code + */ static int radeon_acpi_event(struct notifier_block *nb, unsigned long val, void *data) @@ -330,6 +415,15 @@ static int radeon_acpi_event(struct notifier_block *nb, } /* Call all ACPI methods here */ +/** + * radeon_acpi_init - init driver acpi support + * + * @rdev: radeon_device pointer + * + * Verifies the AMD ACPI interfaces and registers with the acpi + * notifier chain (all asics). + * Returns 0 on success, error on failure. + */ int radeon_acpi_init(struct radeon_device *rdev) { acpi_handle handle; @@ -403,6 +497,13 @@ out: return ret; } +/** + * radeon_acpi_fini - tear down driver acpi support + * + * @rdev: radeon_device pointer + * + * Unregisters with the acpi notifier chain (all asics). + */ void radeon_acpi_fini(struct radeon_device *rdev) { unregister_acpi_notifier(&rdev->acpi_nb); -- cgit v1.2.3-70-g09d2 From e3a1592085988c60a2207eb492b89493573a0303 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 16 Aug 2012 11:13:43 -0400 Subject: drm/radeon: add initial support for ATCS ACPI methods Just verify the interface and track what functions are supported. Not actually used yet. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon.h | 12 ++++ drivers/gpu/drm/radeon/radeon_acpi.c | 127 ++++++++++++++++++++++++++++++++++- 2 files changed, 138 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon/radeon_acpi.c') diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index b5b16878f0c..99a5c844501 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1464,6 +1464,17 @@ struct radeon_atif { struct radeon_encoder *backlight_ctl; }; +struct radeon_atcs_functions { + bool get_ext_state; + bool pcie_perf_req; + bool pcie_dev_rdy; + bool pcie_bus_width; +}; + +struct radeon_atcs { + struct radeon_atcs_functions functions; +}; + /* * Core structure, functions and helpers. */ @@ -1557,6 +1568,7 @@ struct radeon_device { struct mutex gpu_clock_mutex; /* ACPI interface */ struct radeon_atif atif; + struct radeon_atcs atcs; }; int radeon_device_init(struct radeon_device *rdev, diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index 49a7d64be9e..cae895ba8e2 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -74,6 +74,12 @@ struct atif_sbios_requests { #define ATIF_NOTIFY_81 1 #define ATIF_NOTIFY_N 2 +struct atcs_verify_interface { + u16 size; /* structure size in bytes (includes size field) */ + u16 version; /* version */ + u32 function_bits; /* supported functions bit vector */ +} __packed; + /* Call the ATIF method */ /** @@ -383,6 +389,118 @@ int radeon_atif_handler(struct radeon_device *rdev, return NOTIFY_BAD; } +/* Call the ATCS method + */ +/** + * radeon_atcs_call - call an ATCS method + * + * @handle: acpi handle + * @function: the ATCS function to execute + * @params: ATCS function params + * + * Executes the requested ATCS function (all asics). + * Returns a pointer to the acpi output buffer. + */ +static union acpi_object *radeon_atcs_call(acpi_handle handle, int function, + struct acpi_buffer *params) +{ + acpi_status status; + union acpi_object atcs_arg_elements[2]; + struct acpi_object_list atcs_arg; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + + atcs_arg.count = 2; + atcs_arg.pointer = &atcs_arg_elements[0]; + + atcs_arg_elements[0].type = ACPI_TYPE_INTEGER; + atcs_arg_elements[0].integer.value = function; + + if (params) { + atcs_arg_elements[1].type = ACPI_TYPE_BUFFER; + atcs_arg_elements[1].buffer.length = params->length; + atcs_arg_elements[1].buffer.pointer = params->pointer; + } else { + /* We need a second fake parameter */ + atcs_arg_elements[1].type = ACPI_TYPE_INTEGER; + atcs_arg_elements[1].integer.value = 0; + } + + status = acpi_evaluate_object(handle, "ATCS", &atcs_arg, &buffer); + + /* Fail only if calling the method fails and ATIF is supported */ + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { + DRM_DEBUG_DRIVER("failed to evaluate ATCS got %s\n", + acpi_format_exception(status)); + kfree(buffer.pointer); + return NULL; + } + + return buffer.pointer; +} + +/** + * radeon_atcs_parse_functions - parse supported functions + * + * @f: supported functions struct + * @mask: supported functions mask from ATCS + * + * Use the supported functions mask from ATCS function + * ATCS_FUNCTION_VERIFY_INTERFACE to determine what functions + * are supported (all asics). + */ +static void radeon_atcs_parse_functions(struct radeon_atcs_functions *f, u32 mask) +{ + f->get_ext_state = mask & ATCS_GET_EXTERNAL_STATE_SUPPORTED; + f->pcie_perf_req = mask & ATCS_PCIE_PERFORMANCE_REQUEST_SUPPORTED; + f->pcie_dev_rdy = mask & ATCS_PCIE_DEVICE_READY_NOTIFICATION_SUPPORTED; + f->pcie_bus_width = mask & ATCS_SET_PCIE_BUS_WIDTH_SUPPORTED; +} + +/** + * radeon_atcs_verify_interface - verify ATCS + * + * @handle: acpi handle + * @atcs: radeon atcs struct + * + * Execute the ATCS_FUNCTION_VERIFY_INTERFACE ATCS function + * to initialize ATCS and determine what features are supported + * (all asics). + * returns 0 on success, error on failure. + */ +static int radeon_atcs_verify_interface(acpi_handle handle, + struct radeon_atcs *atcs) +{ + union acpi_object *info; + struct atcs_verify_interface output; + size_t size; + int err = 0; + + info = radeon_atcs_call(handle, ATCS_FUNCTION_VERIFY_INTERFACE, NULL); + if (!info) + return -EIO; + + memset(&output, 0, sizeof(output)); + + size = *(u16 *) info->buffer.pointer; + if (size < 8) { + DRM_INFO("ATCS 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? */ + DRM_DEBUG_DRIVER("ATCS version %u\n", output.version); + + radeon_atcs_parse_functions(&atcs->functions, output.function_bits); + +out: + kfree(info); + return err; +} + /** * radeon_acpi_event - handle notify events * @@ -428,6 +546,7 @@ int radeon_acpi_init(struct radeon_device *rdev) { acpi_handle handle; struct radeon_atif *atif = &rdev->atif; + struct radeon_atcs *atcs = &rdev->atcs; int ret; /* Get the device handle */ @@ -437,10 +556,16 @@ int radeon_acpi_init(struct radeon_device *rdev) if (!ASIC_IS_AVIVO(rdev) || !rdev->bios || !handle) return 0; + /* Call the ATCS method */ + ret = radeon_atcs_verify_interface(handle, atcs); + if (ret) { + DRM_DEBUG_DRIVER("Call to ATCS verify_interface failed: %d\n", ret); + } + /* Call the ATIF method */ ret = radeon_atif_verify_interface(handle, atif); if (ret) { - DRM_DEBUG_DRIVER("Call to verify_interface failed: %d\n", ret); + DRM_DEBUG_DRIVER("Call to ATIF verify_interface failed: %d\n", ret); goto out; } -- cgit v1.2.3-70-g09d2 From 37e9b6a62fb775276f8edb5bd2b9f13a3102b9dd Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 3 Aug 2012 11:39:43 -0400 Subject: drm/radeon: rework the backlight control to be an asic callback This cleans up the interface a bit as well. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/atombios_encoders.c | 15 +++++----- drivers/gpu/drm/radeon/radeon.h | 5 +++- drivers/gpu/drm/radeon/radeon_acpi.c | 38 +++++++++++++++++-------- drivers/gpu/drm/radeon/radeon_asic.c | 20 +++++++++++++ drivers/gpu/drm/radeon/radeon_asic.h | 4 +++ drivers/gpu/drm/radeon/radeon_legacy_encoders.c | 33 ++++++++++++++------- drivers/gpu/drm/radeon/radeon_mode.h | 2 -- 7 files changed, 84 insertions(+), 33 deletions(-) (limited to 'drivers/gpu/drm/radeon/radeon_acpi.c') diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index 370b2c4a7c8..f9910f099e6 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -73,7 +73,7 @@ radeon_atom_set_backlight_level_to_reg(struct radeon_device *rdev, } void -atombios_set_panel_brightness(struct radeon_encoder *radeon_encoder) +atombios_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level) { struct drm_encoder *encoder = &radeon_encoder->base; struct drm_device *dev = radeon_encoder->base.dev; @@ -82,8 +82,13 @@ atombios_set_panel_brightness(struct radeon_encoder *radeon_encoder) DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; int index; - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU)) + return; + + if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) && + radeon_encoder->enc_priv) { dig = radeon_encoder->enc_priv; + dig->backlight_level = level; radeon_atom_set_backlight_level_to_reg(rdev, dig->backlight_level); switch (radeon_encoder->encoder_id) { @@ -137,11 +142,7 @@ static int radeon_atom_backlight_update_status(struct backlight_device *bd) struct radeon_backlight_privdata *pdata = bl_get_data(bd); struct radeon_encoder *radeon_encoder = pdata->encoder; - if (radeon_encoder->enc_priv) { - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - dig->backlight_level = radeon_atom_bl_level(bd); - atombios_set_panel_brightness(radeon_encoder); - } + atombios_set_backlight_level(radeon_encoder, radeon_atom_bl_level(bd)); return 0; } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 99a5c844501..a1c4d4dac7d 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1153,6 +1153,8 @@ struct radeon_asic { u32 (*get_vblank_counter)(struct radeon_device *rdev, int crtc); /* wait for vblank */ void (*wait_for_vblank)(struct radeon_device *rdev, int crtc); + /* set backlight level */ + void (*set_backlight_level)(struct radeon_encoder *radeon_encoder, u8 level); } display; /* copy functions for bo handling */ struct { @@ -1461,7 +1463,7 @@ struct radeon_atif { struct radeon_atif_notifications notifications; struct radeon_atif_functions functions; struct radeon_atif_notification_cfg notification_cfg; - struct radeon_encoder *backlight_ctl; + struct radeon_encoder *encoder_for_bl; }; struct radeon_atcs_functions { @@ -1741,6 +1743,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v); #define radeon_irq_set(rdev) (rdev)->asic->irq.set((rdev)) #define radeon_irq_process(rdev) (rdev)->asic->irq.process((rdev)) #define radeon_get_vblank_counter(rdev, crtc) (rdev)->asic->display.get_vblank_counter((rdev), (crtc)) +#define radeon_set_backlight_level(rdev, e, l) (rdev)->asic->display.set_backlight_level((e), (l)) #define radeon_fence_ring_emit(rdev, r, fence) (rdev)->asic->ring[(r)].emit_fence((rdev), (fence)) #define radeon_semaphore_ring_emit(rdev, r, cp, semaphore, emit_wait) (rdev)->asic->ring[(r)].emit_semaphore((rdev), (cp), (semaphore), (emit_wait)) #define radeon_copy_blit(rdev, s, d, np, f) (rdev)->asic->copy.blit((rdev), (s), (d), (np), (f)) diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index cae895ba8e2..c3976eb341b 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -364,19 +364,23 @@ int radeon_atif_handler(struct radeon_device *rdev, DRM_DEBUG_DRIVER("ATIF: %d pending SBIOS requests\n", count); if (req.pending & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST) { - struct radeon_encoder *enc = atif->backlight_ctl; + struct radeon_encoder *enc = atif->encoder_for_bl; if (enc) { - struct radeon_encoder_atom_dig *dig = enc->enc_priv; - dig->backlight_level = req.backlight_level; - DRM_DEBUG_DRIVER("Changing brightness to %d\n", req.backlight_level); - atombios_set_panel_brightness(enc); + radeon_set_backlight_level(rdev, enc, req.backlight_level); - backlight_force_update(dig->bl_dev, - BACKLIGHT_UPDATE_HOTKEY); + if (rdev->is_atom_bios) { + struct radeon_encoder_atom_dig *dig = enc->enc_priv; + backlight_force_update(dig->bl_dev, + BACKLIGHT_UPDATE_HOTKEY); + } else { + struct radeon_encoder_lvds *dig = enc->enc_priv; + backlight_force_update(dig->bl_dev, + BACKLIGHT_UPDATE_HOTKEY); + } } } /* TODO: check other events */ @@ -577,16 +581,26 @@ int radeon_acpi_init(struct radeon_device *rdev) list_for_each_entry(tmp, &rdev->ddev->mode_config.encoder_list, head) { struct radeon_encoder *enc = to_radeon_encoder(tmp); - struct radeon_encoder_atom_dig *dig = enc->enc_priv; if ((enc->devices & (ATOM_DEVICE_LCD_SUPPORT)) && - dig->bl_dev != NULL) { - target = enc; - break; + enc->enc_priv) { + if (rdev->is_atom_bios) { + struct radeon_encoder_atom_dig *dig = enc->enc_priv; + if (dig->bl_dev) { + target = enc; + break; + } + } else { + struct radeon_encoder_lvds *dig = enc->enc_priv; + if (dig->bl_dev) { + target = enc; + break; + } + } } } - atif->backlight_ctl = target; + atif->encoder_for_bl = target; if (!target) { /* Brightness change notification is enabled, but we * didn't find a backlight controller, this should diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 973417c4b01..29834a2be3e 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -198,6 +198,7 @@ static struct radeon_asic r100_asic = { .bandwidth_update = &r100_bandwidth_update, .get_vblank_counter = &r100_get_vblank_counter, .wait_for_vblank = &r100_wait_for_vblank, + .set_backlight_level = &radeon_legacy_set_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -272,6 +273,7 @@ static struct radeon_asic r200_asic = { .bandwidth_update = &r100_bandwidth_update, .get_vblank_counter = &r100_get_vblank_counter, .wait_for_vblank = &r100_wait_for_vblank, + .set_backlight_level = &radeon_legacy_set_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -346,6 +348,7 @@ static struct radeon_asic r300_asic = { .bandwidth_update = &r100_bandwidth_update, .get_vblank_counter = &r100_get_vblank_counter, .wait_for_vblank = &r100_wait_for_vblank, + .set_backlight_level = &radeon_legacy_set_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -420,6 +423,7 @@ static struct radeon_asic r300_asic_pcie = { .bandwidth_update = &r100_bandwidth_update, .get_vblank_counter = &r100_get_vblank_counter, .wait_for_vblank = &r100_wait_for_vblank, + .set_backlight_level = &radeon_legacy_set_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -494,6 +498,7 @@ static struct radeon_asic r420_asic = { .bandwidth_update = &r100_bandwidth_update, .get_vblank_counter = &r100_get_vblank_counter, .wait_for_vblank = &r100_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -568,6 +573,7 @@ static struct radeon_asic rs400_asic = { .bandwidth_update = &r100_bandwidth_update, .get_vblank_counter = &r100_get_vblank_counter, .wait_for_vblank = &r100_wait_for_vblank, + .set_backlight_level = &radeon_legacy_set_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -642,6 +648,7 @@ static struct radeon_asic rs600_asic = { .bandwidth_update = &rs600_bandwidth_update, .get_vblank_counter = &rs600_get_vblank_counter, .wait_for_vblank = &avivo_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -716,6 +723,7 @@ static struct radeon_asic rs690_asic = { .get_vblank_counter = &rs600_get_vblank_counter, .bandwidth_update = &rs690_bandwidth_update, .wait_for_vblank = &avivo_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -790,6 +798,7 @@ static struct radeon_asic rv515_asic = { .get_vblank_counter = &rs600_get_vblank_counter, .bandwidth_update = &rv515_bandwidth_update, .wait_for_vblank = &avivo_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -864,6 +873,7 @@ static struct radeon_asic r520_asic = { .bandwidth_update = &rv515_bandwidth_update, .get_vblank_counter = &rs600_get_vblank_counter, .wait_for_vblank = &avivo_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -937,6 +947,7 @@ static struct radeon_asic r600_asic = { .bandwidth_update = &rv515_bandwidth_update, .get_vblank_counter = &rs600_get_vblank_counter, .wait_for_vblank = &avivo_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1010,6 +1021,7 @@ static struct radeon_asic rs780_asic = { .bandwidth_update = &rs690_bandwidth_update, .get_vblank_counter = &rs600_get_vblank_counter, .wait_for_vblank = &avivo_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1083,6 +1095,7 @@ static struct radeon_asic rv770_asic = { .bandwidth_update = &rv515_bandwidth_update, .get_vblank_counter = &rs600_get_vblank_counter, .wait_for_vblank = &avivo_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1156,6 +1169,7 @@ static struct radeon_asic evergreen_asic = { .bandwidth_update = &evergreen_bandwidth_update, .get_vblank_counter = &evergreen_get_vblank_counter, .wait_for_vblank = &dce4_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1229,6 +1243,7 @@ static struct radeon_asic sumo_asic = { .bandwidth_update = &evergreen_bandwidth_update, .get_vblank_counter = &evergreen_get_vblank_counter, .wait_for_vblank = &dce4_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1302,6 +1317,7 @@ static struct radeon_asic btc_asic = { .bandwidth_update = &evergreen_bandwidth_update, .get_vblank_counter = &evergreen_get_vblank_counter, .wait_for_vblank = &dce4_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1406,6 +1422,7 @@ static struct radeon_asic cayman_asic = { .bandwidth_update = &evergreen_bandwidth_update, .get_vblank_counter = &evergreen_get_vblank_counter, .wait_for_vblank = &dce4_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1500,6 +1517,7 @@ static struct radeon_asic trinity_asic = { .bandwidth_update = &dce6_bandwidth_update, .get_vblank_counter = &evergreen_get_vblank_counter, .wait_for_vblank = &dce4_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1604,6 +1622,7 @@ static struct radeon_asic si_asic = { .bandwidth_update = &dce6_bandwidth_update, .get_vblank_counter = &evergreen_get_vblank_counter, .wait_for_vblank = &dce4_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = NULL, @@ -1697,6 +1716,7 @@ int radeon_asic_init(struct radeon_device *rdev) rdev->asic->pm.set_engine_clock = &radeon_legacy_set_engine_clock; rdev->asic->pm.get_memory_clock = &radeon_legacy_get_memory_clock; rdev->asic->pm.set_memory_clock = NULL; + rdev->asic->display.set_backlight_level = &radeon_legacy_set_backlight_level; } break; case CHIP_RS400: diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 132429e0ccc..75d6c9e6aa8 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -42,6 +42,10 @@ uint32_t radeon_atom_get_memory_clock(struct radeon_device *rdev); void radeon_atom_set_memory_clock(struct radeon_device *rdev, uint32_t mem_clock); void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable); +void atombios_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level); +void radeon_legacy_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level); + + /* * r100,rv100,rs100,rv200,rs200 */ diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 9910fe49474..ec00deaab9c 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -290,10 +290,9 @@ static uint8_t radeon_legacy_lvds_level(struct backlight_device *bd) return level; } -static int radeon_legacy_backlight_update_status(struct backlight_device *bd) +void +radeon_legacy_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level) { - struct radeon_backlight_privdata *pdata = bl_get_data(bd); - struct radeon_encoder *radeon_encoder = pdata->encoder; struct drm_device *dev = radeon_encoder->base.dev; struct radeon_device *rdev = dev->dev_private; int dpms_mode = DRM_MODE_DPMS_ON; @@ -301,19 +300,31 @@ static int radeon_legacy_backlight_update_status(struct backlight_device *bd) if (radeon_encoder->enc_priv) { if (rdev->is_atom_bios) { struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv; - dpms_mode = lvds->dpms_mode; - lvds->backlight_level = radeon_legacy_lvds_level(bd); + if (lvds->backlight_level > 0) + dpms_mode = lvds->dpms_mode; + else + dpms_mode = DRM_MODE_DPMS_OFF; + lvds->backlight_level = level; } else { struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv; - dpms_mode = lvds->dpms_mode; - lvds->backlight_level = radeon_legacy_lvds_level(bd); + if (lvds->backlight_level > 0) + dpms_mode = lvds->dpms_mode; + else + dpms_mode = DRM_MODE_DPMS_OFF; + lvds->backlight_level = level; } } - if (bd->props.brightness > 0) - radeon_legacy_lvds_update(&radeon_encoder->base, dpms_mode); - else - radeon_legacy_lvds_update(&radeon_encoder->base, DRM_MODE_DPMS_OFF); + radeon_legacy_lvds_update(&radeon_encoder->base, dpms_mode); +} + +static int radeon_legacy_backlight_update_status(struct backlight_device *bd) +{ + struct radeon_backlight_privdata *pdata = bl_get_data(bd); + struct radeon_encoder *radeon_encoder = pdata->encoder; + + radeon_legacy_set_backlight_level(radeon_encoder, + radeon_legacy_lvds_level(bd)); return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 1f411c2609d..5005057974b 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -698,8 +698,6 @@ void radeon_panel_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode); void atom_rv515_force_tv_scaler(struct radeon_device *rdev, struct radeon_crtc *radeon_crtc); -void atombios_set_panel_brightness(struct radeon_encoder *radeon_encoder); - /* legacy tv */ void radeon_legacy_tv_adjust_crtc_reg(struct drm_encoder *encoder, uint32_t *h_total_disp, uint32_t *h_sync_strt_wid, -- cgit v1.2.3-70-g09d2