>From 1d48218e22427dbeeca3e31fd18c78c4fbd35969 Mon Sep 17 00:00:00 2001 From: Luca Tettamanti 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 --- 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 #include #include +#include #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 @@ -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