Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Luca Tettamanti and committed by
Alex Deucher
fda4b25c ce3cf821

+152 -11
+1 -1
drivers/gpu/drm/radeon/atombios_encoders.c
··· 72 72 WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch); 73 73 } 74 74 75 - static void 75 + void 76 76 atombios_set_panel_brightness(struct radeon_encoder *radeon_encoder) 77 77 { 78 78 struct drm_encoder *encoder = &radeon_encoder->base;
+1
drivers/gpu/drm/radeon/radeon.h
··· 1461 1461 struct radeon_atif_notifications notifications; 1462 1462 struct radeon_atif_functions functions; 1463 1463 struct radeon_atif_notification_cfg notification_cfg; 1464 + struct radeon_encoder *backlight_ctl; 1464 1465 }; 1465 1466 1466 1467 /*
+128 -4
drivers/gpu/drm/radeon/radeon_acpi.c
··· 26 26 #include <linux/slab.h> 27 27 #include <acpi/acpi_drivers.h> 28 28 #include <acpi/acpi_bus.h> 29 + #include <acpi/video.h> 29 30 30 31 #include "drmP.h" 31 32 #include "drm.h" ··· 34 33 #include "drm_crtc_helper.h" 35 34 #include "radeon.h" 36 35 #include "radeon_acpi.h" 36 + #include "atom.h" 37 37 38 38 #include <linux/vga_switcheroo.h> 39 39 ··· 46 44 } __packed; 47 45 48 46 struct atif_system_params { 49 - u16 size; 50 - u32 valid_mask; 51 - u32 flags; 52 - u8 command_code; 47 + u16 size; /* structure size in bytes (includes size field) */ 48 + u32 valid_mask; /* valid flags mask */ 49 + u32 flags; /* flags */ 50 + u8 command_code; /* notify command code */ 51 + } __packed; 52 + 53 + struct atif_sbios_requests { 54 + u16 size; /* structure size in bytes (includes size field) */ 55 + u32 pending; /* pending sbios requests */ 56 + u8 panel_exp_mode; /* panel expansion mode */ 57 + u8 thermal_gfx; /* thermal state: target gfx controller */ 58 + u8 thermal_state; /* thermal state: state id (0: exit state, non-0: state) */ 59 + u8 forced_power_gfx; /* forced power state: target gfx controller */ 60 + u8 forced_power_state; /* forced power state: state id */ 61 + u8 system_power_src; /* system power source */ 62 + u8 backlight_level; /* panel backlight level (0-255) */ 53 63 } __packed; 54 64 55 65 #define ATIF_NOTIFY_MASK 0x3 ··· 194 180 size = min(sizeof(params), size); 195 181 memcpy(&params, info->buffer.pointer, size); 196 182 183 + DRM_DEBUG_DRIVER("SYSTEM_PARAMS: mask = %#x, flags = %#x\n", 184 + params.flags, params.valid_mask); 197 185 params.flags = params.flags & params.valid_mask; 198 186 199 187 if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_NONE) { ··· 214 198 } 215 199 216 200 out: 201 + DRM_DEBUG_DRIVER("Notification %s, command code = %#x\n", 202 + (n->enabled ? "enabled" : "disabled"), 203 + n->command_code); 217 204 kfree(info); 218 205 return err; 206 + } 207 + 208 + static int radeon_atif_get_sbios_requests(acpi_handle handle, 209 + struct atif_sbios_requests *req) 210 + { 211 + union acpi_object *info; 212 + size_t size; 213 + int count = 0; 214 + 215 + info = radeon_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS, NULL); 216 + if (!info) 217 + return -EIO; 218 + 219 + size = *(u16 *)info->buffer.pointer; 220 + if (size < 0xd) { 221 + count = -EINVAL; 222 + goto out; 223 + } 224 + memset(req, 0, sizeof(*req)); 225 + 226 + size = min(sizeof(*req), size); 227 + memcpy(req, info->buffer.pointer, size); 228 + DRM_DEBUG_DRIVER("SBIOS pending requests: %#x\n", req->pending); 229 + 230 + count = hweight32(req->pending); 231 + 232 + out: 233 + kfree(info); 234 + return count; 235 + } 236 + 237 + int radeon_atif_handler(struct radeon_device *rdev, 238 + struct acpi_bus_event *event) 239 + { 240 + struct radeon_atif *atif = &rdev->atif; 241 + struct atif_sbios_requests req; 242 + acpi_handle handle; 243 + int count; 244 + 245 + DRM_DEBUG_DRIVER("event, device_class = %s, type = %#x\n", 246 + event->device_class, event->type); 247 + 248 + if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0) 249 + return NOTIFY_DONE; 250 + 251 + if (!atif->notification_cfg.enabled || 252 + event->type != atif->notification_cfg.command_code) 253 + /* Not our event */ 254 + return NOTIFY_DONE; 255 + 256 + /* Check pending SBIOS requests */ 257 + handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev); 258 + count = radeon_atif_get_sbios_requests(handle, &req); 259 + 260 + if (count <= 0) 261 + return NOTIFY_DONE; 262 + 263 + DRM_DEBUG_DRIVER("ATIF: %d pending SBIOS requests\n", count); 264 + 265 + if (req.pending & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST) { 266 + struct radeon_encoder *enc = atif->backlight_ctl; 267 + 268 + if (enc) { 269 + struct radeon_encoder_atom_dig *dig = enc->enc_priv; 270 + dig->backlight_level = req.backlight_level; 271 + 272 + DRM_DEBUG_DRIVER("Changing brightness to %d\n", 273 + req.backlight_level); 274 + 275 + atombios_set_panel_brightness(enc); 276 + 277 + backlight_force_update(dig->bl_dev, 278 + BACKLIGHT_UPDATE_HOTKEY); 279 + } 280 + } 281 + /* TODO: check other events */ 282 + 283 + return NOTIFY_OK; 219 284 } 220 285 221 286 /* Call all ACPI methods here */ ··· 318 221 if (ret) { 319 222 DRM_DEBUG_DRIVER("Call to verify_interface failed: %d\n", ret); 320 223 goto out; 224 + } 225 + 226 + if (atif->notifications.brightness_change) { 227 + struct drm_encoder *tmp; 228 + struct radeon_encoder *target = NULL; 229 + 230 + /* Find the encoder controlling the brightness */ 231 + list_for_each_entry(tmp, &rdev->ddev->mode_config.encoder_list, 232 + head) { 233 + struct radeon_encoder *enc = to_radeon_encoder(tmp); 234 + struct radeon_encoder_atom_dig *dig = enc->enc_priv; 235 + 236 + if ((enc->devices & (ATOM_DEVICE_LCD_SUPPORT)) && 237 + dig->bl_dev != NULL) { 238 + target = enc; 239 + break; 240 + } 241 + } 242 + 243 + atif->backlight_ctl = target; 244 + if (!target) { 245 + /* Brightness change notification is enabled, but we 246 + * didn't find a backlight controller, this should 247 + * never happen. 248 + */ 249 + DRM_ERROR("Cannot find a backlight controller\n"); 250 + } 321 251 } 322 252 323 253 if (atif->functions.sbios_requests && !atif->functions.system_params) {
+6
drivers/gpu/drm/radeon/radeon_acpi.h
··· 24 24 #ifndef RADEON_ACPI_H 25 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 33 /* AMD hw uses four ACPI control methods: 28 34 * 1. ATIF 29 35 * ARG0: (ACPI_INTEGER) function code
+11 -5
drivers/gpu/drm/radeon/radeon_kms.c
··· 103 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 106 /* Again modeset_init should fail only on fatal error 112 107 * otherwise it should provide enough functionalities 113 108 * for shadowfb to run ··· 110 115 r = radeon_modeset_init(rdev); 111 116 if (r) 112 117 dev_err(&dev->pdev->dev, "Fatal error during modeset init\n"); 118 + 119 + /* Call ACPI methods: require modeset init 120 + * but failure is not fatal 121 + */ 122 + if (!r) { 123 + acpi_status = radeon_acpi_init(rdev); 124 + if (acpi_status) 125 + dev_dbg(&dev->pdev->dev, 126 + "Error during ACPI methods call\n"); 127 + } 128 + 113 129 out: 114 130 if (r) 115 131 radeon_driver_unload_kms(dev);
+2
drivers/gpu/drm/radeon/radeon_mode.h
··· 698 698 struct drm_display_mode *adjusted_mode); 699 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 703 /* legacy tv */ 702 704 void radeon_legacy_tv_adjust_crtc_reg(struct drm_encoder *encoder, 703 705 uint32_t *h_total_disp, uint32_t *h_sync_strt_wid,
+3 -1
drivers/gpu/drm/radeon/radeon_pm.c
··· 22 22 */ 23 23 #include "drmP.h" 24 24 #include "radeon.h" 25 + #include "radeon_acpi.h" 25 26 #include "avivod.h" 26 27 #include "atom.h" 27 28 #ifdef CONFIG_ACPI ··· 95 94 } 96 95 } 97 96 98 - return NOTIFY_OK; 97 + /* Check for pending SBIOS requests */ 98 + return radeon_atif_handler(rdev, entry); 99 99 } 100 100 #endif 101 101