[PATCH] drm/radeon: add new AMD ACPI header and update relevant code

Luca Tettamanti kronos.it at gmail.com
Mon Jul 30 13:24:49 PDT 2012


On Mon, Jul 30, 2012 at 10:20:15AM -0400, Alex Deucher wrote:
> On Sun, Jul 29, 2012 at 9:06 AM, Luca Tettamanti <kronos.it at gmail.com> wrote:
> > On Sat, Jul 28, 2012 at 05:29:25PM -0400, Alex Deucher wrote:
> >> On Sat, Jul 28, 2012 at 10:56 AM, Luca Tettamanti <kronos.it at gmail.com> wrote:
> >> > I just found the first problem (probably a BIOS bug):
> >> > ATIF_FUNCTION_GET_SYSTEM_PARAMETERS is implemented in the DSDT, but the
> >> > corresponding bit ATIF_GET_SYSTEM_PARAMETERS_SUPPORTED is not set :(
> >> > I intended to use the method to set up the notification handler but now
> >> > my BIOS says that it's not there even if it is...
> >> > Can I assume some default values (e.g. notifications are enabled and will
> >> > use 0x81 unless ATIF_FUNCTION_GET_SYSTEM_PARAMETERS says something
> >> > different)?
> >>
> >> The spec says that the bits in the supported functions vector mean
> >> that if bit n is set, function n+1 exists,
> >
> > Hum, I don't follow. The vector in my case is 0x2 (1 << 1), that would
> > mean that ATIF_SELECT_ACTIVE_DISPLAYS_SUPPORTED (1 << 2) is supported?
> >
> > Maybe if the bit n is set then functions 0..n are available? That would
> > (almost) match what I see...
> 
> From the spec:
> 
> Supported     DWORD Bit vector providing supported functions
> information. Each bit marks
> Functions Bit              support for one specific function of the
> ATIF method. Bit n, if set,
> Vector                        indicates that Function n+1 is supported.

Sorry, I still don't understand it... what's "Function n+1" in this
context?
Does this mean that if bit n is set then the function defined as
1 << (n+1) is supported?

> I don't know how wonky bioses in the wild are however.  I can see what
> our internal teams do in these sort of cases.

That would be helpful :)
Note that on this machine (Toshiba L855-10W) brightness control under
windows does not work with the stock catalyst driver, it works only with
the (oldish) driver supplied by Toshiba.

Anyway, I'm attaching v2 of my patches, I've incorporated the
suggestions and some bits of code from joeyli, and now brightness
control is actually implemented.

Still missing is the issue of event 0x81 and the conflict with video.ko;
the handler should probably return NOTIFY_BAD to veto the keypress.

Luca
-------------- next part --------------
>From f0f8699eabee0d47b93fba14f8126b821cc106a5 Mon Sep 17 00:00:00 2001
From: Luca Tettamanti <kronos.it at gmail.com>
Date: Sun, 29 Jul 2012 17:04:43 +0200
Subject: [PATCH 1/4] 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
<jlee at suse.com>).

Signed-off-by: Luca Tettamanti <kronos.it at gmail.com>
---
 drivers/gpu/drm/radeon/radeon_acpi.c |   38 ++++++++++++++++++++--------------
 1 file changed, 23 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c
index 5b32e49..158e514 100644
--- a/drivers/gpu/drm/radeon/radeon_acpi.c
+++ b/drivers/gpu/drm/radeon/radeon_acpi.c
@@ -14,23 +14,30 @@
 #include <linux/vga_switcheroo.h>
 
 /* 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);
 
@@ -39,18 +46,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);
@@ -60,10 +67,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;
 }
 
-- 
1.7.10.4

-------------- next part --------------
>From 427002ddf653b0abd0fb820b09322bf2a0b281af Mon Sep 17 00:00:00 2001
From: Luca Tettamanti <kronos.it at gmail.com>
Date: Mon, 30 Jul 2012 21:11:58 +0200
Subject: [PATCH 2/4] 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 <jlee at suse.com>).

Signed-off-by: Luca Tettamanti <kronos.it at gmail.com>
---
 drivers/gpu/drm/radeon/radeon.h      |   40 +++++++++++++++++
 drivers/gpu/drm/radeon/radeon_acpi.c |   79 +++++++++++++++++++++++++++++++---
 2 files changed, 113 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index fefcca5..0db98eb 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1456,6 +1456,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.
@@ -1548,6 +1586,8 @@ struct radeon_device {
 	unsigned 		debugfs_count;
 	/* virtual memory */
 	struct radeon_vm_manager	vm_manager;
