linux/drivers/gpu/drm/radeon/radeon_atpx_handler.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2010 Red Hat Inc.
   3 * Author : Dave Airlie <airlied@redhat.com>
   4 *
   5 * Licensed under GPLv2
   6 *
   7 * ATPX support for both Intel/ATI
   8 */
   9#include <linux/vga_switcheroo.h>
  10#include <linux/slab.h>
  11#include <linux/acpi.h>
  12#include <linux/pci.h>
  13#include <linux/delay.h>
  14
  15#include "radeon_acpi.h"
  16
  17struct radeon_atpx_functions {
  18        bool px_params;
  19        bool power_cntl;
  20        bool disp_mux_cntl;
  21        bool i2c_mux_cntl;
  22        bool switch_start;
  23        bool switch_end;
  24        bool disp_connectors_mapping;
  25        bool disp_detetion_ports;
  26};
  27
  28struct radeon_atpx {
  29        acpi_handle handle;
  30        struct radeon_atpx_functions functions;
  31        bool is_hybrid;
  32        bool dgpu_req_power_for_displays;
  33};
  34
  35static struct radeon_atpx_priv {
  36        bool atpx_detected;
  37        bool bridge_pm_usable;
  38        /* handle for device - and atpx */
  39        acpi_handle dhandle;
  40        struct radeon_atpx atpx;
  41} radeon_atpx_priv;
  42
  43struct atpx_verify_interface {
  44        u16 size;               /* structure size in bytes (includes size field) */
  45        u16 version;            /* version */
  46        u32 function_bits;      /* supported functions bit vector */
  47} __packed;
  48
  49struct atpx_px_params {
  50        u16 size;               /* structure size in bytes (includes size field) */
  51        u32 valid_flags;        /* which flags are valid */
  52        u32 flags;              /* flags */
  53} __packed;
  54
  55struct atpx_power_control {
  56        u16 size;
  57        u8 dgpu_state;
  58} __packed;
  59
  60struct atpx_mux {
  61        u16 size;
  62        u16 mux;
  63} __packed;
  64
  65bool radeon_has_atpx(void) {
  66        return radeon_atpx_priv.atpx_detected;
  67}
  68
  69bool radeon_has_atpx_dgpu_power_cntl(void) {
  70        return radeon_atpx_priv.atpx.functions.power_cntl;
  71}
  72
  73bool radeon_is_atpx_hybrid(void) {
  74        return radeon_atpx_priv.atpx.is_hybrid;
  75}
  76
  77bool radeon_atpx_dgpu_req_power_for_displays(void) {
  78        return radeon_atpx_priv.atpx.dgpu_req_power_for_displays;
  79}
  80
  81/**
  82 * radeon_atpx_call - call an ATPX method
  83 *
  84 * @handle: acpi handle
  85 * @function: the ATPX function to execute
  86 * @params: ATPX function params
  87 *
  88 * Executes the requested ATPX function (all asics).
  89 * Returns a pointer to the acpi output buffer.
  90 */
  91static union acpi_object *radeon_atpx_call(acpi_handle handle, int function,
  92                                           struct acpi_buffer *params)
  93{
  94        acpi_status status;
  95        union acpi_object atpx_arg_elements[2];
  96        struct acpi_object_list atpx_arg;
  97        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
  98
  99        atpx_arg.count = 2;
 100        atpx_arg.pointer = &atpx_arg_elements[0];
 101
 102        atpx_arg_elements[0].type = ACPI_TYPE_INTEGER;
 103        atpx_arg_elements[0].integer.value = function;
 104
 105        if (params) {
 106                atpx_arg_elements[1].type = ACPI_TYPE_BUFFER;
 107                atpx_arg_elements[1].buffer.length = params->length;
 108                atpx_arg_elements[1].buffer.pointer = params->pointer;
 109        } else {
 110                /* We need a second fake parameter */
 111                atpx_arg_elements[1].type = ACPI_TYPE_INTEGER;
 112                atpx_arg_elements[1].integer.value = 0;
 113        }
 114
 115        status = acpi_evaluate_object(handle, NULL, &atpx_arg, &buffer);
 116
 117        /* Fail only if calling the method fails and ATPX is supported */
 118        if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
 119                printk("failed to evaluate ATPX got %s\n",
 120                       acpi_format_exception(status));
 121                kfree(buffer.pointer);
 122                return NULL;
 123        }
 124
 125        return buffer.pointer;
 126}
 127
 128/**
 129 * radeon_atpx_parse_functions - parse supported functions
 130 *
 131 * @f: supported functions struct
 132 * @mask: supported functions mask from ATPX
 133 *
 134 * Use the supported functions mask from ATPX function
 135 * ATPX_FUNCTION_VERIFY_INTERFACE to determine what functions
 136 * are supported (all asics).
 137 */
 138static void radeon_atpx_parse_functions(struct radeon_atpx_functions *f, u32 mask)
 139{
 140        f->px_params = mask & ATPX_GET_PX_PARAMETERS_SUPPORTED;
 141        f->power_cntl = mask & ATPX_POWER_CONTROL_SUPPORTED;
 142        f->disp_mux_cntl = mask & ATPX_DISPLAY_MUX_CONTROL_SUPPORTED;
 143        f->i2c_mux_cntl = mask & ATPX_I2C_MUX_CONTROL_SUPPORTED;
 144        f->switch_start = mask & ATPX_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION_SUPPORTED;
 145        f->switch_end = mask & ATPX_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION_SUPPORTED;
 146        f->disp_connectors_mapping = mask & ATPX_GET_DISPLAY_CONNECTORS_MAPPING_SUPPORTED;
 147        f->disp_detetion_ports = mask & ATPX_GET_DISPLAY_DETECTION_PORTS_SUPPORTED;
 148}
 149
 150/**
 151 * radeon_atpx_validate_functions - validate ATPX functions
 152 *
 153 * @atpx: radeon atpx struct
 154 *
 155 * Validate that required functions are enabled (all asics).
 156 * returns 0 on success, error on failure.
 157 */
 158static int radeon_atpx_validate(struct radeon_atpx *atpx)
 159{
 160        u32 valid_bits = 0;
 161
 162        if (atpx->functions.px_params) {
 163                union acpi_object *info;
 164                struct atpx_px_params output;
 165                size_t size;
 166
 167                info = radeon_atpx_call(atpx->handle, ATPX_FUNCTION_GET_PX_PARAMETERS, NULL);
 168                if (!info)
 169                        return -EIO;
 170
 171                memset(&output, 0, sizeof(output));
 172
 173                size = *(u16 *) info->buffer.pointer;
 174                if (size < 10) {
 175                        printk("ATPX buffer is too small: %zu\n", size);
 176                        kfree(info);
 177                        return -EINVAL;
 178                }
 179                size = min(sizeof(output), size);
 180
 181                memcpy(&output, info->buffer.pointer, size);
 182
 183                valid_bits = output.flags & output.valid_flags;
 184
 185                kfree(info);
 186        }
 187
 188        /* if separate mux flag is set, mux controls are required */
 189        if (valid_bits & ATPX_SEPARATE_MUX_FOR_I2C) {
 190                atpx->functions.i2c_mux_cntl = true;
 191                atpx->functions.disp_mux_cntl = true;
 192        }
 193        /* if any outputs are muxed, mux controls are required */
 194        if (valid_bits & (ATPX_CRT1_RGB_SIGNAL_MUXED |
 195                          ATPX_TV_SIGNAL_MUXED |
 196                          ATPX_DFP_SIGNAL_MUXED))
 197                atpx->functions.disp_mux_cntl = true;
 198
 199        /* some bioses set these bits rather than flagging power_cntl as supported */
 200        if (valid_bits & (ATPX_DYNAMIC_PX_SUPPORTED |
 201                          ATPX_DYNAMIC_DGPU_POWER_OFF_SUPPORTED))
 202                atpx->functions.power_cntl = true;
 203
 204        atpx->is_hybrid = false;
 205        if (valid_bits & ATPX_MS_HYBRID_GFX_SUPPORTED) {
 206                printk("ATPX Hybrid Graphics\n");
 207                /*
 208                 * Disable legacy PM methods only when pcie port PM is usable,
 209                 * otherwise the device might fail to power off or power on.
 210                 */
 211                atpx->functions.power_cntl = !radeon_atpx_priv.bridge_pm_usable;
 212                atpx->is_hybrid = true;
 213        }
 214
 215        return 0;
 216}
 217
 218/**
 219 * radeon_atpx_verify_interface - verify ATPX
 220 *
 221 * @atpx: radeon atpx struct
 222 *
 223 * Execute the ATPX_FUNCTION_VERIFY_INTERFACE ATPX function
 224 * to initialize ATPX and determine what features are supported
 225 * (all asics).
 226 * returns 0 on success, error on failure.
 227 */
 228static int radeon_atpx_verify_interface(struct radeon_atpx *atpx)
 229{
 230        union acpi_object *info;
 231        struct atpx_verify_interface output;
 232        size_t size;
 233        int err = 0;
 234
 235        info = radeon_atpx_call(atpx->handle, ATPX_FUNCTION_VERIFY_INTERFACE, NULL);
 236        if (!info)
 237                return -EIO;
 238
 239        memset(&output, 0, sizeof(output));
 240
 241        size = *(u16 *) info->buffer.pointer;
 242        if (size < 8) {
 243                printk("ATPX buffer is too small: %zu\n", size);
 244                err = -EINVAL;
 245                goto out;
 246        }
 247        size = min(sizeof(output), size);
 248
 249        memcpy(&output, info->buffer.pointer, size);
 250
 251        /* TODO: check version? */
 252        printk("ATPX version %u, functions 0x%08x\n",
 253               output.version, output.function_bits);
 254
 255        radeon_atpx_parse_functions(&atpx->functions, output.function_bits);
 256
 257out:
 258        kfree(info);
 259        return err;
 260}
 261
 262/**
 263 * radeon_atpx_set_discrete_state - power up/down discrete GPU
 264 *
 265 * @atpx: atpx info struct
 266 * @state: discrete GPU state (0 = power down, 1 = power up)
 267 *
 268 * Execute the ATPX_FUNCTION_POWER_CONTROL ATPX function to
 269 * power down/up the discrete GPU (all asics).
 270 * Returns 0 on success, error on failure.
 271 */
 272static int radeon_atpx_set_discrete_state(struct radeon_atpx *atpx, u8 state)
 273{
 274        struct acpi_buffer params;
 275        union acpi_object *info;
 276        struct atpx_power_control input;
 277
 278        if (atpx->functions.power_cntl) {
 279                input.size = 3;
 280                input.dgpu_state = state;
 281                params.length = input.size;
 282                params.pointer = &input;
 283                info = radeon_atpx_call(atpx->handle,
 284                                        ATPX_FUNCTION_POWER_CONTROL,
 285                                        &params);
 286                if (!info)
 287                        return -EIO;
 288                kfree(info);
 289
 290                /* 200ms delay is required after off */
 291                if (state == 0)
 292                        msleep(200);
 293        }
 294        return 0;
 295}
 296
 297/**
 298 * radeon_atpx_switch_disp_mux - switch display mux
 299 *
 300 * @atpx: atpx info struct
 301 * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU)
 302 *
 303 * Execute the ATPX_FUNCTION_DISPLAY_MUX_CONTROL ATPX function to
 304 * switch the display mux between the discrete GPU and integrated GPU
 305 * (all asics).
 306 * Returns 0 on success, error on failure.
 307 */
 308static int radeon_atpx_switch_disp_mux(struct radeon_atpx *atpx, u16 mux_id)
 309{
 310        struct acpi_buffer params;
 311        union acpi_object *info;
 312        struct atpx_mux input;
 313
 314        if (atpx->functions.disp_mux_cntl) {
 315                input.size = 4;
 316                input.mux = mux_id;
 317                params.length = input.size;
 318                params.pointer = &input;
 319                info = radeon_atpx_call(atpx->handle,
 320                                        ATPX_FUNCTION_DISPLAY_MUX_CONTROL,
 321                                        &params);
 322                if (!info)
 323                        return -EIO;
 324                kfree(info);
 325        }
 326        return 0;
 327}
 328
 329/**
 330 * radeon_atpx_switch_i2c_mux - switch i2c/hpd mux
 331 *
 332 * @atpx: atpx info struct
 333 * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU)
 334 *
 335 * Execute the ATPX_FUNCTION_I2C_MUX_CONTROL ATPX function to
 336 * switch the i2c/hpd mux between the discrete GPU and integrated GPU
 337 * (all asics).
 338 * Returns 0 on success, error on failure.
 339 */
 340static int radeon_atpx_switch_i2c_mux(struct radeon_atpx *atpx, u16 mux_id)
 341{
 342        struct acpi_buffer params;
 343        union acpi_object *info;
 344        struct atpx_mux input;
 345
 346        if (atpx->functions.i2c_mux_cntl) {
 347                input.size = 4;
 348                input.mux = mux_id;
 349                params.length = input.size;
 350                params.pointer = &input;
 351                info = radeon_atpx_call(atpx->handle,
 352                                        ATPX_FUNCTION_I2C_MUX_CONTROL,
 353                                        &params);
 354                if (!info)
 355                        return -EIO;
 356                kfree(info);
 357        }
 358        return 0;
 359}
 360
 361/**
 362 * radeon_atpx_switch_start - notify the sbios of a GPU switch
 363 *
 364 * @atpx: atpx info struct
 365 * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU)
 366 *
 367 * Execute the ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION ATPX
 368 * function to notify the sbios that a switch between the discrete GPU and
 369 * integrated GPU has begun (all asics).
 370 * Returns 0 on success, error on failure.
 371 */
 372static int radeon_atpx_switch_start(struct radeon_atpx *atpx, u16 mux_id)
 373{
 374        struct acpi_buffer params;
 375        union acpi_object *info;
 376        struct atpx_mux input;
 377
 378        if (atpx->functions.switch_start) {
 379                input.size = 4;
 380                input.mux = mux_id;
 381                params.length = input.size;
 382                params.pointer = &input;
 383                info = radeon_atpx_call(atpx->handle,
 384                                        ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION,
 385                                        &params);
 386                if (!info)
 387                        return -EIO;
 388                kfree(info);
 389        }
 390        return 0;
 391}
 392
 393/**
 394 * radeon_atpx_switch_end - notify the sbios of a GPU switch
 395 *
 396 * @atpx: atpx info struct
 397 * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU)
 398 *
 399 * Execute the ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION ATPX
 400 * function to notify the sbios that a switch between the discrete GPU and
 401 * integrated GPU has ended (all asics).
 402 * Returns 0 on success, error on failure.
 403 */
 404static int radeon_atpx_switch_end(struct radeon_atpx *atpx, u16 mux_id)
 405{
 406        struct acpi_buffer params;
 407        union acpi_object *info;
 408        struct atpx_mux input;
 409
 410        if (atpx->functions.switch_end) {
 411                input.size = 4;
 412                input.mux = mux_id;
 413                params.length = input.size;
 414                params.pointer = &input;
 415                info = radeon_atpx_call(atpx->handle,
 416                                        ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION,
 417                                        &params);
 418                if (!info)
 419                        return -EIO;
 420                kfree(info);
 421        }
 422        return 0;
 423}
 424
 425/**
 426 * radeon_atpx_switchto - switch to the requested GPU
 427 *
 428 * @id: GPU to switch to
 429 *
 430 * Execute the necessary ATPX functions to switch between the discrete GPU and
 431 * integrated GPU (all asics).
 432 * Returns 0 on success, error on failure.
 433 */
 434static int radeon_atpx_switchto(enum vga_switcheroo_client_id id)
 435{
 436        u16 gpu_id;
 437
 438        if (id == VGA_SWITCHEROO_IGD)
 439                gpu_id = ATPX_INTEGRATED_GPU;
 440        else
 441                gpu_id = ATPX_DISCRETE_GPU;
 442
 443        radeon_atpx_switch_start(&radeon_atpx_priv.atpx, gpu_id);
 444        radeon_atpx_switch_disp_mux(&radeon_atpx_priv.atpx, gpu_id);
 445        radeon_atpx_switch_i2c_mux(&radeon_atpx_priv.atpx, gpu_id);
 446        radeon_atpx_switch_end(&radeon_atpx_priv.atpx, gpu_id);
 447
 448        return 0;
 449}
 450
 451/**
 452 * radeon_atpx_power_state - power down/up the requested GPU
 453 *
 454 * @id: GPU to power down/up
 455 * @state: requested power state (0 = off, 1 = on)
 456 *
 457 * Execute the necessary ATPX function to power down/up the discrete GPU
 458 * (all asics).
 459 * Returns 0 on success, error on failure.
 460 */
 461static int radeon_atpx_power_state(enum vga_switcheroo_client_id id,
 462                                   enum vga_switcheroo_state state)
 463{
 464        /* on w500 ACPI can't change intel gpu state */
 465        if (id == VGA_SWITCHEROO_IGD)
 466                return 0;
 467
 468        radeon_atpx_set_discrete_state(&radeon_atpx_priv.atpx, state);
 469        return 0;
 470}
 471
 472/**
 473 * radeon_atpx_pci_probe_handle - look up the ATPX handle
 474 *
 475 * @pdev: pci device
 476 *
 477 * Look up the ATPX handles (all asics).
 478 * Returns true if the handles are found, false if not.
 479 */
 480static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev)
 481{
 482        acpi_handle dhandle, atpx_handle;
 483        acpi_status status;
 484
 485        dhandle = ACPI_HANDLE(&pdev->dev);
 486        if (!dhandle)
 487                return false;
 488
 489        status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
 490        if (ACPI_FAILURE(status))
 491                return false;
 492
 493        radeon_atpx_priv.dhandle = dhandle;
 494        radeon_atpx_priv.atpx.handle = atpx_handle;
 495        return true;
 496}
 497
 498/**
 499 * radeon_atpx_init - verify the ATPX interface
 500 *
 501 * Verify the ATPX interface (all asics).
 502 * Returns 0 on success, error on failure.
 503 */
 504static int radeon_atpx_init(void)
 505{
 506        int r;
 507
 508        /* set up the ATPX handle */
 509        r = radeon_atpx_verify_interface(&radeon_atpx_priv.atpx);
 510        if (r)
 511                return r;
 512
 513        /* validate the atpx setup */
 514        r = radeon_atpx_validate(&radeon_atpx_priv.atpx);
 515        if (r)
 516                return r;
 517
 518        return 0;
 519}
 520
 521/**
 522 * radeon_atpx_get_client_id - get the client id
 523 *
 524 * @pdev: pci device
 525 *
 526 * look up whether we are the integrated or discrete GPU (all asics).
 527 * Returns the client id.
 528 */
 529static int radeon_atpx_get_client_id(struct pci_dev *pdev)
 530{
 531        if (radeon_atpx_priv.dhandle == ACPI_HANDLE(&pdev->dev))
 532                return VGA_SWITCHEROO_IGD;
 533        else
 534                return VGA_SWITCHEROO_DIS;
 535}
 536
 537static const struct vga_switcheroo_handler radeon_atpx_handler = {
 538        .switchto = radeon_atpx_switchto,
 539        .power_state = radeon_atpx_power_state,
 540        .get_client_id = radeon_atpx_get_client_id,
 541};
 542
 543/**
 544 * radeon_atpx_detect - detect whether we have PX
 545 *
 546 * Check if we have a PX system (all asics).
 547 * Returns true if we have a PX system, false if not.
 548 */
 549static bool radeon_atpx_detect(void)
 550{
 551        char acpi_method_name[255] = { 0 };
 552        struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
 553        struct pci_dev *pdev = NULL;
 554        bool has_atpx = false;
 555        int vga_count = 0;
 556        bool d3_supported = false;
 557        struct pci_dev *parent_pdev;
 558
 559        while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
 560                vga_count++;
 561
 562                has_atpx |= (radeon_atpx_pci_probe_handle(pdev) == true);
 563
 564                parent_pdev = pci_upstream_bridge(pdev);
 565                d3_supported |= parent_pdev && parent_pdev->bridge_d3;
 566        }
 567
 568        /* some newer PX laptops mark the dGPU as a non-VGA display device */
 569        while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) {
 570                vga_count++;
 571
 572                has_atpx |= (radeon_atpx_pci_probe_handle(pdev) == true);
 573
 574                parent_pdev = pci_upstream_bridge(pdev);
 575                d3_supported |= parent_pdev && parent_pdev->bridge_d3;
 576        }
 577
 578        if (has_atpx && vga_count == 2) {
 579                acpi_get_name(radeon_atpx_priv.atpx.handle, ACPI_FULL_PATHNAME, &buffer);
 580                pr_info("vga_switcheroo: detected switching method %s handle\n",
 581                        acpi_method_name);
 582                radeon_atpx_priv.atpx_detected = true;
 583                radeon_atpx_priv.bridge_pm_usable = d3_supported;
 584                radeon_atpx_init();
 585                return true;
 586        }
 587        return false;
 588}
 589
 590/**
 591 * radeon_register_atpx_handler - register with vga_switcheroo
 592 *
 593 * Register the PX callbacks with vga_switcheroo (all asics).
 594 */
 595void radeon_register_atpx_handler(void)
 596{
 597        bool r;
 598        enum vga_switcheroo_handler_flags_t handler_flags = 0;
 599
 600        /* detect if we have any ATPX + 2 VGA in the system */
 601        r = radeon_atpx_detect();
 602        if (!r)
 603                return;
 604
 605        vga_switcheroo_register_handler(&radeon_atpx_handler, handler_flags);
 606}
 607
 608/**
 609 * radeon_unregister_atpx_handler - unregister with vga_switcheroo
 610 *
 611 * Unregister the PX callbacks with vga_switcheroo (all asics).
 612 */
 613void radeon_unregister_atpx_handler(void)
 614{
 615        vga_switcheroo_unregister_handler();
 616}
 617