diff options
author | Luca Tettamanti <kronos.it@gmail.com> | 2012-07-30 15:20:35 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2012-09-20 13:10:36 -0400 |
commit | fda4b25c55a59ba12378e4b9e4553f6ea57d802d (patch) | |
tree | 931f98eee8fb7f2ebb90e2bd689c7ff34b0b2a4a | |
parent | ce3cf821a31f9824eda788cbd3e710d8047e82df (diff) |
drm/radeon: implement handler for ACPI event
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 <pali.rohar@gmail.com>); 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 <kronos.it@gmail.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r-- | drivers/gpu/drm/radeon/atombios_encoders.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_acpi.c | 132 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_acpi.h | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_kms.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_mode.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_pm.c | 4 |
7 files changed, 152 insertions, 11 deletions
diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index f3645e15ef11..370b2c4a7c86 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, | |||
72 | WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch); | 72 | WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch); |
73 | } | 73 | } |
74 | 74 | ||
75 | static void | 75 | void |
76 | atombios_set_panel_brightness(struct radeon_encoder *radeon_encoder) | 76 | atombios_set_panel_brightness(struct radeon_encoder *radeon_encoder) |
77 | { | 77 | { |
78 | struct drm_encoder *encoder = &radeon_encoder->base; | 78 | struct drm_encoder *encoder = &radeon_encoder->base; |
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 763f3333776e..dea5f08bd23b 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h | |||
@@ -1461,6 +1461,7 @@ struct radeon_atif { | |||
1461 | struct radeon_atif_notifications notifications; | 1461 | struct radeon_atif_notifications notifications; |
1462 | struct radeon_atif_functions functions; | 1462 | struct radeon_atif_functions functions; |
1463 | struct radeon_atif_notification_cfg notification_cfg; | 1463 | struct radeon_atif_notification_cfg notification_cfg; |
1464 | struct radeon_encoder *backlight_ctl; | ||
1464 | }; | 1465 | }; |
1465 | 1466 | ||
1466 | /* | 1467 | /* |
diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index 0454eccc9c03..b052a556db79 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <acpi/acpi_drivers.h> | 27 | #include <acpi/acpi_drivers.h> |
28 | #include <acpi/acpi_bus.h> | 28 | #include <acpi/acpi_bus.h> |
29 | #include <acpi/video.h> | ||
29 | 30 | ||
30 | #include "drmP.h" | 31 | #include "drmP.h" |
31 | #include "drm.h" | 32 | #include "drm.h" |
@@ -33,6 +34,7 @@ | |||
33 | #include "drm_crtc_helper.h" | 34 | #include "drm_crtc_helper.h" |
34 | #include "radeon.h" | 35 | #include "radeon.h" |
35 | #include "radeon_acpi.h" | 36 | #include "radeon_acpi.h" |
37 | #include "atom.h" | ||
36 | 38 | ||
37 | #include <linux/vga_switcheroo.h> | 39 | #include <linux/vga_switcheroo.h> |
38 | 40 | ||
@@ -44,10 +46,22 @@ struct atif_verify_interface { | |||
44 | } __packed; | 46 | } __packed; |
45 | 47 | ||
46 | struct atif_system_params { | 48 | struct atif_system_params { |
47 | u16 size; | 49 | u16 size; /* structure size in bytes (includes size field) */ |
48 | u32 valid_mask; | 50 | u32 valid_mask; /* valid flags mask */ |
49 | u32 flags; | 51 | u32 flags; /* flags */ |
50 | u8 command_code; | 52 | u8 command_code; /* notify command code */ |
53 | } __packed; | ||
54 | |||
55 | struct atif_sbios_requests { | ||
56 | u16 size; /* structure size in bytes (includes size field) */ | ||
57 | u32 pending; /* pending sbios requests */ | ||
58 | u8 panel_exp_mode; /* panel expansion mode */ | ||
59 | u8 thermal_gfx; /* thermal state: target gfx controller */ | ||
60 | u8 thermal_state; /* thermal state: state id (0: exit state, non-0: state) */ | ||
61 | u8 forced_power_gfx; /* forced power state: target gfx controller */ | ||
62 | u8 forced_power_state; /* forced power state: state id */ | ||
63 | u8 system_power_src; /* system power source */ | ||
64 | u8 backlight_level; /* panel backlight level (0-255) */ | ||
51 | } __packed; | 65 | } __packed; |
52 | 66 | ||
53 | #define ATIF_NOTIFY_MASK 0x3 | 67 | #define ATIF_NOTIFY_MASK 0x3 |
@@ -180,6 +194,8 @@ static int radeon_atif_get_notification_params(acpi_handle handle, | |||
180 | size = min(sizeof(params), size); | 194 | size = min(sizeof(params), size); |
181 | memcpy(¶ms, info->buffer.pointer, size); | 195 | memcpy(¶ms, info->buffer.pointer, size); |
182 | 196 | ||
197 | DRM_DEBUG_DRIVER("SYSTEM_PARAMS: mask = %#x, flags = %#x\n", | ||
198 | params.flags, params.valid_mask); | ||
183 | params.flags = params.flags & params.valid_mask; | 199 | params.flags = params.flags & params.valid_mask; |
184 | 200 | ||
185 | if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_NONE) { | 201 | if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_NONE) { |
@@ -198,10 +214,91 @@ static int radeon_atif_get_notification_params(acpi_handle handle, | |||
198 | } | 214 | } |
199 | 215 | ||
200 | out: | 216 | out: |
217 | DRM_DEBUG_DRIVER("Notification %s, command code = %#x\n", | ||
218 | (n->enabled ? "enabled" : "disabled"), | ||
219 | n->command_code); | ||
201 | kfree(info); | 220 | kfree(info); |
202 | return err; | 221 | return err; |
203 | } | 222 | } |
204 | 223 | ||
224 | static int radeon_atif_get_sbios_requests(acpi_handle handle, | ||
225 | struct atif_sbios_requests *req) | ||
226 | { | ||
227 | union acpi_object *info; | ||
228 | size_t size; | ||
229 | int count = 0; | ||
230 | |||
231 | info = radeon_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS, NULL); | ||
232 | if (!info) | ||
233 | return -EIO; | ||
234 | |||
235 | size = *(u16 *)info->buffer.pointer; | ||
236 | if (size < 0xd) { | ||
237 | count = -EINVAL; | ||
238 | goto out; | ||
239 | } | ||
240 | memset(req, 0, sizeof(*req)); | ||
241 | |||
242 | size = min(sizeof(*req), size); | ||
243 | memcpy(req, info->buffer.pointer, size); | ||
244 | DRM_DEBUG_DRIVER("SBIOS pending requests: %#x\n", req->pending); | ||
245 | |||
246 | count = hweight32(req->pending); | ||
247 | |||
248 | out: | ||
249 | kfree(info); | ||
250 | return count; | ||
251 | } | ||
252 | |||
253 | int radeon_atif_handler(struct radeon_device *rdev, | ||
254 | struct acpi_bus_event *event) | ||
255 | { | ||
256 | struct radeon_atif *atif = &rdev->atif; | ||
257 | struct atif_sbios_requests req; | ||
258 | acpi_handle handle; | ||
259 | int count; | ||
260 | |||
261 | DRM_DEBUG_DRIVER("event, device_class = %s, type = %#x\n", | ||
262 | event->device_class, event->type); | ||
263 | |||
264 | if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0) | ||
265 | return NOTIFY_DONE; | ||
266 | |||
267 | if (!atif->notification_cfg.enabled || | ||
268 | event->type != atif->notification_cfg.command_code) | ||
269 | /* Not our event */ | ||
270 | return NOTIFY_DONE; | ||
271 | |||
272 | /* Check pending SBIOS requests */ | ||
273 | handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev); | ||
274 | count = radeon_atif_get_sbios_requests(handle, &req); | ||
275 | |||
276 | if (count <= 0) | ||
277 | return NOTIFY_DONE; | ||
278 | |||
279 | DRM_DEBUG_DRIVER("ATIF: %d pending SBIOS requests\n", count); | ||
280 | |||
281 | if (req.pending & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST) { | ||
282 | struct radeon_encoder *enc = atif->backlight_ctl; | ||
283 | |||
284 | if (enc) { | ||
285 | struct radeon_encoder_atom_dig *dig = enc->enc_priv; | ||
286 | dig->backlight_level = req.backlight_level; | ||
287 | |||
288 | DRM_DEBUG_DRIVER("Changing brightness to %d\n", | ||
289 | req.backlight_level); | ||
290 | |||
291 | atombios_set_panel_brightness(enc); | ||
292 | |||
293 | backlight_force_update(dig->bl_dev, | ||
294 | BACKLIGHT_UPDATE_HOTKEY); | ||
295 | } | ||
296 | } | ||
297 | /* TODO: check other events */ | ||
298 | |||
299 | return NOTIFY_OK; | ||
300 | } | ||
301 | |||
205 | /* Call all ACPI methods here */ | 302 | /* Call all ACPI methods here */ |
206 | int radeon_acpi_init(struct radeon_device *rdev) | 303 | int radeon_acpi_init(struct radeon_device *rdev) |
207 | { | 304 | { |
@@ -223,6 +320,33 @@ int radeon_acpi_init(struct radeon_device *rdev) | |||
223 | goto out; | 320 | goto out; |
224 | } | 321 | } |
225 | 322 | ||
323 | if (atif->notifications.brightness_change) { | ||
324 | struct drm_encoder *tmp; | ||
325 | struct radeon_encoder *target = NULL; | ||
326 | |||
327 | /* Find the encoder controlling the brightness */ | ||
328 | list_for_each_entry(tmp, &rdev->ddev->mode_config.encoder_list, | ||
329 | head) { | ||
330 | struct radeon_encoder *enc = to_radeon_encoder(tmp); | ||
331 | struct radeon_encoder_atom_dig *dig = enc->enc_priv; | ||
332 | |||
333 | if ((enc->devices & (ATOM_DEVICE_LCD_SUPPORT)) && | ||
334 | dig->bl_dev != NULL) { | ||
335 | target = enc; | ||
336 | break; | ||
337 | } | ||
338 | } | ||
339 | |||
340 | atif->backlight_ctl = target; | ||
341 | if (!target) { | ||
342 | /* Brightness change notification is enabled, but we | ||
343 | * didn't find a backlight controller, this should | ||
344 | * never happen. | ||
345 | */ | ||
346 | DRM_ERROR("Cannot find a backlight controller\n"); | ||
347 | } | ||
348 | } | ||
349 | |||
226 | if (atif->functions.sbios_requests && !atif->functions.system_params) { | 350 | if (atif->functions.sbios_requests && !atif->functions.system_params) { |
227 | /* XXX check this workraround, if sbios request function is | 351 | /* XXX check this workraround, if sbios request function is |
228 | * present we have to see how it's configured in the system | 352 | * 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 642aa4719454..be4af76f213d 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.h +++ b/drivers/gpu/drm/radeon/radeon_acpi.h | |||
@@ -24,6 +24,12 @@ | |||
24 | #ifndef RADEON_ACPI_H | 24 | #ifndef RADEON_ACPI_H |
25 | #define RADEON_ACPI_H | 25 | #define RADEON_ACPI_H |
26 | 26 | ||
27 | struct radeon_device; | ||
28 | struct acpi_bus_event; | ||
29 | |||
30 | int radeon_atif_handler(struct radeon_device *rdev, | ||
31 | struct acpi_bus_event *event); | ||
32 | |||
27 | /* AMD hw uses four ACPI control methods: | 33 | /* AMD hw uses four ACPI control methods: |
28 | * 1. ATIF | 34 | * 1. ATIF |
29 | * ARG0: (ACPI_INTEGER) function code | 35 | * ARG0: (ACPI_INTEGER) function code |
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 414b4acf6947..8c2471854cd7 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) | |||
103 | goto out; | 103 | goto out; |
104 | } | 104 | } |
105 | 105 | ||
106 | /* Call ACPI methods */ | ||
107 | acpi_status = radeon_acpi_init(rdev); | ||
108 | if (acpi_status) | ||
109 | dev_dbg(&dev->pdev->dev, "Error during ACPI methods call\n"); | ||
110 | |||
111 | /* Again modeset_init should fail only on fatal error | 106 | /* Again modeset_init should fail only on fatal error |
112 | * otherwise it should provide enough functionalities | 107 | * otherwise it should provide enough functionalities |
113 | * for shadowfb to run | 108 | * for shadowfb to run |
@@ -115,6 +110,17 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags) | |||
115 | r = radeon_modeset_init(rdev); | 110 | r = radeon_modeset_init(rdev); |
116 | if (r) | 111 | if (r) |
117 | dev_err(&dev->pdev->dev, "Fatal error during modeset init\n"); | 112 | dev_err(&dev->pdev->dev, "Fatal error during modeset init\n"); |
113 | |||
114 | /* Call ACPI methods: require modeset init | ||
115 | * but failure is not fatal | ||
116 | */ | ||
117 | if (!r) { | ||
118 | acpi_status = radeon_acpi_init(rdev); | ||
119 | if (acpi_status) | ||
120 | dev_dbg(&dev->pdev->dev, | ||
121 | "Error during ACPI methods call\n"); | ||
122 | } | ||
123 | |||
118 | out: | 124 | out: |
119 | if (r) | 125 | if (r) |
120 | radeon_driver_unload_kms(dev); | 126 | radeon_driver_unload_kms(dev); |
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 5005057974b1..1f411c2609d8 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, | |||
698 | struct drm_display_mode *adjusted_mode); | 698 | struct drm_display_mode *adjusted_mode); |
699 | void atom_rv515_force_tv_scaler(struct radeon_device *rdev, struct radeon_crtc *radeon_crtc); | 699 | void atom_rv515_force_tv_scaler(struct radeon_device *rdev, struct radeon_crtc *radeon_crtc); |
700 | 700 | ||
701 | void atombios_set_panel_brightness(struct radeon_encoder *radeon_encoder); | ||
702 | |||
701 | /* legacy tv */ | 703 | /* legacy tv */ |
702 | void radeon_legacy_tv_adjust_crtc_reg(struct drm_encoder *encoder, | 704 | void radeon_legacy_tv_adjust_crtc_reg(struct drm_encoder *encoder, |
703 | uint32_t *h_total_disp, uint32_t *h_sync_strt_wid, | 705 | 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 2c2c901226f4..14e544e0eb31 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c | |||
@@ -22,6 +22,7 @@ | |||
22 | */ | 22 | */ |
23 | #include "drmP.h" | 23 | #include "drmP.h" |
24 | #include "radeon.h" | 24 | #include "radeon.h" |
25 | #include "radeon_acpi.h" | ||
25 | #include "avivod.h" | 26 | #include "avivod.h" |
26 | #include "atom.h" | 27 | #include "atom.h" |
27 | #ifdef CONFIG_ACPI | 28 | #ifdef CONFIG_ACPI |
@@ -94,7 +95,8 @@ static int radeon_acpi_event(struct notifier_block *nb, | |||
94 | } | 95 | } |
95 | } | 96 | } |
96 | 97 | ||
97 | return NOTIFY_OK; | 98 | /* Check for pending SBIOS requests */ |
99 | return radeon_atif_handler(rdev, entry); | ||
98 | } | 100 | } |
99 | #endif | 101 | #endif |
100 | 102 | ||