+	/* 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 158e514..53c519d 100644
--- a/drivers/gpu/drm/radeon/radeon_acpi.c
+++ b/drivers/gpu/drm/radeon/radeon_acpi.c
@@ -13,6 +13,13 @@
 
 #include <linux/vga_switcheroo.h>
 
+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,
@@ -52,12 +59,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 = ATIF_GET_SYSTEM_PARAMETERS_SUPPORTED;
+	f->sbios_requests = ATIF_GET_SYSTEM_BIOS_REQUESTS_SUPPORTED;
+	f->select_active_disp = ATIF_SELECT_ACTIVE_DISPLAYS_SUPPORTED;
+	f->lid_state = ATIF_GET_LID_STATE_SUPPORTED;
+	f->get_tv_standard = ATIF_GET_TV_STANDARD_FROM_CMOS_SUPPORTED;
+	f->set_tv_standard = ATIF_SET_TV_STANDARD_IN_CMOS_SUPPORTED;
+	f->get_panel_expansion_mode = ATIF_GET_PANEL_EXPANSION_MODE_FROM_CMOS_SUPPORTED;
+	f->set_panel_expansion_mode = ATIF_SET_PANEL_EXPANSION_MODE_IN_CMOS_SUPPORTED;
+	f->temperature_change = ATIF_TEMPERATURE_CHANGE_NOTIFICATION_SUPPORTED;
+	f->graphics_device_types = 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);
@@ -67,11 +135,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;
 }
 
-- 
1.7.10.4

-------------- next part --------------
>From e83d04d1b60c5cf46611f6afc9680024e1dad73b Mon Sep 17 00:00:00 2001
From: Luca Tettamanti <kronos.it at gmail.com>
Date: Mon, 30 Jul 2012 21:16:06 +0200
Subject: [PATCH 3/4] 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 <jlee at suse.com>)

Signed-off-by: Luca Tettamanti <kronos.it at gmail.com>
---
 drivers/gpu/drm/radeon/radeon_acpi.c |   84 +++++++++++++++++++++++++++++++++-
 1 file changed, 82 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c
index 53c519d..3d025dd 100644
--- a/drivers/gpu/drm/radeon/radeon_acpi.c
+++ b/drivers/gpu/drm/radeon/radeon_acpi.c
@@ -20,6 +20,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,
@@ -121,10 +133,56 @@ 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(&params, 0, sizeof(params));
+	size = min(sizeof(params), size);
+	memcpy(&params, 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->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 */
@@ -135,10 +193,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;
 }
 
-- 
1.7.10.4

-------------- next part --------------
>From 1d48218e22427dbeeca3e31fd18c78c4fbd35969 Mon Sep 17 00:00:00 2001
From: Luca Tettamanti <kronos.it at gmail.com>
Date: Mon, 30 Jul 2012 21:20:35 +0200
Subject: [PATCH 4/4] drm/radeon: implement handler for ACPI event

Set up an handler for ACPI events and respond to brightness change
requests from the system BIOS.

Signed-off-by: Luca Tettamanti <kronos.it at gmail.com>
---
 drivers/gpu/drm/radeon/atombios_encoders.c |    2 +-
 drivers/gpu/drm/radeon/radeon_acpi.c       |  119 +++++++++++++++++++++++++++-
 drivers/gpu/drm/radeon/radeon_acpi.h       |    6 ++
 drivers/gpu/drm/radeon/radeon_mode.h       |    2 +
 drivers/gpu/drm/radeon/radeon_pm.c         |    4 +-
 5 files changed, 127 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c
index c2d3552..e4152d6 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_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c
index 3d025dd..d1a45e0 100644
--- a/drivers/gpu/drm/radeon/radeon_acpi.c
+++ b/drivers/gpu/drm/radeon/radeon_acpi.c
@@ -3,6 +3,7 @@
 #include <linux/slab.h>
 #include <acpi/acpi_drivers.h>
 #include <acpi/acpi_bus.h>
+#include <acpi/video.h>
 
 #include "drmP.h"
 #include "drm.h"
@@ -10,6 +11,7 @@
 #include "drm_crtc_helper.h"
 #include "radeon.h"
 #include "radeon_acpi.h"
+#include "atom.h"
 
 #include <linux/vga_switcheroo.h>
 
@@ -21,10 +23,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
@@ -32,6 +46,11 @@ struct atif_system_params {
 #define ATIF_NOTIFY_81		1
 #define ATIF_NOTIFY_N		2
 
+struct radeon_atif_sbios_requests {
+	bool brightness_change;
+	int brightness_target;
+};
+
 /* Call the ATIF method
  */
 static union acpi_object *radeon_atif_call(acpi_handle handle, int function,
@@ -178,6 +197,98 @@ out:
 	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);
+
+	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;
+	
+	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 drm_encoder *tmp;
+		struct radeon_encoder *target = NULL;
+
+		DRM_DEBUG_DRIVER("Changing brightness to %d\n",
+				req.backlight_level);
+
+		/* Find the backlight controller */
+		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;
+			}
+		}
+
+		if (target) {
+			struct radeon_encoder_atom_dig *dig = target->enc_priv;
+			dig->backlight_level = req.backlight_level;
+
+			atombios_set_panel_brightness(target);
+
+			backlight_force_update(dig->bl_dev,
+					BACKLIGHT_UPDATE_HOTKEY);
+		} else {
+			/* This should never happen */
+			dev_warn(rdev->dev, "Brightness change requested, "
+					"but not suitable encoder found\n");
+		}
+	}
+	/* TODO: check other events */
+
+	return NOTIFY_OK;
+}
+
 /* Call all ACPI methods here */
 int radeon_acpi_init(struct radeon_device *rdev)
 {
diff --git a/drivers/gpu/drm/radeon/radeon_acpi.h b/drivers/gpu/drm/radeon/radeon_acpi.h
index a42288d..df1f162 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_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 129ed8e..ce91d62 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -697,6 +697,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 5b37e28..8621748 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
@@ -95,7 +96,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
 
-- 
1.7.10.4



More information about the dri-devel mailing list