Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 | /* * 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 <linux/pci.h> #include <linux/acpi.h> #include <linux/slab.h> #include <linux/power_supply.h> #include <acpi/acpi_drivers.h> #include <acpi/acpi_bus.h> #include <acpi/video.h> #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> #include "radeon.h" #include "radeon_acpi.h" #include "atom.h" #include <linux/vga_switcheroo.h> #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 */ u32 notification_mask; /* supported notifications mask */ u32 function_bits; /* supported functions bit vector */ } __packed; struct atif_system_params { 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 #define ATIF_NOTIFY_NONE 0 #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 */ /** * 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) { acpi_status status; union acpi_object atif_arg_elements[2]; struct acpi_object_list atif_arg; 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 = 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); /* 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 ATIF got %s\n", acpi_format_exception(status)); kfree(buffer.pointer); return NULL; } 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; 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; } /** * 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; 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; } /** * 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) { 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: %zu\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; } /** * 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) { 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); 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) { 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: DRM_DEBUG_DRIVER("Notification %s, command code = %#x\n", (n->enabled ? "enabled" : "disabled"), n->command_code); kfree(info); 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) { 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; } /** * 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) { 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->encoder_for_bl; if (enc) { DRM_DEBUG_DRIVER("Changing brightness to %d\n", req.backlight_level); radeon_set_backlight_level(rdev, enc, req.backlight_level); #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) 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); } #endif } } /* TODO: check other events */ /* 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; } /* 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: %zu\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 * * @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) { 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 */ /** * 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; struct radeon_atif *atif = &rdev->atif; struct radeon_atcs *atcs = &rdev->atcs; int ret; /* Get the device handle */ handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev); /* No need to proceed if we're sure that ATIF is not supported */ 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 ATIF verify_interface failed: %d\n", ret); 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); if ((enc->devices & (ATOM_DEVICE_LCD_SUPPORT)) && 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->encoder_for_bl = 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 * 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: rdev->acpi_nb.notifier_call = radeon_acpi_event; register_acpi_notifier(&rdev->acpi_nb); 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); } |